Merge pull request #2609 from wpaulino/monitor-get-spendable-output
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Fri, 29 Sep 2023 01:29:47 +0000 (01:29 +0000)
committerGitHub <noreply@github.com>
Fri, 29 Sep 2023 01:29:47 +0000 (01:29 +0000)
Allow retrieval of SpendableOutputDescriptors from relevant transactions

1  2 
lightning/src/ln/monitor_tests.rs

index 9cf3f4ca29a323b16f5d76114a9a413138f2633f,892ddce2a7dc86bde458f7d9153d7245c695b3bc..f0cc872db0ad6731706cc380f59fd0c78be122f9
@@@ -9,7 -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 +21,7 @@@ use crate::ln::msgs::ChannelMessageHand
  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 +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() {
                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 +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());
                }],
                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);
@@@ -1867,35 -1886,23 +1886,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);
                        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 {
  
        // 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]