@@ -23,11 +23,12 @@ use bitcoin::secp256k1;
23
23
24
24
use ln:: msgs:: DecodeError ;
25
25
use ln:: PaymentPreimage ;
26
+ use ln:: chan_utils;
26
27
use ln:: chan_utils:: { ChannelTransactionParameters , HolderCommitmentTransaction } ;
27
- use chain:: chaininterface:: { FeeEstimator , BroadcasterInterface , LowerBoundedFeeEstimator } ;
28
+ use chain:: chaininterface:: { ConfirmationTarget , FeeEstimator , BroadcasterInterface , LowerBoundedFeeEstimator } ;
28
29
use chain:: channelmonitor:: { ANTI_REORG_DELAY , CLTV_SHARED_CLAIM_BUFFER } ;
29
30
use chain:: keysinterface:: { Sign , KeysInterface } ;
30
- use chain:: package:: PackageTemplate ;
31
+ use chain:: package:: { PackageSolvingData , PackageTemplate } ;
31
32
use util:: logger:: Logger ;
32
33
use util:: ser:: { Readable , ReadableArgs , MaybeReadable , Writer , Writeable , VecWriter } ;
33
34
use util:: byte_utils;
@@ -162,8 +163,17 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
162
163
}
163
164
}
164
165
166
+ pub ( crate ) enum ClaimEvent {
167
+ BumpCommitment {
168
+ package_target_feerate_sat_per_1000_weight : u32 ,
169
+ commitment_tx : Transaction ,
170
+ anchor_output_idx : u32 ,
171
+ } ,
172
+ }
173
+
165
174
pub ( crate ) enum OnchainClaim {
166
175
Tx ( Transaction ) ,
176
+ Event ( ClaimEvent ) ,
167
177
}
168
178
169
179
/// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
@@ -196,6 +206,7 @@ pub struct OnchainTxHandler<ChannelSigner: Sign> {
196
206
pub ( crate ) pending_claim_requests : HashMap < Txid , PackageTemplate > ,
197
207
#[ cfg( not( test) ) ]
198
208
pending_claim_requests : HashMap < Txid , PackageTemplate > ,
209
+ pending_claim_events : HashMap < Txid , ClaimEvent > ,
199
210
200
211
// Used to link outpoints claimed in a connected block to a pending claim request.
201
212
// Key is outpoint than monitor parsing has detected we have keys/scripts to claim
@@ -345,6 +356,7 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
345
356
locktimed_packages,
346
357
pending_claim_requests,
347
358
onchain_events_awaiting_threshold_conf,
359
+ pending_claim_events : HashMap :: new ( ) ,
348
360
secp_ctx,
349
361
} )
350
362
}
@@ -364,6 +376,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
364
376
claimable_outpoints : HashMap :: new ( ) ,
365
377
locktimed_packages : BTreeMap :: new ( ) ,
366
378
onchain_events_awaiting_threshold_conf : Vec :: new ( ) ,
379
+ pending_claim_events : HashMap :: new ( ) ,
367
380
368
381
secp_ctx,
369
382
}
@@ -377,10 +390,14 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
377
390
self . holder_commitment . to_broadcaster_value_sat ( )
378
391
}
379
392
380
- /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize coutnerparty onchain) lays on the assumption of claim transactions getting confirmed before timelock expiration
381
- /// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent.
382
- /// Panics if there are signing errors, because signing operations in reaction to on-chain events
383
- /// are not expected to fail, and if they do, we may lose funds.
393
+ /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
394
+ /// onchain) lays on the assumption of claim transactions getting confirmed before timelock
395
+ /// expiration (CSV or CLTV following cases). In case of high-fee spikes, claim tx may get stuck
396
+ /// in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or
397
+ /// Child-Pay-For-Parent.
398
+ ///
399
+ /// Panics if there are signing errors, because signing operations in reaction to on-chain
400
+ /// events are not expected to fail, and if they do, we may lose funds.
384
401
fn generate_claim < F : Deref , L : Deref > ( & mut self , cur_height : u32 , cached_request : & PackageTemplate , fee_estimator : & LowerBoundedFeeEstimator < F > , logger : & L ) -> Option < ( Option < u32 > , u64 , OnchainClaim ) >
385
402
where F :: Target : FeeEstimator ,
386
403
L :: Target : Logger ,
@@ -402,12 +419,51 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
402
419
return Some ( ( new_timer, new_feerate, OnchainClaim :: Tx ( transaction) ) )
403
420
}
404
421
} else {
405
- // Note: Currently, amounts of holder outputs spending witnesses aren't used
406
- // as we can't malleate spending package to increase their feerate. This
407
- // should change with the remaining anchor output patchset.
408
- if let Some ( transaction) = cached_request. finalize_untractable_package ( self , logger) {
409
- return Some ( ( None , 0 , OnchainClaim :: Tx ( transaction) ) ) ;
422
+ // Untractable packages cannot have their fees bumped through Replace-By-Fee. Some
423
+ // packages may support fee bumping through Child-Pays-For-Parent, indicated by those
424
+ // which require external funding.
425
+ let inputs = cached_request. inputs ( ) ;
426
+ debug_assert_eq ! ( inputs. len( ) , 1 ) ;
427
+ let tx = match cached_request. finalize_untractable_package ( self , logger) {
428
+ Some ( tx) => tx,
429
+ None => return None ,
430
+ } ;
431
+ if !cached_request. requires_external_funding ( ) {
432
+ return Some ( ( None , 0 , OnchainClaim :: Tx ( tx) ) ) ;
410
433
}
434
+ return inputs. iter ( ) . find_map ( |input| match input {
435
+ // Commitment inputs with anchors support are the only untractable inputs supported
436
+ // thus far that require external funding.
437
+ PackageSolvingData :: HolderFundingOutput ( ..) => {
438
+ // We'll locate an anchor output we can spend within the commitment transaction.
439
+ let funding_pubkey = & self . channel_transaction_parameters . holder_pubkeys . funding_pubkey ;
440
+ match chan_utils:: get_anchor_output ( & tx, funding_pubkey) {
441
+ // An anchor output was found, so we should yield a funding event externally.
442
+ Some ( ( idx, _) ) => {
443
+ let package_target_feerate_sat_per_1000_weight = cached_request
444
+ . compute_package_feerate ( fee_estimator, ConfirmationTarget :: HighPriority ) ;
445
+ Some ( (
446
+ new_timer,
447
+ package_target_feerate_sat_per_1000_weight as u64 ,
448
+ OnchainClaim :: Event ( ClaimEvent :: BumpCommitment {
449
+ package_target_feerate_sat_per_1000_weight,
450
+ commitment_tx : tx. clone ( ) ,
451
+ anchor_output_idx : idx,
452
+ } ) ,
453
+ ) )
454
+ } ,
455
+ // An anchor output was not found. There's nothing we can do other than
456
+ // attempt to broadcast the transaction with its current fee rate and hope
457
+ // it confirms. This is essentially the same behavior as a commitment
458
+ // transaction without anchor outputs.
459
+ None => Some ( ( None , 0 , OnchainClaim :: Tx ( tx. clone ( ) ) ) ) ,
460
+ }
461
+ } ,
462
+ _ => {
463
+ debug_assert ! ( false , "Only HolderFundingOutput inputs should be untractable and require external funding" ) ;
464
+ None
465
+ } ,
466
+ } ) ;
411
467
}
412
468
None
413
469
}
@@ -481,18 +537,25 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
481
537
if let Some ( ( new_timer, new_feerate, claim) ) = self . generate_claim ( cur_height, & req, & * fee_estimator, & * logger) {
482
538
req. set_timer ( new_timer) ;
483
539
req. set_feerate ( new_feerate) ;
484
- match claim {
540
+ let txid = match claim {
485
541
OnchainClaim :: Tx ( tx) => {
486
- let txid = tx. txid ( ) ;
487
- for k in req. outpoints ( ) {
488
- log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
489
- self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
490
- }
491
- self . pending_claim_requests . insert ( txid, req) ;
492
542
log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( tx) ) ;
493
543
broadcaster. broadcast_transaction ( & tx) ;
544
+ tx. txid ( )
545
+ } ,
546
+ OnchainClaim :: Event ( claim_event) => {
547
+ let txid = match claim_event {
548
+ ClaimEvent :: BumpCommitment { ref commitment_tx, .. } => commitment_tx. txid ( ) ,
549
+ } ;
550
+ self . pending_claim_events . insert ( txid, claim_event) ;
551
+ txid
494
552
} ,
553
+ } ;
554
+ for k in req. outpoints ( ) {
555
+ log_info ! ( logger, "Registering claiming request for {}:{}" , k. txid, k. vout) ;
556
+ self . claimable_outpoints . insert ( k. clone ( ) , ( txid, conf_height) ) ;
495
557
}
558
+ self . pending_claim_requests . insert ( txid, req) ;
496
559
}
497
560
}
498
561
@@ -584,6 +647,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
584
647
for outpoint in request. outpoints ( ) {
585
648
log_debug ! ( logger, "Removing claim tracking for {} due to maturation of claim tx {}." , outpoint, claim_request) ;
586
649
self . claimable_outpoints . remove ( & outpoint) ;
650
+ self . pending_claim_events . remove ( & claim_request) ;
587
651
}
588
652
}
589
653
} ,
@@ -616,6 +680,9 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
616
680
log_info ! ( logger, "Broadcasting RBF-bumped onchain {}" , log_tx!( bump_tx) ) ;
617
681
broadcaster. broadcast_transaction ( & bump_tx) ;
618
682
} ,
683
+ OnchainClaim :: Event ( claim_event) => {
684
+ self . pending_claim_events . insert ( * first_claim_txid, claim_event) ;
685
+ } ,
619
686
}
620
687
if let Some ( request) = self . pending_claim_requests . get_mut ( first_claim_txid) {
621
688
request. set_timer ( new_timer) ;
@@ -678,7 +745,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
678
745
self . onchain_events_awaiting_threshold_conf . push ( entry) ;
679
746
}
680
747
}
681
- for ( _ , request) in bump_candidates. iter_mut ( ) {
748
+ for ( first_claim_txid_height , request) in bump_candidates. iter_mut ( ) {
682
749
if let Some ( ( new_timer, new_feerate, bump_claim) ) = self . generate_claim ( height, & request, fee_estimator, & & * logger) {
683
750
request. set_timer ( new_timer) ;
684
751
request. set_feerate ( new_feerate) ;
@@ -687,6 +754,9 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
687
754
log_info ! ( logger, "Broadcasting onchain {}" , log_tx!( bump_tx) ) ;
688
755
broadcaster. broadcast_transaction ( & bump_tx) ;
689
756
} ,
757
+ OnchainClaim :: Event ( claim_event) => {
758
+ self . pending_claim_events . insert ( first_claim_txid_height. 0 , claim_event) ;
759
+ } ,
690
760
}
691
761
}
692
762
}
0 commit comments