@@ -2318,3 +2318,90 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
23182318 // revoked commitment which Bob has the preimage for.
23192319 assert_eq ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_claimable_balances( & [ ] ) . len( ) , 6 ) ;
23202320}
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