@@ -170,6 +170,18 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
170
170
}
171
171
}
172
172
173
+ #[ cfg( anchors) ]
174
+ pub ( crate ) enum ExternalHTLCClaim {
175
+ /// The claim commonly referred to as the pre-signed second-stage HTLC transaction.
176
+ SecondStage {
177
+ amount : u64 ,
178
+ per_commitment_number : u64 ,
179
+ redeem_script : Script ,
180
+ preimage : Option < PaymentPreimage > ,
181
+ counterparty_sig : Signature ,
182
+ }
183
+ }
184
+
173
185
// Represents the different types of claims for which events are yielded externally to satisfy said
174
186
// claims.
175
187
#[ cfg( anchors) ]
@@ -181,6 +193,11 @@ pub(crate) enum ClaimEvent {
181
193
commitment_tx : Transaction ,
182
194
anchor_output_idx : u32 ,
183
195
} ,
196
+ BumpHTLC {
197
+ target_feerate_sat_per_1000_weight : u32 ,
198
+ tx_template : Transaction ,
199
+ htlcs : Vec < ExternalHTLCClaim > ,
200
+ } ,
184
201
}
185
202
186
203
/// Represents the different ways an output can be claimed (i.e., spent to an address under our
@@ -472,15 +489,32 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
472
489
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
473
490
let new_timer = Some ( cached_request. get_height_timer ( cur_height) ) ;
474
491
if cached_request. is_malleable ( ) {
492
+ #[ cfg( anchors) ]
493
+ if cached_request. requires_external_funding ( ) {
494
+ let target_feerate_sat_per_1000_weight = cached_request
495
+ . compute_package_feerate ( fee_estimator, ConfirmationTarget :: HighPriority ) ;
496
+ let ( tx_template, htlcs) = cached_request. construct_malleable_package_with_external_funding ( self ) ;
497
+ return Some ( (
498
+ new_timer,
499
+ target_feerate_sat_per_1000_weight as u64 ,
500
+ OnchainClaim :: Event ( ClaimEvent :: BumpHTLC {
501
+ target_feerate_sat_per_1000_weight,
502
+ tx_template,
503
+ htlcs,
504
+ } ) ,
505
+ ) ) ;
506
+ }
507
+
475
508
let predicted_weight = cached_request. package_weight ( & self . destination_script ) ;
476
- if let Some ( ( output_value, new_feerate) ) =
477
- cached_request. compute_package_output ( predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger) {
509
+ if let Some ( ( output_value, new_feerate) ) = cached_request. compute_package_output (
510
+ predicted_weight, self . destination_script . dust_value ( ) . to_sat ( ) , fee_estimator, logger,
511
+ ) {
478
512
assert ! ( new_feerate != 0 ) ;
479
513
480
514
let transaction = cached_request. finalize_malleable_package ( self , output_value, self . destination_script . clone ( ) , logger) . unwrap ( ) ;
481
515
log_trace ! ( logger, "...with timer {} and feerate {}" , new_timer. unwrap( ) , new_feerate) ;
482
516
assert ! ( predicted_weight >= transaction. weight( ) ) ;
483
- return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
517
+ return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) ) ;
484
518
}
485
519
} else {
486
520
// Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
@@ -536,7 +570,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
536
570
debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
537
571
None
538
572
} ,
539
- } ) ;
573
+ } )
540
574
}
541
575
None
542
576
}
@@ -621,6 +655,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
621
655
log_info ! ( logger, "Yielding onchain event to spend inputs {:?}" , req. outpoints( ) ) ;
622
656
let txid = match claim_event {
623
657
ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
658
+ ClaimEvent :: BumpHTLC { ref tx_template, .. } => tx_template. txid ( ) ,
624
659
} ;
625
660
self . pending_claim_events . insert ( txid, claim_event) ;
626
661
txid
@@ -646,14 +681,28 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
646
681
// outpoints to know if transaction is the original claim or a bumped one issued
647
682
// by us.
648
683
let mut set_equality = true ;
649
- if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
650
- set_equality = false ;
651
- } else {
652
- for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
653
- if * * claim_inp != tx_inp. previous_output {
654
- set_equality = false ;
684
+ if !request. requires_external_funding ( ) {
685
+ if request. outpoints ( ) . len ( ) != tx. input . len ( ) {
686
+ set_equality = false ;
687
+ } else {
688
+ for ( claim_inp, tx_inp) in request. outpoints ( ) . iter ( ) . zip ( tx. input . iter ( ) ) {
689
+ if * * claim_inp != tx_inp. previous_output {
690
+ set_equality = false ;
691
+ }
655
692
}
656
693
}
694
+ } else {
695
+ let request_inputs = request. outpoints ( ) ;
696
+ let mut input_set = HashSet :: with_capacity ( request_inputs. len ( ) ) ;
697
+ for input in request_inputs {
698
+ let _ = input_set. insert ( input) ;
699
+ }
700
+ for tx_input in & tx. input {
701
+ let _ = input_set. remove ( & tx_input. previous_output ) ;
702
+ }
703
+ if !input_set. is_empty ( ) {
704
+ set_equality = false ;
705
+ }
657
706
}
658
707
659
708
macro_rules! clean_claim_request_after_safety_delay {
@@ -956,6 +1005,40 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
956
1005
htlc_tx
957
1006
}
958
1007
1008
+ #[ cfg( anchors) ]
1009
+ pub ( crate ) fn unsigned_htlc_tx (
1010
+ & mut self , outp : & :: bitcoin:: OutPoint , preimage : & Option < PaymentPreimage >
1011
+ ) -> Option < ( Transaction , ExternalHTLCClaim ) > {
1012
+ let find_htlc = |holder_commitment : & HolderCommitmentTransaction | -> Option < ( Transaction , ExternalHTLCClaim ) > {
1013
+ let trusted_tx = holder_commitment. trust ( ) ;
1014
+ trusted_tx. htlcs ( ) . iter ( ) . enumerate ( )
1015
+ . find ( |( _, htlc) | if let Some ( output_index) = htlc. transaction_output_index {
1016
+ output_index == outp. vout
1017
+ } else {
1018
+ false
1019
+ } )
1020
+ . map ( |( htlc_idx, htlc) | {
1021
+ let counterparty_htlc_sig = holder_commitment. counterparty_htlc_sigs [ htlc_idx] ;
1022
+ let htlc_tx = trusted_tx. unsigned_htlc_tx (
1023
+ & self . channel_transaction_parameters . as_holder_broadcastable ( ) , htlc_idx, preimage,
1024
+ ) ;
1025
+ ( htlc_tx, ExternalHTLCClaim :: SecondStage {
1026
+ amount : htlc. amount_msat / 1000 ,
1027
+ per_commitment_number : trusted_tx. commitment_number ( ) ,
1028
+ redeem_script : chan_utils:: get_htlc_redeemscript_with_explicit_keys (
1029
+ & htlc, self . opt_anchors ( ) , & trusted_tx. keys ( ) . broadcaster_htlc_key ,
1030
+ & trusted_tx. keys ( ) . countersignatory_htlc_key , & trusted_tx. keys ( ) . revocation_key ,
1031
+ ) ,
1032
+ preimage : * preimage,
1033
+ counterparty_sig : counterparty_htlc_sig,
1034
+ } )
1035
+ } )
1036
+ } ;
1037
+ // Check if the HTLC spends from the current holder commitment or the previous one otherwise.
1038
+ find_htlc ( & self . holder_commitment )
1039
+ . or ( self . prev_holder_commitment . as_ref ( ) . map ( |c| find_htlc ( c) ) . flatten ( ) )
1040
+ }
1041
+
959
1042
pub ( crate ) fn opt_anchors ( & self ) -> bool {
960
1043
self . channel_transaction_parameters . opt_anchors . is_some ( )
961
1044
}
0 commit comments