X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=50aed2c5b4355283f77695708235c25f5d36d761;hb=6f580725856674fa2b4126f582b5c30a8483c8ba;hp=88e1b77f8d69ce4367c793efe46e023a97c12941;hpb=aefe276fcb0f344e02315279da52b3dd464089e5;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 88e1b77f..39396685 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,35 +10,34 @@ //! A bunch of useful utilities for building networks of nodes and exchanging messages between //! nodes for functional tests. -use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::EntropySource}; +use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch}; +use crate::sign::EntropySource; use crate::chain::channelmonitor::ChannelMonitor; use crate::chain::transaction::OutPoint; +use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason}; +use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource}; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; -use crate::ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA}; +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::{PaymentParameters, Route, get_route}; +use crate::routing::router::{self, PaymentParameters, Route}; use crate::ln::features::InitFeatures; use crate::ln::msgs; use crate::ln::msgs::{ChannelMessageHandler,RoutingMessageHandler}; use crate::util::enforcing_trait_impls::EnforcingSigner; use crate::util::scid_utils; use crate::util::test_utils; -use crate::util::test_utils::{panicking, TestChainMonitor}; -use crate::util::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose}; +use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface}; use crate::util::errors::APIError; -use crate::util::config::UserConfig; +use crate::util::config::{UserConfig, MaxDustHTLCExposure}; use crate::util::ser::{ReadableArgs, Writeable}; use bitcoin::blockdata::block::{Block, BlockHeader}; -use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; -use bitcoin::network::constants::Network; - use bitcoin::hash_types::BlockHash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash as _; - -use bitcoin::secp256k1::PublicKey; +use bitcoin::network::constants::Network; +use bitcoin::secp256k1::{PublicKey, SecretKey}; use crate::io; use crate::prelude::*; @@ -62,9 +61,12 @@ pub fn confirm_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Tran scid } /// Mine a single block containing the given transaction -pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) { +/// +/// Returns the SCID a channel confirmed in the given transaction will have, assuming the funding +/// output is the 1st output in the transaction. +pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) -> u64 { let height = node.best_block_info().1 + 1; - confirm_transaction_at(node, tx, height); + confirm_transaction_at(node, tx, height) } /// Mine a single block containing the given transactions pub fn mine_transactions<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: &[&Transaction]) { @@ -82,16 +84,14 @@ pub fn confirm_transactions_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: if conf_height > first_connect_height { connect_blocks(node, conf_height - first_connect_height); } - let mut block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: conf_height, bits: 42, nonce: 42 }, - txdata: Vec::new(), - }; + 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 - block.txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); + txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }); } for tx in txn { - block.txdata.push((*tx).clone()); + txdata.push((*tx).clone()); } + let block = create_dummy_block(node.best_block_hash(), conf_height, txdata); connect_block(node, &block); scid_utils::scid_from_parts(conf_height as u64, block.txdata.len() as u64 - 1, 0).unwrap() } @@ -134,6 +134,34 @@ pub enum ConnectStyle { } impl ConnectStyle { + pub fn skips_blocks(&self) -> bool { + match self { + ConnectStyle::BestBlockFirst => false, + ConnectStyle::BestBlockFirstSkippingBlocks => true, + ConnectStyle::BestBlockFirstReorgsOnlyTip => true, + ConnectStyle::TransactionsFirst => false, + ConnectStyle::TransactionsFirstSkippingBlocks => true, + ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks => true, + ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks => true, + ConnectStyle::TransactionsFirstReorgsOnlyTip => true, + ConnectStyle::FullBlockViaListen => false, + } + } + + pub fn updates_best_block_first(&self) -> bool { + match self { + ConnectStyle::BestBlockFirst => true, + ConnectStyle::BestBlockFirstSkippingBlocks => true, + ConnectStyle::BestBlockFirstReorgsOnlyTip => true, + ConnectStyle::TransactionsFirst => false, + ConnectStyle::TransactionsFirstSkippingBlocks => false, + ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks => false, + ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks => false, + ConnectStyle::TransactionsFirstReorgsOnlyTip => false, + ConnectStyle::FullBlockViaListen => false, + } + } + fn random_style() -> ConnectStyle { #[cfg(feature = "std")] { use core::hash::{BuildHasher, Hasher}; @@ -160,27 +188,31 @@ impl ConnectStyle { } } +pub fn create_dummy_header(prev_blockhash: BlockHash, time: u32) -> BlockHeader { + BlockHeader { + version: 0x2000_0000, + prev_blockhash, + merkle_root: TxMerkleNode::all_zeros(), + time, + bits: 42, + nonce: 42, + } +} + +pub fn create_dummy_block(prev_blockhash: BlockHash, time: u32, txdata: Vec) -> Block { + Block { header: create_dummy_header(prev_blockhash, time), txdata } +} + pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32) -> BlockHash { - let skip_intermediaries = match *node.connect_style.borrow() { - ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks| - ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks|ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks| - ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::TransactionsFirstReorgsOnlyTip => true, - _ => false, - }; + let skip_intermediaries = node.connect_style.borrow().skips_blocks(); let height = node.best_block_info().1 + 1; - let mut block = Block { - header: BlockHeader { version: 0x2000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 }, - txdata: vec![], - }; + let mut block = create_dummy_block(node.best_block_hash(), height, Vec::new()); assert!(depth >= 1); for i in 1..depth { let prev_blockhash = block.header.block_hash(); do_connect_block(node, block, skip_intermediaries); - block = Block { - header: BlockHeader { version: 0x20000000, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time: height + i, bits: 42, nonce: 42 }, - txdata: vec![], - }; + block = create_dummy_block(prev_blockhash, height + i, Vec::new()); } let hash = block.header.block_hash(); do_connect_block(node, block, false); @@ -204,6 +236,9 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk #[cfg(feature = "std")] { eprintln!("Connecting block using Block Connection Style: {:?}", *node.connect_style.borrow()); } + // Update the block internally before handing it over to LDK, to ensure our assertions regarding + // transaction broadcast are correct. + node.blocks.lock().unwrap().push((block.clone(), height)); if !skip_intermediaries { let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); match *node.connect_style.borrow() { @@ -253,7 +288,19 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk } call_claimable_balances(node); node.node.test_process_background_events(); - node.blocks.lock().unwrap().push((block, height)); + + for tx in &block.txdata { + for input in &tx.input { + node.wallet_source.remove_utxo(input.previous_output); + } + let wallet_script = node.wallet_source.get_change_script().unwrap(); + for (idx, output) in tx.output.iter().enumerate() { + if output.script_pubkey == wallet_script { + let outpoint = bitcoin::OutPoint { txid: tx.txid(), vout: idx as u32 }; + node.wallet_source.add_utxo(outpoint, output.value); + } + } + } } pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) { @@ -321,6 +368,8 @@ pub struct NodeCfg<'a> { pub override_init_features: Rc>>, } +type TestChannelManager<'a, 'b, 'c> = ChannelManager<&'b TestChainMonitor<'c>, &'c test_utils::TestBroadcaster, &'b test_utils::TestKeysInterface, &'b test_utils::TestKeysInterface, &'b test_utils::TestKeysInterface, &'c test_utils::TestFeeEstimator, &'b test_utils::TestRouter<'c>, &'c test_utils::TestLogger>; + pub struct Node<'a, 'b: 'a, 'c: 'b> { pub chain_source: &'c test_utils::TestChainSource, pub tx_broadcaster: &'c test_utils::TestBroadcaster, @@ -328,7 +377,7 @@ pub struct Node<'a, 'b: 'a, 'c: 'b> { pub router: &'b test_utils::TestRouter<'c>, pub chain_monitor: &'b test_utils::TestChainMonitor<'c>, pub keys_manager: &'b test_utils::TestKeysInterface, - pub node: &'a ChannelManager<&'b TestChainMonitor<'c>, &'c test_utils::TestBroadcaster, &'b test_utils::TestKeysInterface, &'b test_utils::TestKeysInterface, &'b test_utils::TestKeysInterface, &'c test_utils::TestFeeEstimator, &'b test_utils::TestRouter<'c>, &'c test_utils::TestLogger>, + pub node: &'a TestChannelManager<'a, 'b, 'c>, pub network_graph: &'a NetworkGraph<&'c test_utils::TestLogger>, pub gossip_sync: P2PGossipSync<&'b NetworkGraph<&'c test_utils::TestLogger>, &'c test_utils::TestChainSource, &'c test_utils::TestLogger>, pub node_seed: [u8; 32], @@ -338,6 +387,13 @@ pub struct Node<'a, 'b: 'a, 'c: 'b> { pub blocks: Arc>>, pub connect_style: Rc>, pub override_init_features: Rc>>, + pub wallet_source: Arc, + pub bump_tx_handler: BumpTransactionEventHandler< + &'c test_utils::TestBroadcaster, + Arc, &'c test_utils::TestLogger>>, + &'b test_utils::TestKeysInterface, + &'c test_utils::TestLogger, + >, } impl<'a, 'b, 'c> Node<'a, 'b, 'c> { pub fn best_block_hash(&self) -> BlockHash { @@ -364,6 +420,39 @@ impl NodePtr { unsafe impl Send for NodePtr {} unsafe impl Sync for NodePtr {} + +pub trait NodeHolder { + type CM: AChannelManager; + fn node(&self) -> &ChannelManager< + ::M, + ::T, + ::ES, + ::NS, + ::SP, + ::F, + ::R, + ::L>; + fn chain_monitor(&self) -> Option<&test_utils::TestChainMonitor>; +} +impl NodeHolder for &H { + type CM = H::CM; + fn node(&self) -> &ChannelManager< + ::M, + ::T, + ::ES, + ::NS, + ::SP, + ::F, + ::R, + ::L> { (*self).node() } + fn chain_monitor(&self) -> Option<&test_utils::TestChainMonitor> { (*self).chain_monitor() } +} +impl<'a, 'b: 'a, 'c: 'b> NodeHolder for Node<'a, 'b, 'c> { + type CM = TestChannelManager<'a, 'b, 'c>; + fn node(&self) -> &TestChannelManager<'a, 'b, 'c> { &self.node } + fn chain_monitor(&self) -> Option<&test_utils::TestChainMonitor> { Some(self.chain_monitor) } +} + impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { fn drop(&mut self) { if !panicking() { @@ -482,33 +571,37 @@ pub fn create_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, (announcement, as_update, bs_update, channel_id, tx) } +/// Gets an RAA and CS which were sent in response to a commitment update +pub fn get_revoke_commit_msgs>(node: &H, recipient: &PublicKey) -> (msgs::RevokeAndACK, msgs::CommitmentSigned) { + let events = node.node().get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 2); + (match events[0] { + MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { + assert_eq!(node_id, recipient); + (*msg).clone() + }, + _ => panic!("Unexpected event"), + }, match events[1] { + MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + assert_eq!(node_id, recipient); + assert!(updates.update_add_htlcs.is_empty()); + assert!(updates.update_fulfill_htlcs.is_empty()); + assert!(updates.update_fail_htlcs.is_empty()); + assert!(updates.update_fail_malformed_htlcs.is_empty()); + assert!(updates.update_fee.is_none()); + updates.commitment_signed.clone() + }, + _ => panic!("Unexpected event"), + }) +} + #[macro_export] /// Gets an RAA and CS which were sent in response to a commitment update +/// +/// Don't use this, use the identically-named function instead. macro_rules! get_revoke_commit_msgs { ($node: expr, $node_id: expr) => { - { - use $crate::util::events::MessageSendEvent; - let events = $node.node.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 2); - (match events[0] { - MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { - assert_eq!(*node_id, $node_id); - (*msg).clone() - }, - _ => panic!("Unexpected event"), - }, match events[1] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { - assert_eq!(*node_id, $node_id); - assert!(updates.update_add_htlcs.is_empty()); - assert!(updates.update_fulfill_htlcs.is_empty()); - assert!(updates.update_fail_htlcs.is_empty()); - assert!(updates.update_fail_malformed_htlcs.is_empty()); - assert!(updates.update_fee.is_none()); - updates.commitment_signed.clone() - }, - _ => panic!("Unexpected event"), - }) - } + $crate::ln::functional_test_utils::get_revoke_commit_msgs(&$node, &$node_id) } } @@ -531,22 +624,17 @@ macro_rules! get_event_msg { } /// Get an error message from the pending events queue. -#[macro_export] -macro_rules! get_err_msg { - ($node: expr, $node_id: expr) => { - { - let events = $node.node.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - match events[0] { - $crate::util::events::MessageSendEvent::HandleError { - action: $crate::ln::msgs::ErrorAction::SendErrorMessage { ref msg }, ref node_id - } => { - assert_eq!(*node_id, $node_id); - (*msg).clone() - }, - _ => panic!("Unexpected event"), - } - } +pub fn get_err_msg(node: &Node, recipient: &PublicKey) -> msgs::ErrorMessage { + let events = node.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::HandleError { + action: msgs::ErrorAction::SendErrorMessage { ref msg }, ref node_id + } => { + assert_eq!(node_id, recipient); + (*msg).clone() + }, + _ => panic!("Unexpected event"), } } @@ -568,21 +656,26 @@ macro_rules! get_event { } } +/// Gets an UpdateHTLCs MessageSendEvent +pub fn get_htlc_update_msgs(node: &Node, recipient: &PublicKey) -> msgs::CommitmentUpdate { + let events = node.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + assert_eq!(node_id, recipient); + (*updates).clone() + }, + _ => panic!("Unexpected event"), + } +} + #[macro_export] /// Gets an UpdateHTLCs MessageSendEvent +/// +/// Don't use this, use the identically-named function instead. macro_rules! get_htlc_update_msgs { ($node: expr, $node_id: expr) => { - { - let events = $node.node.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - match events[0] { - $crate::util::events::MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { - assert_eq!(*node_id, $node_id); - (*updates).clone() - }, - _ => panic!("Unexpected event"), - } - } + $crate::ln::functional_test_utils::get_htlc_update_msgs(&$node, &$node_id) } } @@ -657,6 +750,39 @@ pub fn remove_first_msg_event_to_node(msg_node_id: &PublicKey, msg_events: &mut MessageSendEvent::SendGossipTimestampFilter { node_id, .. } => { node_id == msg_node_id }, + MessageSendEvent::SendAcceptChannelV2 { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendOpenChannelV2 { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAddInput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAddOutput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxRemoveInput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxRemoveOutput { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxComplete { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxSignatures { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxInitRbf { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAckRbf { node_id, .. } => { + node_id == msg_node_id + }, + MessageSendEvent::SendTxAbort { node_id, .. } => { + node_id == msg_node_id + }, }}); if ev_index.is_some() { msg_events.remove(ev_index.unwrap()) @@ -676,6 +802,28 @@ macro_rules! get_channel_ref { } } +#[cfg(test)] +macro_rules! get_outbound_v1_channel_ref { + ($node: expr, $counterparty_node: expr, $per_peer_state_lock: ident, $peer_state_lock: ident, $channel_id: expr) => { + { + $per_peer_state_lock = $node.node.per_peer_state.read().unwrap(); + $peer_state_lock = $per_peer_state_lock.get(&$counterparty_node.node.get_our_node_id()).unwrap().lock().unwrap(); + $peer_state_lock.outbound_v1_channel_by_id.get_mut(&$channel_id).unwrap() + } + } +} + +#[cfg(test)] +macro_rules! get_inbound_v1_channel_ref { + ($node: expr, $counterparty_node: expr, $per_peer_state_lock: ident, $peer_state_lock: ident, $channel_id: expr) => { + { + $per_peer_state_lock = $node.node.per_peer_state.read().unwrap(); + $peer_state_lock = $per_peer_state_lock.get(&$counterparty_node.node.get_our_node_id()).unwrap().lock().unwrap(); + $peer_state_lock.inbound_v1_channel_by_id.get_mut(&$channel_id).unwrap() + } + } +} + #[cfg(test)] macro_rules! get_feerate { ($node: expr, $counterparty_node: expr, $channel_id: expr) => { @@ -683,19 +831,19 @@ macro_rules! get_feerate { let mut per_peer_state_lock; let mut peer_state_lock; let chan = get_channel_ref!($node, $counterparty_node, per_peer_state_lock, peer_state_lock, $channel_id); - chan.get_feerate() + chan.context.get_feerate_sat_per_1000_weight() } } } #[cfg(test)] -macro_rules! get_opt_anchors { +macro_rules! get_channel_type_features { ($node: expr, $counterparty_node: expr, $channel_id: expr) => { { let mut per_peer_state_lock; let mut peer_state_lock; let chan = get_channel_ref!($node, $counterparty_node, per_peer_state_lock, peer_state_lock, $channel_id); - chan.opt_anchors() + chan.context.get_channel_type().clone() } } } @@ -758,10 +906,12 @@ macro_rules! unwrap_send_err { } /// Check whether N channel monitor(s) have been added. -pub fn check_added_monitors(node: &Node, count: usize) { - let mut added_monitors = node.chain_monitor.added_monitors.lock().unwrap(); - assert_eq!(added_monitors.len(), count); - added_monitors.clear(); +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); + added_monitors.clear(); + } } /// Check whether N channel monitor(s) have been added. @@ -867,6 +1017,7 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: & assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&node_b, &node_a.node.get_our_node_id()); node_a.node.handle_funding_signed(&node_b.node.get_our_node_id(), &get_event_msg!(node_b, MessageSendEvent::SendFundingSigned, node_a.node.get_our_node_id())); { @@ -875,6 +1026,7 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: & assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&node_a, &node_b.node.get_our_node_id()); let events_4 = node_a.node.get_and_clear_pending_events(); assert_eq!(events_4.len(), 0); @@ -926,6 +1078,8 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r MessageSendEvent::SendFundingSigned { node_id, msg } => { assert_eq!(*node_id, initiator.node.get_our_node_id()); initiator.node.handle_funding_signed(&receiver.node.get_our_node_id(), &msg); + expect_channel_pending_event(&initiator, &receiver.node.get_our_node_id()); + expect_channel_pending_event(&receiver, &initiator.node.get_our_node_id()); check_added_monitors!(initiator, 1); assert_eq!(initiator.tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1); @@ -939,11 +1093,13 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r MessageSendEvent::SendChannelReady { node_id, msg } => { assert_eq!(*node_id, initiator.node.get_our_node_id()); initiator.node.handle_channel_ready(&receiver.node.get_our_node_id(), &msg); + expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id()); } _ => panic!("Unexpected event"), } receiver.node.handle_channel_ready(&initiator.node.get_our_node_id(), &as_channel_ready); + expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id()); let as_channel_update = get_event_msg!(initiator, MessageSendEvent::SendChannelUpdate, receiver.node.get_our_node_id()); let bs_channel_update = get_event_msg!(receiver, MessageSendEvent::SendChannelUpdate, initiator.node.get_our_node_id()); @@ -954,9 +1110,6 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r assert_eq!(initiator.node.list_usable_channels().len(), initiator_channels + 1); assert_eq!(receiver.node.list_usable_channels().len(), receiver_channels + 1); - expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id()); - expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id()); - (tx, as_channel_ready.channel_id) } @@ -966,6 +1119,15 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, ' assert_eq!(open_channel_msg.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 { + let events = node_b.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match &events[0] { + Event::OpenChannelRequest { temporary_channel_id, counterparty_node_id, .. } => + node_b.node.accept_inbound_channel(temporary_channel_id, counterparty_node_id, 42).unwrap(), + _ => panic!("Unexpected event"), + }; + } 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); node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), &accept_channel_msg); @@ -1081,9 +1243,16 @@ pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: & check_added_monitors!(nodes[b], 1); let cs_funding_signed = get_event_msg!(nodes[b], MessageSendEvent::SendFundingSigned, nodes[a].node.get_our_node_id()); + expect_channel_pending_event(&nodes[b], &nodes[a].node.get_our_node_id()); + nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed); + expect_channel_pending_event(&nodes[a], &nodes[b].node.get_our_node_id()); check_added_monitors!(nodes[a], 1); + assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1); + assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap()[0], tx); + nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().clear(); + let conf_height = core::cmp::max(nodes[a].best_block_info().1 + 1, nodes[b].best_block_info().1 + 1); confirm_transaction_at(&nodes[a], &tx, conf_height); connect_blocks(&nodes[a], CHAN_CONFIRM_DEPTH - 1); @@ -1136,6 +1305,24 @@ pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec Option>(tx: &Transaction, get_output: F) { + for outp in tx.output.iter() { + assert!(outp.value >= outp.script_pubkey.dust_value().to_sat(), "Spending tx output didn't meet dust limit"); + } + let mut total_value_in = 0; + for input in tx.input.iter() { + total_value_in += get_output(&input.previous_output).unwrap().value; + } + let mut total_value_out = 0; + 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) + // 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(); +} + #[macro_export] macro_rules! check_spends { ($tx: expr, $($spends_txn: expr),*) => { @@ -1145,9 +1332,6 @@ macro_rules! check_spends { assert!(outp.value >= outp.script_pubkey.dust_value().to_sat(), "Input tx output didn't meet dust limit"); } )* - for outp in $tx.output.iter() { - assert!(outp.value >= outp.script_pubkey.dust_value().to_sat(), "Spending tx output didn't meet dust limit"); - } let get_output = |out_point: &bitcoin::blockdata::transaction::OutPoint| { $( if out_point.txid == $spends_txn.txid() { @@ -1156,18 +1340,7 @@ macro_rules! check_spends { )* None }; - let mut total_value_in = 0; - for input in $tx.input.iter() { - total_value_in += get_output(&input.previous_output).unwrap().value; - } - let mut total_value_out = 0; - 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) - // 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(); + $crate::ln::functional_test_utils::do_check_spends(&$tx, get_output); } } } @@ -1214,58 +1387,66 @@ macro_rules! check_warn_msg { /// Check that a channel's closing channel update has been broadcasted, and optionally /// check whether an error message event has occurred. -#[macro_export] -macro_rules! check_closed_broadcast { - ($node: expr, $with_error_msg: expr) => {{ - use $crate::util::events::MessageSendEvent; - use $crate::ln::msgs::ErrorAction; - - let msg_events = $node.node.get_and_clear_pending_msg_events(); - assert_eq!(msg_events.len(), if $with_error_msg { 2 } else { 1 }); - match msg_events[0] { +pub fn check_closed_broadcast(node: &Node, num_channels: usize, with_error_msg: bool) -> Vec { + let msg_events = node.node.get_and_clear_pending_msg_events(); + assert_eq!(msg_events.len(), if with_error_msg { num_channels * 2 } else { num_channels }); + msg_events.into_iter().filter_map(|msg_event| { + match msg_event { MessageSendEvent::BroadcastChannelUpdate { ref msg } => { assert_eq!(msg.contents.flags & 2, 2); + None + }, + MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => { + assert!(with_error_msg); + // TODO: Check node_id + Some(msg.clone()) }, _ => panic!("Unexpected event"), } - if $with_error_msg { - match msg_events[1] { - MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => { - // TODO: Check node_id - Some(msg.clone()) - }, - _ => panic!("Unexpected event"), + }).collect() +} + +/// Check that a channel's closing channel update has been broadcasted, and optionally +/// check whether an error message event has occurred. +/// +/// Don't use this, use the identically-named function instead. +#[macro_export] +macro_rules! check_closed_broadcast { + ($node: expr, $with_error_msg: expr) => { + $crate::ln::functional_test_utils::check_closed_broadcast(&$node, 1, $with_error_msg).pop() + } +} + +/// Check that a channel's closing channel events has been issued +pub fn check_closed_event(node: &Node, events_count: usize, expected_reason: ClosureReason, is_check_discard_funding: bool) { + let events = node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), events_count, "{:?}", events); + let mut issues_discard_funding = false; + for event in events { + match event { + Event::ChannelClosed { ref reason, .. } => { + assert_eq!(*reason, expected_reason); + }, + Event::DiscardFunding { .. } => { + issues_discard_funding = true; } - } else { None } - }} + _ => panic!("Unexpected event"), + } + } + assert_eq!(is_check_discard_funding, issues_discard_funding); } /// Check that a channel's closing channel events has been issued +/// +/// Don't use this, use the identically-named function instead. #[macro_export] macro_rules! check_closed_event { ($node: expr, $events: expr, $reason: expr) => { check_closed_event!($node, $events, $reason, false); }; - ($node: expr, $events: expr, $reason: expr, $is_check_discard_funding: expr) => {{ - use $crate::util::events::Event; - - let events = $node.node.get_and_clear_pending_events(); - assert_eq!(events.len(), $events, "{:?}", events); - let expected_reason = $reason; - let mut issues_discard_funding = false; - for event in events { - match event { - Event::ChannelClosed { ref reason, .. } => { - assert_eq!(*reason, expected_reason); - }, - Event::DiscardFunding { .. } => { - issues_discard_funding = true; - } - _ => panic!("Unexpected event"), - } - } - assert_eq!($is_check_discard_funding, issues_discard_funding); - }} + ($node: expr, $events: expr, $reason: expr, $is_check_discard_funding: expr) => { + $crate::ln::functional_test_utils::check_closed_event(&$node, $events, $reason, $is_check_discard_funding); + } } pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node: &Node<'a, 'b, 'c>, channel_id: &[u8; 32], funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, Transaction) { @@ -1367,22 +1548,11 @@ impl SendEvent { } #[macro_export] +/// Don't use this, use the identically-named function instead. macro_rules! expect_pending_htlcs_forwardable_conditions { - ($node: expr, $expected_failures: expr) => {{ - let expected_failures = $expected_failures; - let events = $node.node.get_and_clear_pending_events(); - match events[0] { - $crate::util::events::Event::PendingHTLCsForwardable { .. } => { }, - _ => panic!("Unexpected event {:?}", events), - }; - - let count = expected_failures.len() + 1; - assert_eq!(events.len(), count); - - if expected_failures.len() > 0 { - expect_htlc_handling_failed_destinations!(events, expected_failures) - } - }} + ($node: expr, $expected_failures: expr) => { + $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures); + } } #[macro_export] @@ -1390,8 +1560,8 @@ macro_rules! expect_htlc_handling_failed_destinations { ($events: expr, $expected_failures: expr) => {{ for event in $events { match event { - $crate::util::events::Event::PendingHTLCsForwardable { .. } => { }, - $crate::util::events::Event::HTLCHandlingFailed { ref failed_next_destination, .. } => { + $crate::events::Event::PendingHTLCsForwardable { .. } => { }, + $crate::events::Event::HTLCHandlingFailed { ref failed_next_destination, .. } => { assert!($expected_failures.contains(&failed_next_destination)) }, _ => panic!("Unexpected destination"), @@ -1400,27 +1570,49 @@ macro_rules! expect_htlc_handling_failed_destinations { }} } +/// Checks that an [`Event::PendingHTLCsForwardable`] is available in the given events and, if +/// there are any [`Event::HTLCHandlingFailed`] events their [`HTLCDestination`] is included in the +/// `expected_failures` set. +pub fn expect_pending_htlcs_forwardable_conditions(events: Vec, expected_failures: &[HTLCDestination]) { + match events[0] { + Event::PendingHTLCsForwardable { .. } => { }, + _ => panic!("Unexpected event {:?}", events), + }; + + let count = expected_failures.len() + 1; + assert_eq!(events.len(), count); + + if expected_failures.len() > 0 { + expect_htlc_handling_failed_destinations!(events, expected_failures) + } +} + #[macro_export] /// Clears (and ignores) a PendingHTLCsForwardable event +/// +/// Don't use this, call [`expect_pending_htlcs_forwardable_conditions()`] with an empty failure +/// set instead. macro_rules! expect_pending_htlcs_forwardable_ignore { - ($node: expr) => {{ - expect_pending_htlcs_forwardable_conditions!($node, vec![]); - }}; + ($node: expr) => { + $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &[]); + } } #[macro_export] /// Clears (and ignores) PendingHTLCsForwardable and HTLCHandlingFailed events +/// +/// Don't use this, call [`expect_pending_htlcs_forwardable_conditions()`] instead. macro_rules! expect_pending_htlcs_forwardable_and_htlc_handling_failed_ignore { - ($node: expr, $expected_failures: expr) => {{ - expect_pending_htlcs_forwardable_conditions!($node, $expected_failures); - }}; + ($node: expr, $expected_failures: expr) => { + $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures); + } } #[macro_export] /// Handles a PendingHTLCsForwardable event macro_rules! expect_pending_htlcs_forwardable { ($node: expr) => {{ - expect_pending_htlcs_forwardable_ignore!($node); + $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &[]); $node.node.process_pending_htlc_forwards(); // Ensure process_pending_htlc_forwards is idempotent. @@ -1432,7 +1624,7 @@ macro_rules! expect_pending_htlcs_forwardable { /// Handles a PendingHTLCsForwardable and HTLCHandlingFailed event macro_rules! expect_pending_htlcs_forwardable_and_htlc_handling_failed { ($node: expr, $expected_failures: expr) => {{ - expect_pending_htlcs_forwardable_and_htlc_handling_failed_ignore!($node, $expected_failures); + $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures); $node.node.process_pending_htlc_forwards(); // Ensure process_pending_htlc_forwards is idempotent. @@ -1478,23 +1670,30 @@ macro_rules! commitment_signed_dance { bs_revoke_and_ack } }; - ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, true /* return extra message */) => { - { - let (extra_msg_option, bs_revoke_and_ack) = $crate::ln::functional_test_utils::do_main_commitment_signed_dance(&$node_a, &$node_b, $fail_backwards); - $node_a.node.handle_revoke_and_ack(&$node_b.node.get_our_node_id(), &bs_revoke_and_ack); - $crate::ln::functional_test_utils::check_added_monitors(&$node_a, 1); - extra_msg_option - } - }; ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, false /* no extra message */) => { - assert!(commitment_signed_dance!($node_a, $node_b, (), $fail_backwards, true, true).is_none()); + assert!($crate::ln::functional_test_utils::commitment_signed_dance_through_cp_raa(&$node_a, &$node_b, $fail_backwards).is_none()); }; ($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backwards: expr) => { $crate::ln::functional_test_utils::do_commitment_signed_dance(&$node_a, &$node_b, &$commitment_signed, $fail_backwards, false); } } - +/// Runs the commitment_signed dance after the initial commitment_signed is delivered through to +/// the initiator's `revoke_and_ack` response. i.e. [`do_main_commitment_signed_dance`] plus the +/// `revoke_and_ack` response to it. +/// +/// Returns any additional message `node_b` generated in addition to the `revoke_and_ack` response. +pub fn commitment_signed_dance_through_cp_raa(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool) -> Option { + let (extra_msg_option, bs_revoke_and_ack) = do_main_commitment_signed_dance(node_a, node_b, fail_backwards); + node_a.node.handle_revoke_and_ack(&node_b.node.get_our_node_id(), &bs_revoke_and_ack); + check_added_monitors(node_a, 1); + extra_msg_option +} + +/// Does the main logic in the commitment_signed dance. After the first `commitment_signed` has +/// been delivered, this method picks up and delivers the response `revoke_and_ack` and +/// `commitment_signed`, returning the recipient's `revoke_and_ack` and any extra message it may +/// have included. pub fn do_main_commitment_signed_dance(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool) -> (Option, msgs::RevokeAndACK) { let (as_revoke_and_ack, as_commitment_signed) = get_revoke_commit_msgs!(node_a, node_b.node.get_our_node_id()); check_added_monitors!(node_b, 0); @@ -1523,6 +1722,11 @@ pub fn do_main_commitment_signed_dance(node_a: &Node<'_, '_, '_>, node_b: &Node< (extra_msg_option, bs_revoke_and_ack) } +/// Runs a full commitment_signed dance, delivering a commitment_signed, the responding +/// `revoke_and_ack` and `commitment_signed`, and then the final `revoke_and_ack` response. +/// +/// If `skip_last_step` is unset, also checks for the payment failure update for the previous hop +/// on failure or that no new messages are left over on success. pub fn do_commitment_signed_dance(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, commitment_signed: &msgs::CommitmentSigned, fail_backwards: bool, skip_last_step: bool) { check_added_monitors!(node_a, 0); assert!(node_a.node.get_and_clear_pending_msg_events().is_empty()); @@ -1535,7 +1739,7 @@ pub fn do_commitment_signed_dance(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, ' if fail_backwards { expect_pending_htlcs_forwardable_and_htlc_handling_failed!(node_a, - vec![crate::util::events::HTLCDestination::NextHopChannel{ node_id: Some(node_b.node.get_our_node_id()), channel_id: commitment_signed.channel_id }]); + vec![crate::events::HTLCDestination::NextHopChannel{ node_id: Some(node_b.node.get_our_node_id()), channel_id: commitment_signed.channel_id }]); check_added_monitors!(node_a, 1); let node_a_per_peer_state = node_a.node.per_peer_state.read().unwrap(); @@ -1583,19 +1787,26 @@ macro_rules! get_payment_preimage_hash { }; } +/// Gets a route from the given sender to the node described in `payment_params`. +pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_value: u64) -> 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::get_route( + &send_node.node.get_our_node_id(), payment_params, &send_node.network_graph.read_only(), + Some(&send_node.node.list_usable_channels().iter().collect::>()), + recv_value, send_node.logger, &scorer, &(), &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. #[macro_export] macro_rules! get_route { - ($send_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ - use $crate::chain::keysinterface::EntropySource; - let scorer = $crate::util::test_utils::TestScorer::new(); - let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet); - let random_seed_bytes = keys_manager.get_secure_random_bytes(); - $crate::routing::router::get_route( - &$send_node.node.get_our_node_id(), &$payment_params, &$send_node.network_graph.read_only(), - Some(&$send_node.node.list_usable_channels().iter().collect::>()), - $recv_value, $cltv, $send_node.logger, &scorer, &random_seed_bytes - ) - }} + ($send_node: expr, $payment_params: expr, $recv_value: expr) => { + $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value) + } } #[cfg(test)] @@ -1603,19 +1814,41 @@ macro_rules! get_route { macro_rules! get_route_and_payment_hash { ($send_node: expr, $recv_node: expr, $recv_value: expr) => {{ let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features($recv_node.node.invoice_features()); - $crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, TEST_FINAL_CLTV) + .with_bolt11_features($recv_node.node.invoice_features()).unwrap(); + $crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value) }}; - ($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ + ($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr) => {{ let (payment_preimage, payment_hash, payment_secret) = $crate::ln::functional_test_utils::get_payment_preimage_hash(&$recv_node, Some($recv_value), None); - let route = $crate::get_route!($send_node, $payment_params, $recv_value, $cltv); + let route = $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value); (route.unwrap(), payment_hash, payment_preimage, payment_secret) }} } +pub fn check_payment_claimable( + event: &Event, expected_payment_hash: PaymentHash, expected_payment_secret: PaymentSecret, + expected_recv_value: u64, expected_payment_preimage: Option, + expected_receiver_node_id: PublicKey, +) { + match event { + Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, .. } => { + assert_eq!(expected_payment_hash, *payment_hash); + assert_eq!(expected_recv_value, *amount_msat); + assert_eq!(expected_receiver_node_id, receiver_node_id.unwrap()); + match purpose { + PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { + assert_eq!(&expected_payment_preimage, payment_preimage); + assert_eq!(expected_payment_secret, *payment_secret); + }, + _ => {}, + } + }, + _ => panic!("Unexpected event"), + } +} + #[macro_export] -#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] +#[cfg(any(test, ldk_bench, feature = "_test_utils"))] macro_rules! expect_payment_claimable { ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr) => { expect_payment_claimable!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None, $node.node.get_our_node_id()) @@ -1623,32 +1856,18 @@ macro_rules! expect_payment_claimable { ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr, $expected_receiver_node_id: expr) => { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); - match events[0] { - $crate::util::events::Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, via_channel_id: _, via_user_channel_id: _ } => { - assert_eq!($expected_payment_hash, *payment_hash); - assert_eq!($expected_recv_value, amount_msat); - assert_eq!($expected_receiver_node_id, receiver_node_id.unwrap()); - match purpose { - $crate::util::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { - assert_eq!(&$expected_payment_preimage, payment_preimage); - assert_eq!($expected_payment_secret, *payment_secret); - }, - _ => {}, - } - }, - _ => panic!("Unexpected event"), - } - } + $crate::ln::functional_test_utils::check_payment_claimable(&events[0], $expected_payment_hash, $expected_payment_secret, $expected_recv_value, $expected_payment_preimage, $expected_receiver_node_id) + }; } #[macro_export] -#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] +#[cfg(any(test, ldk_bench, feature = "_test_utils"))] macro_rules! expect_payment_claimed { ($node: expr, $expected_payment_hash: expr, $expected_recv_value: expr) => { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - $crate::util::events::Event::PaymentClaimed { ref payment_hash, amount_msat, .. } => { + $crate::events::Event::PaymentClaimed { ref payment_hash, amount_msat, .. } => { assert_eq!($expected_payment_hash, *payment_hash); assert_eq!($expected_recv_value, amount_msat); }, @@ -1657,6 +1876,44 @@ macro_rules! expect_payment_claimed { } } +pub fn expect_payment_sent>(node: &H, + expected_payment_preimage: PaymentPreimage, expected_fee_msat_opt: Option>, + expect_per_path_claims: bool, +) { + 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()); + if expect_per_path_claims { + assert!(events.len() > 1); + } else { + assert_eq!(events.len(), 1); + } + let expected_payment_id = match events[0] { + Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { + assert_eq!(expected_payment_preimage, *payment_preimage); + assert_eq!(expected_payment_hash, *payment_hash); + if let Some(expected_fee_msat) = expected_fee_msat_opt { + assert_eq!(*fee_paid_msat, expected_fee_msat); + } else { + assert!(fee_paid_msat.is_some()); + } + payment_id.unwrap() + }, + _ => panic!("Unexpected event"), + }; + if expect_per_path_claims { + for i in 1..events.len() { + match events[i] { + Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => { + assert_eq!(payment_id, expected_payment_id); + assert_eq!(payment_hash, Some(expected_payment_hash)); + }, + _ => panic!("Unexpected event"), + } + } + } +} + #[cfg(test)] #[macro_export] macro_rules! expect_payment_sent_without_paths { @@ -1676,40 +1933,10 @@ macro_rules! expect_payment_sent { ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr) => { $crate::expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, true); }; - ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => { { - use bitcoin::hashes::Hash as _; - let events = $node.node.get_and_clear_pending_events(); - let expected_payment_hash = $crate::ln::PaymentHash( - bitcoin::hashes::sha256::Hash::hash(&$expected_payment_preimage.0).into_inner()); - if $expect_paths { - assert!(events.len() > 1); - } else { - assert_eq!(events.len(), 1); - } - let expected_payment_id = match events[0] { - $crate::util::events::Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { - assert_eq!($expected_payment_preimage, *payment_preimage); - assert_eq!(expected_payment_hash, *payment_hash); - assert!(fee_paid_msat.is_some()); - if $expected_fee_msat_opt.is_some() { - assert_eq!(*fee_paid_msat, $expected_fee_msat_opt); - } - payment_id.unwrap() - }, - _ => panic!("Unexpected event"), - }; - if $expect_paths { - for i in 1..events.len() { - match events[i] { - $crate::util::events::Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => { - assert_eq!(payment_id, expected_payment_id); - assert_eq!(payment_hash, Some(expected_payment_hash)); - }, - _ => panic!("Unexpected event"), - } - } - } - } } + ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => { + $crate::ln::functional_test_utils::expect_payment_sent(&$node, $expected_payment_preimage, + $expected_fee_msat_opt.map(|o| Some(o)), $expect_paths); + } } #[cfg(test)] @@ -1719,7 +1946,7 @@ macro_rules! expect_payment_path_successful { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - $crate::util::events::Event::PaymentPathSuccessful { .. } => {}, + $crate::events::Event::PaymentPathSuccessful { .. } => {}, _ => panic!("Unexpected event"), } } @@ -1730,7 +1957,10 @@ macro_rules! expect_payment_forwarded { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PaymentForwarded { fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id } => { + Event::PaymentForwarded { + fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id, + outbound_amount_forwarded_msat: _ + } => { assert_eq!(fee_earned_msat, $expected_fee); if fee_earned_msat.is_some() { // Is the event prev_channel_id in one of the channels between the two nodes? @@ -1748,18 +1978,39 @@ macro_rules! expect_payment_forwarded { } } -#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] -pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) { +#[cfg(test)] +#[macro_export] +macro_rules! expect_channel_shutdown_state { + ($node: expr, $chan_id: expr, $state: path) => { + let chan_details = $node.node.list_channels().into_iter().filter(|cd| cd.channel_id == $chan_id).collect::>(); + assert_eq!(chan_details.len(), 1); + assert_eq!(chan_details[0].channel_shutdown_state, Some($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) { let events = node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - crate::util::events::Event::ChannelReady{ ref counterparty_node_id, .. } => { + crate::events::Event::ChannelPending { ref counterparty_node_id, .. } => { assert_eq!(*expected_counterparty_node_id, *counterparty_node_id); }, _ => panic!("Unexpected event"), } } +#[cfg(any(test, ldk_bench, feature = "_test_utils"))] +pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) { + let events = node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + crate::events::Event::ChannelReady{ ref counterparty_node_id, .. } => { + assert_eq!(*expected_counterparty_node_id, *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + } +} pub struct PaymentFailedConditions<'a> { pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>, @@ -1823,20 +2074,13 @@ pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>( ) { if conditions.expected_mpp_parts_remain { assert_eq!(payment_failed_events.len(), 1); } else { assert_eq!(payment_failed_events.len(), 2); } let expected_payment_id = match &payment_failed_events[0] { - Event::PaymentPathFailed { payment_hash, payment_failed_permanently, path, retry, payment_id, failure, short_channel_id, + Event::PaymentPathFailed { payment_hash, payment_failed_permanently, payment_id, failure, #[cfg(test)] error_code, #[cfg(test)] error_data, .. } => { assert_eq!(*payment_hash, expected_payment_hash, "unexpected payment_hash"); assert_eq!(*payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value"); - assert!(retry.is_some(), "expected retry.is_some()"); - assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path"); - assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path"); - if let Some(scid) = short_channel_id { - assert!(retry.as_ref().unwrap().payment_params.previously_failed_channels.contains(&scid)); - } - #[cfg(test)] { assert!(error_code.is_some(), "expected error_code.is_some() = true"); @@ -1874,9 +2118,14 @@ pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>( }; if !conditions.expected_mpp_parts_remain { match &payment_failed_events[1] { - Event::PaymentFailed { ref payment_hash, ref payment_id } => { + Event::PaymentFailed { ref payment_hash, ref payment_id, ref reason } => { assert_eq!(*payment_hash, expected_payment_hash, "unexpected second payment_hash"); assert_eq!(*payment_id, expected_payment_id); + assert_eq!(reason.unwrap(), if expected_payment_failed_permanently { + PaymentFailureReason::RecipientRejected + } else { + PaymentFailureReason::RetriesExhausted + }); } _ => panic!("Unexpected second event"), } @@ -1893,15 +2142,17 @@ pub fn expect_payment_failed_conditions<'a, 'b, 'c, 'd, 'e>( pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route, expected_paths: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) -> PaymentId { let payment_id = PaymentId(origin_node.keys_manager.backing.get_secure_random_bytes()); - origin_node.node.send_payment(&route, our_payment_hash, &Some(our_payment_secret), payment_id).unwrap(); + origin_node.node.send_payment_with_route(&route, our_payment_hash, + RecipientOnionFields::secret_only(our_payment_secret), payment_id).unwrap(); check_added_monitors!(origin_node, expected_paths.len()); pass_along_route(origin_node, expected_paths, recv_value, our_payment_hash, our_payment_secret); 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) { +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 { 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() { assert_eq!(node.node.get_our_node_id(), payment_event.node_id); @@ -1916,26 +2167,33 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p let events_2 = node.node.get_and_clear_pending_events(); if payment_claimable_expected { assert_eq!(events_2.len(), 1); - match events_2[0] { - Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, ref via_channel_id, ref via_user_channel_id } => { + match &events_2[0] { + Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, + receiver_node_id, ref via_channel_id, ref via_user_channel_id, + claim_deadline, onion_fields, .. + } => { assert_eq!(our_payment_hash, *payment_hash); assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap()); + assert!(onion_fields.is_some()); match &purpose { PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { assert_eq!(expected_preimage, *payment_preimage); assert_eq!(our_payment_secret.unwrap(), *payment_secret); + assert_eq!(Some(*payment_secret), onion_fields.as_ref().unwrap().payment_secret); }, PaymentPurpose::SpontaneousPayment(payment_preimage) => { assert_eq!(expected_preimage.unwrap(), *payment_preimage); - assert!(our_payment_secret.is_none()); + assert_eq!(our_payment_secret, onion_fields.as_ref().unwrap().payment_secret); }, } - assert_eq!(amount_msat, recv_value); + assert_eq!(*amount_msat, recv_value); assert!(node.node.list_channels().iter().any(|details| details.channel_id == via_channel_id.unwrap())); assert!(node.node.list_channels().iter().any(|details| details.user_channel_id == via_user_channel_id.unwrap())); + assert!(claim_deadline.unwrap() > node.best_block_info().1); }, _ => panic!("Unexpected event"), } + event = Some(events_2[0].clone()); } else { assert!(events_2.is_empty()); } @@ -1949,10 +2207,11 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p prev_node = node; } + event } -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) { - do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_claimable_expected, true, expected_preimage); +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) } 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) { @@ -1973,7 +2232,20 @@ pub fn send_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route (our_payment_preimage, our_payment_hash, our_payment_secret, payment_id) } -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 { +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()); } @@ -2023,7 +2295,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, } } - for (expected_route, (path_msgs, next_hop)) in expected_paths.iter().zip(per_path_msgs.drain(..)) { + for (i, (expected_route, (path_msgs, next_hop))) in expected_paths.iter().zip(per_path_msgs.drain(..)).enumerate() { let mut next_msgs = Some(path_msgs); let mut expected_next_node = next_hop; @@ -2038,20 +2310,21 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, } } macro_rules! mid_update_fulfill_dance { - ($node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => { + ($idx: expr, $node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => { { $node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0); - let fee = { + 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.prev_config() { + if let Some(prev_config) = channel.context.prev_config() { prev_config.forwarding_fee_base_msat } else { - channel.config().forwarding_fee_base_msat + channel.context.config().forwarding_fee_base_msat } }; + 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; check_added_monitors!($node, 1); @@ -2083,7 +2356,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, } else { next_node = expected_route[expected_route.len() - 1 - idx - 1]; } - mid_update_fulfill_dance!(node, prev_node, next_node, update_next_msgs); + mid_update_fulfill_dance!(idx, node, prev_node, next_node, update_next_msgs); } else { assert!(!update_next_msgs); assert!(node.node.get_and_clear_pending_msg_events().is_empty()); @@ -2122,11 +2395,11 @@ pub const TEST_FINAL_CLTV: u32 = 70; pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) { let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features(expected_route.last().unwrap().node.invoice_features()); - let route = get_route!(origin_node, payment_params, recv_value, TEST_FINAL_CLTV).unwrap(); + .with_bolt11_features(expected_route.last().unwrap().node.invoice_features()).unwrap(); + let route = get_route(origin_node, &payment_params, recv_value).unwrap(); assert_eq!(route.paths.len(), 1); - assert_eq!(route.paths[0].len(), expected_route.len()); - for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) { + assert_eq!(route.paths[0].hops.len(), expected_route.len()); + for (node, hop) in expected_route.iter().zip(route.paths[0].hops.iter()) { assert_eq!(hop.pubkey, node.node.get_our_node_id()); } @@ -2136,23 +2409,25 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) { let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV) - .with_features(expected_route.last().unwrap().node.invoice_features()); + .with_bolt11_features(expected_route.last().unwrap().node.invoice_features()).unwrap(); let network_graph = origin_node.network_graph.read_only(); let scorer = test_utils::TestScorer::new(); let seed = [0u8; 32]; let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); - let route = get_route( + let route = router::get_route( &origin_node.node.get_our_node_id(), &payment_params, &network_graph, - None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap(); + None, recv_value, origin_node.logger, &scorer, &(), &random_seed_bytes).unwrap(); assert_eq!(route.paths.len(), 1); - assert_eq!(route.paths[0].len(), expected_route.len()); - for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) { + assert_eq!(route.paths[0].hops.len(), expected_route.len()); + for (node, hop) in expected_route.iter().zip(route.paths[0].hops.iter()) { assert_eq!(hop.pubkey, node.node.get_our_node_id()); } - let (_, our_payment_hash, our_payment_preimage) = get_payment_preimage_hash!(expected_route.last().unwrap()); - unwrap_send_err!(origin_node.node.send_payment(&route, our_payment_hash, &Some(our_payment_preimage), PaymentId(our_payment_hash.0)), true, APIError::ChannelUnavailable { ref err }, + let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(expected_route.last().unwrap()); + unwrap_send_err!(origin_node.node.send_payment_with_route(&route, our_payment_hash, + RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0)), + true, APIError::ChannelUnavailable { ref err }, assert!(err.contains("Cannot send value that would put us over the max HTLC value in flight our peer will accept"))); } @@ -2170,10 +2445,10 @@ pub fn fail_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe let expected_destinations: Vec = repeat(HTLCDestination::FailedPayment { payment_hash: our_payment_hash }).take(expected_paths.len()).collect(); expect_pending_htlcs_forwardable_and_htlc_handling_failed!(expected_paths[0].last().unwrap(), expected_destinations); - pass_failed_payment_back(origin_node, expected_paths, skip_last, our_payment_hash); + pass_failed_payment_back(origin_node, expected_paths, skip_last, our_payment_hash, PaymentFailureReason::RecipientRejected); } -pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) { +pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash, expected_fail_reason: PaymentFailureReason) { let mut expected_paths: Vec<_> = expected_paths_slice.iter().collect(); check_added_monitors!(expected_paths[0].last().unwrap(), expected_paths.len()); @@ -2251,7 +2526,7 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe assert_eq!(payment_hash, our_payment_hash); assert!(payment_failed_permanently); for (idx, hop) in expected_route.iter().enumerate() { - assert_eq!(hop.node.get_our_node_id(), path[idx].pubkey); + assert_eq!(hop.node.get_our_node_id(), path.hops[idx].pubkey); } payment_id.unwrap() }, @@ -2259,9 +2534,10 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe }; if i == expected_paths.len() - 1 { match events[1] { - Event::PaymentFailed { ref payment_hash, ref payment_id } => { + Event::PaymentFailed { ref payment_hash, ref payment_id, ref reason } => { assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash"); assert_eq!(*payment_id, expected_payment_id); + assert_eq!(reason.unwrap(), expected_fail_reason); } _ => panic!("Unexpected second event"), } @@ -2283,10 +2559,7 @@ pub fn fail_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: & pub fn create_chanmon_cfgs(node_count: usize) -> Vec { let mut chan_mon_cfgs = Vec::new(); for i in 0..node_count { - let tx_broadcaster = test_utils::TestBroadcaster { - txn_broadcasted: Mutex::new(Vec::new()), - blocks: Arc::new(Mutex::new(vec![(genesis_block(Network::Testnet), 0)])), - }; + let tx_broadcaster = test_utils::TestBroadcaster::new(Network::Testnet); let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }; let chain_source = test_utils::TestChainSource::new(Network::Testnet); let logger = test_utils::TestLogger::with_id(format!("node {}", i)); @@ -2336,8 +2609,10 @@ pub fn test_default_channel_config() -> UserConfig { // It now defaults to 1, so we simply set it to the expected value here. default_config.channel_handshake_config.our_htlc_minimum_msat = 1000; // When most of our tests were written, we didn't have the notion of a `max_dust_htlc_exposure_msat`, - // It now defaults to 5_000_000 msat; to avoid interfering with tests we bump it to 50_000_000 msat. - default_config.channel_config.max_dust_htlc_exposure_msat = 50_000_000; + // to avoid interfering with tests we bump it to 50_000_000 msat (assuming the default test + // feerate of 253). + default_config.channel_config.max_dust_htlc_exposure = + MaxDustHTLCExposure::FeeRateMultiplier(50_000_000 / 253); default_config } @@ -2345,12 +2620,13 @@ pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec let mut chanmgrs = Vec::new(); for i in 0..node_count { let network = Network::Testnet; + let genesis_block = bitcoin::blockdata::constants::genesis_block(network); let params = ChainParameters { network, best_block: BestBlock::from_network(network), }; let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, &cfgs[i].router, cfgs[i].logger, cfgs[i].keys_manager, - cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params); + cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params, genesis_block.header.time); chanmgrs.push(node); } @@ -2365,6 +2641,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec(node_count: usize, cfgs: &'b Vec(node: &Node<'a, 'b, 'c>, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], 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(); + 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 }); let mut res = Vec::with_capacity(2); @@ -2469,22 +2761,23 @@ 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(); + node_txn.retain(|tx| txn_seen.insert(tx.txid())); - assert!(node_txn.len() >= 1); - assert_eq!(node_txn[0].input.len(), 1); let mut found_prev = false; - - for tx in prev_txn { - if node_txn[0].input[0].previous_output.txid == tx.txid() { - check_spends!(node_txn[0], tx); - let mut iter = node_txn[0].input[0].witness.iter(); - iter.next().expect("expected 3 witness items"); - iter.next().expect("expected 3 witness items"); - assert!(iter.next().expect("expected 3 witness items").len() > 106); // must spend an htlc output - assert_eq!(tx.input.len(), 1); // must spend a commitment tx - - found_prev = true; - break; + for prev_tx in prev_txn { + for tx in &*node_txn { + if tx.input[0].previous_output.txid == prev_tx.txid() { + check_spends!(tx, prev_tx); + let mut iter = tx.input[0].witness.iter(); + iter.next().expect("expected 3 witness items"); + iter.next().expect("expected 3 witness items"); + assert!(iter.next().expect("expected 3 witness items").len() > 106); // must spend an htlc output + assert_eq!(tx.input.len(), 1); // must spend a commitment tx + + found_prev = true; + break; + } } } assert!(found_prev); @@ -2568,13 +2861,6 @@ macro_rules! get_chan_reestablish_msgs { panic!("Unexpected event") } } - for chan in $src_node.node.list_channels() { - if chan.is_public && chan.counterparty.node_id != $dst_node.node.get_our_node_id() { - if let Some(scid) = chan.short_channel_id { - assert!(announcements.remove(&scid)); - } - } - } assert!(announcements.is_empty()); res } @@ -2600,10 +2886,9 @@ macro_rules! handle_chan_reestablish_msgs { } let mut had_channel_update = false; // ChannelUpdate may be now or later, but not both - if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, ref msg }) = msg_events.get(idx) { + if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, .. }) = msg_events.get(idx) { assert_eq!(*node_id, $dst_node.node.get_our_node_id()); idx += 1; - assert_eq!(msg.contents.flags & 2, 0); // "disabled" flag must not be set as we just reconnected. had_channel_update = true; } @@ -2647,10 +2932,9 @@ macro_rules! handle_chan_reestablish_msgs { } } - if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, ref msg }) = msg_events.get(idx) { + if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, .. }) = msg_events.get(idx) { assert_eq!(*node_id, $dst_node.node.get_our_node_id()); idx += 1; - assert_eq!(msg.contents.flags & 2, 0); // "disabled" flag must not be set as we just reconnected. assert!(!had_channel_update); } @@ -2661,12 +2945,48 @@ macro_rules! handle_chan_reestablish_msgs { } } +pub struct ReconnectArgs<'a, 'b, 'c, 'd> { + pub node_a: &'a Node<'b, 'c, 'd>, + pub node_b: &'a Node<'b, 'c, 'd>, + pub send_channel_ready: (bool, bool), + pub pending_htlc_adds: (i64, i64), + pub pending_htlc_claims: (usize, usize), + pub pending_htlc_fails: (usize, usize), + pub pending_cell_htlc_claims: (usize, usize), + pub pending_cell_htlc_fails: (usize, usize), + pub pending_raa: (bool, bool), +} + +impl<'a, 'b, 'c, 'd> ReconnectArgs<'a, 'b, 'c, 'd> { + pub fn new(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>) -> Self { + Self { + node_a, + node_b, + send_channel_ready: (false, false), + pending_htlc_adds: (0, 0), + pending_htlc_claims: (0, 0), + pending_htlc_fails: (0, 0), + pending_cell_htlc_claims: (0, 0), + pending_cell_htlc_fails: (0, 0), + pending_raa: (false, false), + } + } +} + /// pending_htlc_adds includes both the holding cell and in-flight update_add_htlcs, whereas /// for claims/fails they are separated out. -pub fn reconnect_nodes<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, send_channel_ready: (bool, bool), pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize), pending_cell_htlc_claims: (usize, usize), pending_cell_htlc_fails: (usize, usize), pending_raa: (bool, bool)) { - node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: node_b.node.init_features(), remote_network_address: None }, true).unwrap(); +pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) { + let ReconnectArgs { + node_a, node_b, send_channel_ready, pending_htlc_adds, pending_htlc_claims, pending_htlc_fails, + pending_cell_htlc_claims, pending_cell_htlc_fails, pending_raa + } = args; + node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { + features: node_b.node.init_features(), networks: None, remote_network_address: None + }, true).unwrap(); let reestablish_1 = get_chan_reestablish_msgs!(node_a, node_b); - node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: node_a.node.init_features(), remote_network_address: None }, false).unwrap(); + node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { + features: node_a.node.init_features(), networks: None, remote_network_address: None + }, false).unwrap(); let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a); if send_channel_ready.0 {