X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fpayment_tests.rs;h=60310e9a3df33aa445af24c33fd574753d468e98;hb=46333affb9538fcaf00ffce86b78dc2cf80b8c79;hp=d3146a6e68667f1426e2edf55f22f28c3ea782e3;hpb=fcf73f0f45d05e0bb2e6118c6d05291adcb5bc0b;p=rust-lightning diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index d3146a6e..60310e9a 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -12,28 +12,27 @@ //! payments thereafter. use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch}; -use crate::chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS}; +use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS}; use crate::chain::transaction::OutPoint; use crate::chain::keysinterface::KeysInterface; use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS; -use crate::ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS}; +use crate::ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS}; use crate::ln::msgs; use crate::ln::msgs::ChannelMessageHandler; use crate::routing::router::{PaymentParameters, get_route}; use crate::util::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider}; use crate::util::test_utils; use crate::util::errors::APIError; -use crate::util::enforcing_trait_impls::EnforcingSigner; -use crate::util::ser::{ReadableArgs, Writeable}; -use crate::io; +use crate::util::ser::Writeable; -use bitcoin::{Block, BlockHeader, BlockHash, TxMerkleNode}; +use bitcoin::{Block, BlockHeader, TxMerkleNode}; use bitcoin::hashes::Hash; use bitcoin::network::constants::Network; use crate::prelude::*; use crate::ln::functional_test_utils::*; +use crate::routing::gossip::NodeId; #[test] fn retry_single_path_payment() { @@ -409,39 +408,8 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) { // The ChannelMonitor should always be the latest version, as we're required to persist it // during the `commitment_signed_dance!()`. - let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); - - persister = test_utils::TestPersister::new(); - let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); - nodes[0].chain_monitor = &new_chain_monitor; - let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; - let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( - &mut chan_0_monitor_read, keys_manager).unwrap(); - assert!(chan_0_monitor_read.is_empty()); - - let mut nodes_0_read = &nodes_0_serialized[..]; - let (_, nodes_0_deserialized_tmp) = { - let mut channel_monitors = HashMap::new(); - channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor); - <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_0_read, ChannelManagerReadArgs { - default_config: test_default_channel_config(), - keys_manager, - fee_estimator: node_cfgs[0].fee_estimator, - chain_monitor: nodes[0].chain_monitor, - tx_broadcaster: nodes[0].tx_broadcaster.clone(), - logger: nodes[0].logger, - channel_monitors, - }).unwrap() - }; - nodes_0_deserialized = nodes_0_deserialized_tmp; - assert!(nodes_0_read.is_empty()); - - assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor), - ChannelMonitorUpdateStatus::Completed); - nodes[0].node = &nodes_0_deserialized; - check_added_monitors!(nodes[0], 1); + let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode(); + reload_node!(nodes[0], test_default_channel_config(), &nodes_0_serialized, &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_0_deserialized); // On reload, the ChannelManager should realize it is stale compared to the ChannelMonitor and // force-close the channel. @@ -603,64 +571,10 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) { // The ChannelMonitor should always be the latest version, as we're required to persist it // during the `commitment_signed_dance!()`. - let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); - - let mut chan_1_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - - macro_rules! reload_node { - ($chain_monitor: ident, $chan_manager: ident, $persister: ident) => { { - $persister = test_utils::TestPersister::new(); - let keys_manager = &chanmon_cfgs[0].keys_manager; - $chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &$persister, keys_manager); - nodes[0].chain_monitor = &$chain_monitor; - let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; - let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( - &mut chan_0_monitor_read, keys_manager).unwrap(); - assert!(chan_0_monitor_read.is_empty()); - - let mut chan_1_monitor = None; - let mut channel_monitors = HashMap::new(); - channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor); - - if !chan_1_monitor_serialized.0.is_empty() { - let mut chan_1_monitor_read = &chan_1_monitor_serialized.0[..]; - chan_1_monitor = Some(<(BlockHash, ChannelMonitor)>::read( - &mut chan_1_monitor_read, keys_manager).unwrap().1); - assert!(chan_1_monitor_read.is_empty()); - channel_monitors.insert(chan_1_monitor.as_ref().unwrap().get_funding_txo().0, chan_1_monitor.as_mut().unwrap()); - } - - let mut nodes_0_read = &nodes_0_serialized[..]; - let (_, nodes_0_deserialized_tmp) = { - <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_0_read, ChannelManagerReadArgs { - default_config: test_default_channel_config(), - keys_manager, - fee_estimator: node_cfgs[0].fee_estimator, - chain_monitor: nodes[0].chain_monitor, - tx_broadcaster: nodes[0].tx_broadcaster.clone(), - logger: nodes[0].logger, - channel_monitors, - }).unwrap() - }; - $chan_manager = nodes_0_deserialized_tmp; - assert!(nodes_0_read.is_empty()); - - assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor), - ChannelMonitorUpdateStatus::Completed); - if !chan_1_monitor_serialized.0.is_empty() { - let funding_txo = chan_1_monitor.as_ref().unwrap().get_funding_txo().0; - assert_eq!(nodes[0].chain_monitor.watch_channel(funding_txo, chan_1_monitor.unwrap()), - ChannelMonitorUpdateStatus::Completed); - } - nodes[0].node = &$chan_manager; - check_added_monitors!(nodes[0], if !chan_1_monitor_serialized.0.is_empty() { 2 } else { 1 }); - - nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - } } - } + let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode(); - reload_node!(first_new_chain_monitor, first_nodes_0_deserialized, first_persister); + reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized], first_persister, first_new_chain_monitor, first_nodes_0_deserialized); + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); // On reload, the ChannelManager should realize it is stale compared to the ChannelMonitor and // force-close the channel. @@ -744,16 +658,16 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) { // We set mpp_parts_remain to avoid having abandon_payment called expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain()); - chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); - chan_1_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id_3).write(&mut chan_1_monitor_serialized).unwrap(); + let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode(); + let chan_1_monitor_serialized = get_monitor!(nodes[0], chan_id_3).encode(); nodes_0_serialized = nodes[0].node.encode(); assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_ok()); assert!(!nodes[0].node.get_and_clear_pending_msg_events().is_empty()); - reload_node!(second_new_chain_monitor, second_nodes_0_deserialized, second_persister); + reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], second_persister, second_new_chain_monitor, second_nodes_0_deserialized); + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); + reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); // Now resend the payment, delivering the HTLC and actually claiming it this time. This ensures @@ -766,14 +680,14 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) { assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_err()); assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); - chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); - chan_1_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id_3).write(&mut chan_1_monitor_serialized).unwrap(); + let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode(); + let chan_1_monitor_serialized = get_monitor!(nodes[0], chan_id_3).encode(); nodes_0_serialized = nodes[0].node.encode(); // Ensure that after reload we cannot retry the payment. - reload_node!(third_new_chain_monitor, third_nodes_0_deserialized, third_persister); + reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], third_persister, third_new_chain_monitor, third_nodes_0_deserialized); + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); + reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_err()); @@ -879,16 +793,15 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co // If we persist the ChannelManager here, we should get the PaymentSent event after // deserialization. - let mut chan_manager_serialized = test_utils::TestVecWriter(Vec::new()); + let mut chan_manager_serialized = Vec::new(); if !persist_manager_post_event { - nodes[0].node.write(&mut chan_manager_serialized).unwrap(); + chan_manager_serialized = nodes[0].node.encode(); } // Now persist the ChannelMonitor and inform the ChainMonitor that we're done, generating the // payment sent event. chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed); - let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[0], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); + let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode(); for update in mon_updates { nodes[0].chain_monitor.chain_monitor.channel_monitor_updated(funding_txo, update).unwrap(); } @@ -901,39 +814,11 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co // If we persist the ChannelManager after we get the PaymentSent event, we shouldn't get it // twice. if persist_manager_post_event { - nodes[0].node.write(&mut chan_manager_serialized).unwrap(); + chan_manager_serialized = nodes[0].node.encode(); } // Now reload nodes[0]... - persister = test_utils::TestPersister::new(); - let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); - nodes[0].chain_monitor = &new_chain_monitor; - let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; - let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( - &mut chan_0_monitor_read, keys_manager).unwrap(); - assert!(chan_0_monitor_read.is_empty()); - - let (_, nodes_0_deserialized_tmp) = { - let mut channel_monitors = HashMap::new(); - channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor); - <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)> - ::read(&mut io::Cursor::new(&chan_manager_serialized.0[..]), ChannelManagerReadArgs { - default_config: Default::default(), - keys_manager, - fee_estimator: node_cfgs[0].fee_estimator, - chain_monitor: nodes[0].chain_monitor, - tx_broadcaster: nodes[0].tx_broadcaster.clone(), - logger: nodes[0].logger, - channel_monitors, - }).unwrap() - }; - nodes_0_deserialized = nodes_0_deserialized_tmp; - - assert_eq!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor), - ChannelMonitorUpdateStatus::Completed); - check_added_monitors!(nodes[0], 1); - nodes[0].node = &nodes_0_deserialized; + reload_node!(nodes[0], &chan_manager_serialized, &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_0_deserialized); if persist_manager_post_event { assert!(nodes[0].node.get_and_clear_pending_events().is_empty()); @@ -982,10 +867,8 @@ fn test_fulfill_restart_failure() { // The simplest way to get a failure after a fulfill is to reload nodes[1] from a state // pre-fulfill, which we do by serializing it here. - let mut chan_manager_serialized = test_utils::TestVecWriter(Vec::new()); - nodes[1].node.write(&mut chan_manager_serialized).unwrap(); - let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new()); - get_monitor!(nodes[1], chan_id).write(&mut chan_0_monitor_serialized).unwrap(); + let chan_manager_serialized = nodes[1].node.encode(); + let chan_0_monitor_serialized = get_monitor!(nodes[1], chan_id).encode(); nodes[1].node.claim_funds(payment_preimage); check_added_monitors!(nodes[1], 1); @@ -996,35 +879,7 @@ fn test_fulfill_restart_failure() { expect_payment_sent_without_paths!(nodes[0], payment_preimage); // Now reload nodes[1]... - persister = test_utils::TestPersister::new(); - let keys_manager = &chanmon_cfgs[1].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[1].chain_source), nodes[1].tx_broadcaster.clone(), nodes[1].logger, node_cfgs[1].fee_estimator, &persister, keys_manager); - nodes[1].chain_monitor = &new_chain_monitor; - let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; - let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( - &mut chan_0_monitor_read, keys_manager).unwrap(); - assert!(chan_0_monitor_read.is_empty()); - - let (_, nodes_1_deserialized_tmp) = { - let mut channel_monitors = HashMap::new(); - channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor); - <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)> - ::read(&mut io::Cursor::new(&chan_manager_serialized.0[..]), ChannelManagerReadArgs { - default_config: Default::default(), - keys_manager, - fee_estimator: node_cfgs[1].fee_estimator, - chain_monitor: nodes[1].chain_monitor, - tx_broadcaster: nodes[1].tx_broadcaster.clone(), - logger: nodes[1].logger, - channel_monitors, - }).unwrap() - }; - nodes_1_deserialized = nodes_1_deserialized_tmp; - - assert_eq!(nodes[1].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor), - ChannelMonitorUpdateStatus::Completed); - check_added_monitors!(nodes[1], 1); - nodes[1].node = &nodes_1_deserialized; + reload_node!(nodes[1], &chan_manager_serialized, &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_1_deserialized); nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); @@ -1385,3 +1240,133 @@ fn abandoned_send_payment_idempotent() { pass_along_route(&nodes[0], &[&[&nodes[1]]], 100_000, second_payment_hash, second_payment_secret); claim_payment(&nodes[0], &[&nodes[1]], second_payment_preimage); } + +#[test] +fn test_trivial_inflight_htlc_tracking(){ + // In this test, we test three scenarios: + // (1) Sending + claiming a payment successfully should return `None` when querying InFlightHtlcs + // (2) Sending a payment without claiming it should return the payment's value (500000) when querying InFlightHtlcs + // (3) After we claim the payment sent in (2), InFlightHtlcs should return `None` for the query. + let chanmon_cfgs = create_chanmon_cfgs(3); + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); + + let (_, _, chan_1_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()); + let (_, _, chan_2_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()); + + // Send and claim the payment. Inflight HTLCs should be empty. + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 500000); + { + let inflight_htlcs = node_chanmgrs[0].compute_inflight_htlcs(); + + let node_0_channel_lock = nodes[0].node.channel_state.lock().unwrap(); + let node_1_channel_lock = nodes[1].node.channel_state.lock().unwrap(); + let channel_1 = node_0_channel_lock.by_id.get(&chan_1_id).unwrap(); + let channel_2 = node_1_channel_lock.by_id.get(&chan_2_id).unwrap(); + + let chan_1_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[0].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()), + channel_1.get_short_channel_id().unwrap() + ); + let chan_2_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[2].node.get_our_node_id()), + channel_2.get_short_channel_id().unwrap() + ); + + assert_eq!(chan_1_used_liquidity, None); + assert_eq!(chan_2_used_liquidity, None); + } + + // Send the payment, but do not claim it. Our inflight HTLCs should contain the pending payment. + let (payment_preimage, _, _) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 500000); + { + let inflight_htlcs = node_chanmgrs[0].compute_inflight_htlcs(); + + let node_0_channel_lock = nodes[0].node.channel_state.lock().unwrap(); + let node_1_channel_lock = nodes[1].node.channel_state.lock().unwrap(); + let channel_1 = node_0_channel_lock.by_id.get(&chan_1_id).unwrap(); + let channel_2 = node_1_channel_lock.by_id.get(&chan_2_id).unwrap(); + + let chan_1_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[0].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()), + channel_1.get_short_channel_id().unwrap() + ); + let chan_2_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[2].node.get_our_node_id()), + channel_2.get_short_channel_id().unwrap() + ); + + // First hop accounts for expected 1000 msat fee + assert_eq!(chan_1_used_liquidity, Some(501000)); + assert_eq!(chan_2_used_liquidity, Some(500000)); + } + + // Now, let's claim the payment. This should result in the used liquidity to return `None`. + claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage); + { + let inflight_htlcs = node_chanmgrs[0].compute_inflight_htlcs(); + + let node_0_channel_lock = nodes[0].node.channel_state.lock().unwrap(); + let node_1_channel_lock = nodes[1].node.channel_state.lock().unwrap(); + let channel_1 = node_0_channel_lock.by_id.get(&chan_1_id).unwrap(); + let channel_2 = node_1_channel_lock.by_id.get(&chan_2_id).unwrap(); + + let chan_1_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[0].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()), + channel_1.get_short_channel_id().unwrap() + ); + let chan_2_used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[2].node.get_our_node_id()), + channel_2.get_short_channel_id().unwrap() + ); + + assert_eq!(chan_1_used_liquidity, None); + assert_eq!(chan_2_used_liquidity, None); + } +} + +#[test] +fn test_holding_cell_inflight_htlcs() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2; + + let (route, payment_hash_1, _, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], 1000000); + let (_, payment_hash_2, payment_secret_2) = get_payment_preimage_hash!(nodes[1]); + + // Queue up two payments - one will be delivered right away, one immediately goes into the + // holding cell as nodes[0] is AwaitingRAA. + { + nodes[0].node.send_payment(&route, payment_hash_1, &Some(payment_secret_1), PaymentId(payment_hash_1.0)).unwrap(); + check_added_monitors!(nodes[0], 1); + nodes[0].node.send_payment(&route, payment_hash_2, &Some(payment_secret_2), PaymentId(payment_hash_2.0)).unwrap(); + check_added_monitors!(nodes[0], 0); + } + + let inflight_htlcs = node_chanmgrs[0].compute_inflight_htlcs(); + + { + let channel_lock = nodes[0].node.channel_state.lock().unwrap(); + let channel = channel_lock.by_id.get(&channel_id).unwrap(); + + let used_liquidity = inflight_htlcs.used_liquidity_msat( + &NodeId::from_pubkey(&nodes[0].node.get_our_node_id()) , + &NodeId::from_pubkey(&nodes[1].node.get_our_node_id()), + channel.get_short_channel_id().unwrap() + ); + + assert_eq!(used_liquidity, Some(2000000)); + } + + // Clear pending events so test doesn't throw a "Had excess message on node..." error + nodes[0].node.get_and_clear_pending_msg_events(); +}