@@ -2715,3 +2715,102 @@ fn test_anchors_monitor_fixes_counterparty_payment_script_on_reload() {
27152715 do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( false ) ;
27162716 do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( true ) ;
27172717}
2718+
2719+ #[ cfg( not( feature = "_test_vectors" ) ) ]
2720+ fn do_test_monitor_claims_with_random_signatures ( anchors : 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 ( _, _, _, 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+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1 ) ;
2752+
2753+ // The commitment transaction comes first.
2754+ let commitment_tx = {
2755+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2756+ assert_eq ! ( txn. len( ) , if anchors { 1 } else { 2 } ) ;
2757+ check_spends ! ( txn[ 0 ] , funding_tx) ;
2758+ txn. remove ( 0 )
2759+ } ;
2760+
2761+ // Check we rebroadcast it with a different wtxid.
2762+ nodes[ 0 ] . chain_monitor . chain_monitor . rebroadcast_pending_claims ( ) ;
2763+ {
2764+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2765+ assert_eq ! ( txn. len( ) , if anchors { 1 } else { 2 } ) ;
2766+ let new_commitment_tx = if txn[ 0 ] . input [ 0 ] . previous_output . txid == funding_tx. txid ( ) {
2767+ & txn[ 0 ]
2768+ } else {
2769+ & txn[ 1 ]
2770+ } ;
2771+ assert_eq ! ( new_commitment_tx. txid( ) , commitment_tx. txid( ) ) ;
2772+ assert_ne ! ( new_commitment_tx. wtxid( ) , commitment_tx. wtxid( ) ) ;
2773+ } ;
2774+
2775+ mine_transaction ( & nodes[ 0 ] , & commitment_tx) ;
2776+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
2777+ check_closed_broadcast ! ( nodes[ 0 ] , true ) ;
2778+ check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: CommitmentTxConfirmed , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 1_000_000 ) ;
2779+
2780+ // Then comes the HTLC timeout transaction.
2781+ if anchors {
2782+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
2783+ }
2784+ let htlc_timeout_tx = {
2785+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2786+ // If we update the best block to the new height before providing the confirmed
2787+ // transactions, we'll see another broadcast of the commitment transaction.
2788+ assert_eq ! ( txn. len( ) , if nodes[ 0 ] . connect_style. borrow( ) . updates_best_block_first( ) { 2 } else { 1 } ) ;
2789+ let tx = if txn[ 0 ] . input [ 0 ] . previous_output . txid == commitment_tx. txid ( ) {
2790+ txn[ 0 ] . clone ( )
2791+ } else {
2792+ txn[ 1 ] . clone ( )
2793+ } ;
2794+ check_spends ! ( tx, commitment_tx, coinbase_tx) ;
2795+ tx
2796+ } ;
2797+
2798+ // Check we rebroadcast it with a different wtxid.
2799+ nodes[ 0 ] . chain_monitor . chain_monitor . rebroadcast_pending_claims ( ) ;
2800+ if anchors {
2801+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
2802+ }
2803+ {
2804+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
2805+ assert_eq ! ( txn. len( ) , 1 ) ;
2806+ assert_eq ! ( txn[ 0 ] . txid( ) , htlc_timeout_tx. txid( ) ) ;
2807+ assert_ne ! ( txn[ 0 ] . wtxid( ) , htlc_timeout_tx. wtxid( ) ) ;
2808+ }
2809+ }
2810+
2811+ #[ cfg( not( feature = "_test_vectors" ) ) ]
2812+ #[ test]
2813+ fn test_monitor_claims_with_random_signatures ( ) {
2814+ do_test_monitor_claims_with_random_signatures ( false ) ;
2815+ do_test_monitor_claims_with_random_signatures ( true ) ;
2816+ }
0 commit comments