X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=5840fead943049a6ac2a26eb4e784253ad3bcffb;hb=a36b529752778f519b27e62582d1b2a758ce48d6;hp=8f9c206f108c66c6c23bb0fc006ecc13caa20532;hpb=b6f3d0a5fa6cf6036d317d3ff47e5252be47bc40;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 8f9c206f..5840fead 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -11,42 +11,48 @@ //! nodes for functional tests. use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, chainmonitor::Persist}; -use crate::sign::EntropySource; use crate::chain::channelmonitor::ChannelMonitor; use crate::chain::transaction::OutPoint; use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason}; use crate::events::bump_transaction::{BumpTransactionEvent, BumpTransactionEventHandler, Wallet, WalletSource}; use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA}; -use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate}; -use crate::routing::router::{self, PaymentParameters, Route, RouteParameters}; use crate::ln::features::InitFeatures; use crate::ln::msgs; -use crate::ln::msgs::{ChannelMessageHandler,RoutingMessageHandler}; -use crate::util::test_channel_signer::TestChannelSigner; +use crate::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMessageHandler}; +use crate::ln::peer_handler::IgnoringMessageHandler; +use crate::onion_message::messenger::OnionMessenger; +use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate}; +use crate::routing::router::{self, PaymentParameters, Route, RouteParameters}; +use crate::sign::{EntropySource, RandomBytes}; +use crate::util::config::{UserConfig, MaxDustHTLCExposure}; +use crate::util::errors::APIError; +#[cfg(test)] +use crate::util::logger::Logger; use crate::util::scid_utils; +use crate::util::test_channel_signer::TestChannelSigner; use crate::util::test_utils; use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface}; -use crate::util::errors::APIError; -use crate::util::config::{UserConfig, MaxDustHTLCExposure}; use crate::util::ser::{ReadableArgs, Writeable}; -use bitcoin::blockdata::block::{Block, BlockHeader}; -use bitcoin::blockdata::transaction::{Transaction, TxOut}; -use bitcoin::hash_types::BlockHash; +use bitcoin::blockdata::block::{Block, Header, Version}; +use bitcoin::blockdata::locktime::absolute::LockTime; +use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut}; +use bitcoin::hash_types::{BlockHash, TxMerkleNode}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash as _; use bitcoin::network::constants::Network; +use bitcoin::pow::CompactTarget; use bitcoin::secp256k1::{PublicKey, SecretKey}; +use alloc::rc::Rc; +use core::cell::RefCell; +use core::iter::repeat; +use core::mem; +use core::ops::Deref; use crate::io; use crate::prelude::*; -use core::cell::RefCell; -use alloc::rc::Rc; use crate::sync::{Arc, Mutex, LockTestExt, RwLock}; -use core::mem; -use core::iter::repeat; -use bitcoin::{PackedLockTime, TxIn, TxMerkleNode}; pub const CHAN_CONFIRM_DEPTH: u32 = 10; @@ -78,11 +84,18 @@ pub fn mine_transactions<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: &[&Tra pub fn mine_transaction_without_consistency_checks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) { let height = node.best_block_info().1 + 1; let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 }, + header: Header { + version: Version::NO_SOFT_FORK_SIGNALLING, + prev_blockhash: node.best_block_hash(), + merkle_root: TxMerkleNode::all_zeros(), + time: height, + bits: CompactTarget::from_consensus(42), + nonce: 42, + }, txdata: Vec::new(), }; for _ in 0..*node.network_chan_count.borrow() { // Make sure we don't end up with channels at the same short id by offsetting by chan_count - block.txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); + block.txdata.push(Transaction { version: 0, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }); } block.txdata.push((*tx).clone()); do_connect_block_without_consistency_checks(node, block, false); @@ -100,7 +113,7 @@ pub fn confirm_transactions_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: } let mut txdata = Vec::new(); for _ in 0..*node.network_chan_count.borrow() { // Make sure we don't end up with channels at the same short id by offsetting by chan_count - txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); + txdata.push(Transaction { version: 0, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }); } for tx in txn { txdata.push((*tx).clone()); @@ -202,13 +215,13 @@ impl ConnectStyle { } } -pub fn create_dummy_header(prev_blockhash: BlockHash, time: u32) -> BlockHeader { - BlockHeader { - version: 0x2000_0000, +pub fn create_dummy_header(prev_blockhash: BlockHash, time: u32) -> Header { + Header { + version: Version::NO_SOFT_FORK_SIGNALLING, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time, - bits: 42, + bits: CompactTarget::from_consensus(42), nonce: 42, } } @@ -239,7 +252,7 @@ pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block) fn call_claimable_balances<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>) { // Ensure `get_claimable_balances`' self-tests never panic - for funding_outpoint in node.chain_monitor.chain_monitor.list_monitors() { + for (funding_outpoint, _channel_id) in node.chain_monitor.chain_monitor.list_monitors() { node.chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances(); } } @@ -378,6 +391,7 @@ pub struct NodeCfg<'a> { pub tx_broadcaster: &'a test_utils::TestBroadcaster, pub fee_estimator: &'a test_utils::TestFeeEstimator, pub router: test_utils::TestRouter<'a>, + pub message_router: test_utils::TestMessageRouter<'a>, pub chain_monitor: test_utils::TestChainMonitor<'a>, pub keys_manager: &'a test_utils::TestKeysInterface, pub logger: &'a test_utils::TestLogger, @@ -397,6 +411,26 @@ type TestChannelManager<'node_cfg, 'chan_mon_cfg> = ChannelManager< &'chan_mon_cfg test_utils::TestLogger, >; +type TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg> = OnionMessenger< + DedicatedEntropy, + &'node_cfg test_utils::TestKeysInterface, + &'chan_mon_cfg test_utils::TestLogger, + &'node_cfg test_utils::TestMessageRouter<'chan_mon_cfg>, + &'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>, + IgnoringMessageHandler, +>; + +/// For use with [`OnionMessenger`] otherwise `test_restored_packages_retry` will fail. This is +/// because that test uses older serialized data produced by calling [`EntropySource`] in a specific +/// manner. Using the same [`EntropySource`] with [`OnionMessenger`] would introduce another call, +/// causing the produced data to no longer match. +pub struct DedicatedEntropy(RandomBytes); + +impl Deref for DedicatedEntropy { + type Target = RandomBytes; + fn deref(&self) -> &Self::Target { &self.0 } +} + pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> { pub chain_source: &'chan_mon_cfg test_utils::TestChainSource, pub tx_broadcaster: &'chan_mon_cfg test_utils::TestBroadcaster, @@ -405,6 +439,7 @@ pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> { pub chain_monitor: &'node_cfg test_utils::TestChainMonitor<'chan_mon_cfg>, pub keys_manager: &'chan_mon_cfg test_utils::TestKeysInterface, pub node: &'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>, + pub onion_messenger: TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg>, pub network_graph: &'node_cfg NetworkGraph<&'chan_mon_cfg test_utils::TestLogger>, pub gossip_sync: P2PGossipSync<&'node_cfg NetworkGraph<&'chan_mon_cfg test_utils::TestLogger>, &'chan_mon_cfg test_utils::TestChainSource, &'chan_mon_cfg test_utils::TestLogger>, pub node_seed: [u8; 32], @@ -422,6 +457,14 @@ pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> { &'chan_mon_cfg test_utils::TestLogger, >, } + +impl<'a, 'b, 'c> Node<'a, 'b, 'c> { + pub fn init_features(&self, peer_node_id: &PublicKey) -> InitFeatures { + self.override_init_features.borrow().clone() + .unwrap_or_else(|| self.node.init_features() | self.onion_messenger.provided_init_features(peer_node_id)) + } +} + #[cfg(feature = "std")] impl<'a, 'b, 'c> std::panic::UnwindSafe for Node<'a, 'b, 'c> {} #[cfg(feature = "std")] @@ -433,9 +476,50 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> { pub fn best_block_info(&self) -> (BlockHash, u32) { self.blocks.lock().unwrap().last().map(|(a, b)| (a.block_hash(), *b)).unwrap() } - pub fn get_block_header(&self, height: u32) -> BlockHeader { + pub fn get_block_header(&self, height: u32) -> Header { self.blocks.lock().unwrap()[height as usize].0.header } + /// Changes the channel signer's availability for the specified peer and channel. + /// + /// When `available` is set to `true`, the channel signer will behave normally. When set to + /// `false`, the channel signer will act like an off-line remote signer and will return `Err` for + /// several of the signing methods. Currently, only `get_per_commitment_point` and + /// `release_commitment_secret` are affected by this setting. + #[cfg(test)] + pub fn set_channel_signer_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, available: bool) { + use crate::sign::ChannelSigner; + log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available); + + let per_peer_state = self.node.per_peer_state.read().unwrap(); + let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap(); + + let mut channel_keys_id = None; + if let Some(chan) = chan_lock.channel_by_id.get(chan_id).map(|phase| phase.context()) { + chan.get_signer().as_ecdsa().unwrap().set_available(available); + channel_keys_id = Some(chan.channel_keys_id); + } + + let mut monitor = None; + for (funding_txo, channel_id) in self.chain_monitor.chain_monitor.list_monitors() { + if *chan_id == channel_id { + monitor = self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok(); + } + } + if let Some(monitor) = monitor { + monitor.do_signer_call(|signer| { + channel_keys_id = channel_keys_id.or(Some(signer.inner.channel_keys_id())); + signer.set_available(available) + }); + } + + if available { + self.keys_manager.unavailable_signers.lock().unwrap() + .remove(channel_keys_id.as_ref().unwrap()); + } else { + self.keys_manager.unavailable_signers.lock().unwrap() + .insert(channel_keys_id.unwrap()); + } + } } /// If we need an unsafe pointer to a `Node` (ie to reference it in a thread @@ -539,7 +623,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { let feeest = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }; let mut deserialized_monitors = Vec::new(); { - for outpoint in self.chain_monitor.chain_monitor.list_monitors() { + for (outpoint, _channel_id) in self.chain_monitor.chain_monitor.list_monitors() { let mut w = test_utils::TestVecWriter(Vec::new()); self.chain_monitor.chain_monitor.get_monitor(outpoint).unwrap().write(&mut w).unwrap(); let (_, deserialized_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -556,7 +640,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { // Before using all the new monitors to check the watch outpoints, use the full set of // them to ensure we can write and reload our ChannelManager. { - let mut channel_monitors = HashMap::new(); + let mut channel_monitors = new_hash_map(); for monitor in deserialized_monitors.iter_mut() { channel_monitors.insert(monitor.get_funding_txo().0, monitor); } @@ -570,7 +654,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { node_signer: self.keys_manager, signer_provider: self.keys_manager, fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, - router: &test_utils::TestRouter::new(Arc::new(network_graph), &scorer), + router: &test_utils::TestRouter::new(Arc::new(network_graph), &self.logger, &scorer), chain_monitor: self.chain_monitor, tx_broadcaster: &broadcaster, logger: &self.logger, @@ -582,7 +666,8 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { let chain_source = test_utils::TestChainSource::new(Network::Testnet); let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager); for deserialized_monitor in deserialized_monitors.drain(..) { - if chain_monitor.watch_channel(deserialized_monitor.get_funding_txo().0, deserialized_monitor) != Ok(ChannelMonitorUpdateStatus::Completed) { + let funding_outpoint = deserialized_monitor.get_funding_txo().0; + if chain_monitor.watch_channel(funding_outpoint, deserialized_monitor) != Ok(ChannelMonitorUpdateStatus::Completed) { panic!(); } } @@ -793,6 +878,18 @@ pub fn remove_first_msg_event_to_node(msg_node_id: &PublicKey, msg_events: &mut MessageSendEvent::SendOpenChannelV2 { node_id, .. } => { node_id == msg_node_id }, + MessageSendEvent::SendStfu { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendSplice { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendSpliceAck { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendSpliceLocked { node_id, .. } => { + node_id == msg_node_id + }, MessageSendEvent::SendTxAddInput { node_id, .. } => { node_id == msg_node_id }, @@ -915,7 +1012,14 @@ macro_rules! unwrap_send_err { _ => panic!(), } }, - _ => panic!(), + &Err(PaymentSendFailure::PathParameterError(ref result)) if !$all_failed => { + assert_eq!(result.len(), 1); + match result[0] { + Err($type) => { $check }, + _ => panic!(), + } + }, + _ => {panic!()}, } } } @@ -924,7 +1028,8 @@ macro_rules! unwrap_send_err { pub fn check_added_monitors>(node: &H, count: usize) { if let Some(chain_monitor) = node.chain_monitor() { let mut added_monitors = chain_monitor.added_monitors.lock().unwrap(); - assert_eq!(added_monitors.len(), count); + let n = added_monitors.len(); + assert_eq!(n, count, "expected {} monitors to be added, not {}", count, n); added_monitors.clear(); } } @@ -966,7 +1071,7 @@ pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: User let mut node_read = &chanman_encoded[..]; let (_, node_deserialized) = { - let mut channel_monitors = HashMap::new(); + let mut channel_monitors = new_hash_map(); for monitor in monitors_read.iter_mut() { assert!(channel_monitors.insert(monitor.get_funding_txo().0, monitor).is_none()); } @@ -986,7 +1091,8 @@ pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: User assert!(node_read.is_empty()); for monitor in monitors_read.drain(..) { - assert_eq!(node.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor), + let funding_outpoint = monitor.get_funding_txo().0; + assert_eq!(node.chain_monitor.watch_channel(funding_outpoint, monitor), Ok(ChannelMonitorUpdateStatus::Completed)); check_added_monitors!(node, 1); } @@ -1005,6 +1111,7 @@ macro_rules! reload_node { $new_channelmanager = _reload_node(&$node, $new_config, &chanman_encoded, $monitors_encoded); $node.node = &$new_channelmanager; + $node.onion_messenger.set_offers_handler(&$new_channelmanager); }; ($node: expr, $chanman_encoded: expr, $monitors_encoded: expr, $persister: ident, $new_chain_monitor: ident, $new_channelmanager: ident) => { reload_node!($node, $crate::util::config::UserConfig::default(), $chanman_encoded, $monitors_encoded, $persister, $new_chain_monitor, $new_channelmanager); @@ -1047,7 +1154,7 @@ fn internal_create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, Vec::new() }; - let tx = Transaction { version: chan_id as i32, lock_time: PackedLockTime::ZERO, input, output: vec![TxOut { + let tx = Transaction { version: chan_id as i32, lock_time: LockTime::ZERO, input, output: vec![TxOut { value: *channel_value_satoshis, script_pubkey: output_script.clone(), }]}; let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 }; @@ -1104,7 +1211,7 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r let initiator_channels = initiator.node.list_usable_channels().len(); let receiver_channels = receiver.node.list_usable_channels().len(); - initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, initiator_config).unwrap(); + initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, None, initiator_config).unwrap(); let open_channel = get_event_msg!(initiator, MessageSendEvent::SendOpenChannel, receiver.node.get_our_node_id()); receiver.node.handle_open_channel(&initiator.node.get_our_node_id(), &open_channel); @@ -1118,7 +1225,7 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r }; let accept_channel = get_event_msg!(receiver, MessageSendEvent::SendAcceptChannel, initiator.node.get_our_node_id()); - assert_eq!(accept_channel.minimum_depth, 0); + assert_eq!(accept_channel.common_fields.minimum_depth, 0); initiator.node.handle_accept_channel(&receiver.node.get_our_node_id(), &accept_channel); let (temporary_channel_id, tx, _) = create_funding_transaction(&initiator, &receiver.node.get_our_node_id(), 100_000, 42); @@ -1169,10 +1276,10 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r (tx, as_channel_ready.channel_id) } -pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64) -> Transaction { - let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap(); +pub fn exchange_open_accept_chan<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64) -> ChannelId { + let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None, None).unwrap(); let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id()); - assert_eq!(open_channel_msg.temporary_channel_id, create_chan_id); + assert_eq!(open_channel_msg.common_fields.temporary_channel_id, create_chan_id); assert_eq!(node_a.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 42); node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &open_channel_msg); if node_b.node.get_current_default_configuration().manually_accept_inbound_channels { @@ -1185,10 +1292,15 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, ' }; } let accept_channel_msg = get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id()); - assert_eq!(accept_channel_msg.temporary_channel_id, create_chan_id); + assert_eq!(accept_channel_msg.common_fields.temporary_channel_id, create_chan_id); node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), &accept_channel_msg); assert_ne!(node_b.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 0); + create_chan_id +} + +pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64) -> Transaction { + let create_chan_id = exchange_open_accept_chan(node_a, node_b, channel_value, push_msat); sign_funding_transaction(node_a, node_b, channel_value, create_chan_id) } @@ -1287,7 +1399,7 @@ pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c: 'd, 'd>(nodes: pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec>, a: usize, b: usize, channel_value: u64, push_msat: u64) -> (msgs::ChannelReady, Transaction) { let mut no_announce_cfg = test_default_channel_config(); no_announce_cfg.channel_handshake_config.announced_channel = false; - nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, Some(no_announce_cfg)).unwrap(); + nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, None, Some(no_announce_cfg)).unwrap(); let open_channel = get_event_msg!(nodes[a], MessageSendEvent::SendOpenChannel, nodes[b].node.get_our_node_id()); nodes[b].node.handle_open_channel(&nodes[a].node.get_our_node_id(), &open_channel); let accept_channel = get_event_msg!(nodes[b], MessageSendEvent::SendAcceptChannel, nodes[a].node.get_our_node_id()); @@ -1373,7 +1485,7 @@ pub fn do_check_spends Opti for output in tx.output.iter() { total_value_out += output.value; } - let min_fee = (tx.weight() as u64 + 3) / 4; // One sat per vbyte (ie per weight/4, rounded up) + let min_fee = (tx.weight().to_wu() as u64 + 3) / 4; // One sat per vbyte (ie per weight/4, rounded up) // Input amount - output amount = fee, so check that out + min_fee is smaller than input assert!(total_value_out + min_fee <= total_value_in); tx.verify(get_output).unwrap(); @@ -1485,6 +1597,22 @@ pub struct ExpectedCloseEvent { pub counterparty_node_id: Option, pub discard_funding: bool, pub reason: Option, + pub channel_funding_txo: Option, + pub user_channel_id: Option, +} + +impl ExpectedCloseEvent { + pub fn from_id_reason(channel_id: ChannelId, discard_funding: bool, reason: ClosureReason) -> Self { + Self { + channel_capacity_sats: None, + channel_id: Some(channel_id), + counterparty_node_id: None, + discard_funding, + reason: Some(reason), + channel_funding_txo: None, + user_channel_id: None, + } + } } /// Check that multiple channel closing events have been issued. @@ -1501,12 +1629,20 @@ pub fn check_closed_events(node: &Node, expected_close_events: &[ExpectedCloseEv reason, counterparty_node_id, channel_capacity_sats, + channel_funding_txo, + user_channel_id, .. } if ( expected_event.channel_id.map(|expected| *channel_id == expected).unwrap_or(true) && expected_event.reason.as_ref().map(|expected| reason == expected).unwrap_or(true) && - expected_event.counterparty_node_id.map(|expected| *counterparty_node_id == Some(expected)).unwrap_or(true) && - expected_event.channel_capacity_sats.map(|expected| *channel_capacity_sats == Some(expected)).unwrap_or(true) + expected_event. + counterparty_node_id.map(|expected| *counterparty_node_id == Some(expected)).unwrap_or(true) && + expected_event.channel_capacity_sats + .map(|expected| *channel_capacity_sats == Some(expected)).unwrap_or(true) && + expected_event.channel_funding_txo + .map(|expected| *channel_funding_txo == Some(expected)).unwrap_or(true) && + expected_event.user_channel_id + .map(|expected| *user_channel_id == expected).unwrap_or(true) ) ))); } @@ -1531,6 +1667,8 @@ pub fn check_closed_event(node: &Node, events_count: usize, expected_reason: Clo counterparty_node_id: Some(*node_id), discard_funding: is_check_discard_funding, reason: Some(expected_reason.clone()), + channel_funding_txo: None, + user_channel_id: None, }).collect::>(); check_closed_events(node, expected_close_events.as_slice()); } @@ -1889,7 +2027,7 @@ pub fn get_payment_preimage_hash(recipient: &Node, min_value_msat: Option, let mut payment_count = recipient.network_payment_count.borrow_mut(); let payment_preimage = PaymentPreimage([*payment_count; 32]); *payment_count += 1; - let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); + let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array()); let payment_secret = recipient.node.create_inbound_payment_for_hash(payment_hash, min_value_msat, 7200, min_final_cltv_expiry_delta).unwrap(); (payment_preimage, payment_hash, payment_secret) } @@ -1922,6 +2060,18 @@ pub fn get_route(send_node: &Node, route_params: &RouteParameters) -> Result Result { + let scorer = TestScorer::new(); + let keys_manager = TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet); + let random_seed_bytes = keys_manager.get_secure_random_bytes(); + router::find_route( + &send_node.node.get_our_node_id(), route_params, &send_node.network_graph, + Some(&send_node.node.list_usable_channels().iter().collect::>()), + send_node.logger, &scorer, &Default::default(), &random_seed_bytes + ) +} + /// Gets a route from the given sender to the node described in `payment_params`. /// /// Don't use this, use the identically-named function instead. @@ -2011,7 +2161,7 @@ pub fn expect_payment_sent>(node: &H, ) { let events = node.node().get_and_clear_pending_events(); let expected_payment_hash = PaymentHash( - bitcoin::hashes::sha256::Hash::hash(&expected_payment_preimage.0).into_inner()); + bitcoin::hashes::sha256::Hash::hash(&expected_payment_preimage.0).to_byte_array()); if expect_per_path_claims { assert!(events.len() > 1); } else { @@ -2073,38 +2223,74 @@ macro_rules! expect_payment_path_successful { } } +/// Returns the total fee earned by this HTLC forward, in msat. pub fn expect_payment_forwarded>( event: Event, node: &H, prev_node: &H, next_node: &H, expected_fee: Option, - upstream_force_closed: bool, downstream_force_closed: bool -) { + expected_extra_fees_msat: Option, upstream_force_closed: bool, + downstream_force_closed: bool, allow_1_msat_fee_overpay: bool, +) -> Option { match event { Event::PaymentForwarded { - fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id, - outbound_amount_forwarded_msat: _ + prev_channel_id, next_channel_id, prev_user_channel_id, next_user_channel_id, + total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, .. } => { - assert_eq!(fee_earned_msat, expected_fee); + if allow_1_msat_fee_overpay { + // Aggregating fees for blinded paths may result in a rounding error, causing slight + // overpayment in fees. + let actual_fee = total_fee_earned_msat.unwrap(); + let expected_fee = expected_fee.unwrap(); + assert!(actual_fee == expected_fee || actual_fee == expected_fee + 1); + } else { + assert_eq!(total_fee_earned_msat, expected_fee); + } + + // Check that the (knowingly) withheld amount is always less or equal to the expected + // overpaid amount. + assert!(skimmed_fee_msat == expected_extra_fees_msat); if !upstream_force_closed { // Is the event prev_channel_id in one of the channels between the two nodes? - assert!(node.node().list_channels().iter().any(|x| x.counterparty.node_id == prev_node.node().get_our_node_id() && x.channel_id == prev_channel_id.unwrap())); + assert!(node.node().list_channels().iter().any(|x| + x.counterparty.node_id == prev_node.node().get_our_node_id() && + x.channel_id == prev_channel_id.unwrap() && + x.user_channel_id == prev_user_channel_id.unwrap() + )); } // We check for force closures since a force closed channel is removed from the // node's channel list if !downstream_force_closed { - assert!(node.node().list_channels().iter().any(|x| x.counterparty.node_id == next_node.node().get_our_node_id() && x.channel_id == next_channel_id.unwrap())); + // As documented, `next_user_channel_id` will only be `Some` if we didn't settle via an + // onchain transaction, just as the `total_fee_earned_msat` field. Rather than + // introducing yet another variable, we use the latter's state as a flag to detect + // this and only check if it's `Some`. + if total_fee_earned_msat.is_none() { + assert!(node.node().list_channels().iter().any(|x| + x.counterparty.node_id == next_node.node().get_our_node_id() && + x.channel_id == next_channel_id.unwrap() + )); + } else { + assert!(node.node().list_channels().iter().any(|x| + x.counterparty.node_id == next_node.node().get_our_node_id() && + x.channel_id == next_channel_id.unwrap() && + x.user_channel_id == next_user_channel_id.unwrap() + )); + } } assert_eq!(claim_from_onchain_tx, downstream_force_closed); + total_fee_earned_msat }, _ => panic!("Unexpected event"), } } +#[macro_export] macro_rules! expect_payment_forwarded { ($node: expr, $prev_node: expr, $next_node: expr, $expected_fee: expr, $upstream_force_closed: expr, $downstream_force_closed: expr) => { let mut events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); $crate::ln::functional_test_utils::expect_payment_forwarded( - events.pop().unwrap(), &$node, &$prev_node, &$next_node, $expected_fee, - $upstream_force_closed, $downstream_force_closed); + events.pop().unwrap(), &$node, &$prev_node, &$next_node, $expected_fee, None, + $upstream_force_closed, $downstream_force_closed, false + ); } } @@ -2119,12 +2305,13 @@ macro_rules! expect_channel_shutdown_state { } #[cfg(any(test, ldk_bench, feature = "_test_utils"))] -pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) { +pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) -> ChannelId { let events = node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); - match events[0] { - crate::events::Event::ChannelPending { ref counterparty_node_id, .. } => { + match &events[0] { + crate::events::Event::ChannelPending { channel_id, counterparty_node_id, .. } => { assert_eq!(*expected_counterparty_node_id, *counterparty_node_id); + *channel_id }, _ => panic!("Unexpected event"), } @@ -2142,6 +2329,26 @@ pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, ex } } +#[cfg(any(test, feature = "_test_utils"))] +pub fn expect_probe_successful_events(node: &Node, mut probe_results: Vec<(PaymentHash, PaymentId)>) { + let mut events = node.node.get_and_clear_pending_events(); + + for event in events.drain(..) { + match event { + Event::ProbeSuccessful { payment_hash: ev_ph, payment_id: ev_pid, ..} => { + let result_idx = probe_results.iter().position(|(payment_hash, payment_id)| *payment_hash == ev_ph && *payment_id == ev_pid); + assert!(result_idx.is_some()); + + probe_results.remove(result_idx.unwrap()); + }, + _ => panic!(), + } + }; + + // Ensure that we received a ProbeSuccessful event for each probe result. + assert!(probe_results.is_empty()); +} + pub struct PaymentFailedConditions<'a> { pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>, pub(crate) expected_blamed_scid: Option, @@ -2279,21 +2486,94 @@ pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, payment_id } -pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: Option, ev: MessageSendEvent, payment_claimable_expected: bool, clear_recipient_events: bool, expected_preimage: Option) -> Option { +fn fail_payment_along_path<'a, 'b, 'c>(expected_path: &[&Node<'a, 'b, 'c>]) { + let origin_node_id = expected_path[0].node.get_our_node_id(); + + // iterate from the receiving node to the origin node and handle update fail htlc. + for (&node, &prev_node) in expected_path.iter().rev().zip(expected_path.iter().rev().skip(1)) { + let updates = get_htlc_update_msgs!(node, prev_node.node.get_our_node_id()); + prev_node.node.handle_update_fail_htlc(&node.node.get_our_node_id(), &updates.update_fail_htlcs[0]); + check_added_monitors!(prev_node, 0); + + let is_first_hop = origin_node_id == prev_node.node.get_our_node_id(); + // We do not want to fail backwards on the first hop. All other hops should fail backwards. + commitment_signed_dance!(prev_node, node, updates.commitment_signed, !is_first_hop); + } +} + +pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> { + pub origin_node: &'a Node<'b, 'c, 'd>, + pub expected_path: &'a [&'a Node<'b, 'c, 'd>], + pub recv_value: u64, + pub payment_hash: PaymentHash, + pub payment_secret: Option, + pub event: MessageSendEvent, + pub payment_claimable_expected: bool, + pub clear_recipient_events: bool, + pub expected_preimage: Option, + pub is_probe: bool, +} + +impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> { + pub fn new( + origin_node: &'a Node<'b, 'c, 'd>, expected_path: &'a [&'a Node<'b, 'c, 'd>], recv_value: u64, + payment_hash: PaymentHash, event: MessageSendEvent, + ) -> Self { + Self { + origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event, + payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None, + is_probe: false, + } + } + pub fn without_clearing_recipient_events(mut self) -> Self { + self.clear_recipient_events = false; + self + } + pub fn is_probe(mut self) -> Self { + self.payment_claimable_expected = false; + self.is_probe = true; + self + } + pub fn without_claimable_event(mut self) -> Self { + self.payment_claimable_expected = false; + self + } + pub fn with_payment_secret(mut self, payment_secret: PaymentSecret) -> Self { + self.payment_secret = Some(payment_secret); + self + } + pub fn with_payment_preimage(mut self, payment_preimage: PaymentPreimage) -> Self { + self.expected_preimage = Some(payment_preimage); + self + } +} + +pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option { + let PassAlongPathArgs { + origin_node, expected_path, recv_value, payment_hash: our_payment_hash, + payment_secret: our_payment_secret, event: ev, payment_claimable_expected, + clear_recipient_events, expected_preimage, is_probe + } = args; + let mut payment_event = SendEvent::from_event(ev); let mut prev_node = origin_node; let mut event = None; for (idx, &node) in expected_path.iter().enumerate() { + let is_last_hop = idx == expected_path.len() - 1; assert_eq!(node.node.get_our_node_id(), payment_event.node_id); node.node.handle_update_add_htlc(&prev_node.node.get_our_node_id(), &payment_event.msgs[0]); check_added_monitors!(node, 0); - commitment_signed_dance!(node, prev_node, payment_event.commitment_msg, false); - expect_pending_htlcs_forwardable!(node); + if is_last_hop && is_probe { + commitment_signed_dance!(node, prev_node, payment_event.commitment_msg, true, true); + } else { + commitment_signed_dance!(node, prev_node, payment_event.commitment_msg, false); + expect_pending_htlcs_forwardable!(node); + } - if idx == expected_path.len() - 1 && clear_recipient_events { + if is_last_hop && clear_recipient_events { let events_2 = node.node.get_and_clear_pending_events(); if payment_claimable_expected { assert_eq!(events_2.len(), 1); @@ -2327,7 +2607,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p } else { assert!(events_2.is_empty()); } - } else if idx != expected_path.len() - 1 { + } else if !is_last_hop { let mut events_2 = node.node.get_and_clear_pending_msg_events(); assert_eq!(events_2.len(), 1); check_added_monitors!(node, 1); @@ -2341,16 +2621,46 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p } pub fn pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: Option, ev: MessageSendEvent, payment_claimable_expected: bool, expected_preimage: Option) -> Option { - do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_claimable_expected, true, expected_preimage) + let mut args = PassAlongPathArgs::new(origin_node, expected_path, recv_value, our_payment_hash, ev); + if !payment_claimable_expected { + args = args.without_claimable_event(); + } + if let Some(payment_secret) = our_payment_secret { + args = args.with_payment_secret(payment_secret); + } + if let Some(payment_preimage) = expected_preimage { + args = args.with_payment_preimage(payment_preimage); + } + do_pass_along_path(args) +} + +pub fn send_probe_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&[&Node<'a, 'b, 'c>]]) { + let mut events = origin_node.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), expected_route.len()); + + check_added_monitors!(origin_node, expected_route.len()); + + for path in expected_route.iter() { + let ev = remove_first_msg_event_to_node(&path[0].node.get_our_node_id(), &mut events); + + do_pass_along_path(PassAlongPathArgs::new(origin_node, path, 0, PaymentHash([0_u8; 32]), ev) + .is_probe() + .without_clearing_recipient_events()); + + let nodes_to_fail_payment: Vec<_> = vec![origin_node].into_iter().chain(path.iter().cloned()).collect(); + + fail_payment_along_path(nodes_to_fail_payment.as_slice()); + } } pub fn pass_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) { let mut events = origin_node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), expected_route.len()); + for (path_idx, expected_path) in expected_route.iter().enumerate() { let ev = remove_first_msg_event_to_node(&expected_path[0].node.get_our_node_id(), &mut events); // Once we've gotten through all the HTLCs, the last one should result in a - // PaymentClaimable (but each previous one should not!), . + // PaymentClaimable (but each previous one should not!). let expect_payment = path_idx == expected_route.len() - 1; pass_along_path(origin_node, expected_path, recv_value, our_payment_hash.clone(), Some(our_payment_secret), ev, expect_payment, None); } @@ -2366,26 +2676,71 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>( origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_preimage: PaymentPreimage ) -> u64 { - let extra_fees = vec![0; expected_paths.len()]; - do_claim_payment_along_route_with_extra_penultimate_hop_fees(origin_node, expected_paths, - &extra_fees[..], skip_last, our_payment_preimage) -} - -pub fn do_claim_payment_along_route_with_extra_penultimate_hop_fees<'a, 'b, 'c>( - origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees: - &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage -) -> u64 { - assert_eq!(expected_paths.len(), expected_extra_fees.len()); for path in expected_paths.iter() { assert_eq!(path.last().unwrap().node.get_our_node_id(), expected_paths[0].last().unwrap().node.get_our_node_id()); } expected_paths[0].last().unwrap().node.claim_funds(our_payment_preimage); - pass_claimed_payment_along_route(origin_node, expected_paths, expected_extra_fees, skip_last, our_payment_preimage) + pass_claimed_payment_along_route( + ClaimAlongRouteArgs::new(origin_node, expected_paths, our_payment_preimage) + .skip_last(skip_last) + ) +} + +pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { + pub origin_node: &'a Node<'b, 'c, 'd>, + pub expected_paths: &'a [&'a [&'a Node<'b, 'c, 'd>]], + pub expected_extra_fees: Vec, + pub expected_min_htlc_overpay: Vec, + pub skip_last: bool, + pub payment_preimage: PaymentPreimage, + // Allow forwarding nodes to have taken 1 msat more fee than expected based on the downstream + // fulfill amount. + // + // Necessary because our test utils calculate the expected fee for an intermediate node based on + // the amount was claimed in their downstream peer's fulfill, but blinded intermediate nodes + // calculate their fee based on the inbound amount from their upstream peer, causing a difference + // in rounding. + pub allow_1_msat_fee_overpay: bool, +} + +impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { + pub fn new( + origin_node: &'a Node<'b, 'c, 'd>, expected_paths: &'a [&'a [&'a Node<'b, 'c, 'd>]], + payment_preimage: PaymentPreimage, + ) -> Self { + Self { + origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()], + expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage, + allow_1_msat_fee_overpay: false, + } + } + pub fn skip_last(mut self, skip_last: bool) -> Self { + self.skip_last = skip_last; + self + } + pub fn with_expected_extra_fees(mut self, extra_fees: Vec) -> Self { + self.expected_extra_fees = extra_fees; + self + } + pub fn with_expected_min_htlc_overpay(mut self, extra_fees: Vec) -> Self { + self.expected_min_htlc_overpay = extra_fees; + self + } + pub fn allow_1_msat_fee_overpay(mut self) -> Self { + self.allow_1_msat_fee_overpay = true; + self + } } -pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees: &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage) -> u64 { +pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArgs) -> u64 { + let ClaimAlongRouteArgs { + origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last, + payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, + } = args; let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events(); assert_eq!(claim_event.len(), 1); + #[allow(unused)] + let mut fwd_amt_msat = 0; match claim_event[0] { Event::PaymentClaimed { purpose: PaymentPurpose::SpontaneousPayment(preimage), @@ -2402,6 +2757,7 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, ' assert_eq!(htlcs.len(), expected_paths.len()); // One per path. assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc)); + fwd_amt_msat = amount_msat; }, Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { .. }, @@ -2414,6 +2770,7 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, ' assert_eq!(htlcs.len(), expected_paths.len()); // One per path. assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc)); + fwd_amt_msat = amount_msat; } _ => panic!(), } @@ -2445,8 +2802,12 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, ' per_path_msgs.push(msgs_from_ev!(&events[0])); } else { for expected_path in expected_paths.iter() { - // For MPP payments, we always want the message to the first node in the path. - let ev = remove_first_msg_event_to_node(&expected_path[0].node.get_our_node_id(), &mut events); + // For MPP payments, we want the fulfill message from the payee to the penultimate hop in the + // path. + let penultimate_hop_node_id = expected_path.iter().rev().skip(1).next() + .map(|n| n.node.get_our_node_id()) + .unwrap_or(origin_node.node.get_our_node_id()); + let ev = remove_first_msg_event_to_node(&penultimate_hop_node_id, &mut events); per_path_msgs.push(msgs_from_ev!(&ev)); } } @@ -2470,19 +2831,34 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, ' { $node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0); let mut fee = { - let per_peer_state = $node.node.per_peer_state.read().unwrap(); - let peer_state = per_peer_state.get(&$prev_node.node.get_our_node_id()) - .unwrap().lock().unwrap(); - let channel = peer_state.channel_by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap(); - if let Some(prev_config) = channel.context().prev_config() { - prev_config.forwarding_fee_base_msat - } else { - channel.context().config().forwarding_fee_base_msat - } + let (base_fee, prop_fee) = { + let per_peer_state = $node.node.per_peer_state.read().unwrap(); + let peer_state = per_peer_state.get(&$prev_node.node.get_our_node_id()) + .unwrap().lock().unwrap(); + let channel = peer_state.channel_by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap(); + if let Some(prev_config) = channel.context().prev_config() { + (prev_config.forwarding_fee_base_msat as u64, + prev_config.forwarding_fee_proportional_millionths as u64) + } else { + (channel.context().config().forwarding_fee_base_msat as u64, + channel.context().config().forwarding_fee_proportional_millionths as u64) + } + }; + ((fwd_amt_msat * prop_fee / 1_000_000) + base_fee) as u32 }; - if $idx == 1 { fee += expected_extra_fees[i]; } - expect_payment_forwarded!(*$node, $next_node, $prev_node, Some(fee as u64), false, false); - expected_total_fee_msat += fee as u64; + + let mut expected_extra_fee = None; + if $idx == 1 { + fee += expected_extra_fees[i]; + fee += expected_min_htlc_overpay[i]; + expected_extra_fee = if expected_extra_fees[i] > 0 { Some(expected_extra_fees[i] as u64) } else { None }; + } + let mut events = $node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + let actual_fee = expect_payment_forwarded(events.pop().unwrap(), *$node, $next_node, $prev_node, + Some(fee as u64), expected_extra_fee, false, false, allow_1_msat_fee_overpay); + expected_total_fee_msat += actual_fee.unwrap(); + fwd_amt_msat += actual_fee.unwrap(); check_added_monitors!($node, 1); let new_next_msgs = if $new_msgs { let events = $node.node.get_and_clear_pending_msg_events(); @@ -2747,7 +3123,8 @@ pub fn create_node_cfgs_with_persisters<'a>(node_count: usize, chanmon_cfgs: &'a logger: &chanmon_cfgs[i].logger, tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster, fee_estimator: &chanmon_cfgs[i].fee_estimator, - router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].scorer), + router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].logger, &chanmon_cfgs[i].scorer), + message_router: test_utils::TestMessageRouter::new(network_graph.clone(), &chanmon_cfgs[i].keys_manager), chain_monitor, keys_manager: &chanmon_cfgs[i].keys_manager, node_seed: seed, @@ -2801,6 +3178,11 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec(node_count: usize, cfgs: &'b Vec(node_count: usize, cfgs: &'b Vec(node: &Node<'a, 'b, 'c>, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction), commitment_tx: Option, has_htlc_tx: HTLCType) -> Vec { let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap(); - let mut txn_seen = HashSet::new(); + let mut txn_seen = new_hash_set(); node_txn.retain(|tx| txn_seen.insert(tx.txid())); assert!(node_txn.len() >= if commitment_tx.is_some() { 0 } else { 1 } + if has_htlc_tx == HTLCType::NONE { 0 } else { 1 }); @@ -2883,9 +3273,9 @@ pub fn test_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, chan: &(msgs::Cha if tx.input.len() == 1 && tx.input[0].previous_output.txid == res[0].txid() { check_spends!(tx, res[0]); if has_htlc_tx == HTLCType::TIMEOUT { - assert!(tx.lock_time.0 != 0); + assert_ne!(tx.lock_time, LockTime::ZERO); } else { - assert!(tx.lock_time.0 == 0); + assert_eq!(tx.lock_time, LockTime::ZERO); } res.push(tx.clone()); false @@ -2923,7 +3313,7 @@ pub fn test_revoked_htlc_claim_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c> pub fn check_preimage_claim<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, prev_txn: &Vec) -> Vec { let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap(); - let mut txn_seen = HashSet::new(); + let mut txn_seen = new_hash_set(); node_txn.retain(|tx| txn_seen.insert(tx.txid())); let mut found_prev = false; @@ -3023,7 +3413,7 @@ macro_rules! get_channel_value_stat { macro_rules! get_chan_reestablish_msgs { ($src_node: expr, $dst_node: expr) => { { - let mut announcements = $crate::prelude::HashSet::new(); + let mut announcements = $crate::prelude::new_hash_set(); let mut res = Vec::with_capacity(1); for msg in $src_node.node.get_and_clear_pending_msg_events() { if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { @@ -3175,24 +3565,28 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) { // If a expects a channel_ready, it better not think it has received a revoke_and_ack // from b for reestablish in reestablish_1.iter() { - assert_eq!(reestablish.next_remote_commitment_number, 0); + let n = reestablish.next_remote_commitment_number; + assert_eq!(n, 0, "expected a->b next_remote_commitment_number to be 0, got {}", n); } } if send_channel_ready.1 { // If b expects a channel_ready, it better not think it has received a revoke_and_ack // from a for reestablish in reestablish_2.iter() { - assert_eq!(reestablish.next_remote_commitment_number, 0); + let n = reestablish.next_remote_commitment_number; + assert_eq!(n, 0, "expected b->a next_remote_commitment_number to be 0, got {}", n); } } if send_channel_ready.0 || send_channel_ready.1 { // If we expect any channel_ready's, both sides better have set // next_holder_commitment_number to 1 for reestablish in reestablish_1.iter() { - assert_eq!(reestablish.next_local_commitment_number, 1); + let n = reestablish.next_local_commitment_number; + assert_eq!(n, 1, "expected a->b next_local_commitment_number to be 1, got {}", n); } for reestablish in reestablish_2.iter() { - assert_eq!(reestablish.next_local_commitment_number, 1); + let n = reestablish.next_local_commitment_number; + assert_eq!(n, 1, "expected b->a next_local_commitment_number to be 1, got {}", n); } } @@ -3354,6 +3748,7 @@ pub fn create_batch_channel_funding<'a, 'b, 'c>( // Initialize channel opening. let temp_chan_id = funding_node.node.create_channel( other_node.node.get_our_node_id(), *channel_value_satoshis, *push_msat, *user_channel_id, + None, *override_config, ).unwrap(); let open_channel_msg = get_event_msg!(funding_node, MessageSendEvent::SendOpenChannel, other_node.node.get_our_node_id()); @@ -3388,7 +3783,7 @@ pub fn create_batch_channel_funding<'a, 'b, 'c>( // Compose the batch funding transaction and give it to the ChannelManager. let tx = Transaction { version: 2, - lock_time: PackedLockTime::ZERO, + lock_time: LockTime::ZERO, input: Vec::new(), output: tx_outs, };