Merge pull request #2624 from wpaulino/2609-follow-up
[rust-lightning] / lightning / src / ln / monitor_tests.rs
index cb78cda714f83d4edec2b64f44364fc88f55864d..c950d13bb01d7d4c63695e4acd3bf9654b7603bc 100644 (file)
@@ -9,7 +9,7 @@
 
 //! Further functional tests which test blockchain reorganizations.
 
-use crate::sign::EcdsaChannelSigner;
+use crate::sign::{EcdsaChannelSigner, SpendableOutputDescriptor};
 use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS, Balance};
 use crate::chain::transaction::OutPoint;
 use crate::chain::chaininterface::{LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight};
@@ -21,6 +21,7 @@ use crate::ln::msgs::ChannelMessageHandler;
 use crate::util::config::UserConfig;
 use crate::util::crypto::sign;
 use crate::util::ser::Writeable;
+use crate::util::scid_utils::block_from_scid;
 use crate::util::test_utils;
 
 use bitcoin::blockdata::transaction::EcdsaSighashType;
@@ -92,7 +93,7 @@ fn chanmon_fail_from_stale_commitment() {
        expect_payment_failed_with_update!(nodes[0], payment_hash, false, update_a.contents.short_channel_id, true);
 }
 
-fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_tx: &Transaction) {
+fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_tx: &Transaction) -> Vec<SpendableOutputDescriptor> {
        let mut spendable = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
        assert_eq!(spendable.len(), 1);
        if let Event::SpendableOutputs { outputs, .. } = spendable.pop().unwrap() {
@@ -100,6 +101,7 @@ fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_t
                let spend_tx = node.keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
                        Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap();
                check_spends!(spend_tx, spendable_tx);
+               outputs
        } else { panic!(); }
 }
 
@@ -196,8 +198,8 @@ fn chanmon_claim_value_coop_close() {
        assert_eq!(shutdown_tx, nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0));
        assert_eq!(shutdown_tx.len(), 1);
 
-       mine_transaction(&nodes[0], &shutdown_tx[0]);
-       mine_transaction(&nodes[1], &shutdown_tx[0]);
+       let shutdown_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &shutdown_tx[0]));
+       let shutdown_tx_conf_height_b = block_from_scid(&mine_transaction(&nodes[1], &shutdown_tx[0]));
 
        assert!(nodes[0].node.list_channels().is_empty());
        assert!(nodes[1].node.list_channels().is_empty());
@@ -216,16 +218,33 @@ fn chanmon_claim_value_coop_close() {
                }],
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
-       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
-       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 2);
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 2);
+
+       assert!(get_monitor!(nodes[0], chan_id)
+               .get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_a).is_empty());
+       assert!(get_monitor!(nodes[1], chan_id)
+               .get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_b).is_empty());
+
+       connect_blocks(&nodes[0], 1);
+       connect_blocks(&nodes[1], 1);
 
        assert_eq!(Vec::<Balance>::new(),
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
        assert_eq!(Vec::<Balance>::new(),
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
-       test_spendable_output(&nodes[0], &shutdown_tx[0]);
-       test_spendable_output(&nodes[1], &shutdown_tx[0]);
+       let spendable_outputs_a = test_spendable_output(&nodes[0], &shutdown_tx[0]);
+       assert_eq!(
+               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_a),
+               spendable_outputs_a
+       );
+
+       let spendable_outputs_b = test_spendable_output(&nodes[1], &shutdown_tx[0]);
+       assert_eq!(
+               get_monitor!(nodes[1], chan_id).get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_b),
+               spendable_outputs_b
+       );
 
        check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure, [nodes[1].node.get_our_node_id()], 1000000);
        check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure, [nodes[0].node.get_our_node_id()], 1000000);
@@ -618,7 +637,7 @@ fn test_balances_on_local_commitment_htlcs() {
        // First confirm the commitment transaction on nodes[0], which should leave us with three
        // claimable balances.
        let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
-       mine_transaction(&nodes[0], &as_txn[0]);
+       let commitment_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &as_txn[0]));
        check_added_monitors!(nodes[0], 1);
        check_closed_broadcast!(nodes[0], true);
        check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 1000000);
@@ -710,13 +729,20 @@ fn test_balances_on_local_commitment_htlcs() {
 
        // Connect blocks until the commitment transaction's CSV expires, providing us the relevant
        // `SpendableOutputs` event and removing the claimable balance entry.
-       connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1);
+       connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1 - 1);
+       assert!(get_monitor!(nodes[0], chan_id)
+               .get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a).is_empty());
+       connect_blocks(&nodes[0], 1);
        assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
                        confirmation_height: node_a_htlc_claimable,
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
-       test_spendable_output(&nodes[0], &as_txn[0]);
+       let to_self_spendable_output = test_spendable_output(&nodes[0], &as_txn[0]);
+       assert_eq!(
+               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a),
+               to_self_spendable_output
+       );
 
        // Connect blocks until the HTLC-Timeout's CSV expires, providing us the relevant
        // `SpendableOutputs` event and removing the claimable balance entry.
@@ -1867,23 +1893,35 @@ fn test_yield_anchors_events() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-       let chan_id = create_announced_chan_between_nodes_with_value(
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(
                &nodes, 0, 1, 1_000_000, 500_000_000
-       ).2;
-       route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
-       let (payment_preimage, payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 1_000_000);
+       );
+       let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
+       let (payment_preimage_2, payment_hash_2, ..) = route_payment(&nodes[1], &[&nodes[0]], 2_000_000);
 
        assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
 
        *nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
+
        connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
-       check_closed_broadcast!(&nodes[0], true);
-       assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
+       assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
+
+       connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
+       {
+               let txn = nodes[1].tx_broadcaster.txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               check_spends!(txn[0], funding_tx);
+       }
 
        get_monitor!(nodes[0], chan_id).provide_payment_preimage(
-               &payment_hash, &payment_preimage, &node_cfgs[0].tx_broadcaster,
+               &payment_hash_2, &payment_preimage_2, &node_cfgs[0].tx_broadcaster,
                &LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
        );
+       get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+               &payment_hash_1, &payment_preimage_1, &node_cfgs[0].tx_broadcaster,
+               &LowerBoundedFeeEstimator::new(node_cfgs[1].fee_estimator), &nodes[1].logger
+       );
 
        let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
        assert_eq!(holder_events.len(), 1);
@@ -1904,27 +1942,50 @@ fn test_yield_anchors_events() {
                        assert_eq!(txn.len(), 2);
                        let anchor_tx = txn.pop().unwrap();
                        let commitment_tx = txn.pop().unwrap();
+                       check_spends!(commitment_tx, funding_tx);
                        check_spends!(anchor_tx, coinbase_tx, commitment_tx);
                        (commitment_tx, anchor_tx)
                },
                _ => panic!("Unexpected event"),
        };
 
+       assert_eq!(commitment_tx.output[2].value, 1_000); // HTLC A -> B
+       assert_eq!(commitment_tx.output[3].value, 2_000); // HTLC B -> A
+
        mine_transactions(&nodes[0], &[&commitment_tx, &anchor_tx]);
        check_added_monitors!(nodes[0], 1);
+       mine_transactions(&nodes[1], &[&commitment_tx, &anchor_tx]);
+       check_added_monitors!(nodes[1], 1);
+
+       {
+               let mut txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
+               assert_eq!(txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
+
+               let htlc_preimage_tx = txn.pop().unwrap();
+               assert_eq!(htlc_preimage_tx.input.len(), 1);
+               assert_eq!(htlc_preimage_tx.input[0].previous_output.vout, 3);
+               check_spends!(htlc_preimage_tx, commitment_tx);
+
+               let htlc_timeout_tx = txn.pop().unwrap();
+               assert_eq!(htlc_timeout_tx.input.len(), 1);
+               assert_eq!(htlc_timeout_tx.input[0].previous_output.vout, 2);
+               check_spends!(htlc_timeout_tx, commitment_tx);
+
+               if let Some(commitment_tx) = txn.pop() {
+                       check_spends!(commitment_tx, funding_tx);
+               }
+       }
 
        let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
        // Certain block `ConnectStyle`s cause an extra `ChannelClose` event to be emitted since the
        // best block is updated before the confirmed transactions are notified.
-       match *nodes[0].connect_style.borrow() {
-               ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::BestBlockFirstSkippingBlocks => {
-                       assert_eq!(holder_events.len(), 3);
-                       if let Event::BumpTransaction(BumpTransactionEvent::ChannelClose { .. }) = holder_events.remove(0) {}
-                       else { panic!("unexpected event"); }
-
-               },
-               _ => assert_eq!(holder_events.len(), 2),
-       };
+       if nodes[0].connect_style.borrow().updates_best_block_first() {
+               assert_eq!(holder_events.len(), 3);
+               if let Event::BumpTransaction(BumpTransactionEvent::ChannelClose { .. }) = holder_events.remove(0) {}
+               else { panic!("unexpected event"); }
+       } else {
+               assert_eq!(holder_events.len(), 2);
+       }
        let mut htlc_txs = Vec::with_capacity(2);
        for event in holder_events {
                match event {
@@ -1958,6 +2019,9 @@ fn test_yield_anchors_events() {
 
        // Clear the remaining events as they're not relevant to what we're testing.
        nodes[0].node.get_and_clear_pending_events();
+       nodes[1].node.get_and_clear_pending_events();
+       nodes[0].node.get_and_clear_pending_msg_events();
+       nodes[1].node.get_and_clear_pending_msg_events();
 }
 
 #[test]