@@ -24,7 +24,7 @@ use bitcoin::secp256k1;
24
24
use crate :: ln:: msgs:: DecodeError ;
25
25
use crate :: ln:: PaymentPreimage ;
26
26
#[ cfg( anchors) ]
27
- use crate :: ln:: chan_utils;
27
+ use crate :: ln:: chan_utils:: { self , HTLCOutputInCommitment } ;
28
28
use crate :: ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
29
29
#[ cfg( anchors) ]
30
30
use crate :: chain:: chaininterface:: ConfirmationTarget ;
@@ -174,6 +174,16 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
174
174
}
175
175
}
176
176
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
+
177
187
// Represents the different types of claims for which events are yielded externally to satisfy said
178
188
// claims.
179
189
#[ cfg( anchors) ]
@@ -185,6 +195,10 @@ pub(crate) enum ClaimEvent {
185
195
commitment_tx : Transaction ,
186
196
anchor_output_idx : u32 ,
187
197
} ,
198
+ BumpHTLC {
199
+ target_feerate_sat_per_1000_weight : u32 ,
200
+ htlcs : Vec < ExternalHTLCClaim > ,
201
+ } ,
188
202
}
189
203
190
204
/// Represents the different ways an output can be claimed (i.e., spent to an address under our
@@ -479,15 +493,33 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
479
493
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
480
494
let new_timer = Some ( cached_request. get_height_timer ( cur_height) ) ;
481
495
if cached_request. is_malleable ( ) {
496
+ #[ cfg( anchors) ]
497
+ { // Attributes are not allowed on if expressions on our current MSRV of 1.41.
498
+ if cached_request. requires_external_funding ( ) {
499
+ let target_feerate_sat_per_1000_weight = cached_request
500
+ . compute_package_feerate ( fee_estimator, ConfirmationTarget :: HighPriority ) ;
501
+ let htlcs = cached_request. construct_malleable_package_with_external_funding ( self ) ;
502
+ return Some ( (
503
+ new_timer,
504
+ target_feerate_sat_per_1000_weight as u64 ,
505
+ OnchainClaim :: Event ( ClaimEvent :: BumpHTLC {
506
+ target_feerate_sat_per_1000_weight,
507
+ htlcs,
508
+ } ) ,
509
+ ) ) ;
510
+ }
511
+ }
512
+
482
513
let predicted_weight = cached_request. package_weight ( & self . destination_script ) ;
483
- if let Some ( ( output_value, new_feerate) ) =
484
- cached_request. compute_package_output ( predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger) {
514
+ if let Some ( ( output_value, new_feerate) ) = cached_request. compute_package_output (
515
+ predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger,
516
+ ) {
485
517
assert ! ( new_feerate != 0 ) ;
486
518
487
519
let transaction = cached_request. finalize_malleable_package ( self , output_value, self . destination_script . clone ( ) , logger) . unwrap ( ) ;
488
520
log_trace ! ( logger, "...with timer {} and feerate {}" , new_timer. unwrap( ) , new_feerate) ;
489
521
assert ! ( predicted_weight >= transaction. weight( ) ) ;
490
- return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
522
+ return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) ) ;
491
523
}
492
524
} else {
493
525
// Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
@@ -543,7 +575,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
543
575
debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
544
576
None
545
577
} ,
546
- } ) ;
578
+ } )
547
579
}
548
580
None
549
581
}
@@ -631,10 +663,20 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
631
663
#[ cfg( anchors) ]
632
664
OnchainClaim :: Event ( claim_event) => {
633
665
log_info ! ( logger, "Yielding onchain event to spend inputs {:?}" , req. outpoints( ) ) ;
634
- let txid = match claim_event {
635
- ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
666
+ let package_id = match claim_event {
667
+ ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) . into_inner ( ) ,
668
+ ClaimEvent :: BumpHTLC { ref htlcs, .. } => {
669
+ // Use the same construction as a lightning channel id to generate
670
+ // the package id for this request based on the first HTLC. It
671
+ // doesn't matter what we use as long as it's unique per request.
672
+ let mut package_id = [ 0 ; 32 ] ;
673
+ package_id[ ..] . copy_from_slice ( & htlcs[ 0 ] . commitment_txid [ ..] ) ;
674
+ let htlc_output_index = htlcs[ 0 ] . htlc . transaction_output_index . unwrap ( ) ;
675
+ package_id[ 30 ] ^= ( ( htlc_output_index >> 8 ) & 0xff ) as u8 ;
676
+ package_id[ 31 ] ^= ( ( htlc_output_index >> 0 ) & 0xff ) as u8 ;
677
+ package_id
678
+ } ,
636
679
} ;
637
- let package_id = txid. into_inner ( ) ;
638
680
self . pending_claim_events . insert ( package_id, claim_event) ;
639
681
package_id
640
682
} ,
@@ -677,14 +719,31 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
677
719
// outpoints to know if transaction is the original claim or a bumped one issued
678
720
// by us.
679
721
let mut set_equality = true ;
680
- if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
681
- set_equality = false ;
722
+ if !request. requires_external_funding ( ) || !request. is_malleable ( ) {
723
+ // If the claim does not require external funds to be allocated through
724
+ // additional inputs we can simply check the inputs in order as they
725
+ // cannot change under us.
726
+ if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
727
+ set_equality = false ;
728
+ } else {
729
+ for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
730
+ if * * claim_inp != tx_inp. previous_output {
731
+ set_equality = false ;
732
+ }
733
+ }
734
+ }
682
735
} else {
683
- for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
684
- if * * claim_inp != tx_inp. previous_output {
685
- set_equality = false ;
736
+ // Otherwise, we'll do a linear search for each input (we don't expect
737
+ // large input sets to exist) to ensure the request's input set is fully
738
+ // spent to be resilient against the external claim reordering inputs.
739
+ let mut spends_all_inputs = true ;
740
+ for request_input in request. outpoints ( ) {
741
+ if tx. input . iter ( ) . find ( |input| input. previous_output == * request_input) . is_none ( ) {
742
+ spends_all_inputs = false ;
743
+ break ;
686
744
}
687
745
}
746
+ set_equality = spends_all_inputs;
688
747
}
689
748
690
749
macro_rules! clean_claim_request_after_safety_delay {
@@ -990,6 +1049,37 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
990
1049
htlc_tx
991
1050
}
992
1051
1052
+ #[ cfg( anchors) ]
1053
+ pub ( crate ) fn generate_external_htlc_claim (
1054
+ & mut self , outp : & :: bitcoin:: OutPoint , preimage : & Option < PaymentPreimage >
1055
+ ) -> Option < ExternalHTLCClaim > {
1056
+ let find_htlc = |holder_commitment : & HolderCommitmentTransaction | -> Option < ExternalHTLCClaim > {
1057
+ let trusted_tx = holder_commitment. trust ( ) ;
1058
+ if outp. txid != trusted_tx. txid ( ) {
1059
+ return None ;
1060
+ }
1061
+ trusted_tx. htlcs ( ) . iter ( ) . enumerate ( )
1062
+ . find ( |( _, htlc) | if let Some ( output_index) = htlc. transaction_output_index {
1063
+ output_index == outp. vout
1064
+ } else {
1065
+ false
1066
+ } )
1067
+ . map ( |( htlc_idx, htlc) | {
1068
+ let counterparty_htlc_sig = holder_commitment. counterparty_htlc_sigs [ htlc_idx] ;
1069
+ ExternalHTLCClaim {
1070
+ commitment_txid : trusted_tx. txid ( ) ,
1071
+ per_commitment_number : trusted_tx. commitment_number ( ) ,
1072
+ htlc : htlc. clone ( ) ,
1073
+ preimage : * preimage,
1074
+ counterparty_sig : counterparty_htlc_sig,
1075
+ }
1076
+ } )
1077
+ } ;
1078
+ // Check if the HTLC spends from the current holder commitment or the previous one otherwise.
1079
+ find_htlc ( & self . holder_commitment )
1080
+ . or_else ( || self . prev_holder_commitment . as_ref ( ) . map ( |c| find_htlc ( c) ) . flatten ( ) )
1081
+ }
1082
+
993
1083
pub ( crate ) fn opt_anchors ( & self ) -> bool {
994
1084
self . channel_transaction_parameters . opt_anchors . is_some ( )
995
1085
}
0 commit comments