X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=34568b07cad5e4d5dd5f13bb4404e17b6c8948d0;hb=861e0eee9e2461fbb2c21454da746f5def5d39a5;hp=b5ac22d47dd7a76acf959e69e795d4491f4633fa;hpb=8e92223a44f7b20560b374012dc32222dbfb5cf7;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index b5ac22d4..34568b07 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,14 +10,14 @@ //! 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}; +use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, chainmonitor::Persist}; 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::{ClaimedHTLC, 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::ln::channelmanager::{self, AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA}; use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate}; use crate::routing::router::{self, PaymentParameters, Route}; use crate::ln::features::InitFeatures; @@ -933,6 +933,21 @@ macro_rules! check_added_monitors { } } +/// Checks whether the claimed HTLC for the specified path has the correct channel information. +/// +/// This will panic if the path is empty, if the HTLC's channel ID is not actually a channel that +/// connects the final two nodes in the path, or if the `user_channel_id` is incorrect. +pub fn check_claimed_htlc_channel<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], htlc: &ClaimedHTLC) { + let mut nodes = path.iter().rev(); + let dest = nodes.next().expect("path should have a destination").node; + let prev = nodes.next().unwrap_or(&origin_node).node; + let dest_channels = dest.list_channels(); + let ch = dest_channels.iter().find(|ch| ch.channel_id == htlc.channel_id) + .expect("HTLC's channel should be one of destination node's channels"); + assert_eq!(htlc.user_channel_id, ch.user_channel_id); + assert_eq!(ch.counterparty.node_id, prev.get_our_node_id()); +} + pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: UserConfig, chanman_encoded: &[u8], monitors_encoded: &[&[u8]]) -> TestChannelManager<'b, 'c> { let mut monitors_read = Vec::with_capacity(monitors_encoded.len()); for encoded in monitors_encoded { @@ -1684,8 +1699,8 @@ macro_rules! commitment_signed_dance { bs_revoke_and_ack } }; - ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, false /* no extra message */) => { - assert!($crate::ln::functional_test_utils::commitment_signed_dance_through_cp_raa(&$node_a, &$node_b, $fail_backwards).is_none()); + ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, false /* no extra message */, $incl_claim: expr) => { + assert!($crate::ln::functional_test_utils::commitment_signed_dance_through_cp_raa(&$node_a, &$node_b, $fail_backwards, $incl_claim).is_none()); }; ($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backwards: expr) => { $crate::ln::functional_test_utils::do_commitment_signed_dance(&$node_a, &$node_b, &$commitment_signed, $fail_backwards, false); @@ -1696,11 +1711,16 @@ macro_rules! commitment_signed_dance { /// the initiator's `revoke_and_ack` response. i.e. [`do_main_commitment_signed_dance`] plus the /// `revoke_and_ack` response to it. /// +/// An HTLC claim on one channel blocks the RAA channel monitor update for the outbound edge +/// channel until the inbound edge channel preimage monitor update completes. Thus, when checking +/// for channel monitor updates, we need to know if an `update_fulfill_htlc` was included in the +/// the commitment we're exchanging. `includes_claim` provides that information. +/// /// Returns any additional message `node_b` generated in addition to the `revoke_and_ack` response. -pub fn commitment_signed_dance_through_cp_raa(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool) -> Option { +pub fn commitment_signed_dance_through_cp_raa(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool, includes_claim: bool) -> Option { let (extra_msg_option, bs_revoke_and_ack) = do_main_commitment_signed_dance(node_a, node_b, fail_backwards); node_a.node.handle_revoke_and_ack(&node_b.node.get_our_node_id(), &bs_revoke_and_ack); - check_added_monitors(node_a, 1); + check_added_monitors(node_a, if includes_claim { 0 } else { 1 }); extra_msg_option } @@ -1747,7 +1767,23 @@ pub fn do_commitment_signed_dance(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, ' node_a.node.handle_commitment_signed(&node_b.node.get_our_node_id(), commitment_signed); check_added_monitors!(node_a, 1); - commitment_signed_dance!(node_a, node_b, (), fail_backwards, true, false); + // If this commitment signed dance was due to a claim, don't check for an RAA monitor update. + let got_claim = node_a.node.pending_events.lock().unwrap().iter().any(|(ev, action)| { + let matching_action = if let Some(channelmanager::EventCompletionAction::ReleaseRAAChannelMonitorUpdate + { channel_funding_outpoint, counterparty_node_id }) = action + { + if channel_funding_outpoint.to_channel_id() == commitment_signed.channel_id { + assert_eq!(*counterparty_node_id, node_b.node.get_our_node_id()); + true + } else { false } + } else { false }; + if matching_action { + if let Event::PaymentSent { .. } = ev {} else { panic!(); } + } + matching_action + }); + if fail_backwards { assert!(!got_claim); } + commitment_signed_dance!(node_a, node_b, (), fail_backwards, true, false, got_claim); if skip_last_step { return; } @@ -1892,7 +1928,7 @@ macro_rules! expect_payment_claimed { pub fn expect_payment_sent>(node: &H, expected_payment_preimage: PaymentPreimage, expected_fee_msat_opt: Option>, - expect_per_path_claims: bool, + expect_per_path_claims: bool, expect_post_ev_mon_update: bool, ) { let events = node.node().get_and_clear_pending_events(); let expected_payment_hash = PaymentHash( @@ -1902,6 +1938,9 @@ pub fn expect_payment_sent>(node: &H, } else { assert_eq!(events.len(), 1); } + if expect_post_ev_mon_update { + check_added_monitors(node, 1); + } let expected_payment_id = match events[0] { Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { assert_eq!(expected_payment_preimage, *payment_preimage); @@ -1928,17 +1967,6 @@ pub fn expect_payment_sent>(node: &H, } } -#[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) => { @@ -1949,7 +1977,7 @@ macro_rules! expect_payment_sent { }; ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => { $crate::ln::functional_test_utils::expect_payment_sent(&$node, $expected_payment_preimage, - $expected_fee_msat_opt.map(|o| Some(o)), $expect_paths); + $expected_fee_msat_opt.map(|o| Some(o)), $expect_paths, true); } } @@ -2271,11 +2299,34 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, ' let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events(); assert_eq!(claim_event.len(), 1); match claim_event[0] { - Event::PaymentClaimed { purpose: PaymentPurpose::SpontaneousPayment(preimage), .. }| - Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..}, .. } => - assert_eq!(preimage, our_payment_preimage), - Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { .. }, payment_hash, .. } => - assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]), + Event::PaymentClaimed { + purpose: PaymentPurpose::SpontaneousPayment(preimage), + amount_msat, + ref htlcs, + .. } + | Event::PaymentClaimed { + purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..}, + ref htlcs, + amount_msat, + .. + } => { + assert_eq!(preimage, our_payment_preimage); + assert_eq!(htlcs.len(), expected_paths.len()); // One per path. + assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); + expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc)); + }, + Event::PaymentClaimed { + purpose: PaymentPurpose::InvoicePayment { .. }, + payment_hash, + amount_msat, + ref htlcs, + .. + } => { + assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]); + assert_eq!(htlcs.len(), expected_paths.len()); // One per path. + assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); + expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc)); + } _ => panic!(), } @@ -2592,10 +2643,14 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec { } pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec) -> Vec> { + create_node_cfgs_with_persisters(node_count, chanmon_cfgs, chanmon_cfgs.iter().map(|c| &c.persister).collect()) +} + +pub fn create_node_cfgs_with_persisters<'a>(node_count: usize, chanmon_cfgs: &'a Vec, persisters: Vec<&'a impl Persist>) -> Vec> { let mut nodes = Vec::new(); for i in 0..node_count { - let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[i].chain_source), &chanmon_cfgs[i].tx_broadcaster, &chanmon_cfgs[i].logger, &chanmon_cfgs[i].fee_estimator, &chanmon_cfgs[i].persister, &chanmon_cfgs[i].keys_manager); + let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[i].chain_source), &chanmon_cfgs[i].tx_broadcaster, &chanmon_cfgs[i].logger, &chanmon_cfgs[i].fee_estimator, persisters[i], &chanmon_cfgs[i].keys_manager); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &chanmon_cfgs[i].logger)); let seed = [i as u8; 32]; nodes.push(NodeCfg {