@@ -18,13 +18,15 @@ use bitcoin::blockdata::script::Script;
1818
1919use bitcoin:: hash_types:: { Txid , BlockHash } ;
2020
21+ #[ cfg( anchors) ]
22+ use bitcoin:: secp256k1:: PublicKey ;
2123use bitcoin:: secp256k1:: { Secp256k1 , ecdsa:: Signature } ;
2224use bitcoin:: secp256k1;
2325
2426use crate :: ln:: msgs:: DecodeError ;
2527use crate :: ln:: PaymentPreimage ;
2628#[ cfg( anchors) ]
27- use crate :: ln:: chan_utils;
29+ use crate :: ln:: chan_utils:: { self , HTLCOutputInCommitment } ;
2830use crate :: ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
2931#[ cfg( anchors) ]
3032use crate :: chain:: chaininterface:: ConfirmationTarget ;
@@ -174,6 +176,17 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
174176 }
175177}
176178
179+ #[ cfg( anchors) ]
180+ /// The claim commonly referred to as the pre-signed second-stage HTLC transaction.
181+ pub ( crate ) struct ExternalHTLCClaim {
182+ pub ( crate ) per_commitment_number : u64 ,
183+ pub ( crate ) htlc : HTLCOutputInCommitment ,
184+ pub ( crate ) preimage : Option < PaymentPreimage > ,
185+ pub ( crate ) counterparty_base_htlc_key : PublicKey ,
186+ pub ( crate ) counterparty_base_revocation_key : PublicKey ,
187+ pub ( crate ) counterparty_sig : Signature ,
188+ }
189+
177190// Represents the different types of claims for which events are yielded externally to satisfy said
178191// claims.
179192#[ cfg( anchors) ]
@@ -185,6 +198,11 @@ pub(crate) enum ClaimEvent {
185198 commitment_tx : Transaction ,
186199 anchor_output_idx : u32 ,
187200 } ,
201+ BumpHTLC {
202+ target_feerate_sat_per_1000_weight : u32 ,
203+ tx_template : Transaction ,
204+ htlcs : Vec < ExternalHTLCClaim > ,
205+ } ,
188206}
189207
190208/// Represents the different ways an output can be claimed (i.e., spent to an address under our
@@ -476,15 +494,34 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
476494 // didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
477495 let new_timer = Some ( cached_request. get_height_timer ( cur_height) ) ;
478496 if cached_request. is_malleable ( ) {
497+ #[ cfg( anchors) ]
498+ { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
499+ if cached_request. requires_external_funding ( ) {
500+ let target_feerate_sat_per_1000_weight = cached_request
501+ . compute_package_feerate ( fee_estimator, ConfirmationTarget :: HighPriority ) ;
502+ let ( tx_template, htlcs) = cached_request. construct_malleable_package_with_external_funding ( self ) ;
503+ return Some ( (
504+ new_timer,
505+ target_feerate_sat_per_1000_weight as u64 ,
506+ OnchainClaim :: Event ( ClaimEvent :: BumpHTLC {
507+ target_feerate_sat_per_1000_weight,
508+ tx_template,
509+ htlcs,
510+ } ) ,
511+ ) ) ;
512+ }
513+ }
514+
479515 let predicted_weight = cached_request. package_weight ( & self . destination_script ) ;
480- if let Some ( ( output_value, new_feerate) ) =
481- cached_request. compute_package_output ( predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger) {
516+ if let Some ( ( output_value, new_feerate) ) = cached_request. compute_package_output (
517+ predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger,
518+ ) {
482519 assert ! ( new_feerate != 0 ) ;
483520
484521 let transaction = cached_request. finalize_malleable_package ( self , output_value, self . destination_script . clone ( ) , logger) . unwrap ( ) ;
485522 log_trace ! ( logger, "...with timer {} and feerate {}" , new_timer. unwrap( ) , new_feerate) ;
486523 assert ! ( predicted_weight >= transaction. weight( ) ) ;
487- return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
524+ return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) ) ;
488525 }
489526 } else {
490527 // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
@@ -540,7 +577,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
540577 debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
541578 None
542579 } ,
543- } ) ;
580+ } )
544581 }
545582 None
546583 }
@@ -630,6 +667,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
630667 log_info ! ( logger, "Yielding onchain event to spend inputs {:?}" , req. outpoints( ) ) ;
631668 let txid = match claim_event {
632669 ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
670+ ClaimEvent :: BumpHTLC { ref tx_template, .. } => tx_template. txid ( ) ,
633671 } ;
634672 self . pending_claim_events . insert ( txid, claim_event) ;
635673 txid
@@ -673,14 +711,33 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
673711 // outpoints to know if transaction is the original claim or a bumped one issued
674712 // by us.
675713 let mut set_equality = true ;
676- if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
677- set_equality = false ;
714+ if !request. requires_external_funding ( ) ||
715+ ( request. requires_external_funding ( ) && !request. is_malleable ( ) )
716+ {
717+ // If the claim does not require external funds to be allocated through
718+ // additional inputs we can simply check the inputs in order as they
719+ // cannot change under us.
720+ if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
721+ set_equality = false ;
722+ } else {
723+ for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
724+ if * * claim_inp != tx_inp. previous_output {
725+ set_equality = false ;
726+ }
727+ }
728+ }
678729 } else {
679- for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
680- if * * claim_inp != tx_inp. previous_output {
681- set_equality = false ;
730+ // Otherwise, we'll do a linear search for each input (we don't expect
731+ // large input sets to exist) to ensure the request's input set is fully
732+ // spent to be resilient against the external claim reordering inputs.
733+ let mut spends_all_inputs = true ;
734+ for request_input in request. outpoints ( ) {
735+ if tx. input . iter ( ) . find ( |input| input. previous_output == * request_input) . is_none ( ) {
736+ spends_all_inputs = false ;
737+ break ;
682738 }
683739 }
740+ set_equality = spends_all_inputs;
684741 }
685742
686743 macro_rules! clean_claim_request_after_safety_delay {
@@ -985,6 +1042,40 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
9851042 htlc_tx
9861043 }
9871044
1045+ #[ cfg( anchors) ]
1046+ pub ( crate ) fn unsigned_htlc_tx (
1047+ & mut self , outp : & :: bitcoin:: OutPoint , preimage : & Option < PaymentPreimage >
1048+ ) -> Option < ( Transaction , ExternalHTLCClaim ) > {
1049+ let find_htlc = |holder_commitment : & HolderCommitmentTransaction | -> Option < ( Transaction , ExternalHTLCClaim ) > {
1050+ let trusted_tx = holder_commitment. trust ( ) ;
1051+ if outp. txid != trusted_tx. txid ( ) {
1052+ return None ;
1053+ }
1054+ trusted_tx. htlcs ( ) . iter ( ) . enumerate ( )
1055+ . find ( |( _, htlc) | if let Some ( output_index) = htlc. transaction_output_index {
1056+ output_index == outp. vout
1057+ } else {
1058+ false
1059+ } )
1060+ . map ( |( htlc_idx, _) | {
1061+ let counterparty_htlc_sig = holder_commitment. counterparty_htlc_sigs [ htlc_idx] ;
1062+ let channel_params = self . channel_transaction_parameters . as_holder_broadcastable ( ) ;
1063+ let ( htlc_tx, htlc) = trusted_tx. unsigned_htlc_tx ( & channel_params, htlc_idx, preimage) ;
1064+ ( htlc_tx, ExternalHTLCClaim {
1065+ per_commitment_number : trusted_tx. commitment_number ( ) ,
1066+ htlc,
1067+ preimage : * preimage,
1068+ counterparty_base_htlc_key : channel_params. countersignatory_pubkeys ( ) . htlc_basepoint ,
1069+ counterparty_base_revocation_key : channel_params. countersignatory_pubkeys ( ) . revocation_basepoint ,
1070+ counterparty_sig : counterparty_htlc_sig,
1071+ } )
1072+ } )
1073+ } ;
1074+ // Check if the HTLC spends from the current holder commitment or the previous one otherwise.
1075+ find_htlc ( & self . holder_commitment )
1076+ . or ( self . prev_holder_commitment . as_ref ( ) . map ( |c| find_htlc ( c) ) . flatten ( ) )
1077+ }
1078+
9881079 pub ( crate ) fn opt_anchors ( & self ) -> bool {
9891080 self . channel_transaction_parameters . opt_anchors . is_some ( )
9901081 }
0 commit comments