@@ -2318,3 +2318,90 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
2318
2318
// revoked commitment which Bob has the preimage for.
2319
2319
assert_eq ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_claimable_balances( & [ ] ) . len( ) , 6 ) ;
2320
2320
}
2321
+
2322
+ fn do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( confirm_commitment_before_reload : bool ) {
2323
+ // Tests that we'll fix a ChannelMonitor's `counterparty_payment_script` for an anchor outputs
2324
+ // channel upon deserialization.
2325
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
2326
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
2327
+ let persister;
2328
+ let chain_monitor;
2329
+ let mut user_config = test_default_channel_config ( ) ;
2330
+ user_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
2331
+ user_config. manually_accept_inbound_channels = true ;
2332
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( user_config) , Some ( user_config) ] ) ;
2333
+ let node_deserialized;
2334
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
2335
+
2336
+ let ( _, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 50_000_000 ) ;
2337
+
2338
+ // Set the monitor's `counterparty_payment_script` to a dummy P2WPKH script.
2339
+ let secp = Secp256k1 :: new ( ) ;
2340
+ let privkey = bitcoin:: PrivateKey :: from_slice ( & [ 1 ; 32 ] , bitcoin:: Network :: Testnet ) . unwrap ( ) ;
2341
+ let pubkey = bitcoin:: PublicKey :: from_private_key ( & secp, & privkey) ;
2342
+ let p2wpkh_script = Script :: new_v0_p2wpkh ( & pubkey. wpubkey_hash ( ) . unwrap ( ) ) ;
2343
+ get_monitor ! ( nodes[ 1 ] , chan_id) . set_counterparty_payment_script ( p2wpkh_script. clone ( ) ) ;
2344
+ assert_eq ! ( get_monitor!( nodes[ 1 ] , chan_id) . get_counterparty_payment_script( ) , p2wpkh_script) ;
2345
+
2346
+ // Confirm the counterparty's commitment and reload the monitor (either before or after) such
2347
+ // that we arrive at the correct `counterparty_payment_script` after the reload.
2348
+ nodes[ 0 ] . node . force_close_broadcasting_latest_txn ( & chan_id, & nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
2349
+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
2350
+ check_closed_broadcast ( & nodes[ 0 ] , 1 , true ) ;
2351
+ check_closed_event ! ( & nodes[ 0 ] , 1 , ClosureReason :: HolderForceClosed , false ,
2352
+ [ nodes[ 1 ] . node. get_our_node_id( ) ] , 100000 ) ;
2353
+
2354
+ let commitment_tx = {
2355
+ let mut txn = nodes[ 0 ] . tx_broadcaster . unique_txn_broadcast ( ) ;
2356
+ assert_eq ! ( txn. len( ) , 1 ) ;
2357
+ assert_eq ! ( txn[ 0 ] . output. len( ) , 4 ) ;
2358
+ check_spends ! ( txn[ 0 ] , funding_tx) ;
2359
+ txn. pop ( ) . unwrap ( )
2360
+ } ;
2361
+
2362
+ mine_transaction ( & nodes[ 0 ] , & commitment_tx) ;
2363
+ let commitment_tx_conf_height = if confirm_commitment_before_reload {
2364
+ // We should expect our round trip serialization check to fail as we're writing the monitor
2365
+ // with the incorrect P2WPKH script but reading it with the correct P2WSH script.
2366
+ * nodes[ 1 ] . chain_monitor . expect_monitor_round_trip_fail . lock ( ) . unwrap ( ) = Some ( chan_id) ;
2367
+ let commitment_tx_conf_height = block_from_scid ( & mine_transaction ( & nodes[ 1 ] , & commitment_tx) ) ;
2368
+ let serialized_monitor = get_monitor ! ( nodes[ 1 ] , chan_id) . encode ( ) ;
2369
+ reload_node ! ( nodes[ 1 ] , user_config, & nodes[ 1 ] . node. encode( ) , & [ & serialized_monitor] , persister, chain_monitor, node_deserialized) ;
2370
+ commitment_tx_conf_height
2371
+ } else {
2372
+ let serialized_monitor = get_monitor ! ( nodes[ 1 ] , chan_id) . encode ( ) ;
2373
+ reload_node ! ( nodes[ 1 ] , user_config, & nodes[ 1 ] . node. encode( ) , & [ & serialized_monitor] , persister, chain_monitor, node_deserialized) ;
2374
+ let commitment_tx_conf_height = block_from_scid ( & mine_transaction ( & nodes[ 1 ] , & commitment_tx) ) ;
2375
+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
2376
+ check_closed_broadcast ( & nodes[ 1 ] , 1 , true ) ;
2377
+ commitment_tx_conf_height
2378
+ } ;
2379
+ check_closed_event ! ( & nodes[ 1 ] , 1 , ClosureReason :: CommitmentTxConfirmed , false ,
2380
+ [ nodes[ 0 ] . node. get_our_node_id( ) ] , 100000 ) ;
2381
+ assert ! ( get_monitor!( nodes[ 1 ] , chan_id) . get_counterparty_payment_script( ) . is_v0_p2wsh( ) ) ;
2382
+
2383
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
2384
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
2385
+
2386
+ if confirm_commitment_before_reload {
2387
+ // If we saw the commitment before our `counterparty_payment_script` was fixed, we'll never
2388
+ // get the spendable output event for the `to_remote` output, so we'll need to get it
2389
+ // manually via `get_spendable_outputs`.
2390
+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
2391
+ let outputs = get_monitor ! ( nodes[ 1 ] , chan_id) . get_spendable_outputs ( & commitment_tx, commitment_tx_conf_height) ;
2392
+ assert_eq ! ( outputs. len( ) , 1 ) ;
2393
+ let spend_tx = nodes[ 1 ] . keys_manager . backing . spend_spendable_outputs (
2394
+ & [ & outputs[ 0 ] ] , Vec :: new ( ) , Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) ,
2395
+ 253 , None , & secp
2396
+ ) . unwrap ( ) ;
2397
+ check_spends ! ( spend_tx, & commitment_tx) ;
2398
+ } else {
2399
+ test_spendable_output ( & nodes[ 1 ] , & commitment_tx) ;
2400
+ }
2401
+ }
2402
+
2403
+ #[ test]
2404
+ fn test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( ) {
2405
+ do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( false ) ;
2406
+ do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload ( true ) ;
2407
+ }
0 commit comments