@@ -732,8 +732,9 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
732732 test_spendable_output ( & nodes[ 0 ] , & remote_txn[ 0 ] , false ) ;
733733 assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
734734
735- // After broadcasting the HTLC claim transaction, node A will still consider the HTLC
736- // possibly-claimable up to ANTI_REORG_DELAY, at which point it will drop it.
735+ // After confirming the HTLC claim transaction, node A will no longer attempt to claim said
736+ // HTLC, unless the transaction is reorged. However, we'll still report a
737+ // `MaybeTimeoutClaimableHTLC` balance for it until we reach `ANTI_REORG_DELAY` confirmations.
737738 mine_transaction ( & nodes[ 0 ] , & b_broadcast_txn[ 0 ] ) ;
738739 if prev_commitment_tx {
739740 expect_payment_path_successful ! ( nodes[ 0 ] ) ;
@@ -749,18 +750,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
749750 // When the HTLC timeout output is spendable in the next block, A should broadcast it
750751 connect_blocks ( & nodes[ 0 ] , htlc_cltv_timeout - nodes[ 0 ] . best_block_info ( ) . 1 ) ;
751752 let a_broadcast_txn = nodes[ 0 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
752- // Aggregated claim transaction.
753753 assert_eq ! ( a_broadcast_txn. len( ) , 1 ) ;
754754 check_spends ! ( a_broadcast_txn[ 0 ] , remote_txn[ 0 ] ) ;
755- assert_eq ! ( a_broadcast_txn[ 0 ] . input. len( ) , 2 ) ;
756- assert_ne ! ( a_broadcast_txn[ 0 ] . input[ 0 ] . previous_output. vout, a_broadcast_txn[ 0 ] . input[ 1 ] . previous_output. vout) ;
757- // a_broadcast_txn [0] and [1] should spend the HTLC outputs of the commitment tx
758- assert ! ( a_broadcast_txn[ 0 ] . input. iter( ) . any( |input| remote_txn[ 0 ] . output[ input. previous_output. vout as usize ] . value. to_sat( ) == 3_000 ) ) ;
755+ assert_eq ! ( a_broadcast_txn[ 0 ] . input. len( ) , 1 ) ;
759756 assert ! ( a_broadcast_txn[ 0 ] . input. iter( ) . any( |input| remote_txn[ 0 ] . output[ input. previous_output. vout as usize ] . value. to_sat( ) == 4_000 ) ) ;
760-
761- // Confirm node B's claim for node A to remove that claim from the aggregated claim transaction.
762- mine_transaction ( & nodes[ 0 ] , & b_broadcast_txn[ 0 ] ) ;
763- let a_broadcast_txn = nodes[ 0 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
764757 let a_htlc_timeout_tx = a_broadcast_txn. into_iter ( ) . next_back ( ) . unwrap ( ) ;
765758
766759 // Once the HTLC-Timeout transaction confirms, A will no longer consider the HTLC
@@ -3328,3 +3321,162 @@ fn test_update_replay_panics() {
33283321 monitor. update_monitor ( & updates[ 2 ] , & nodes[ 1 ] . tx_broadcaster , & nodes[ 1 ] . fee_estimator , & nodes[ 1 ] . logger ) . unwrap ( ) ;
33293322 monitor. update_monitor ( & updates[ 3 ] , & nodes[ 1 ] . tx_broadcaster , & nodes[ 1 ] . fee_estimator , & nodes[ 1 ] . logger ) . unwrap ( ) ;
33303323}
3324+
3325+ #[ test]
3326+ pub fn test_pruned_locktimed_packages_recovery_after_block_disconnected ( ) {
3327+ use crate :: events:: bump_transaction:: sync:: WalletSourceSync ;
3328+
3329+ // ====== TEST SETUP ======
3330+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
3331+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
3332+
3333+ let mut user_cfg = test_default_channel_config ( ) ;
3334+ user_cfg. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
3335+ user_cfg. manually_accept_inbound_channels = true ;
3336+
3337+ let configs = [ Some ( user_cfg. clone ( ) ) , Some ( user_cfg. clone ( ) ) ] ;
3338+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & configs) ;
3339+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
3340+
3341+ let node_a_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
3342+ let node_b_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
3343+
3344+ // Since we're using anchor channels, make sure each node has a UTXO for paying fees.
3345+ let coinbase_tx = Transaction {
3346+ version : Version :: TWO ,
3347+ lock_time : LockTime :: ZERO ,
3348+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
3349+ output : vec ! [
3350+ TxOut {
3351+ value: Amount :: ONE_BTC ,
3352+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
3353+ } ,
3354+ TxOut {
3355+ value: Amount :: ONE_BTC ,
3356+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
3357+ } ,
3358+ ] ,
3359+ } ;
3360+ nodes[ 0 ] . wallet_source . add_utxo (
3361+ bitcoin:: OutPoint { txid : coinbase_tx. compute_txid ( ) , vout : 0 } ,
3362+ coinbase_tx. output [ 0 ] . value ,
3363+ ) ;
3364+ nodes[ 1 ] . wallet_source . add_utxo (
3365+ bitcoin:: OutPoint { txid : coinbase_tx. compute_txid ( ) , vout : 1 } ,
3366+ coinbase_tx. output [ 1 ] . value ,
3367+ ) ;
3368+
3369+ const CHAN_CAPACITY : u64 = 10_000_000 ;
3370+ let ( _, _, channel_id, funding_tx) =
3371+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , CHAN_CAPACITY , 0 ) ;
3372+
3373+ // Ensure all nodes are at the same initial height.
3374+ let node_max_height = nodes. iter ( ) . map ( |node| node. best_block_info ( ) . 1 ) . max ( ) . unwrap ( ) ;
3375+ for node in & nodes {
3376+ let blocks_to_mine = node_max_height - node. best_block_info ( ) . 1 ;
3377+ if blocks_to_mine > 0 {
3378+ connect_blocks ( node, blocks_to_mine) ;
3379+ }
3380+ }
3381+
3382+ // ====== TEST PROCESS ======
3383+
3384+ // Route HTLC 1 from A to B.
3385+ let ( preimage_1, payment_hash_1, ..) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
3386+
3387+ // Node B claims HTLC 1.
3388+ nodes[ 1 ] . node . claim_funds ( preimage_1) ;
3389+ expect_payment_claimed ! ( nodes[ 1 ] , payment_hash_1, 1_000_000 ) ;
3390+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
3391+ let _ = get_htlc_update_msgs ( & nodes[ 1 ] , & node_a_id) ;
3392+
3393+ // Force close the channel by broadcasting node B's commitment tx.
3394+ let node_b_commit_tx = get_local_commitment_txn ! ( nodes[ 1 ] , channel_id) ;
3395+ assert_eq ! ( node_b_commit_tx. len( ) , 1 ) ;
3396+ let node_b_commit_tx = & node_b_commit_tx[ 0 ] ;
3397+ check_spends ! ( node_b_commit_tx, funding_tx) ;
3398+
3399+ let htlc_1_locktime = nodes[ 0 ] . best_block_info ( ) . 1 + 1 + TEST_FINAL_CLTV ;
3400+ mine_transaction ( & nodes[ 0 ] , node_b_commit_tx) ;
3401+ check_closed_event (
3402+ & nodes[ 0 ] ,
3403+ 1 ,
3404+ ClosureReason :: CommitmentTxConfirmed ,
3405+ false ,
3406+ & [ node_b_id] ,
3407+ CHAN_CAPACITY ,
3408+ ) ;
3409+ check_closed_broadcast ! ( nodes[ 0 ] , true ) ;
3410+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
3411+
3412+ mine_transaction ( & nodes[ 1 ] , node_b_commit_tx) ;
3413+ check_closed_event (
3414+ & nodes[ 1 ] ,
3415+ 1 ,
3416+ ClosureReason :: CommitmentTxConfirmed ,
3417+ false ,
3418+ & [ node_a_id] ,
3419+ CHAN_CAPACITY ,
3420+ ) ;
3421+ check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
3422+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
3423+
3424+ // Node B generate HTLC 1 claim tx.
3425+ let process_bump_event = |node : & Node | {
3426+ let events = node. chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
3427+ assert_eq ! ( events. len( ) , 1 ) ;
3428+ let bump_event = match & events[ 0 ] {
3429+ Event :: BumpTransaction ( bump_event) => bump_event,
3430+ e => panic ! ( "Unexepected event: {:#?}" , e) ,
3431+ } ;
3432+ node. bump_tx_handler . handle_event ( bump_event) ;
3433+
3434+ let mut tx = node. tx_broadcaster . txn_broadcast ( ) ;
3435+ assert_eq ! ( tx. len( ) , 1 ) ;
3436+ tx. pop ( ) . unwrap ( )
3437+ } ;
3438+ let bs_htlc_1_claim_tx = process_bump_event ( & nodes[ 1 ] ) ;
3439+
3440+ let get_locktimed_packages = || {
3441+ let monitor = nodes[ 0 ] . chain_monitor . chain_monitor . get_monitor ( channel_id) . unwrap ( ) ;
3442+ let onchain_tx_handler = & monitor. inner . lock ( ) . unwrap ( ) . onchain_tx_handler ;
3443+ onchain_tx_handler. locktimed_packages . clone ( )
3444+ } ;
3445+
3446+ let locktimed_packages = get_locktimed_packages ( ) ;
3447+ let htlc_1_locktimed_package = {
3448+ let packages = locktimed_packages. get ( & htlc_1_locktime)
3449+ . expect ( "HTLC 1 locktimed package should exist" ) ;
3450+ assert_eq ! ( packages. len( ) , 1 , "HTLC 1 locktimed package should have only one package" ) ;
3451+ packages. first ( ) . unwrap ( ) . clone ( )
3452+ } ;
3453+
3454+ // HTLC 1 claim tx confirmed - Node A should prune its claim request from locktimed HTLC packages.
3455+ mine_transaction ( & nodes[ 0 ] , & bs_htlc_1_claim_tx) ;
3456+ let locktimed_packages = get_locktimed_packages ( ) ;
3457+ assert ! ( locktimed_packages. is_empty( ) , "locktimed packages should be pruned" ) ;
3458+
3459+ // Disconnect the block containing HTLC 1 claim tx to simulate a reorg. Node A should recover
3460+ // the pruned locktimed package.
3461+ disconnect_blocks ( & nodes[ 0 ] , 1 ) ;
3462+ let locktimed_packages = get_locktimed_packages ( ) ;
3463+ let recovered_htlc_1_locktimed_package = {
3464+ let packages = locktimed_packages. get ( & htlc_1_locktime)
3465+ . expect ( "HTLC 1 locktimed package should be recovered" ) ;
3466+ assert_eq ! ( packages. len( ) , 1 , "HTLC 1 locktimed package should have only one package" ) ;
3467+ packages. first ( ) . unwrap ( ) . clone ( )
3468+ } ;
3469+ assert ! ( recovered_htlc_1_locktimed_package == htlc_1_locktimed_package,
3470+ "Recovered HTLC 1 locktimed package should match the original one" ) ;
3471+
3472+ // HTLC 1 locktime expires.
3473+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV ) ;
3474+ // HTLC 1 timeout tx should be broadcasted.
3475+ let mut txs = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
3476+ assert_eq ! ( txs. len( ) , 1 ) ;
3477+ check_spends ! ( txs[ 0 ] , node_b_commit_tx) ;
3478+
3479+ // PaymentSent and PaymentPathSuccessful events.
3480+ let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
3481+ assert_eq ! ( events. len( ) , 2 ) ;
3482+ }
0 commit comments