Skip to content

Commit 3b4a7da

Browse files
author
Antoine Riard
committed
Build and broadcast CPFP for HolderCommitmentTx
This commit build a CPFP tx for HolderCommitmentTx and broadcast them as a whole thus bumping package feerate. A next commit condition CPFP on feerate fluctuation observation.
1 parent 021717e commit 3b4a7da

File tree

3 files changed

+173
-82
lines changed

3 files changed

+173
-82
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15381538
for (idx, outp) in tx.output.iter().enumerate() {
15391539
if outp.script_pubkey == revokeable_p2wsh {
15401540
let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_tx_cache.on_counterparty_tx_csv);
1541-
let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height);
1541+
let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height, 0);
15421542
claimable_outpoints.push(justice_package);
15431543
}
15441544
}
@@ -1552,7 +1552,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15521552
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
15531553
}
15541554
let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone());
1555-
let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height);
1555+
let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height, 0);
15561556
claimable_outpoints.push(justice_package);
15571557
}
15581558
}
@@ -1704,7 +1704,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
17041704
if preimage.is_some() || !htlc.offered {
17051705
let counterparty_htlc_outp = if htlc.offered { PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(*revocation_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, preimage.unwrap(), htlc.clone())) } else { PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(*revocation_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, htlc.clone())) };
17061706
let aggregation = if !htlc.offered { false } else { true };
1707-
let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0);
1707+
let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0, 0);
17081708
claimable_outpoints.push(counterparty_package);
17091709
}
17101710
}
@@ -1737,7 +1737,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
17371737

17381738
log_trace!(logger, "Counterparty HTLC broadcast {}:{}", htlc_txid, 0);
17391739
let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, tx.output[0].value, self.counterparty_tx_cache.on_counterparty_tx_csv);
1740-
let justice_package = PackageTemplate::build_package(htlc_txid, 0, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height);
1740+
let justice_package = PackageTemplate::build_package(htlc_txid, 0, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height, 0);
17411741
let claimable_outpoints = vec!(justice_package);
17421742
let outputs = vec![(0, tx.output[0].clone())];
17431743
(claimable_outpoints, Some((htlc_txid, outputs)))
@@ -1765,7 +1765,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
17651765
};
17661766
HolderHTLCOutput::build_accepted(payment_preimage, htlc.amount_msat)
17671767
};
1768-
let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height);
1768+
let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height, 0);
17691769
claim_requests.push(htlc_package);
17701770
}
17711771
}
@@ -2054,7 +2054,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
20542054
let should_broadcast = self.would_broadcast_at_height(height, &logger);
20552055
if should_broadcast {
20562056
let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone());
2057-
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), height, false, height);
2057+
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), height, false, height, self.current_holder_commitment_tx.feerate_per_kw as u64);
20582058
claimable_outpoints.push(commitment_package);
20592059
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
20602060
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);

lightning/src/chain/onchaintx.rs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use bitcoin::secp256k1;
2424
use ln::msgs::DecodeError;
2525
use ln::PaymentPreimage;
2626
use ln::chan_utils::{ChannelTransactionParameters, HolderCommitmentTransaction};
27-
use chain::chaininterface::{FeeEstimator, BroadcasterInterface};
27+
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget};
2828
use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
2929
use chain::keysinterface::{Sign, KeysInterface};
3030
use chain::utxointerface::UtxoPool;
@@ -144,7 +144,7 @@ impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
144144
/// do RBF bumping if possible.
145145
pub struct OnchainTxHandler<ChannelSigner: Sign> {
146146
destination_script: Script,
147-
holder_commitment: HolderCommitmentTransaction,
147+
pub(super) holder_commitment: HolderCommitmentTransaction,
148148
// holder_htlc_sigs and prev_holder_htlc_sigs are in the order as they appear in the commitment
149149
// transaction outputs (hence the Option<>s inside the Vec). The first usize is the index in
150150
// the set of HTLCs in the HolderCommitmentTransaction.
@@ -345,37 +345,39 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
345345
/// (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.
346346
/// Panics if there are signing errors, because signing operations in reaction to on-chain events
347347
/// are not expected to fail, and if they do, we may lose funds.
348-
fn generate_claim_tx<F: Deref, L: Deref, U: Deref>(&mut self, height: u32, cached_request: &mut PackageTemplate, fee_estimator: &F, logger: &L, utxo_pool: &U) -> Option<(Option<u32>, u64, Transaction)>
348+
fn generate_claim_tx<F: Deref, L: Deref, U: Deref>(&mut self, height: u32, cached_request: &mut PackageTemplate, fee_estimator: &F, logger: &L, utxo_pool: &U) -> Option<(Option<u32>, u64, Vec<Transaction>)>
349349
where F::Target: FeeEstimator,
350350
L::Target: Logger,
351351
U::Target: UtxoPool,
352352
{
353353
if cached_request.outpoints().len() == 0 { return None } // But don't prune pending claiming request yet, we may have to resurrect HTLCs
354354

355355
if !cached_request.is_malleable() {
356-
cached_request.set_bumping_utxo(utxo_pool);
356+
if cached_request.feerate_previous() < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 {
357+
// Bumping UTXO is allocated the first time we detect the pre-signed feerate
358+
// is under our fee estimator confirmation target
359+
cached_request.set_bumping_utxo(utxo_pool);
360+
}
357361
}
358362

359363
// Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we
360364
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
361-
let new_timer = Some(cached_request.get_height_timer(height));
362-
if cached_request.is_malleable() {
363-
let predicted_weight = cached_request.package_weight(&self.destination_script, self.holder_commitment.get_num_outputs());
364-
if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) {
365-
assert!(new_feerate != 0);
366-
367-
let transaction = cached_request.finalize_package(self, output_value, self.destination_script.clone(), logger).unwrap();
368-
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
369-
assert!(predicted_weight >= transaction.get_weight());
370-
return Some((new_timer, new_feerate, transaction))
371-
}
372-
} else {
373-
// Note: Currently, amounts of holder outputs spending witnesses aren't used
374-
// as we can't malleate spending package to increase their feerate. This
375-
// should change with the remaining anchor output patchset.
376-
if let Some(transaction) = cached_request.finalize_package(self, 0, self.destination_script.clone(), logger) {
377-
return Some((None, 0, transaction));
365+
let mut new_timer = Some(cached_request.get_height_timer(height));
366+
let predicted_weight = cached_request.package_weight(&self.destination_script, self.holder_commitment.get_num_outputs());
367+
if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) {
368+
if output_value != 0 { assert!(new_feerate != 0); }
369+
370+
let txn = cached_request.finalize_package(self, output_value, self.destination_script.clone(), &*logger, &*utxo_pool).unwrap();
371+
log_trace!(logger, "...with timer {} weight {} feerate {} CPFP: {}", new_timer.unwrap(), predicted_weight, new_feerate, txn.len() > 1);
372+
assert!(predicted_weight >= txn[0].get_weight() + if txn.len() == 2 { txn[1].get_weight() } else { 0 });
373+
374+
//TODO: for now disable timer for untractable package
375+
// Enabling them is pending on fixing tests first
376+
if !cached_request.is_malleable() {
377+
new_timer = None;
378378
}
379+
380+
return Some((new_timer, new_feerate, txn))
379381
}
380382
None
381383
}
@@ -444,17 +446,19 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
444446
// Generate claim transactions and track them to bump if necessary at
445447
// height timer expiration (i.e in how many blocks we're going to take action).
446448
for mut req in preprocessed_requests {
447-
if let Some((new_timer, new_feerate, tx)) = self.generate_claim_tx(height, &mut req, &*fee_estimator, &*logger, &*utxo_pool) {
449+
if let Some((new_timer, new_feerate, txn)) = self.generate_claim_tx(height, &mut req, &*fee_estimator, &*logger, &*utxo_pool) {
448450
req.set_timer(new_timer);
449451
req.set_feerate(new_feerate);
450-
let txid = tx.txid();
452+
let txid = txn[0].txid();
451453
for k in req.outpoints() {
452454
log_trace!(logger, "Registering claiming request for {}:{}", k.txid, k.vout);
453455
self.claimable_outpoints.insert(k.clone(), (txid, height));
454456
}
455457
self.pending_claim_requests.insert(txid, req);
456-
log_trace!(logger, "Broadcasting onchain {}", log_tx!(tx));
457-
broadcaster.broadcast_transaction(&tx);
458+
for tx in txn {
459+
log_trace!(logger, "Broadcasting onchain {}", log_tx!(tx));
460+
broadcaster.broadcast_transaction(&tx);
461+
}
458462
}
459463
}
460464

@@ -569,9 +573,11 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
569573
// Build, bump and rebroadcast tx accordingly
570574
log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
571575
for (first_claim_txid, ref mut request) in bump_candidates.iter_mut() {
572-
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, request, &*fee_estimator, &*logger, &*utxo_pool) {
573-
log_trace!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
574-
broadcaster.broadcast_transaction(&bump_tx);
576+
if let Some((new_timer, new_feerate, bump_txn)) = self.generate_claim_tx(height, request, &*fee_estimator, &*logger, &*utxo_pool) {
577+
for bump_tx in bump_txn {
578+
log_trace!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
579+
broadcaster.broadcast_transaction(&bump_tx);
580+
}
575581
if let Some(request) = self.pending_claim_requests.get_mut(first_claim_txid) {
576582
request.set_timer(new_timer);
577583
request.set_feerate(new_feerate);
@@ -637,11 +643,13 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
637643
}
638644
}
639645
for (_, ref mut request) in bump_candidates.iter_mut() {
640-
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, request, &&*fee_estimator, &&*logger, &&*utxo_pool) {
646+
if let Some((new_timer, new_feerate, bump_txn)) = self.generate_claim_tx(height, request, &&*fee_estimator, &&*logger, &&*utxo_pool) {
641647
request.set_timer(new_timer);
642648
request.set_feerate(new_feerate);
643-
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
644-
broadcaster.broadcast_transaction(&bump_tx);
649+
for bump_tx in bump_txn {
650+
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
651+
broadcaster.broadcast_transaction(&bump_tx);
652+
}
645653
}
646654
}
647655
for (ancestor_claim_txid, request) in bump_candidates.drain() {

0 commit comments

Comments
 (0)