@@ -25,7 +25,7 @@ use crate::chain::keysinterface::BaseSign;
25
25
use crate :: ln:: msgs:: DecodeError ;
26
26
use crate :: ln:: PaymentPreimage ;
27
27
#[ cfg( anchors) ]
28
- use crate :: ln:: chan_utils;
28
+ use crate :: ln:: chan_utils:: { self , HTLCOutputInCommitment } ;
29
29
use crate :: ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
30
30
#[ cfg( anchors) ]
31
31
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,12 @@ pub(crate) enum ClaimEvent {
185
195
commitment_tx : Transaction ,
186
196
anchor_output_idx : u32 ,
187
197
} ,
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
+ } ,
188
204
}
189
205
190
206
/// 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> {
488
504
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
489
505
let new_timer = Some ( cached_request. get_height_timer ( cur_height) ) ;
490
506
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
+
491
527
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
+ ) {
494
531
assert ! ( new_feerate != 0 ) ;
495
532
496
533
let transaction = cached_request. finalize_malleable_package ( self , output_value, self . destination_script . clone ( ) , logger) . unwrap ( ) ;
497
534
log_trace ! ( logger, "...with timer {} and feerate {}" , new_timer. unwrap( ) , new_feerate) ;
498
535
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) ) ) ;
500
537
}
501
538
} else {
502
539
// Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
@@ -552,7 +589,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
552
589
debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
553
590
None
554
591
} ,
555
- } ) ;
592
+ } )
556
593
}
557
594
None
558
595
}
@@ -640,10 +677,20 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
640
677
#[ cfg( anchors) ]
641
678
OnchainClaim :: Event ( claim_event) => {
642
679
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
+ } ,
645
693
} ;
646
- let package_id = txid. into_inner ( ) ;
647
694
self . pending_claim_events . insert ( package_id, claim_event) ;
648
695
package_id
649
696
} ,
@@ -686,14 +733,31 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
686
733
// outpoints to know if transaction is the original claim or a bumped one issued
687
734
// by us.
688
735
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
+ }
691
749
} 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 ;
695
758
}
696
759
}
760
+ set_equality = spends_all_inputs;
697
761
}
698
762
699
763
macro_rules! clean_claim_request_after_safety_delay {
@@ -999,6 +1063,37 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
999
1063
htlc_tx
1000
1064
}
1001
1065
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
+
1002
1097
pub ( crate ) fn opt_anchors ( & self ) -> bool {
1003
1098
self . channel_transaction_parameters . opt_anchors . is_some ( )
1004
1099
}
0 commit comments