X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=9bbd6c0e92aad17decad799c6b866d67e3fe1958;hb=f53d13bcb8220b3ce39e51a4d20beb23b3930d1f;hp=78bf834a6280c33489753992cd5ec28887976607;hpb=3ec529d7cc06e15c0d55161e30b931ac115fac95;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 78bf834a..9bbd6c0e 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,19 +10,19 @@ //! A bunch of useful utilities for building networks of nodes and exchanging messages between //! nodes for functional tests. -use chain::{BestBlock, Confirm, Listen, Watch}; +use chain::{BestBlock, Confirm, Listen, Watch, keysinterface::KeysInterface}; use chain::channelmonitor::ChannelMonitor; use chain::transaction::OutPoint; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; -use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId}; +use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA}; use routing::network_graph::{NetGraphMsgHandler, NetworkGraph}; -use routing::router::{Payee, Route, get_route}; +use routing::router::{PaymentParameters, Route, get_route}; use ln::features::{InitFeatures, InvoiceFeatures}; use ln::msgs; use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler}; use util::enforcing_trait_impls::EnforcingSigner; use util::test_utils; -use util::test_utils::TestChainMonitor; +use util::test_utils::{panicking, TestChainMonitor}; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose}; use util::errors::APIError; use util::config::UserConfig; @@ -40,7 +40,7 @@ use bitcoin::secp256k1::key::PublicKey; use io; use prelude::*; use core::cell::RefCell; -use std::rc::Rc; +use alloc::rc::Rc; use sync::{Arc, Mutex}; use core::mem; @@ -123,19 +123,29 @@ pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block) do_connect_block(node, block, false); } +fn call_claimable_balances<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>) { + // Ensure `get_claimable_balances`' self-tests never panic + for funding_outpoint in node.chain_monitor.chain_monitor.list_monitors() { + node.chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances(); + } +} + fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, skip_intermediaries: bool) { + call_claimable_balances(node); let height = node.best_block_info().1 + 1; if !skip_intermediaries { let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); match *node.connect_style.borrow() { ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstSkippingBlocks => { node.chain_monitor.chain_monitor.best_block_updated(&block.header, height); + call_claimable_balances(node); node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height); node.node.best_block_updated(&block.header, height); node.node.transactions_confirmed(&block.header, &txdata, height); }, ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks => { 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); node.node.best_block_updated(&block.header, height); @@ -146,11 +156,13 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, s } } } + call_claimable_balances(node); node.node.test_process_background_events(); node.blocks.lock().unwrap().push((block.header, height)); } pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) { + call_claimable_balances(node); for i in 0..count { let orig_header = node.blocks.lock().unwrap().pop().unwrap(); assert!(orig_header.1 > 0); // Cannot disconnect genesis @@ -172,6 +184,7 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) node.node.best_block_updated(&prev_header.0, prev_header.1); }, } + call_claimable_balances(node); } } @@ -231,7 +244,7 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> { impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { fn drop(&mut self) { - if !::std::thread::panicking() { + if !panicking() { // Check that we processed all pending events assert!(self.node.get_and_clear_pending_msg_events().is_empty()); assert!(self.node.get_and_clear_pending_events().is_empty()); @@ -336,10 +349,11 @@ pub fn create_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, } #[macro_export] +/// Gets an RAA and CS which were sent in response to a commitment update macro_rules! get_revoke_commit_msgs { ($node: expr, $node_id: expr) => { { - use util::events::MessageSendEvent; + use $crate::util::events::MessageSendEvent; let events = $node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 2); (match events[0] { @@ -382,6 +396,26 @@ 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"), + } + } + } +} + /// Get a specific event from the pending events queue. #[macro_export] macro_rules! get_event { @@ -400,8 +434,8 @@ macro_rules! get_event { } } -#[cfg(test)] #[macro_export] +/// Gets an UpdateHTLCs MessageSendEvent macro_rules! get_htlc_update_msgs { ($node: expr, $node_id: expr) => { { @@ -439,6 +473,17 @@ macro_rules! get_feerate { } } +#[cfg(test)] +macro_rules! get_opt_anchors { + ($node: expr, $channel_id: expr) => { + { + let mut lock; + let chan = get_channel_ref!($node, lock, $channel_id); + chan.opt_anchors() + } + } +} + /// Returns a channel monitor given a channel id, making some naive assumptions #[macro_export] macro_rules! get_monitor { @@ -588,7 +633,14 @@ pub fn create_chan_between_nodes_with_value_confirm_first<'a, 'b, 'c, 'd>(node_r pub fn create_chan_between_nodes_with_value_confirm_second<'a, 'b, 'c>(node_recv: &Node<'a, 'b, 'c>, node_conf: &Node<'a, 'b, 'c>) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32]) { let channel_id; let events_6 = node_conf.node.get_and_clear_pending_msg_events(); - assert_eq!(events_6.len(), 2); + assert_eq!(events_6.len(), 3); + let announcement_sigs_idx = if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = events_6[1] { + assert_eq!(*node_id, node_recv.node.get_our_node_id()); + 2 + } else if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = events_6[2] { + assert_eq!(*node_id, node_recv.node.get_our_node_id()); + 1 + } else { panic!("Unexpected event: {:?}", events_6[1]); }; ((match events_6[0] { MessageSendEvent::SendFundingLocked { ref node_id, ref msg } => { channel_id = msg.channel_id.clone(); @@ -596,7 +648,7 @@ pub fn create_chan_between_nodes_with_value_confirm_second<'a, 'b, 'c>(node_recv msg.clone() }, _ => panic!("Unexpected event"), - }, match events_6[1] { + }, match events_6[announcement_sigs_idx] { MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => { assert_eq!(*node_id, node_recv.node.get_our_node_id()); msg.clone() @@ -661,6 +713,61 @@ pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a (chan_announcement.1, chan_announcement.2, chan_announcement.3, chan_announcement.4) } +pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec>, a: usize, b: usize, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> (msgs::FundingLocked, Transaction) { + let mut no_announce_cfg = test_default_channel_config(); + no_announce_cfg.channel_options.announced_channel = false; + nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, Some(no_announce_cfg)).unwrap(); + let open_channel = get_event_msg!(nodes[a], MessageSendEvent::SendOpenChannel, nodes[b].node.get_our_node_id()); + nodes[b].node.handle_open_channel(&nodes[a].node.get_our_node_id(), a_flags, &open_channel); + let accept_channel = get_event_msg!(nodes[b], MessageSendEvent::SendAcceptChannel, nodes[a].node.get_our_node_id()); + nodes[a].node.handle_accept_channel(&nodes[b].node.get_our_node_id(), b_flags, &accept_channel); + + let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[a], channel_value, 42); + nodes[a].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap(); + nodes[b].node.handle_funding_created(&nodes[a].node.get_our_node_id(), &get_event_msg!(nodes[a], MessageSendEvent::SendFundingCreated, nodes[b].node.get_our_node_id())); + check_added_monitors!(nodes[b], 1); + + let cs_funding_signed = get_event_msg!(nodes[b], MessageSendEvent::SendFundingSigned, nodes[a].node.get_our_node_id()); + nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed); + check_added_monitors!(nodes[a], 1); + + 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); + confirm_transaction_at(&nodes[b], &tx, conf_height); + connect_blocks(&nodes[b], CHAN_CONFIRM_DEPTH - 1); + let as_funding_locked = get_event_msg!(nodes[a], MessageSendEvent::SendFundingLocked, nodes[b].node.get_our_node_id()); + nodes[a].node.handle_funding_locked(&nodes[b].node.get_our_node_id(), &get_event_msg!(nodes[b], MessageSendEvent::SendFundingLocked, nodes[a].node.get_our_node_id())); + let as_update = get_event_msg!(nodes[a], MessageSendEvent::SendChannelUpdate, nodes[b].node.get_our_node_id()); + nodes[b].node.handle_funding_locked(&nodes[a].node.get_our_node_id(), &as_funding_locked); + let bs_update = get_event_msg!(nodes[b], MessageSendEvent::SendChannelUpdate, nodes[a].node.get_our_node_id()); + + nodes[a].node.handle_channel_update(&nodes[b].node.get_our_node_id(), &bs_update); + nodes[b].node.handle_channel_update(&nodes[a].node.get_our_node_id(), &as_update); + + let mut found_a = false; + for chan in nodes[a].node.list_usable_channels() { + if chan.channel_id == as_funding_locked.channel_id { + assert!(!found_a); + found_a = true; + assert!(!chan.is_public); + } + } + assert!(found_a); + + let mut found_b = false; + for chan in nodes[b].node.list_usable_channels() { + if chan.channel_id == as_funding_locked.channel_id { + assert!(!found_b); + found_b = true; + assert!(!chan.is_public); + } + } + assert!(found_b); + + (as_funding_locked, tx) +} + pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec>, a: usize, b: usize, ann: &msgs::ChannelAnnouncement, upd_1: &msgs::ChannelUpdate, upd_2: &msgs::ChannelUpdate) { nodes[a].node.broadcast_node_announcement([0, 0, 0], [0; 32], Vec::new()); let a_events = nodes[a].node.get_and_clear_pending_msg_events(); @@ -716,6 +823,11 @@ pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec {{ + let msg_events = $node.node.get_and_clear_pending_msg_events(); + assert_eq!(msg_events.len(), 1); + match msg_events[0] { + MessageSendEvent::HandleError { action: ErrorAction::SendWarningMessage { ref msg, log_level: _ }, node_id } => { + assert_eq!(node_id, $recipient_node_id); + assert_eq!(msg.channel_id, $chan_id); + msg.data.clone() + }, + _ => panic!("Unexpected event"), + } + }} +} + /// Check that a channel's closing channel update has been broadcasted, and optionally /// check whether an error message event has occurred. #[macro_export] @@ -933,6 +1061,9 @@ impl SendEvent { } } +#[macro_export] +/// Performs the "commitment signed dance" - the series of message exchanges which occur after a +/// commitment update. macro_rules! commitment_signed_dance { ($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backwards: expr, true /* skip last step */) => { { @@ -999,7 +1130,7 @@ macro_rules! commitment_signed_dance { { commitment_signed_dance!($node_a, $node_b, $commitment_signed, $fail_backwards, true); if $fail_backwards { - expect_pending_htlcs_forwardable!($node_a); + $crate::expect_pending_htlcs_forwardable!($node_a); check_added_monitors!($node_a, 1); let channel_state = $node_a.node.channel_state.lock().unwrap(); @@ -1040,37 +1171,43 @@ macro_rules! get_payment_preimage_hash { #[macro_export] macro_rules! get_route_and_payment_hash { ($send_node: expr, $recv_node: expr, $recv_value: expr) => {{ - $crate::get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV) + let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id()) + .with_features($crate::ln::features::InvoiceFeatures::known()); + $crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, TEST_FINAL_CLTV) }}; - ($send_node: expr, $recv_node: expr, $last_hops: expr, $recv_value: expr, $cltv: expr) => {{ + ($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ + use $crate::chain::keysinterface::KeysInterface; let (payment_preimage, payment_hash, payment_secret) = $crate::get_payment_preimage_hash!($recv_node, Some($recv_value)); - let payee = $crate::routing::router::Payee::from_node_id($recv_node.node.get_our_node_id()) - .with_features($crate::ln::features::InvoiceFeatures::known()) - .with_route_hints($last_hops); - let scorer = $crate::util::test_utils::TestScorer::with_fixed_penalty(0); + let scorer = $crate::util::test_utils::TestScorer::with_penalty(0); + 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(); let route = $crate::routing::router::get_route( - &$send_node.node.get_our_node_id(), &payee, $send_node.network_graph, + &$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 + $recv_value, $cltv, $send_node.logger, &scorer, &random_seed_bytes ).unwrap(); (route, payment_hash, payment_preimage, payment_secret) }} } +#[macro_export] +/// Clears (and ignores) a PendingHTLCsForwardable event macro_rules! expect_pending_htlcs_forwardable_ignore { ($node: expr) => {{ let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PendingHTLCsForwardable { .. } => { }, + $crate::util::events::Event::PendingHTLCsForwardable { .. } => { }, _ => panic!("Unexpected event"), }; }} } +#[macro_export] +/// Handles a PendingHTLCsForwardable event macro_rules! expect_pending_htlcs_forwardable { ($node: expr) => {{ - expect_pending_htlcs_forwardable_ignore!($node); + $crate::expect_pending_htlcs_forwardable_ignore!($node); $node.node.process_pending_htlc_forwards(); // Ensure process_pending_htlc_forwards is idempotent. @@ -1095,18 +1232,22 @@ macro_rules! expect_pending_htlcs_forwardable_from_events { }} } -#[cfg(any(test, feature = "unstable"))] +#[macro_export] +#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] macro_rules! expect_payment_received { ($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) + }; + ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr) => { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PaymentReceived { ref payment_hash, ref purpose, amt } => { + $crate::util::events::Event::PaymentReceived { ref payment_hash, ref purpose, amt } => { assert_eq!($expected_payment_hash, *payment_hash); assert_eq!($expected_recv_value, amt); match purpose { - PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { - assert!(payment_preimage.is_none()); + $crate::util::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => { + assert_eq!(&$expected_payment_preimage, payment_preimage); assert_eq!($expected_payment_secret, *payment_secret); }, _ => {}, @@ -1186,12 +1327,16 @@ macro_rules! expect_payment_path_successful { } macro_rules! expect_payment_forwarded { - ($node: expr, $expected_fee: expr, $upstream_force_closed: expr) => { + ($node: expr, $source_node: expr, $expected_fee: expr, $upstream_force_closed: expr) => { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::PaymentForwarded { fee_earned_msat, claim_from_onchain_tx } => { + Event::PaymentForwarded { fee_earned_msat, source_channel_id, claim_from_onchain_tx } => { assert_eq!(fee_earned_msat, $expected_fee); + if fee_earned_msat.is_some() { + // Is the event channel_id in one of the channels between the two nodes? + assert!($node.node.list_channels().iter().any(|x| x.counterparty.node_id == $source_node.node.get_our_node_id() && x.channel_id == source_channel_id.unwrap())); + } assert_eq!(claim_from_onchain_tx, $upstream_force_closed); }, _ => panic!("Unexpected event"), @@ -1199,58 +1344,114 @@ macro_rules! expect_payment_forwarded { } } +pub struct PaymentFailedConditions<'a> { + pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>, + pub(crate) expected_blamed_scid: Option, + pub(crate) expected_blamed_chan_closed: Option, + pub(crate) expected_mpp_parts_remain: bool, +} + +impl<'a> PaymentFailedConditions<'a> { + pub fn new() -> Self { + Self { + expected_htlc_error_data: None, + expected_blamed_scid: None, + expected_blamed_chan_closed: None, + expected_mpp_parts_remain: false, + } + } + pub fn mpp_parts_remain(mut self) -> Self { + self.expected_mpp_parts_remain = true; + self + } + pub fn blamed_scid(mut self, scid: u64) -> Self { + self.expected_blamed_scid = Some(scid); + self + } + pub fn blamed_chan_closed(mut self, closed: bool) -> Self { + self.expected_blamed_chan_closed = Some(closed); + self + } + pub fn expected_htlc_error_data(mut self, code: u16, data: &'a [u8]) -> Self { + self.expected_htlc_error_data = Some((code, data)); + self + } +} + #[cfg(test)] macro_rules! expect_payment_failed_with_update { ($node: expr, $expected_payment_hash: expr, $rejected_by_dest: expr, $scid: expr, $chan_closed: expr) => { - let events = $node.node.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - match events[0] { - Event::PaymentPathFailed { ref payment_hash, rejected_by_dest, ref network_update, ref error_code, ref error_data, ref path, ref retry, .. } => { - assert_eq!(*payment_hash, $expected_payment_hash, "unexpected payment_hash"); - assert_eq!(rejected_by_dest, $rejected_by_dest, "unexpected rejected_by_dest 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().payee.pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path"); - assert!(error_code.is_some(), "expected error_code.is_some() = true"); - assert!(error_data.is_some(), "expected error_data.is_some() = true"); - match network_update { - &Some(NetworkUpdate::ChannelUpdateMessage { ref msg }) if !$chan_closed => { - assert_eq!(msg.contents.short_channel_id, $scid); - assert_eq!(msg.contents.flags & 2, 0); - }, - &Some(NetworkUpdate::ChannelClosed { short_channel_id, is_permanent }) if $chan_closed => { - assert_eq!(short_channel_id, $scid); - assert!(is_permanent); - }, - Some(_) => panic!("Unexpected update type"), - None => panic!("Expected update"), - } - }, - _ => panic!("Unexpected event"), - } + expect_payment_failed_conditions!($node, $expected_payment_hash, $rejected_by_dest, + $crate::ln::functional_test_utils::PaymentFailedConditions::new().blamed_scid($scid).blamed_chan_closed($chan_closed)); } } #[cfg(test)] macro_rules! expect_payment_failed { ($node: expr, $expected_payment_hash: expr, $rejected_by_dest: expr $(, $expected_error_code: expr, $expected_error_data: expr)*) => { + #[allow(unused_mut)] + let mut conditions = $crate::ln::functional_test_utils::PaymentFailedConditions::new(); + $( + conditions = conditions.expected_htlc_error_data($expected_error_code, &$expected_error_data); + )* + expect_payment_failed_conditions!($node, $expected_payment_hash, $rejected_by_dest, conditions); + }; +} + +#[cfg(test)] +macro_rules! expect_payment_failed_conditions { + ($node: expr, $expected_payment_hash: expr, $rejected_by_dest: expr, $conditions: expr) => { let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); - match events[0] { - Event::PaymentPathFailed { ref payment_hash, rejected_by_dest, network_update: _, ref error_code, ref error_data, ref path, ref retry, .. } => { + let expected_payment_id = match events[0] { + Event::PaymentPathFailed { ref payment_hash, rejected_by_dest, ref error_code, ref error_data, ref path, ref retry, ref payment_id, ref network_update, .. } => { assert_eq!(*payment_hash, $expected_payment_hash, "unexpected payment_hash"); assert_eq!(rejected_by_dest, $rejected_by_dest, "unexpected rejected_by_dest 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().payee.pubkey, path.last().unwrap().pubkey, "Retry payee node_id 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"); + assert!(error_code.is_some(), "expected error_code.is_some() = true"); assert!(error_data.is_some(), "expected error_data.is_some() = true"); - $( - assert_eq!(error_code.unwrap(), $expected_error_code, "unexpected error code"); - assert_eq!(&error_data.as_ref().unwrap()[..], $expected_error_data, "unexpected error data"); - )* + if let Some((code, data)) = $conditions.expected_htlc_error_data { + assert_eq!(error_code.unwrap(), code, "unexpected error code"); + assert_eq!(&error_data.as_ref().unwrap()[..], data, "unexpected error data"); + } + + if let Some(chan_closed) = $conditions.expected_blamed_chan_closed { + match network_update { + &Some($crate::routing::network_graph::NetworkUpdate::ChannelUpdateMessage { ref msg }) if !chan_closed => { + if let Some(scid) = $conditions.expected_blamed_scid { + assert_eq!(msg.contents.short_channel_id, scid); + } + assert_eq!(msg.contents.flags & 2, 0); + }, + &Some($crate::routing::network_graph::NetworkUpdate::ChannelClosed { short_channel_id, is_permanent }) if chan_closed => { + if let Some(scid) = $conditions.expected_blamed_scid { + assert_eq!(short_channel_id, scid); + } + assert!(is_permanent); + }, + Some(_) => panic!("Unexpected update type"), + None => panic!("Expected update"), + } + } + + payment_id.unwrap() }, _ => panic!("Unexpected event"), + }; + if !$conditions.expected_mpp_parts_remain { + $node.node.abandon_payment(expected_payment_id); + let events = $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, $expected_payment_hash, "unexpected second payment_hash"); + assert_eq!(*payment_id, expected_payment_id); + } + _ => panic!("Unexpected second event"), + } } } } @@ -1374,11 +1575,11 @@ 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, $new_msgs: 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 = $node.node.channel_state.lock().unwrap().by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap().config.forwarding_fee_base_msat; - expect_payment_forwarded!($node, Some(fee as u64), false); + expect_payment_forwarded!($node, $next_node, Some(fee as u64), false); expected_total_fee_msat += fee as u64; check_added_monitors!($node, 1); let new_next_msgs = if $new_msgs { @@ -1402,7 +1603,14 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, assert_eq!(expected_next_node, node.node.get_our_node_id()); let update_next_msgs = !skip_last || idx != expected_route.len() - 1; if next_msgs.is_some() { - mid_update_fulfill_dance!(node, prev_node, update_next_msgs); + // Since we are traversing in reverse, next_node is actually the previous node + let next_node: &Node; + if idx == expected_route.len() - 1 { + next_node = origin_node; + } else { + next_node = expected_route[expected_route.len() - 1 - idx - 1]; + } + mid_update_fulfill_dance!(node, prev_node, next_node, update_next_msgs); } else { assert!(!update_next_msgs); assert!(node.node.get_and_clear_pending_msg_events().is_empty()); @@ -1440,13 +1648,17 @@ pub fn claim_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: 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 payee = Payee::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) + let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) .with_features(InvoiceFeatures::known()); - let scorer = test_utils::TestScorer::with_fixed_penalty(0); + let network_graph = origin_node.network_graph.read_only(); + let scorer = test_utils::TestScorer::with_penalty(0); + 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( - &origin_node.node.get_our_node_id(), &payee, &origin_node.network_graph, + &origin_node.node.get_our_node_id(), &payment_params, &network_graph, Some(&origin_node.node.list_usable_channels().iter().collect::>()), - recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap(); + recv_value, TEST_FINAL_CLTV, 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()) { @@ -1458,10 +1670,16 @@ 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 payee = Payee::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) + let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) .with_features(InvoiceFeatures::known()); - let scorer = test_utils::TestScorer::with_fixed_penalty(0); - let route = get_route(&origin_node.node.get_our_node_id(), &payee, origin_node.network_graph, None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap(); + let network_graph = origin_node.network_graph.read_only(); + let scorer = test_utils::TestScorer::with_penalty(0); + 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( + &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(); 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()) { @@ -1555,16 +1773,29 @@ pub fn fail_payment_along_route<'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); - match events[0] { - Event::PaymentPathFailed { payment_hash, rejected_by_dest, all_paths_failed, ref path, .. } => { + let expected_payment_id = match events[0] { + Event::PaymentPathFailed { payment_hash, rejected_by_dest, all_paths_failed, ref path, ref payment_id, .. } => { assert_eq!(payment_hash, our_payment_hash); assert!(rejected_by_dest); assert_eq!(all_paths_failed, i == expected_paths.len() - 1); for (idx, hop) in expected_route.iter().enumerate() { assert_eq!(hop.node.get_our_node_id(), path[idx].pubkey); } + 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"), + } } } } @@ -1627,7 +1858,7 @@ pub fn test_default_channel_config() -> UserConfig { let mut default_config = UserConfig::default(); // Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our // tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT). - default_config.channel_options.cltv_expiry_delta = 6*6; + default_config.channel_options.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA; default_config.channel_options.announced_channel = true; default_config.peer_channel_config_limits.force_announced_channel_preference = false; // When most of our tests were written, the default HTLC minimum was fixed at 1000. @@ -1676,8 +1907,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec RAACommitmentOrder::CommitmentFirst, - _ => panic!("Unexpected event"), + _ => RAACommitmentOrder::CommitmentFirst, } } else { RAACommitmentOrder::CommitmentFirst @@ -1917,16 +2147,18 @@ macro_rules! handle_chan_reestablish_msgs { commitment_update = Some(updates.clone()); idx += 1; }, - &MessageSendEvent::SendChannelUpdate { .. } => {}, - _ => panic!("Unexpected event"), + _ => {}, } } if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, ref msg }) = 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_eq!(msg_events.len(), idx); + (funding_locked, revoke_and_ack, commitment_update, order) } } @@ -1935,9 +2167,9 @@ macro_rules! handle_chan_reestablish_msgs { /// 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_funding_locked: (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: InitFeatures::empty() }); + node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None }); 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: InitFeatures::empty() }); + node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), remote_network_address: None }); let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a); if send_funding_locked.0 { @@ -1999,9 +2231,9 @@ pub fn reconnect_nodes<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, let announcement_event = node_a.node.get_and_clear_pending_msg_events(); if !announcement_event.is_empty() { assert_eq!(announcement_event.len(), 1); - if let MessageSendEvent::SendAnnouncementSignatures { .. } = announcement_event[0] { + if let MessageSendEvent::SendChannelUpdate { .. } = announcement_event[0] { //TODO: Test announcement_sigs re-sending - } else { panic!("Unexpected event!"); } + } else { panic!("Unexpected event! {:?}", announcement_event[0]); } } } else { assert!(chan_msgs.0.is_none()); @@ -2056,9 +2288,11 @@ pub fn reconnect_nodes<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, let announcement_event = node_b.node.get_and_clear_pending_msg_events(); if !announcement_event.is_empty() { assert_eq!(announcement_event.len(), 1); - if let MessageSendEvent::SendAnnouncementSignatures { .. } = announcement_event[0] { - //TODO: Test announcement_sigs re-sending - } else { panic!("Unexpected event!"); } + match announcement_event[0] { + MessageSendEvent::SendChannelUpdate { .. } => {}, + MessageSendEvent::SendAnnouncementSignatures { .. } => {}, + _ => panic!("Unexpected event {:?}!", announcement_event[0]), + } } } else { assert!(chan_msgs.0.is_none());