@@ -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;
@@ -36,6 +37,7 @@ use io;
3637use prelude:: * ;
3738use alloc:: collections:: BTreeMap ;
3839use core:: cmp;
40+ use core:: convert:: TryInto ;
3941use core:: ops:: Deref ;
4042use core:: mem:: replace;
4143use bitcoin:: hashes:: Hash ;
@@ -162,8 +164,17 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
162164 }
163165}
164166
167+ pub ( crate ) enum ClaimEvent {
168+ BumpCommitment {
169+ target_feerate_sat_per_1000_weight : u32 ,
170+ commitment_tx : Transaction ,
171+ anchor_output_idx : u32 ,
172+ } ,
173+ }
174+
165175pub ( crate ) enum OnchainClaim {
166176 Tx ( Transaction ) ,
177+ Event ( ClaimEvent ) ,
167178}
168179
169180/// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
@@ -196,6 +207,7 @@ pub struct OnchainTxHandler<ChannelSigner: Sign> {
196207 pub ( crate ) pending_claim_requests : HashMap < Txid , PackageTemplate > ,
197208 #[ cfg( not( test) ) ]
198209 pending_claim_requests : HashMap < Txid , PackageTemplate > ,
210+ pending_claim_events : HashMap < Txid , ClaimEvent > ,
199211
200212 // Used to link outpoints claimed in a connected block to a pending claim request.
201213 // Key is outpoint than monitor parsing has detected we have keys/scripts to claim
@@ -345,6 +357,7 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
345357 locktimed_packages,
346358 pending_claim_requests,
347359 onchain_events_awaiting_threshold_conf,
360+ pending_claim_events : HashMap :: new ( ) ,
348361 secp_ctx,
349362 } )
350363 }
@@ -364,6 +377,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
364377 claimable_outpoints : HashMap :: new ( ) ,
365378 locktimed_packages : BTreeMap :: new ( ) ,
366379 onchain_events_awaiting_threshold_conf : Vec :: new ( ) ,
380+ pending_claim_events : HashMap :: new ( ) ,
367381
368382 secp_ctx,
369383 }
@@ -377,10 +391,14 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
377391 self . holder_commitment . to_broadcaster_value_sat ( )
378392 }
379393
380- /// 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
381- /// (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.
382- /// Panics if there are signing errors, because signing operations in reaction to on-chain events
383- /// are not expected to fail, and if they do, we may lose funds.
394+ /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
395+ /// onchain) lays on the assumption of claim transactions getting confirmed before timelock
396+ /// expiration (CSV or CLTV following cases). In case of high-fee spikes, claim tx may get stuck
397+ /// in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or
398+ /// Child-Pay-For-Parent.
399+ ///
400+ /// Panics if there are signing errors, because signing operations in reaction to on-chain
401+ /// events are not expected to fail, and if they do, we may lose funds.
384402 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 ) >
385403 where F :: Target : FeeEstimator ,
386404 L :: Target : Logger ,
@@ -402,12 +420,57 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
402420 return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
403421 }
404422 } else {
405- // Note: Currently, amounts of holder outputs spending witnesses aren't used
406- // as we can't malleate spending package to increase their feerate. This
407- // should change with the remaining anchor output patchset.
408- if let Some ( transaction) = cached_request. finalize_untractable_package ( self , logger) {
409- return Some ( ( None , 0 , OnchainClaim :: Tx ( transaction) ) ) ;
423+ // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
424+ // packages may support fee bumping through Child-Pays-For-Parent, indicated by those
425+ // which require external funding.
426+ let inputs = cached_request. inputs ( ) ;
427+ debug_assert_eq ! ( inputs. len( ) , 1 ) ;
428+ let tx = match cached_request. finalize_untractable_package ( self , logger) {
429+ Some ( tx) => tx,
430+ None => return None ,
431+ } ;
432+ if !cached_request. requires_external_funding ( ) {
433+ return Some ( ( None , 0 , OnchainClaim :: Tx ( tx) ) ) ;
410434 }
435+ return inputs. iter ( ) . find_map ( |input| match input {
436+ // Commitment inputs with anchors support are the only untractable inputs supported
437+ // thus far that require external funding.
438+ PackageSolvingData :: HolderFundingOutput ( ..) => {
439+ // We'll locate an anchor output we can spend within the commitment transaction.
440+ let funding_pubkey = & self . channel_transaction_parameters . holder_pubkeys . funding_pubkey ;
441+ match chan_utils:: get_anchor_output ( & tx, funding_pubkey) {
442+ // An anchor output was found, so we should yield a funding event externally.
443+ Some ( ( idx, _) ) => {
444+ let target_feerate_sat_per_1000_weight: u32 = match cached_request
445+ . compute_package_child_feerate ( & tx, fee_estimator, ConfirmationTarget :: HighPriority )
446+ . map ( |f| f. try_into ( ) . ok ( ) )
447+ . flatten ( )
448+ {
449+ Some ( f) => f,
450+ _ => return None ,
451+ } ;
452+ Some ( (
453+ new_timer,
454+ target_feerate_sat_per_1000_weight as u64 ,
455+ OnchainClaim :: Event ( ClaimEvent :: BumpCommitment {
456+ target_feerate_sat_per_1000_weight,
457+ commitment_tx : tx. clone ( ) ,
458+ anchor_output_idx : idx,
459+ } ) ,
460+ ) )
461+ } ,
462+ // An anchor output was not found. There's nothing we can do other than
463+ // attempt to broadcast the transaction with its current fee rate and hope
464+ // it confirms. This is essentially the same behavior as a commitment
465+ // transaction without anchor outputs.
466+ None => Some ( ( None , 0 , OnchainClaim :: Tx ( tx. clone ( ) ) ) ) ,
467+ }
468+ } ,
469+ _ => {
470+ debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
471+ None
472+ } ,
473+ } ) ;
411474 }
412475 None
413476 }
@@ -481,18 +544,25 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
481544 if let Some ( ( new_timer, new_feerate, claim) ) = self . generate_claim ( cur_height, & req, & * fee_estimator, & * logger) {
482545 req. set_timer ( new_timer) ;
483546 req. set_feerate ( new_feerate) ;
484- match claim {
547+ let txid = match claim {
485548 OnchainClaim :: Tx ( tx) => {
486- let txid = tx. txid ( ) ;
487- for k in req. outpoints ( ) {
488- log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
489- self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
490- }
491- self . pending_claim_requests . insert ( txid, req) ;
492549 log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( tx) ) ;
493550 broadcaster. broadcast_transaction ( & tx) ;
551+ tx. txid ( )
552+ } ,
553+ OnchainClaim :: Event ( claim_event) => {
554+ let txid = match claim_event {
555+ ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
556+ } ;
557+ self . pending_claim_events . insert ( txid, claim_event) ;
558+ txid
494559 } ,
560+ } ;
561+ for k in req. outpoints ( ) {
562+ log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
563+ self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
495564 }
565+ self . pending_claim_requests . insert ( txid, req) ;
496566 }
497567 }
498568
@@ -584,6 +654,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
584654 for outpoint in request. outpoints ( ) {
585655 log_debug ! ( logger, "Removing claim tracking for {} due to maturation of claim tx {}." , outpoint, claim_request) ;
586656 self . claimable_outpoints . remove ( & outpoint) ;
657+ self . pending_claim_events . remove ( & claim_request) ;
587658 }
588659 }
589660 } ,
@@ -616,6 +687,9 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
616687 log_info ! ( logger, "Broadcasting RBF-bumped onchain {}" , log_tx!( bump_tx) ) ;
617688 broadcaster. broadcast_transaction ( & bump_tx) ;
618689 } ,
690+ OnchainClaim :: Event ( claim_event) => {
691+ self . pending_claim_events . insert ( * first_claim_txid, claim_event) ;
692+ } ,
619693 }
620694 if let Some ( request) = self . pending_claim_requests . get_mut ( first_claim_txid) {
621695 request. set_timer ( new_timer) ;
@@ -678,7 +752,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
678752 self . onchain_events_awaiting_threshold_conf . push ( entry) ;
679753 }
680754 }
681- for ( _ , request) in bump_candidates. iter_mut ( ) {
755+ for ( first_claim_txid_height , request) in bump_candidates. iter_mut ( ) {
682756 if let Some ( ( new_timer, new_feerate, bump_claim) ) = self . generate_claim ( height, & request, fee_estimator, & & * logger) {
683757 request. set_timer ( new_timer) ;
684758 request. set_feerate ( new_feerate) ;
@@ -687,6 +761,9 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
687761 log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( bump_tx) ) ;
688762 broadcaster. broadcast_transaction ( & bump_tx) ;
689763 } ,
764+ OnchainClaim :: Event ( claim_event) => {
765+ self . pending_claim_events . insert ( first_claim_txid_height. 0 , claim_event) ;
766+ } ,
690767 }
691768 }
692769 }
0 commit comments