@@ -2715,3 +2715,113 @@ fn test_anchors_monitor_fixes_counterparty_payment_script_on_reload() {
2715
2715
do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( false ) ;
2716
2716
do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( true ) ;
2717
2717
}
2718
+
2719
+ #[ cfg( not( feature = "_test_vectors" ) ) ]
2720
+ fn do_test_monitor_claims_with_random_signatures ( anchors : bool , confirm_counterparty_commitment : bool ) {
2721
+ // Tests that our monitor claims will always use fresh random signatures (ensuring a unique
2722
+ // wtxid) to prevent certain classes of transaction replacement at the bitcoin P2P layer.
2723
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
2724
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
2725
+ let mut user_config = test_default_channel_config ( ) ;
2726
+ if anchors {
2727
+ user_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
2728
+ user_config. manually_accept_inbound_channels = true ;
2729
+ }
2730
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( user_config) , Some ( user_config) ] ) ;
2731
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
2732
+
2733
+ let coinbase_tx = Transaction {
2734
+ version : 2 ,
2735
+ lock_time : PackedLockTime :: ZERO ,
2736
+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
2737
+ output : vec ! [
2738
+ TxOut {
2739
+ value: Amount :: ONE_BTC . to_sat( ) ,
2740
+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
2741
+ } ,
2742
+ ] ,
2743
+ } ;
2744
+ if anchors {
2745
+ nodes[ 0 ] . wallet_source . add_utxo ( bitcoin:: OutPoint { txid : coinbase_tx. txid ( ) , vout : 0 } , coinbase_tx. output [ 0 ] . value ) ;
2746
+ }
2747
+
2748
+ // Open a channel and route a payment. We'll let it timeout to claim it.
2749
+ let ( _, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
2750
+ route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
2751
+
2752
+ let ( closing_node, other_node) = if confirm_counterparty_commitment {
2753
+ ( & nodes[ 1 ] , & nodes[ 0 ] )
2754
+ } else {
2755
+ ( & nodes[ 0 ] , & nodes[ 1 ] )
2756
+ } ;
2757
+
2758
+ closing_node. node . force_close_broadcasting_latest_txn ( & chan_id, & other_node. node . get_our_node_id ( ) ) . unwrap ( ) ;
2759
+
2760
+ // The commitment transaction comes first.
2761
+ let commitment_tx = {
2762
+ let mut txn = closing_node. tx_broadcaster . unique_txn_broadcast ( ) ;
2763
+ assert_eq ! ( txn. len( ) , 1 ) ;
2764
+ check_spends ! ( txn[ 0 ] , funding_tx) ;
2765
+ txn. pop ( ) . unwrap ( )
2766
+ } ;
2767
+
2768
+ mine_transaction ( closing_node, & commitment_tx) ;
2769
+ check_added_monitors ! ( closing_node, 1 ) ;
2770
+ check_closed_broadcast ! ( closing_node, true ) ;
2771
+ check_closed_event ! ( closing_node, 1 , ClosureReason :: HolderForceClosed , [ other_node. node. get_our_node_id( ) ] , 1_000_000 ) ;
2772
+
2773
+ mine_transaction ( other_node, & commitment_tx) ;
2774
+ check_added_monitors ! ( other_node, 1 ) ;
2775
+ check_closed_broadcast ! ( other_node, true ) ;
2776
+ check_closed_event ! ( other_node, 1 , ClosureReason :: CommitmentTxConfirmed , [ closing_node. node. get_our_node_id( ) ] , 1_000_000 ) ;
2777
+
2778
+ // If we update the best block to the new height before providing the confirmed transactions,
2779
+ // we'll see another broadcast of the commitment transaction.
2780
+ if anchors && !confirm_counterparty_commitment && nodes[ 0 ] . connect_style . borrow ( ) . updates_best_block_first ( ) {
2781
+ let _ = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2782
+ }
2783
+
2784
+ // Then comes the HTLC timeout transaction.
2785
+ if confirm_counterparty_commitment {
2786
+ connect_blocks ( & nodes[ 0 ] , 5 ) ;
2787
+ test_spendable_output ( & nodes[ 0 ] , & commitment_tx, false ) ;
2788
+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV - 5 ) ;
2789
+ } else {
2790
+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV ) ;
2791
+ }
2792
+ if anchors && !confirm_counterparty_commitment {
2793
+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
2794
+ }
2795
+ let htlc_timeout_tx = {
2796
+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2797
+ assert_eq ! ( txn. len( ) , 1 ) ;
2798
+ let tx = if txn[ 0 ] . input [ 0 ] . previous_output . txid == commitment_tx. txid ( ) {
2799
+ txn[ 0 ] . clone ( )
2800
+ } else {
2801
+ txn[ 1 ] . clone ( )
2802
+ } ;
2803
+ check_spends ! ( tx, commitment_tx, coinbase_tx) ;
2804
+ tx
2805
+ } ;
2806
+
2807
+ // Check we rebroadcast it with a different wtxid.
2808
+ nodes[ 0 ] . chain_monitor . chain_monitor . rebroadcast_pending_claims ( ) ;
2809
+ if anchors && !confirm_counterparty_commitment {
2810
+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
2811
+ }
2812
+ {
2813
+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2814
+ assert_eq ! ( txn. len( ) , 1 ) ;
2815
+ assert_eq ! ( txn[ 0 ] . txid( ) , htlc_timeout_tx. txid( ) ) ;
2816
+ assert_ne ! ( txn[ 0 ] . wtxid( ) , htlc_timeout_tx. wtxid( ) ) ;
2817
+ }
2818
+ }
2819
+
2820
+ #[ cfg( not( feature = "_test_vectors" ) ) ]
2821
+ #[ test]
2822
+ fn test_monitor_claims_with_random_signatures ( ) {
2823
+ do_test_monitor_claims_with_random_signatures ( false , false ) ;
2824
+ do_test_monitor_claims_with_random_signatures ( false , true ) ;
2825
+ do_test_monitor_claims_with_random_signatures ( true , false ) ;
2826
+ do_test_monitor_claims_with_random_signatures ( true , true ) ;
2827
+ }
0 commit comments