@@ -25,7 +25,7 @@ use crate::chain::keysinterface::BaseSign;
2525use crate :: ln:: msgs:: DecodeError ;
2626use crate :: ln:: PaymentPreimage ;
2727#[ cfg( anchors) ]
28- use crate :: ln:: chan_utils;
28+ use crate :: ln:: chan_utils:: { self , HTLCOutputInCommitment } ;
2929use crate :: ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
3030#[ cfg( anchors) ]
3131use crate :: chain:: chaininterface:: ConfirmationTarget ;
@@ -174,6 +174,16 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
174174 }
175175}
176176
177+ #[ cfg( anchors) ]
178+ /// The claim commonly referred to as the pre-signed second-stage HTLC transaction.
179+ pub ( crate ) struct ExternalHTLCClaim {
180+ pub ( crate ) commitment_txid : Txid ,
181+ pub ( crate ) per_commitment_number : u64 ,
182+ pub ( crate ) htlc : HTLCOutputInCommitment ,
183+ pub ( crate ) preimage : Option < PaymentPreimage > ,
184+ pub ( crate ) counterparty_sig : Signature ,
185+ }
186+
177187// Represents the different types of claims for which events are yielded externally to satisfy said
178188// claims.
179189#[ cfg( anchors) ]
@@ -185,6 +195,12 @@ pub(crate) enum ClaimEvent {
185195 commitment_tx : Transaction ,
186196 anchor_output_idx : u32 ,
187197 } ,
198+ /// Event yielded to signal that the commitment transaction has confirmed and its HTLCs must be
199+ /// resolved by broadcasting a transaction with sufficient fee to claim them.
200+ BumpHTLC {
201+ target_feerate_sat_per_1000_weight : u32 ,
202+ htlcs : Vec < ExternalHTLCClaim > ,
203+ } ,
188204}
189205
190206/// Represents the different ways an output can be claimed (i.e., spent to an address under our
@@ -488,15 +504,36 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
488504 // didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
489505 let new_timer = Some ( cached_request. get_height_timer ( cur_height) ) ;
490506 if cached_request. is_malleable ( ) {
507+ #[ cfg( anchors) ]
508+ { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
509+ if cached_request. requires_external_funding ( ) {
510+ let target_feerate_sat_per_1000_weight = cached_request
511+ . compute_package_feerate ( fee_estimator, ConfirmationTarget :: HighPriority ) ;
512+ if let Some ( htlcs) = cached_request. construct_malleable_package_with_external_funding ( self ) {
513+ return Some ( (
514+ new_timer,
515+ target_feerate_sat_per_1000_weight as u64 ,
516+ OnchainClaim :: Event ( ClaimEvent :: BumpHTLC {
517+ target_feerate_sat_per_1000_weight,
518+ htlcs,
519+ } ) ,
520+ ) ) ;
521+ } else {
522+ return None ;
523+ }
524+ }
525+ }
526+
491527 let predicted_weight = cached_request. package_weight ( & self . destination_script ) ;
492- if let Some ( ( output_value, new_feerate) ) =
493- cached_request. compute_package_output ( predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger) {
528+ if let Some ( ( output_value, new_feerate) ) = cached_request. compute_package_output (
529+ predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger,
530+ ) {
494531 assert ! ( new_feerate != 0 ) ;
495532
496533 let transaction = cached_request. finalize_malleable_package ( self , output_value, self . destination_script . clone ( ) , logger) . unwrap ( ) ;
497534 log_trace ! ( logger, "...with timer {} and feerate {}" , new_timer. unwrap( ) , new_feerate) ;
498535 assert ! ( predicted_weight >= transaction. weight( ) ) ;
499- return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
536+ return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) ) ;
500537 }
501538 } else {
502539 // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
@@ -552,7 +589,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
552589 debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
553590 None
554591 } ,
555- } ) ;
592+ } )
556593 }
557594 None
558595 }
@@ -640,10 +677,20 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
640677 #[ cfg( anchors) ]
641678 OnchainClaim :: Event ( claim_event) => {
642679 log_info ! ( logger, "Yielding onchain event to spend inputs {:?}" , req. outpoints( ) ) ;
643- let txid = match claim_event {
644- ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
680+ let package_id = match claim_event {
681+ ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) . into_inner ( ) ,
682+ ClaimEvent :: BumpHTLC { ref htlcs, .. } => {
683+ // Use the same construction as a lightning channel id to generate
684+ // the package id for this request based on the first HTLC. It
685+ // doesn't matter what we use as long as it's unique per request.
686+ let mut package_id = [ 0 ; 32 ] ;
687+ package_id[ ..] . copy_from_slice ( & htlcs[ 0 ] . commitment_txid [ ..] ) ;
688+ let htlc_output_index = htlcs[ 0 ] . htlc . transaction_output_index . unwrap ( ) ;
689+ package_id[ 30 ] ^= ( ( htlc_output_index >> 8 ) & 0xff ) as u8 ;
690+ package_id[ 31 ] ^= ( ( htlc_output_index >> 0 ) & 0xff ) as u8 ;
691+ package_id
692+ } ,
645693 } ;
646- let package_id = txid. into_inner ( ) ;
647694 self . pending_claim_events . insert ( package_id, claim_event) ;
648695 package_id
649696 } ,
@@ -686,14 +733,31 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
686733 // outpoints to know if transaction is the original claim or a bumped one issued
687734 // by us.
688735 let mut set_equality = true ;
689- if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
690- set_equality = false ;
736+ if !request. requires_external_funding ( ) || !request. is_malleable ( ) {
737+ // If the claim does not require external funds to be allocated through
738+ // additional inputs we can simply check the inputs in order as they
739+ // cannot change under us.
740+ if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
741+ set_equality = false ;
742+ } else {
743+ for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
744+ if * * claim_inp != tx_inp. previous_output {
745+ set_equality = false ;
746+ }
747+ }
748+ }
691749 } else {
692- for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
693- if * * claim_inp != tx_inp. previous_output {
694- set_equality = false ;
750+ // Otherwise, we'll do a linear search for each input (we don't expect
751+ // large input sets to exist) to ensure the request's input set is fully
752+ // spent to be resilient against the external claim reordering inputs.
753+ let mut spends_all_inputs = true ;
754+ for request_input in request. outpoints ( ) {
755+ if tx. input . iter ( ) . find ( |input| input. previous_output == * request_input) . is_none ( ) {
756+ spends_all_inputs = false ;
757+ break ;
695758 }
696759 }
760+ set_equality = spends_all_inputs;
697761 }
698762
699763 macro_rules! clean_claim_request_after_safety_delay {
@@ -999,6 +1063,37 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
9991063 htlc_tx
10001064 }
10011065
1066+ #[ cfg( anchors) ]
1067+ pub ( crate ) fn generate_external_htlc_claim (
1068+ & mut self , outp : & :: bitcoin:: OutPoint , preimage : & Option < PaymentPreimage >
1069+ ) -> Option < ExternalHTLCClaim > {
1070+ let find_htlc = |holder_commitment : & HolderCommitmentTransaction | -> Option < ExternalHTLCClaim > {
1071+ let trusted_tx = holder_commitment. trust ( ) ;
1072+ if outp. txid != trusted_tx. txid ( ) {
1073+ return None ;
1074+ }
1075+ trusted_tx. htlcs ( ) . iter ( ) . enumerate ( )
1076+ . find ( |( _, htlc) | if let Some ( output_index) = htlc. transaction_output_index {
1077+ output_index == outp. vout
1078+ } else {
1079+ false
1080+ } )
1081+ . map ( |( htlc_idx, htlc) | {
1082+ let counterparty_htlc_sig = holder_commitment. counterparty_htlc_sigs [ htlc_idx] ;
1083+ ExternalHTLCClaim {
1084+ commitment_txid : trusted_tx. txid ( ) ,
1085+ per_commitment_number : trusted_tx. commitment_number ( ) ,
1086+ htlc : htlc. clone ( ) ,
1087+ preimage : * preimage,
1088+ counterparty_sig : counterparty_htlc_sig,
1089+ }
1090+ } )
1091+ } ;
1092+ // Check if the HTLC spends from the current holder commitment or the previous one otherwise.
1093+ find_htlc ( & self . holder_commitment )
1094+ . or_else ( || self . prev_holder_commitment . as_ref ( ) . map ( |c| find_htlc ( c) ) . flatten ( ) )
1095+ }
1096+
10021097 pub ( crate ) fn opt_anchors ( & self ) -> bool {
10031098 self . channel_transaction_parameters . opt_anchors . is_some ( )
10041099 }
0 commit comments