Skip to content

Commit 92adfdf

Browse files
author
Antoine Riard
committed
Allocate UTXO for CPFP-strategy transactions
Pre-committed feerates transactions (commitment, HTLC input-ouput pair) need the adjunction of an unspent transaction output. This will serve as a potential bumping input for a CPFP spending also a commitment transaction anchor output, thus increasing package feerate. Bumping utxo are only committed when the channel transactions goes onchain.
1 parent 445bd2b commit 92adfdf

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

lightning/src/ln/onchain_utils.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use ln::msgs::DecodeError;
1515
use ln::onchaintx::OnchainTxHandler;
1616
use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
1717
use chain::keysinterface::ChannelKeys;
18+
use chain::utxointerface::UtxoPool;
1819
use util::byte_utils;
1920
use util::logger::Logger;
2021
use util::ser::{Readable, Writer, Writeable};
@@ -308,6 +309,7 @@ pub(crate) enum PackageTemplate {
308309
},
309310
HolderCommitmentTx {
310311
input: (BitcoinOutPoint, HolderFundingOutput),
312+
utxo_input: Option<(BitcoinOutPoint, BumpingOutput)>
311313
}
312314
}
313315

@@ -325,7 +327,7 @@ impl PackageTemplate {
325327
outpoints.push(&input.0);
326328
return outpoints;
327329
},
328-
PackageTemplate::HolderCommitmentTx { ref input } => {
330+
PackageTemplate::HolderCommitmentTx { ref input, .. } => {
329331
let mut outpoints = Vec::with_capacity(1);
330332
outpoints.push(&input.0);
331333
return outpoints;
@@ -541,14 +543,28 @@ impl PackageTemplate {
541543
}
542544
return None;
543545
},
544-
PackageTemplate::HolderCommitmentTx { ref input } => {
546+
PackageTemplate::HolderCommitmentTx { ref input, .. } => {
545547
let signed_tx = onchain_handler.get_fully_signed_holder_tx(&input.1.funding_redeemscript).unwrap();
546548
// Timer set to $NEVER given we can't bump tx without anchor outputs
547549
log_trace!(logger, "Going to broadcast Holder Transaction {} claiming funding output {} from {}...", signed_tx.txid(), input.0.vout, input.0.txid);
548550
return Some(signed_tx);
549551
}
550552
}
551553
}
554+
pub(crate) fn package_cpfp<U: Deref>(&mut self, utxo_pool: &U)
555+
where U::Target: UtxoPool,
556+
{
557+
match self {
558+
PackageTemplate::HolderCommitmentTx { ref mut utxo_input, .. } => {
559+
if utxo_input.is_some() { return; }
560+
*utxo_input = utxo_pool.allocate_utxo(0);
561+
},
562+
PackageTemplate::HolderHTLCTx { .. } => {
563+
return; //TODO: Should we anchor output HTLC-txn?
564+
},
565+
_ => panic!("Package template should be bumped through RBF")
566+
}
567+
}
552568
pub(crate) fn build_malleable_justice_tx(per_commitment_point: PublicKey, per_commitment_key: SecretKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, input_descriptor: InputDescriptors, txid: Txid, vout: u32, amount: u64, htlc: Option<HTLCOutputInCommitment>, on_counterparty_tx_csv: u16) -> Self {
553569
let revk_outp = RevokedOutput {
554570
per_commitment_point,
@@ -594,7 +610,8 @@ impl PackageTemplate {
594610
funding_redeemscript,
595611
};
596612
PackageTemplate::HolderCommitmentTx {
597-
input: (BitcoinOutPoint { txid, vout }, funding_outp)
613+
input: (BitcoinOutPoint { txid, vout }, funding_outp),
614+
utxo_input: None,
598615
}
599616
}
600617
}
@@ -631,10 +648,11 @@ impl Writeable for PackageTemplate {
631648
input.0.write(writer)?;
632649
input.1.write(writer)?;
633650
},
634-
&PackageTemplate::HolderCommitmentTx { ref input } => {
651+
&PackageTemplate::HolderCommitmentTx { ref input, ref utxo_input } => {
635652
writer.write_all(&[3; 1])?;
636653
input.0.write(writer)?;
637654
input.1.write(writer)?;
655+
utxo_input.write(writer)?;
638656
}
639657
}
640658
Ok(())
@@ -678,8 +696,10 @@ impl Readable for PackageTemplate {
678696
3 => {
679697
let outpoint = Readable::read(reader)?;
680698
let funding_outp = Readable::read(reader)?;
699+
let utxo_input = Readable::read(reader)?;
681700
PackageTemplate::HolderCommitmentTx {
682-
input: (outpoint, funding_outp)
701+
input: (outpoint, funding_outp),
702+
utxo_input,
683703
}
684704
},
685705
_ => return Err(DecodeError::InvalidValue),

lightning/src/ln/onchaintx.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,17 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
303303

304304
/// 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
305305
/// (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.
306-
fn generate_claim_tx<F: Deref, L: Deref, U: Deref>(&mut self, height: u32, cached_request: &OnchainRequest, fee_estimator: F, logger: L, utxo_pool: U) -> Option<(Option<u32>, u64, Transaction)>
306+
fn generate_claim_tx<F: Deref, L: Deref, U: Deref>(&mut self, height: u32, cached_request: &mut OnchainRequest, fee_estimator: F, logger: L, utxo_pool: U) -> Option<(Option<u32>, u64, Transaction)>
307307
where F::Target: FeeEstimator,
308308
L::Target: Logger,
309309
U::Target: UtxoPool,
310310
{
311311
if cached_request.content.outpoints().len() == 0 { return None } // But don't prune pending claiming request yet, we may have to resurrect HTLCs
312312

313+
if cached_request.bump_strategy == BumpStrategy::CPFP {
314+
cached_request.content.package_cpfp(&utxo_pool);
315+
}
316+
313317
// Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we
314318
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
315319
let new_timer = Some(Self::get_height_timer(height, cached_request.absolute_timelock));
@@ -361,7 +365,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
361365
// Generate claim transactions and track them to bump if necessary at
362366
// height timer expiration (i.e in how many blocks we're going to take action).
363367
for mut req in preprocessed_requests {
364-
if let Some((new_timer, new_feerate, tx)) = self.generate_claim_tx(height, &req, &*fee_estimator, &*logger, &*utxo_pool) {
368+
if let Some((new_timer, new_feerate, tx)) = self.generate_claim_tx(height, &mut req, &*fee_estimator, &*logger, &*utxo_pool) {
365369
req.height_timer = new_timer;
366370
req.feerate_previous = new_feerate;
367371
let txid = tx.txid();
@@ -487,8 +491,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
487491

488492
// Build, bump and rebroadcast tx accordingly
489493
log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
490-
for (first_claim_txid, request) in bump_candidates.iter() {
491-
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &*fee_estimator, &*logger, &*utxo_pool) {
494+
for (first_claim_txid, ref mut request) in bump_candidates.iter_mut() {
495+
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, request, &*fee_estimator, &*logger, &*utxo_pool) {
492496
log_trace!(logger, "Broadcast onchain {}", log_tx!(bump_tx));
493497
broadcaster.broadcast_transaction(&bump_tx);
494498
if let Some(request) = self.pending_claim_requests.get_mut(first_claim_txid) {
@@ -525,8 +529,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
525529
}
526530
}
527531
}
528-
for (_, request) in bump_candidates.iter_mut() {
529-
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &*fee_estimator, &*logger, &*utxo_pool) {
532+
for (_, ref mut request) in bump_candidates.iter_mut() {
533+
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, request, &*fee_estimator, &*logger, &*utxo_pool) {
530534
request.height_timer = new_timer;
531535
request.feerate_previous = new_feerate;
532536
broadcaster.broadcast_transaction(&bump_tx);

0 commit comments

Comments
 (0)