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=6d96877625ccb4c74d1b41c0d56ee1ab5c46c1d0;hpb=b8ed4d2608e32128dd5a1dee92911638a4301138;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 6d968776..39396685 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,10 +10,12 @@ //! 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::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA}; use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate}; @@ -26,19 +28,16 @@ use crate::util::scid_utils; use crate::util::test_utils; 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::*; @@ -85,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() } @@ -151,6 +148,20 @@ impl ConnectStyle { } } + 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}; @@ -177,22 +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 = 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); @@ -216,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() { @@ -265,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) { @@ -352,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 { @@ -708,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()) @@ -727,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) => { @@ -734,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_sat_per_1000_weight() + 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() } } } @@ -1022,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); @@ -1682,14 +1788,14 @@ 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, final_cltv_expiry_delta: u32) -> Result { +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, final_cltv_expiry_delta, send_node.logger, &scorer, &random_seed_bytes + recv_value, send_node.logger, &scorer, &(), &random_seed_bytes ) } @@ -1698,8 +1804,8 @@ pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_valu /// 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) => { - $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value, $cltv) + ($send_node: expr, $payment_params: expr, $recv_value: expr) => { + $crate::ln::functional_test_utils::get_route(&$send_node, &$payment_params, $recv_value) } } @@ -1708,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::ln::functional_test_utils::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()) @@ -1728,26 +1856,12 @@ 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::events::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 { - $crate::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(); @@ -1864,7 +1978,17 @@ macro_rules! expect_payment_forwarded { } } -#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] +#[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); @@ -1876,7 +2000,7 @@ pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, } } -#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] +#[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); @@ -2046,7 +2170,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p 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, + claim_deadline, onion_fields, .. } => { assert_eq!(our_payment_hash, *payment_hash); assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap()); @@ -2059,7 +2183,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p }, 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); @@ -2108,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()); } @@ -2158,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; @@ -2173,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); @@ -2218,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()); @@ -2257,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()); } @@ -2271,7 +2409,7 @@ 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]; @@ -2279,10 +2417,10 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou let random_seed_bytes = keys_manager.get_secure_random_bytes(); 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()); } @@ -2388,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() }, @@ -2421,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)); @@ -2474,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 } @@ -2483,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); } @@ -2503,6 +2641,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec(node_count: usize, cfgs: &'b Vec { + 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 {