@@ -2391,12 +2391,15 @@ fn test_restored_packages_retry() {
23912391fn do_test_duplicate_delayed_holder_htlc_claims_after_claim_funds_replay ( p2a_anchor : bool ) {
23922392 let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
23932393 let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
2394+ let persister;
2395+ let new_chain_monitor;
2396+ let node_deserialized;
23942397 let mut anchors_config = test_default_channel_config ( ) ;
23952398 anchors_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
23962399 anchors_config. channel_handshake_config . negotiate_anchor_zero_fee_commitments = p2a_anchor;
23972400 let node_chanmgrs =
23982401 create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( anchors_config. clone ( ) ) , Some ( anchors_config) ] ) ;
2399- let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
2402+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
24002403
24012404 let coinbase_tx = provide_anchor_reserves ( & nodes) ;
24022405 let ( _, _, chan_id, funding_tx) =
@@ -2475,11 +2478,14 @@ fn do_test_duplicate_delayed_holder_htlc_claims_after_claim_funds_replay(p2a_anc
24752478 // the delayed package's outpoints.
24762479 connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV + 1 ) ;
24772480
2478- let mut htlc_event_sizes = nodes[ 0 ]
2481+ let events = nodes[ 0 ]
24792482 . chain_monitor
24802483 . chain_monitor
24812484 . get_and_clear_pending_events ( )
24822485 . into_iter ( )
2486+ . collect :: < Vec < _ > > ( ) ;
2487+ let mut htlc_event_sizes = events
2488+ . iter ( )
24832489 . filter_map ( |event| {
24842490 if let Event :: BumpTransaction ( BumpTransactionEvent :: HTLCResolution {
24852491 htlc_descriptors, ..
@@ -2493,6 +2499,89 @@ fn do_test_duplicate_delayed_holder_htlc_claims_after_claim_funds_replay(p2a_anc
24932499 . collect :: < Vec < _ > > ( ) ;
24942500 htlc_event_sizes. sort_unstable ( ) ;
24952501 assert_eq ! ( htlc_event_sizes, vec![ 1 , 2 ] ) ;
2502+
2503+ // Drive only the replayed single-HTLC event on-chain. A preimage replay
2504+ // before its CSV-delayed output is final may create a live conflicting
2505+ // claim, so the final replay assertion below waits for the monitor's
2506+ // persisted resolution state instead.
2507+ for event in events {
2508+ if let Event :: BumpTransaction ( event) = event {
2509+ let is_single_htlc = if let BumpTransactionEvent :: HTLCResolution {
2510+ ref htlc_descriptors,
2511+ ..
2512+ } = event
2513+ {
2514+ htlc_descriptors. len ( ) == 1
2515+ } else {
2516+ false
2517+ } ;
2518+ if is_single_htlc {
2519+ nodes[ 0 ] . bump_tx_handler . handle_event ( & event) ;
2520+ break ;
2521+ }
2522+ }
2523+ }
2524+ let mut htlc_txn = nodes[ 0 ] . tx_broadcaster . unique_txn_broadcast ( ) ;
2525+ assert_eq ! ( htlc_txn. len( ) , 1 ) ;
2526+ let htlc_tx = htlc_txn. pop ( ) . unwrap ( ) ;
2527+ mine_transaction ( & nodes[ 0 ] , & htlc_tx) ;
2528+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
2529+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
2530+
2531+ // The spend has passed OnchainTxHandler's anti-reorg cleanup, but its
2532+ // CSV-delayed output is not yet final according to the monitor. Replaying
2533+ // the preimage in this window creates a live conflicting claim, which is
2534+ // kept as retry state in case the spend reorgs out.
2535+ get_monitor ! ( nodes[ 0 ] , chan_id) . provide_payment_preimage_unsafe_legacy (
2536+ & claim_hash,
2537+ & claim_preimage,
2538+ & node_cfgs[ 0 ] . tx_broadcaster ,
2539+ & LowerBoundedFeeEstimator :: new ( node_cfgs[ 0 ] . fee_estimator ) ,
2540+ & nodes[ 0 ] . logger ,
2541+ ) ;
2542+ let live_conflict_events = nodes[ 0 ]
2543+ . chain_monitor
2544+ . chain_monitor
2545+ . get_and_clear_pending_events ( )
2546+ . into_iter ( )
2547+ . collect :: < Vec < _ > > ( ) ;
2548+ let mut live_conflict_htlc_event_sizes = live_conflict_events
2549+ . iter ( )
2550+ . filter_map ( |event| {
2551+ if let Event :: BumpTransaction ( BumpTransactionEvent :: HTLCResolution {
2552+ htlc_descriptors, ..
2553+ } ) = event
2554+ {
2555+ Some ( htlc_descriptors. len ( ) )
2556+ } else {
2557+ None
2558+ }
2559+ } )
2560+ . collect :: < Vec < _ > > ( ) ;
2561+ live_conflict_htlc_event_sizes. sort_unstable ( ) ;
2562+ assert_eq ! ( live_conflict_htlc_event_sizes, vec![ 1 ] ) ;
2563+
2564+ connect_blocks ( & nodes[ 0 ] , BREAKDOWN_TIMEOUT as u32 - ANTI_REORG_DELAY ) ;
2565+ let _ = nodes[ 0 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
2566+
2567+ // Reload before replaying the preimage so the regression covers persisted
2568+ // resolution state, not only in-memory filtering.
2569+ let serialized_channel_manager = nodes[ 0 ] . node . encode ( ) ;
2570+ let serialized_monitor = get_monitor ! ( nodes[ 0 ] , chan_id) . encode ( ) ;
2571+ reload_node ! (
2572+ nodes[ 0 ] , & serialized_channel_manager, & [ & serialized_monitor] , persister,
2573+ new_chain_monitor, node_deserialized
2574+ ) ;
2575+
2576+ // Replaying the preimage update must not regenerate a claim for the HTLC
2577+ // whose commitment output has final persisted resolution state.
2578+ get_monitor ! ( nodes[ 0 ] , chan_id) . provide_payment_preimage_unsafe_legacy (
2579+ & claim_hash, & claim_preimage, & node_cfgs[ 0 ] . tx_broadcaster ,
2580+ & LowerBoundedFeeEstimator :: new ( node_cfgs[ 0 ] . fee_estimator ) , & nodes[ 0 ] . logger ,
2581+ ) ;
2582+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_and_clear_pending_events( ) . is_empty( ) ) ;
2583+ expect_payment_claimed ! ( nodes[ 0 ] , claim_hash, 12_000_000 ) ;
2584+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
24962585}
24972586
24982587#[ test]
0 commit comments