@@ -248,8 +248,19 @@ pub struct OnchainTxHandler<ChannelSigner: WriteableEcdsaChannelSigner> {
248
248
pub ( crate ) pending_claim_requests : HashMap < PackageID , PackageTemplate > ,
249
249
#[ cfg( not( test) ) ]
250
250
pending_claim_requests : HashMap < PackageID , PackageTemplate > ,
251
+
252
+ // Used to track external events that need to be forwarded to the `ChainMonitor`. This `Vec`
253
+ // essentially acts as an insertion-ordered `HashMap` – there should only ever be one occurrence
254
+ // of a `PackageID`, which tracks its latest `ClaimEvent`, i.e., if a pending claim exists, and
255
+ // a new block has been connected, resulting in a new claim, the previous will be replaced with
256
+ // the new.
257
+ //
258
+ // These external events may be generated in the following cases:
259
+ // - A channel has been force closed by broadcasting the holder's latest commitment transaction
260
+ // - A block being connected/disconnected
261
+ // - Learning the preimage for an HTLC we can claim onchain
251
262
#[ cfg( anchors) ]
252
- pending_claim_events : HashMap < PackageID , ClaimEvent > ,
263
+ pending_claim_events : Vec < ( PackageID , ClaimEvent ) > ,
253
264
254
265
// Used to link outpoints claimed in a connected block to a pending claim request. The keys
255
266
// represent the outpoints that our `ChannelMonitor` has detected we have keys/scripts to
@@ -426,7 +437,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
426
437
pending_claim_requests,
427
438
onchain_events_awaiting_threshold_conf,
428
439
#[ cfg( anchors) ]
429
- pending_claim_events : HashMap :: new ( ) ,
440
+ pending_claim_events : Vec :: new ( ) ,
430
441
secp_ctx,
431
442
} )
432
443
}
@@ -447,8 +458,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
447
458
locktimed_packages : BTreeMap :: new ( ) ,
448
459
onchain_events_awaiting_threshold_conf : Vec :: new ( ) ,
449
460
#[ cfg( anchors) ]
450
- pending_claim_events : HashMap :: new ( ) ,
451
-
461
+ pending_claim_events : Vec :: new ( ) ,
452
462
secp_ctx,
453
463
}
454
464
}
@@ -463,9 +473,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
463
473
464
474
#[ cfg( anchors) ]
465
475
pub ( crate ) fn get_and_clear_pending_claim_events ( & mut self ) -> Vec < ClaimEvent > {
466
- let mut ret = HashMap :: new ( ) ;
467
- swap ( & mut ret , & mut self . pending_claim_events ) ;
468
- ret . into_iter ( ) . map ( |( _, event) | event) . collect :: < Vec < _ > > ( )
476
+ let mut events = Vec :: new ( ) ;
477
+ swap ( & mut events , & mut self . pending_claim_events ) ;
478
+ events . into_iter ( ) . map ( |( _, event) | event) . collect ( )
469
479
}
470
480
471
481
/// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
@@ -709,7 +719,8 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
709
719
package_id
710
720
} ,
711
721
} ;
712
- self . pending_claim_events . insert ( package_id, claim_event) ;
722
+ debug_assert_eq ! ( self . pending_claim_events. iter( ) . filter( |entry| entry. 0 == package_id) . count( ) , 0 ) ;
723
+ self . pending_claim_events . push ( ( package_id, claim_event) ) ;
713
724
package_id
714
725
} ,
715
726
} ;
@@ -794,6 +805,14 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
794
805
//TODO: recompute soonest_timelock to avoid wasting a bit on fees
795
806
if at_least_one_drop {
796
807
bump_candidates. insert ( * package_id, request. clone ( ) ) ;
808
+ // If we have any pending claim events for the request being updated
809
+ // that have yet to be consumed, we'll remove them since they will
810
+ // end up producing an invalid transaction by double spending
811
+ // input(s) that already have a confirmed spend. If such spend is
812
+ // reorged out of the chain, then we'll attempt to re-spend the
813
+ // inputs once we see it.
814
+ #[ cfg( anchors) ]
815
+ self . pending_claim_events . retain ( |entry| entry. 0 != * package_id) ;
797
816
}
798
817
}
799
818
break ; //No need to iterate further, either tx is our or their
@@ -829,9 +848,9 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
829
848
log_debug ! ( logger, "Removing claim tracking for {} due to maturation of claim package {}." ,
830
849
outpoint, log_bytes!( package_id) ) ;
831
850
self . claimable_outpoints . remove ( outpoint) ;
832
- #[ cfg( anchors) ]
833
- self . pending_claim_events . remove ( & package_id) ;
834
851
}
852
+ #[ cfg( anchors) ]
853
+ self . pending_claim_events . retain ( |( id, _) | * id != package_id) ;
835
854
}
836
855
} ,
837
856
OnchainEvent :: ContentiousOutpoint { package } => {
@@ -866,7 +885,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
866
885
#[ cfg( anchors) ]
867
886
OnchainClaim :: Event ( claim_event) => {
868
887
log_info ! ( logger, "Yielding RBF-bumped onchain event to spend inputs {:?}" , request. outpoints( ) ) ;
869
- self . pending_claim_events . insert ( * package_id, claim_event) ;
888
+ if let Some ( ( existing_claim_idx, _) ) = self . pending_claim_events . iter ( ) . enumerate ( )
889
+ . find ( |( _, entry) | entry. 0 == * package_id)
890
+ {
891
+ self . pending_claim_events . remove ( existing_claim_idx) ;
892
+ }
893
+ self . pending_claim_events . push ( ( * package_id, claim_event) ) ;
870
894
} ,
871
895
}
872
896
if let Some ( request) = self . pending_claim_requests . get_mut ( package_id) {
@@ -930,7 +954,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
930
954
self . onchain_events_awaiting_threshold_conf . push ( entry) ;
931
955
}
932
956
}
933
- for ( ( _package_id, _) , request) in bump_candidates. iter_mut ( ) {
957
+ for ( ( _package_id, _) , ref mut request) in bump_candidates. iter_mut ( ) {
934
958
if let Some ( ( new_timer, new_feerate, bump_claim) ) = self . generate_claim ( height, & request, fee_estimator, & & * logger) {
935
959
request. set_timer ( new_timer) ;
936
960
request. set_feerate ( new_feerate) ;
@@ -942,7 +966,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
942
966
#[ cfg( anchors) ]
943
967
OnchainClaim :: Event ( claim_event) => {
944
968
log_info ! ( logger, "Yielding onchain event after reorg to spend inputs {:?}" , request. outpoints( ) ) ;
945
- self . pending_claim_events . insert ( _package_id, claim_event) ;
969
+ if let Some ( ( existing_claim_idx, _) ) = self . pending_claim_events . iter ( ) . enumerate ( )
970
+ . find ( |( _, entry) | entry. 0 == * _package_id)
971
+ {
972
+ self . pending_claim_events . remove ( existing_claim_idx) ;
973
+ }
974
+ self . pending_claim_events . push ( ( * _package_id, claim_event) ) ;
946
975
} ,
947
976
}
948
977
}
0 commit comments