X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=bdf40f466e7450b476c4678b343751f70f919337;hb=0aaba2ce45a5f295aa76ff4afeaf96fa5f52bb5a;hp=e19c87e7b8eda611172b6ecc2d9ac40246d5b4dd;hpb=3ba91cea59fc2a9c4edb6b06ba54244a640d659d;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index e19c87e7..bdf40f46 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -107,6 +107,14 @@ pub enum ConnectStyle { /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only /// make a single `best_block_updated` call. TransactionsFirstSkippingBlocks, + /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only + /// make a single `best_block_updated` call. Further, we call `transactions_confirmed` multiple + /// times to ensure it's idempotent. + TransactionsDuplicativelyFirstSkippingBlocks, + /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only + /// make a single `best_block_updated` call. Further, we call `transactions_confirmed` multiple + /// times to ensure it's idempotent. + HighlyRedundantTransactionsFirstSkippingBlocks, /// The same as `TransactionsFirst` when connecting blocks. During disconnection only /// `transaction_unconfirmed` is called. TransactionsFirstReorgsOnlyTip, @@ -121,14 +129,16 @@ impl ConnectStyle { use core::hash::{BuildHasher, Hasher}; // Get a random value using the only std API to do so - the DefaultHasher let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish(); - let res = match rand_val % 7 { + let res = match rand_val % 9 { 0 => ConnectStyle::BestBlockFirst, 1 => ConnectStyle::BestBlockFirstSkippingBlocks, 2 => ConnectStyle::BestBlockFirstReorgsOnlyTip, 3 => ConnectStyle::TransactionsFirst, 4 => ConnectStyle::TransactionsFirstSkippingBlocks, - 5 => ConnectStyle::TransactionsFirstReorgsOnlyTip, - 6 => ConnectStyle::FullBlockViaListen, + 5 => ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks, + 6 => ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks, + 7 => ConnectStyle::TransactionsFirstReorgsOnlyTip, + 8 => ConnectStyle::FullBlockViaListen, _ => unreachable!(), }; eprintln!("Using Block Connection Style: {:?}", res); @@ -143,6 +153,7 @@ impl ConnectStyle { 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, }; @@ -193,8 +204,32 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk node.node.best_block_updated(&block.header, height); node.node.transactions_confirmed(&block.header, &txdata, height); }, - ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks|ConnectStyle::TransactionsFirstReorgsOnlyTip => { + ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks| + ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks|ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks| + ConnectStyle::TransactionsFirstReorgsOnlyTip => { + if *node.connect_style.borrow() == ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks { + let mut connections = Vec::new(); + for (block, height) in node.blocks.lock().unwrap().iter() { + if !block.txdata.is_empty() { + // Reconnect all transactions we've ever seen to ensure transaction connection + // is *really* idempotent. This is a somewhat likely deployment for some + // esplora implementations of chain sync which try to reduce state and + // complexity as much as possible. + // + // Sadly we have to clone the block here to maintain lockorder. In the + // future we should consider Arc'ing the blocks to avoid this. + connections.push((block.clone(), *height)); + } + } + for (old_block, height) in connections { + node.chain_monitor.chain_monitor.transactions_confirmed(&old_block.header, + &old_block.txdata.iter().enumerate().collect::>(), height); + } + } node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height); + if *node.connect_style.borrow() == ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks { + node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height); + } call_claimable_balances(node); node.chain_monitor.chain_monitor.best_block_updated(&block.header, height); node.node.transactions_confirmed(&block.header, &txdata, height); @@ -226,7 +261,8 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) node.chain_monitor.chain_monitor.block_disconnected(&orig.0.header, orig.1); Listen::block_disconnected(node.node, &orig.0.header, orig.1); }, - ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks => { + ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks| + ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks|ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks => { if i == count - 1 { node.chain_monitor.chain_monitor.best_block_updated(&prev.0.header, prev.1); node.node.best_block_updated(&prev.0.header, prev.1); @@ -276,6 +312,7 @@ pub struct NodeCfg<'a> { pub struct Node<'a, 'b: 'a, 'c: 'b> { pub chain_source: &'c test_utils::TestChainSource, pub tx_broadcaster: &'c test_utils::TestBroadcaster, + pub fee_estimator: &'c test_utils::TestFeeEstimator, 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, &'c test_utils::TestFeeEstimator, &'c test_utils::TestLogger>, @@ -587,7 +624,7 @@ macro_rules! get_local_commitment_txn { macro_rules! unwrap_send_err { ($res: expr, $all_failed: expr, $type: pat, $check: expr) => { match &$res { - &Err(PaymentSendFailure::AllFailedRetrySafe(ref fails)) if $all_failed => { + &Err(PaymentSendFailure::AllFailedResendSafe(ref fails)) if $all_failed => { assert_eq!(fails.len(), 1); match fails[0] { $type => { $check }, @@ -618,7 +655,61 @@ macro_rules! check_added_monitors { } } -pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u64) -> ([u8; 32], Transaction, OutPoint) { +pub fn _reload_node<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, default_config: UserConfig, chanman_encoded: &[u8], monitors_encoded: &[&[u8]]) -> ChannelManager<&'b TestChainMonitor<'c>, &'c test_utils::TestBroadcaster, &'b test_utils::TestKeysInterface, &'c test_utils::TestFeeEstimator, &'c test_utils::TestLogger> { + let mut monitors_read = Vec::with_capacity(monitors_encoded.len()); + for encoded in monitors_encoded { + let mut monitor_read = &encoded[..]; + let (_, monitor) = <(BlockHash, ChannelMonitor)> + ::read(&mut monitor_read, node.keys_manager).unwrap(); + assert!(monitor_read.is_empty()); + monitors_read.push(monitor); + } + + let mut node_read = &chanman_encoded[..]; + let (_, node_deserialized) = { + let mut channel_monitors = HashMap::new(); + for monitor in monitors_read.iter_mut() { + assert!(channel_monitors.insert(monitor.get_funding_txo().0, monitor).is_none()); + } + <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut node_read, ChannelManagerReadArgs { + default_config, + keys_manager: node.keys_manager, + fee_estimator: node.fee_estimator, + chain_monitor: node.chain_monitor, + tx_broadcaster: node.tx_broadcaster, + logger: node.logger, + channel_monitors, + }).unwrap() + }; + assert!(node_read.is_empty()); + + for monitor in monitors_read.drain(..) { + assert_eq!(node.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor), + ChannelMonitorUpdateStatus::Completed); + check_added_monitors!(node, 1); + } + + node_deserialized +} + +#[cfg(test)] +macro_rules! reload_node { + ($node: expr, $new_config: expr, $chanman_encoded: expr, $monitors_encoded: expr, $persister: ident, $new_chain_monitor: ident, $new_channelmanager: ident) => { + let chanman_encoded = $chanman_encoded; + + $persister = test_utils::TestPersister::new(); + $new_chain_monitor = test_utils::TestChainMonitor::new(Some($node.chain_source), $node.tx_broadcaster.clone(), $node.logger, $node.fee_estimator, &$persister, &$node.keys_manager); + $node.chain_monitor = &$new_chain_monitor; + + $new_channelmanager = _reload_node(&$node, $new_config, &chanman_encoded, $monitors_encoded); + $node.node = &$new_channelmanager; + }; + ($node: expr, $chanman_encoded: expr, $monitors_encoded: expr, $persister: ident, $new_chain_monitor: ident, $new_channelmanager: ident) => { + reload_node!($node, $crate::util::config::UserConfig::default(), $chanman_encoded, $monitors_encoded, $persister, $new_chain_monitor, $new_channelmanager); + }; +} + +pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u128) -> ([u8; 32], Transaction, OutPoint) { let chan_id = *node.network_chan_count.borrow(); let events = node.node.get_and_clear_pending_events(); @@ -751,10 +842,12 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, ' let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap(); let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id()); assert_eq!(open_channel_msg.temporary_channel_id, create_chan_id); + assert_eq!(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(), a_flags, &open_channel_msg); 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(), b_flags, &accept_channel_msg); + assert_ne!(node_b.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 0); sign_funding_transaction(node_a, node_b, channel_value, create_chan_id) } @@ -1034,7 +1127,7 @@ macro_rules! check_closed_event { use $crate::util::events::Event; let events = $node.node.get_and_clear_pending_events(); - assert_eq!(events.len(), $events); + assert_eq!(events.len(), $events, "{:?}", events); let expected_reason = $reason; let mut issues_discard_funding = false; for event in events { @@ -1293,7 +1386,7 @@ macro_rules! expect_pending_htlcs_forwardable_conditions { let events = $node.node.get_and_clear_pending_events(); match events[0] { $crate::util::events::Event::PendingHTLCsForwardable { .. } => { }, - _ => panic!("Unexpected event"), + _ => panic!("Unexpected event {:?}", events), }; let count = expected_failures.len() + 1; @@ -1376,20 +1469,20 @@ macro_rules! expect_pending_htlcs_forwardable_from_events { } }} } - #[macro_export] #[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] -macro_rules! expect_payment_received { +macro_rules! expect_payment_claimable { ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr) => { - expect_payment_received!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None) + expect_payment_claimable!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None, $node.node.get_our_node_id()) }; - ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr) => { + ($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::PaymentReceived { ref payment_hash, ref purpose, amount_msat } => { + $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); @@ -1503,7 +1596,7 @@ macro_rules! expect_payment_forwarded { if !$downstream_force_closed { assert!($node.node.list_channels().iter().any(|x| x.counterparty.node_id == $next_node.node.get_our_node_id() && x.channel_id == next_channel_id.unwrap())); } - assert_eq!(claim_from_onchain_tx, $upstream_force_closed); + assert_eq!(claim_from_onchain_tx, $downstream_force_closed); }, _ => panic!("Unexpected event"), } @@ -1656,13 +1749,14 @@ 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 = origin_node.node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap(); + 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(); 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_received_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) { let mut payment_event = SendEvent::from_event(ev); let mut prev_node = origin_node; @@ -1677,11 +1771,12 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p if idx == expected_path.len() - 1 && clear_recipient_events { let events_2 = node.node.get_and_clear_pending_events(); - if payment_received_expected { + if payment_claimable_expected { assert_eq!(events_2.len(), 1); match events_2[0] { - Event::PaymentReceived { ref payment_hash, ref purpose, amount_msat } => { + Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, ref via_channel_id, ref via_user_channel_id } => { assert_eq!(our_payment_hash, *payment_hash); + assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap()); match &purpose { PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { assert_eq!(expected_preimage, *payment_preimage); @@ -1693,6 +1788,8 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p }, } 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())); }, _ => panic!("Unexpected event"), } @@ -1711,8 +1808,8 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p } } -pub fn pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: Option, ev: MessageSendEvent, payment_received_expected: bool, expected_preimage: Option) { - do_pass_along_path(origin_node, expected_path, recv_value, our_payment_hash, our_payment_secret, ev, payment_received_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) { + 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) { @@ -1720,7 +1817,7 @@ pub fn pass_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou assert_eq!(events.len(), expected_route.len()); for (path_idx, (ev, expected_path)) in events.drain(..).zip(expected_route.iter()).enumerate() { // Once we've gotten through all the HTLCs, the last one should result in a - // PaymentReceived (but each previous one should not!), . + // PaymentClaimable (but each previous one should not!), . let expect_payment = path_idx == expected_route.len() - 1; pass_along_path(origin_node, expected_path, recv_value, our_payment_hash.clone(), Some(our_payment_secret), ev, expect_payment, None); } @@ -1903,7 +2000,7 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou } 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)), true, APIError::ChannelUnavailable { ref err }, + 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 }, assert!(err.contains("Cannot send value that would put us over the max HTLC value in flight our peer will accept"))); } @@ -1924,6 +2021,22 @@ pub fn fail_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe } 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) { + let expected_payment_id = pass_failed_payment_back_no_abandon(origin_node, expected_paths_slice, skip_last, our_payment_hash); + if !skip_last { + origin_node.node.abandon_payment(expected_payment_id.unwrap()); + let events = origin_node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PaymentFailed { ref payment_hash, ref payment_id } => { + assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash"); + assert_eq!(*payment_id, expected_payment_id.unwrap()); + } + _ => panic!("Unexpected second event"), + } + } +} + +pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) -> Option { let mut expected_paths: Vec<_> = expected_paths_slice.iter().collect(); check_added_monitors!(expected_paths[0].last().unwrap(), expected_paths.len()); @@ -1947,6 +2060,8 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe per_path_msgs.sort_unstable_by(|(_, node_id_a), (_, node_id_b)| node_id_a.cmp(node_id_b)); expected_paths.sort_unstable_by(|path_a, path_b| path_a[path_a.len() - 2].node.get_our_node_id().cmp(&path_b[path_b.len() - 2].node.get_our_node_id())); + let mut expected_payment_id = None; + 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; @@ -1995,7 +2110,7 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe commitment_signed_dance!(origin_node, prev_node, next_msgs.as_ref().unwrap().1, false); let events = origin_node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); - let expected_payment_id = match events[0] { + expected_payment_id = Some(match events[0] { Event::PaymentPathFailed { payment_hash, payment_failed_permanently, all_paths_failed, ref path, ref payment_id, .. } => { assert_eq!(payment_hash, our_payment_hash); assert!(payment_failed_permanently); @@ -2006,19 +2121,7 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe payment_id.unwrap() }, _ => panic!("Unexpected event"), - }; - if i == expected_paths.len() - 1 { - origin_node.node.abandon_payment(expected_payment_id); - let events = origin_node.node.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - match events[0] { - Event::PaymentFailed { ref payment_hash, ref payment_id } => { - assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash"); - assert_eq!(*payment_id, expected_payment_id); - } - _ => panic!("Unexpected second event"), - } - } + }); } } @@ -2027,6 +2130,8 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_events().is_empty()); assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_msg_events().is_empty()); check_added_monitors!(expected_paths[0].last().unwrap(), 0); + + expected_payment_id } pub fn fail_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], our_payment_hash: PaymentHash) { @@ -2117,6 +2222,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec