X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=8ff793ed08b723280c3f089eb2ce74cb7bd2ad53;hb=1c157a2328d23079230143314819d0128ec314fd;hp=5983e4e2871cea3bc4306ee32dc20829036e05d2;hpb=bcdd85227949d17c9a98a9fc0b666bce4a97c856;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 5983e4e2..8ff793ed 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -17,7 +17,6 @@ use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId}; use routing::network_graph::{NetGraphMsgHandler, NetworkGraph}; use routing::router::{Payee, Route, get_route}; -use routing::scorer::Scorer; use ln::features::{InitFeatures, InvoiceFeatures}; use ln::msgs; use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler}; @@ -34,8 +33,6 @@ use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::network::constants::Network; -use bitcoin::hashes::sha256::Hash as Sha256; -use bitcoin::hashes::Hash; use bitcoin::hash_types::BlockHash; use bitcoin::secp256k1::key::PublicKey; @@ -243,10 +240,9 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { // Check that if we serialize the Router, we can deserialize it again. { let mut w = test_utils::TestVecWriter(Vec::new()); - let network_graph_ser = &self.net_graph_msg_handler.network_graph; - network_graph_ser.write(&mut w).unwrap(); + self.network_graph.write(&mut w).unwrap(); let network_graph_deser = ::read(&mut io::Cursor::new(&w.0)).unwrap(); - assert!(network_graph_deser == *self.net_graph_msg_handler.network_graph); + assert!(network_graph_deser == *self.network_graph); let net_graph_msg_handler = NetGraphMsgHandler::new( &network_graph_deser, Some(self.chain_source), self.logger ); @@ -339,9 +335,12 @@ 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) } +#[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 $crate::util::events::MessageSendEvent; let events = $node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 2); (match events[0] { @@ -402,14 +401,15 @@ macro_rules! get_event { } } -#[cfg(test)] +#[macro_export] +/// Gets an UpdateHTLCs MessageSendEvent 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] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + $crate::util::events::MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { assert_eq!(*node_id, $node_id); (*updates).clone() }, @@ -485,9 +485,9 @@ macro_rules! unwrap_send_err { _ => panic!(), } }, - &Err(PaymentSendFailure::PartialFailure(ref fails)) if !$all_failed => { - assert_eq!(fails.len(), 1); - match fails[0] { + &Err(PaymentSendFailure::PartialFailure { ref results, .. }) if !$all_failed => { + assert_eq!(results.len(), 1); + match results[0] { Err($type) => { $check }, _ => panic!(), } @@ -528,19 +528,16 @@ pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_ _ => panic!("Unexpected event"), } } - -pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> Transaction { - let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap(); - node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), a_flags, &get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id())); - node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), b_flags, &get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id())); - +pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, expected_temporary_channel_id: [u8; 32]) -> Transaction { let (temporary_channel_id, tx, funding_output) = create_funding_transaction(node_a, channel_value, 42); - assert_eq!(temporary_channel_id, create_chan_id); + assert_eq!(temporary_channel_id, expected_temporary_channel_id); - node_a.node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap(); + assert!(node_a.node.funding_transaction_generated(&temporary_channel_id, tx.clone()).is_ok()); check_added_monitors!(node_a, 0); - node_b.node.handle_funding_created(&node_a.node.get_our_node_id(), &get_event_msg!(node_a, MessageSendEvent::SendFundingCreated, node_b.node.get_our_node_id())); + let funding_created_msg = get_event_msg!(node_a, MessageSendEvent::SendFundingCreated, node_b.node.get_our_node_id()); + assert_eq!(funding_created_msg.temporary_channel_id, expected_temporary_channel_id); + node_b.node.handle_funding_created(&node_a.node.get_our_node_id(), &funding_created_msg); { let mut added_monitors = node_b.chain_monitor.added_monitors.lock().unwrap(); assert_eq!(added_monitors.len(), 1); @@ -563,9 +560,26 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, ' assert_eq!(node_a.tx_broadcaster.txn_broadcasted.lock().unwrap()[0], tx); node_a.tx_broadcaster.txn_broadcasted.lock().unwrap().clear(); + // Ensure that funding_transaction_generated is idempotent. + assert!(node_a.node.funding_transaction_generated(&temporary_channel_id, tx.clone()).is_err()); + assert!(node_a.node.get_and_clear_pending_msg_events().is_empty()); + check_added_monitors!(node_a, 0); + tx } +pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> Transaction { + 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); + 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); + + sign_funding_transaction(node_a, node_b, channel_value, create_chan_id) +} + pub fn create_chan_between_nodes_with_value_confirm_first<'a, 'b, 'c, 'd>(node_recv: &'a Node<'b, 'c, 'c>, node_conf: &'a Node<'b, 'c, 'd>, tx: &Transaction, conf_height: u32) { confirm_transaction_at(node_conf, tx, conf_height); connect_blocks(node_conf, CHAN_CONFIRM_DEPTH - 1); @@ -706,9 +720,18 @@ pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec { { + $( + for outp in $spends_txn.output.iter() { + assert!(outp.value >= outp.script_pubkey.dust_value().as_sat(), "Input tx output didn't meet dust limit"); + } + )* + for outp in $tx.output.iter() { + assert!(outp.value >= outp.script_pubkey.dust_value().as_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() { @@ -762,6 +785,9 @@ macro_rules! get_closing_signed_broadcast { #[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] { @@ -789,6 +815,8 @@ macro_rules! check_closed_event { 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); let expected_reason = $reason; @@ -906,6 +934,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 */) => { { @@ -972,7 +1003,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(); @@ -997,30 +1028,32 @@ macro_rules! get_payment_preimage_hash { }; ($dest_node: expr, $min_value_msat: expr) => { { + use bitcoin::hashes::Hash as _; let mut payment_count = $dest_node.network_payment_count.borrow_mut(); - let payment_preimage = PaymentPreimage([*payment_count; 32]); + let payment_preimage = $crate::ln::PaymentPreimage([*payment_count; 32]); *payment_count += 1; - let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); - let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, $min_value_msat, 7200, 0).unwrap(); + let payment_hash = $crate::ln::PaymentHash( + bitcoin::hashes::sha256::Hash::hash(&payment_preimage.0[..]).into_inner()); + let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, $min_value_msat, 7200).unwrap(); (payment_preimage, payment_hash, payment_secret) } } } #[cfg(test)] +#[macro_export] macro_rules! get_route_and_payment_hash { ($send_node: expr, $recv_node: expr, $recv_value: expr) => {{ - get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV) + $crate::get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV) }}; ($send_node: expr, $recv_node: expr, $last_hops: expr, $recv_value: expr, $cltv: expr) => {{ - let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash!($recv_node, Some($recv_value)); - let payee = $crate::routing::router::Payee::new($recv_node.node.get_our_node_id()) + 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 net_graph_msg_handler = &$send_node.net_graph_msg_handler; - let scorer = ::routing::scorer::Scorer::with_fixed_penalty(0); - let route = ::routing::router::get_route( - &$send_node.node.get_our_node_id(), &payee, &net_graph_msg_handler.network_graph, + let scorer = $crate::util::test_utils::TestScorer::with_fixed_penalty(0); + let route = $crate::routing::router::get_route( + &$send_node.node.get_our_node_id(), &payee, $send_node.network_graph, Some(&$send_node.node.list_usable_channels().iter().collect::>()), $recv_value, $cltv, $send_node.logger, &scorer ).unwrap(); @@ -1028,6 +1061,8 @@ macro_rules! get_route_and_payment_hash { }} } +#[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(); @@ -1039,9 +1074,14 @@ macro_rules! expect_pending_htlcs_forwardable_ignore { }} } +#[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. $node.node.process_pending_htlc_forwards(); }} } @@ -1056,6 +1096,9 @@ macro_rules! expect_pending_htlcs_forwardable_from_events { }; if $ignore { $node.node.process_pending_htlc_forwards(); + + // Ensure process_pending_htlc_forwards is idempotent. + $node.node.process_pending_htlc_forwards(); } }} } @@ -1082,24 +1125,70 @@ macro_rules! expect_payment_received { } } +#[cfg(test)] +#[macro_export] +macro_rules! expect_payment_sent_without_paths { + ($node: expr, $expected_payment_preimage: expr) => { + expect_payment_sent!($node, $expected_payment_preimage, None::, false); + }; + ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr) => { + expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, false); + } +} + +#[macro_export] macro_rules! expect_payment_sent { ($node: expr, $expected_payment_preimage: expr) => { - expect_payment_sent!($node, $expected_payment_preimage, None::); + $crate::expect_payment_sent!($node, $expected_payment_preimage, None::, true); }; ($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 = PaymentHash(Sha256::hash(&$expected_payment_preimage.0).into_inner()); - assert_eq!(events.len(), 1); - match events[0] { - Event::PaymentSent { payment_id: _, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { + 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"), + } + } + } + } } +} + +#[cfg(test)] +#[macro_export] +macro_rules! expect_payment_path_successful { + ($node: expr) => { + let events = $node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + $crate::util::events::Event::PaymentPathSuccessful { .. } => {}, + _ => panic!("Unexpected event"), } } } @@ -1118,58 +1207,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!(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"), + } } } } @@ -1337,6 +1482,12 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, last_update_fulfill_dance!(origin_node, expected_route.first().unwrap()); } } + + // Ensure that claim_funds is idempotent. + assert!(!expected_paths[0].last().unwrap().node.claim_funds(our_payment_preimage)); + 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_total_fee_msat } pub fn 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) { @@ -1353,12 +1504,11 @@ 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::new(expected_route.last().unwrap().node.get_our_node_id()) + let payee = Payee::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) .with_features(InvoiceFeatures::known()); - let net_graph_msg_handler = &origin_node.net_graph_msg_handler; - let scorer = Scorer::with_fixed_penalty(0); + let scorer = test_utils::TestScorer::with_fixed_penalty(0); let route = get_route( - &origin_node.node.get_our_node_id(), &payee, &net_graph_msg_handler.network_graph, + &origin_node.node.get_our_node_id(), &payee, &origin_node.network_graph, Some(&origin_node.node.list_usable_channels().iter().collect::>()), recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap(); assert_eq!(route.paths.len(), 1); @@ -1372,11 +1522,10 @@ 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::new(expected_route.last().unwrap().node.get_our_node_id()) + let payee = Payee::from_node_id(expected_route.last().unwrap().node.get_our_node_id()) .with_features(InvoiceFeatures::known()); - let net_graph_msg_handler = &origin_node.net_graph_msg_handler; - let scorer = Scorer::with_fixed_penalty(0); - let route = get_route(&origin_node.node.get_our_node_id(), &payee, &net_graph_msg_handler.network_graph, None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap(); + 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(); 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()) { @@ -1470,19 +1619,38 @@ 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"), + } } } } + + // Ensure that fail_htlc_backwards is idempotent. + assert!(!expected_paths[0].last().unwrap().node.fail_htlc_backwards(&our_payment_hash)); + 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); } pub fn fail_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], our_payment_hash: PaymentHash) { @@ -1742,7 +1910,7 @@ pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec(nodes: &Vec>, a: usize, b: usize) { - handle_announce_close_broadcast_events(nodes, a, b, false, "Commitment or closing transaction was confirmed on chain."); + handle_announce_close_broadcast_events(nodes, a, b, false, "Channel closed because commitment or closing transaction was confirmed on chain."); } #[cfg(test)]