From: Jeffrey Czyz Date: Sun, 21 Mar 2021 04:42:58 +0000 (-0400) Subject: Test register_output is called on dependent txn X-Git-Tag: v0.0.14~42^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=rust-lightning;a=commitdiff_plain;h=d8d9eaf398f056a0ff61e0980a04a9e6dc438a00 Test register_output is called on dependent txn chain::Filter::register_output may return an in-block dependent transaction that spends the output. Test the scenario where the txdata given to ChainMonitor::block_connected includes a commitment transaction whose HTLC output is spent in the same block but not included in txdata. Instead, it is returned by chain::Filter::register_output when given the commitment transaction's HTLC output. This is a common scenario for Electrum clients, which provided filtered txdata. --- diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 65b5feb8..0fd08801 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -267,3 +267,56 @@ impl even pending_events } } + +#[cfg(test)] +mod tests { + use ::{check_added_monitors, get_local_commitment_txn}; + use ln::features::InitFeatures; + use ln::functional_test_utils::*; + use util::events::EventsProvider; + use util::events::MessageSendEventsProvider; + use util::test_utils::{OnRegisterOutput, TxOutReference}; + + /// Tests that in-block dependent transactions are processed by `block_connected` when not + /// included in `txdata` but returned by [`chain::Filter::register_output`]. For instance, + /// a (non-anchor) commitment transaction's HTLC output may be spent in the same block as the + /// commitment transaction itself. An Electrum client may filter the commitment transaction but + /// needs to return the HTLC transaction so it can be processed. + #[test] + fn connect_block_checks_dependent_transactions() { + 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 nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let channel = create_announced_chan_between_nodes( + &nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); + + // Send a payment, saving nodes[0]'s revoked commitment and HTLC-Timeout transactions. + let (commitment_tx, htlc_tx) = { + let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 5_000_000).0; + let mut txn = get_local_commitment_txn!(nodes[0], channel.2); + claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage, 5_000_000); + + assert_eq!(txn.len(), 2); + (txn.remove(0), txn.remove(0)) + }; + + // Set expectations on nodes[1]'s chain source to return dependent transactions. + let htlc_output = TxOutReference(commitment_tx.clone(), 0); + let to_local_output = TxOutReference(commitment_tx.clone(), 1); + let htlc_timeout_output = TxOutReference(htlc_tx.clone(), 0); + nodes[1].chain_source + .expect(OnRegisterOutput { with: htlc_output, returns: Some((1, htlc_tx)) }) + .expect(OnRegisterOutput { with: to_local_output, returns: None }) + .expect(OnRegisterOutput { with: htlc_timeout_output, returns: None }); + + // Notify nodes[1] that nodes[0]'s revoked commitment transaction was mined. The chain + // source should return the dependent HTLC transaction when the HTLC output is registered. + mine_transaction(&nodes[1], &commitment_tx); + + // Clean up so uninteresting assertions don't fail. + check_added_monitors!(nodes[1], 1); + nodes[1].node.get_and_clear_pending_msg_events(); + nodes[1].node.get_and_clear_pending_events(); + } +} diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index e7f61c6a..36ca7d64 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -341,7 +341,8 @@ macro_rules! get_feerate { } } -#[cfg(test)] +/// Returns any local commitment transactions for the channel. +#[macro_export] macro_rules! get_local_commitment_txn { ($node: expr, $channel_id: expr) => { {