@@ -23,11 +23,12 @@ use bitcoin::secp256k1;
2323
2424use ln:: msgs:: DecodeError ;
2525use ln:: PaymentPreimage ;
26+ use ln:: chan_utils;
2627use ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
27- use chain:: chaininterface:: { FeeEstimator , BroadcasterInterface , LowerBoundedFeeEstimator } ;
28+ use chain:: chaininterface:: { ConfirmationTarget , FeeEstimator , BroadcasterInterface , LowerBoundedFeeEstimator } ;
2829use chain:: channelmonitor:: { ANTI_REORG_DELAY , CLTV_SHARED_CLAIM_BUFFER } ;
2930use chain:: keysinterface:: { Sign , KeysInterface } ;
30- use chain:: package:: PackageTemplate ;
31+ use chain:: package:: { PackageSolvingData , PackageTemplate } ;
3132use util:: logger:: Logger ;
3233use util:: ser:: { Readable , ReadableArgs , MaybeReadable , Writer , Writeable , VecWriter } ;
3334use util:: byte_utils;
@@ -162,11 +163,27 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
162163 }
163164}
164165
166+ // Represents the different types of claims for which events are yielded externally to satisfy said
167+ // claims.
168+ #[ allow( dead_code) ] // TODO: remove-on-anchors-release
169+ pub ( crate ) enum ClaimEvent {
170+ /// Event yielded to signal that the commitment transaction fee must be bumped to claim any
171+ /// encumbered funds and proceed to HTLC resolution, if any HTLCs exist.
172+ BumpCommitment {
173+ package_target_feerate_sat_per_1000_weight : u32 ,
174+ commitment_tx : Transaction ,
175+ anchor_output_idx : u32 ,
176+ } ,
177+ }
178+
165179/// Represents the different ways an output can be claimed (i.e., spent to an address under our
166180/// control) onchain.
167181pub ( crate ) enum OnchainClaim {
168182 /// A finalized transaction pending confirmation spending the output to claim.
169183 Tx ( Transaction ) ,
184+ /// An event yielded externally to signal additional inputs must be added to a transaction
185+ /// pending confirmation spending the output to claim.
186+ Event ( ClaimEvent ) ,
170187}
171188
172189/// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
@@ -199,6 +216,7 @@ pub struct OnchainTxHandler<ChannelSigner: Sign> {
199216 pub ( crate ) pending_claim_requests : HashMap < Txid , PackageTemplate > ,
200217 #[ cfg( not( test) ) ]
201218 pending_claim_requests : HashMap < Txid , PackageTemplate > ,
219+ pending_claim_events : HashMap < Txid , ClaimEvent > ,
202220
203221 // Used to link outpoints claimed in a connected block to a pending claim request.
204222 // Key is outpoint than monitor parsing has detected we have keys/scripts to claim
@@ -348,6 +366,7 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
348366 locktimed_packages,
349367 pending_claim_requests,
350368 onchain_events_awaiting_threshold_conf,
369+ pending_claim_events : HashMap :: new ( ) ,
351370 secp_ctx,
352371 } )
353372 }
@@ -367,6 +386,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
367386 claimable_outpoints : HashMap :: new ( ) ,
368387 locktimed_packages : BTreeMap :: new ( ) ,
369388 onchain_events_awaiting_threshold_conf : Vec :: new ( ) ,
389+ pending_claim_events : HashMap :: new ( ) ,
370390
371391 secp_ctx,
372392 }
@@ -380,10 +400,14 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
380400 self . holder_commitment . to_broadcaster_value_sat ( )
381401 }
382402
383- /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize coutnerparty onchain) lays on the assumption of claim transactions getting confirmed before timelock expiration
384- /// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent.
385- /// Panics if there are signing errors, because signing operations in reaction to on-chain events
386- /// are not expected to fail, and if they do, we may lose funds.
403+ /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
404+ /// onchain) lays on the assumption of claim transactions getting confirmed before timelock
405+ /// expiration (CSV or CLTV following cases). In case of high-fee spikes, claim tx may get stuck
406+ /// in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or
407+ /// Child-Pay-For-Parent.
408+ ///
409+ /// Panics if there are signing errors, because signing operations in reaction to on-chain
410+ /// events are not expected to fail, and if they do, we may lose funds.
387411 fn generate_claim < F : Deref , L : Deref > ( & mut self , cur_height : u32 , cached_request : & PackageTemplate , fee_estimator : & LowerBoundedFeeEstimator < F > , logger : & L ) -> Option < ( Option < u32 > , u64 , OnchainClaim ) >
388412 where F :: Target : FeeEstimator ,
389413 L :: Target : Logger ,
@@ -405,12 +429,60 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
405429 return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
406430 }
407431 } else {
408- // Note: Currently, amounts of holder outputs spending witnesses aren't used
409- // as we can't malleate spending package to increase their feerate. This
410- // should change with the remaining anchor output patchset.
411- if let Some ( transaction) = cached_request. finalize_untractable_package ( self , logger) {
412- return Some ( ( None , 0 , OnchainClaim :: Tx ( transaction) ) ) ;
432+ // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
433+ // packages may support fee bumping through Child-Pays-For-Parent, indicated by those
434+ // which require external funding.
435+ let inputs = cached_request. inputs ( ) ;
436+ debug_assert_eq ! ( inputs. len( ) , 1 ) ;
437+ let tx = match cached_request. finalize_untractable_package ( self , logger) {
438+ Some ( tx) => tx,
439+ None => return None ,
440+ } ;
441+ if !cached_request. requires_external_funding ( ) {
442+ return Some ( ( None , 0 , OnchainClaim :: Tx ( tx) ) ) ;
413443 }
444+ return inputs. iter ( ) . find_map ( |input| match input {
445+ // Commitment inputs with anchors support are the only untractable inputs supported
446+ // thus far that require external funding.
447+ PackageSolvingData :: HolderFundingOutput ( ..) => {
448+ debug_assert_eq ! ( tx. txid( ) , self . holder_commitment. trust( ) . txid( ) ,
449+ "Holder commitment transaction mismatch" ) ;
450+ // We'll locate an anchor output we can spend within the commitment transaction.
451+ let funding_pubkey = & self . channel_transaction_parameters . holder_pubkeys . funding_pubkey ;
452+ match chan_utils:: get_anchor_output ( & tx, funding_pubkey) {
453+ // An anchor output was found, so we should yield a funding event externally.
454+ Some ( ( idx, _) ) => {
455+ // Our target feerate will depend on whether we have any HTLCs present
456+ // within our commitment.
457+ let conf_target = if self . holder_commitment . trust ( ) . htlcs ( ) . is_empty ( ) {
458+ ConfirmationTarget :: Background
459+ } else {
460+ ConfirmationTarget :: HighPriority
461+ } ;
462+ let package_target_feerate_sat_per_1000_weight = cached_request
463+ . compute_package_feerate ( fee_estimator, conf_target) ;
464+ Some ( (
465+ new_timer,
466+ package_target_feerate_sat_per_1000_weight as u64 ,
467+ OnchainClaim :: Event ( ClaimEvent :: BumpCommitment {
468+ package_target_feerate_sat_per_1000_weight,
469+ commitment_tx : tx. clone ( ) ,
470+ anchor_output_idx : idx,
471+ } ) ,
472+ ) )
473+ } ,
474+ // An anchor output was not found. There's nothing we can do other than
475+ // attempt to broadcast the transaction with its current fee rate and hope
476+ // it confirms. This is essentially the same behavior as a commitment
477+ // transaction without anchor outputs.
478+ None => Some ( ( None , 0 , OnchainClaim :: Tx ( tx. clone ( ) ) ) ) ,
479+ }
480+ } ,
481+ _ => {
482+ debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
483+ None
484+ } ,
485+ } ) ;
414486 }
415487 None
416488 }
@@ -484,18 +556,26 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
484556 if let Some ( ( new_timer, new_feerate, claim) ) = self . generate_claim ( cur_height, & req, & * fee_estimator, & * logger) {
485557 req. set_timer ( new_timer) ;
486558 req. set_feerate ( new_feerate) ;
487- match claim {
559+ let txid = match claim {
488560 OnchainClaim :: Tx ( tx) => {
489- let txid = tx. txid ( ) ;
490- for k in req. outpoints ( ) {
491- log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
492- self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
493- }
494- self . pending_claim_requests . insert ( txid, req) ;
495561 log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( tx) ) ;
496562 broadcaster. broadcast_transaction ( & tx) ;
563+ tx. txid ( )
564+ } ,
565+ OnchainClaim :: Event ( claim_event) => {
566+ log_info ! ( logger, "Yielding onchain event to spend inputs {:?}" , req. outpoints( ) ) ;
567+ let txid = match claim_event {
568+ ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
569+ } ;
570+ self . pending_claim_events . insert ( txid, claim_event) ;
571+ txid
497572 } ,
573+ } ;
574+ for k in req. outpoints ( ) {
575+ log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
576+ self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
498577 }
578+ self . pending_claim_requests . insert ( txid, req) ;
499579 }
500580 }
501581
@@ -587,6 +667,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
587667 for outpoint in request. outpoints ( ) {
588668 log_debug ! ( logger, "Removing claim tracking for {} due to maturation of claim tx {}." , outpoint, claim_request) ;
589669 self . claimable_outpoints . remove ( & outpoint) ;
670+ self . pending_claim_events . remove ( & claim_request) ;
590671 }
591672 }
592673 } ,
@@ -619,6 +700,10 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
619700 log_info ! ( logger, "Broadcasting RBF-bumped onchain {}" , log_tx!( bump_tx) ) ;
620701 broadcaster. broadcast_transaction ( & bump_tx) ;
621702 } ,
703+ OnchainClaim :: Event ( claim_event) => {
704+ log_info ! ( logger, "Yielding RBF-bumped onchain event to spend inputs {:?}" , request. outpoints( ) ) ;
705+ self . pending_claim_events . insert ( * first_claim_txid, claim_event) ;
706+ } ,
622707 }
623708 if let Some ( request) = self . pending_claim_requests . get_mut ( first_claim_txid) {
624709 request. set_timer ( new_timer) ;
@@ -681,7 +766,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
681766 self . onchain_events_awaiting_threshold_conf . push ( entry) ;
682767 }
683768 }
684- for ( _ , request) in bump_candidates. iter_mut ( ) {
769+ for ( first_claim_txid_height , request) in bump_candidates. iter_mut ( ) {
685770 if let Some ( ( new_timer, new_feerate, bump_claim) ) = self . generate_claim ( height, & request, fee_estimator, & & * logger) {
686771 request. set_timer ( new_timer) ;
687772 request. set_feerate ( new_feerate) ;
@@ -690,6 +775,9 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
690775 log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( bump_tx) ) ;
691776 broadcaster. broadcast_transaction ( & bump_tx) ;
692777 } ,
778+ OnchainClaim :: Event ( claim_event) => {
779+ self . pending_claim_events . insert ( first_claim_txid_height. 0 , claim_event) ;
780+ } ,
693781 }
694782 }
695783 }
0 commit comments