Skip to content

Commit 4a0a596

Browse files
committed
Split ConfirmationTarget::OnChainSweep into urgent and non-urgent
When we force-close a channel, occasionally its due to feerate disagreements or other non-HTLC-related issues. In those cases, there's no reason to use a very urgent feerate estimate - we don't have any timers expiring soon. Instead, we should give users the information they need to be more economical on fees in this case, which we do here by splitting `OnChainSweep` into `UrgentOnChainSweep` and `NonUrgentOnChainSweep` `ConfirmationTarget`s.
1 parent 67cbeda commit 4a0a596

File tree

4 files changed

+86
-39
lines changed

4 files changed

+86
-39
lines changed

lightning/src/chain/chaininterface.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,15 @@ pub enum ConfirmationTarget {
5656
/// trying to burn channel balance to dust.
5757
MostConservativeEstimate,
5858
/// We have some funds available on chain which we need to spend prior to some expiry time at
59-
/// which point our counterparty may be able to steal them. Generally we have in the high tens
60-
/// to low hundreds of blocks to get our transaction on-chain, but we shouldn't risk too low a
61-
/// fee - this should be a relatively high priority feerate.
62-
OnChainSweep,
59+
/// which point our counterparty may be able to steal them.
60+
///
61+
/// Generally we have in the high tens to low hundreds of blocks to get our transaction
62+
/// on-chain (it doesn't have to happen in the next few blocks!), but we shouldn't risk too low
63+
/// a fee - this should be a relatively high priority feerate.
64+
UrgentOnChainSweep,
65+
/// We have some funds available on chain which we need to spend but have no particular urgency
66+
/// to do so.
67+
NonUrgentOnChainSweep,
6368
/// This is the lowest feerate we will allow our channel counterparty to have in an anchor
6469
/// channel in order to close the channel if a channel party goes away.
6570
///

lightning/src/chain/channelmonitor.rs

+44-11
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::ln::chan_utils::{self,CommitmentTransaction, CounterpartyCommitmentSe
4040
use crate::ln::channelmanager::{HTLCSource, SentHTLCId};
4141
use crate::chain;
4242
use crate::chain::{BestBlock, WatchedOutput};
43-
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
43+
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
4444
use crate::chain::transaction::{OutPoint, TransactionData};
4545
use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, ecdsa::EcdsaChannelSigner, SignerProvider, EntropySource};
4646
use crate::chain::onchaintx::{ClaimEvent, FeerateStrategy, OnchainTxHandler};
@@ -1902,8 +1902,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
19021902
let mut inner = self.inner.lock().unwrap();
19031903
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
19041904
let current_height = inner.best_block.height;
1905+
let conf_target = inner.closure_conf_target();
19051906
inner.onchain_tx_handler.rebroadcast_pending_claims(
1906-
current_height, FeerateStrategy::HighestOfPreviousOrNew, &broadcaster, &fee_estimator, &logger,
1907+
current_height, FeerateStrategy::HighestOfPreviousOrNew, &broadcaster, conf_target, &fee_estimator, &logger,
19071908
);
19081909
}
19091910

@@ -1927,8 +1928,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
19271928
let mut inner = self.inner.lock().unwrap();
19281929
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
19291930
let current_height = inner.best_block.height;
1931+
let conf_target = inner.closure_conf_target();
19301932
inner.onchain_tx_handler.rebroadcast_pending_claims(
1931-
current_height, FeerateStrategy::RetryPrevious, &broadcaster, &fee_estimator, &logger,
1933+
current_height, FeerateStrategy::RetryPrevious, &broadcaster, conf_target, &fee_estimator, &logger,
19321934
);
19331935
}
19341936

@@ -2684,6 +2686,30 @@ pub fn deliberately_bogus_accepted_htlc_witness() -> Vec<Vec<u8>> {
26842686
}
26852687

26862688
impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
2689+
/// Gets the [`ConfirmationTarget`] we should use when selecting feerates for channel closure
2690+
/// transactions for this channel right now.
2691+
fn closure_conf_target(&self) -> ConfirmationTarget {
2692+
// Treat the sweep as urgent as long as there is at least one HTLC which is pending on a
2693+
// valid commitment transaction.
2694+
if !self.current_holder_commitment_tx.htlc_outputs.is_empty() {
2695+
return ConfirmationTarget::UrgentOnChainSweep;
2696+
}
2697+
if self.prev_holder_signed_commitment_tx.as_ref().map(|t| !t.htlc_outputs.is_empty()).unwrap_or(false) {
2698+
return ConfirmationTarget::UrgentOnChainSweep;
2699+
}
2700+
if let Some(txid) = self.current_counterparty_commitment_txid {
2701+
if !self.counterparty_claimable_outpoints.get(&txid).unwrap().is_empty() {
2702+
return ConfirmationTarget::UrgentOnChainSweep;
2703+
}
2704+
}
2705+
if let Some(txid) = self.prev_counterparty_commitment_txid {
2706+
if !self.counterparty_claimable_outpoints.get(&txid).unwrap().is_empty() {
2707+
return ConfirmationTarget::UrgentOnChainSweep;
2708+
}
2709+
}
2710+
ConfirmationTarget::NonUrgentOnChainSweep
2711+
}
2712+
26872713
/// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither
26882714
/// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen
26892715
/// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key).
@@ -2928,7 +2954,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29282954
macro_rules! claim_htlcs {
29292955
($commitment_number: expr, $txid: expr, $htlcs: expr) => {
29302956
let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None, $htlcs);
2931-
self.onchain_tx_handler.update_claims_view_from_requests(htlc_claim_reqs, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger);
2957+
let conf_target = self.closure_conf_target();
2958+
self.onchain_tx_handler.update_claims_view_from_requests(htlc_claim_reqs, self.best_block.height, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
29322959
}
29332960
}
29342961
if let Some(txid) = self.current_counterparty_commitment_txid {
@@ -2976,7 +3003,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29763003
// block. Even if not, its a reasonable metric for the bump criteria on the HTLC
29773004
// transactions.
29783005
let (claim_reqs, _) = self.get_broadcasted_holder_claims(&holder_commitment_tx, self.best_block.height);
2979-
self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger);
3006+
let conf_target = self.closure_conf_target();
3007+
self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
29803008
}
29813009
}
29823010
}
@@ -3036,9 +3064,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
30363064
L::Target: Logger,
30373065
{
30383066
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) });
3067+
let conf_target = self.closure_conf_target();
30393068
self.onchain_tx_handler.update_claims_view_from_requests(
30403069
claimable_outpoints, self.best_block.height, self.best_block.height, broadcaster,
3041-
fee_estimator, logger
3070+
conf_target, fee_estimator, logger,
30423071
);
30433072
}
30443073

@@ -3851,7 +3880,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38513880
self.best_block = BestBlock::new(block_hash, height);
38523881
log_trace!(logger, "Best block re-orged, replaced with new block {} at height {}", block_hash, height);
38533882
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= height);
3854-
self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, fee_estimator, logger);
3883+
let conf_target = self.closure_conf_target();
3884+
self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, conf_target, fee_estimator, logger);
38553885
Vec::new()
38563886
} else { Vec::new() }
38573887
}
@@ -4116,8 +4146,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
41164146
}
41174147
}
41184148

4119-
self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, conf_height, self.best_block.height, broadcaster, fee_estimator, logger);
4120-
self.onchain_tx_handler.update_claims_view_from_matched_txn(&txn_matched, conf_height, conf_hash, self.best_block.height, broadcaster, fee_estimator, logger);
4149+
let conf_target = self.closure_conf_target();
4150+
self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, conf_height, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
4151+
self.onchain_tx_handler.update_claims_view_from_matched_txn(&txn_matched, conf_height, conf_hash, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
41214152

41224153
// Determine new outputs to watch by comparing against previously known outputs to watch,
41234154
// updating the latter in the process.
@@ -4156,7 +4187,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
41564187
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height < height);
41574188

41584189
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator);
4159-
self.onchain_tx_handler.block_disconnected(height, broadcaster, &bounded_fee_estimator, logger);
4190+
let conf_target = self.closure_conf_target();
4191+
self.onchain_tx_handler.block_disconnected(height, broadcaster, conf_target, &bounded_fee_estimator, logger);
41604192

41614193
self.best_block = BestBlock::new(header.prev_blockhash, height - 1);
41624194
}
@@ -4190,7 +4222,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
41904222

41914223
debug_assert!(!self.onchain_events_awaiting_threshold_conf.iter().any(|ref entry| entry.txid == *txid));
41924224

4193-
self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger);
4225+
let conf_target = self.closure_conf_target();
4226+
self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, conf_target, fee_estimator, logger);
41944227
}
41954228

41964229
/// Filters a block's `txdata` for transactions spending watched outputs or for any child

lightning/src/chain/onchaintx.rs

+20-15
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use bitcoin::secp256k1::PublicKey;
2424
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
2525
use bitcoin::secp256k1;
2626

27-
use crate::chain::chaininterface::compute_feerate_sat_per_1000_weight;
27+
use crate::chain::chaininterface::{ConfirmationTarget, compute_feerate_sat_per_1000_weight};
2828
use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, ChannelSigner, EntropySource, SignerProvider, ecdsa::EcdsaChannelSigner};
2929
use crate::ln::msgs::DecodeError;
3030
use crate::ln::types::PaymentPreimage;
3131
use crate::ln::chan_utils::{self, ChannelTransactionParameters, HTLCOutputInCommitment, HolderCommitmentTransaction};
3232
use crate::chain::ClaimId;
33-
use crate::chain::chaininterface::{ConfirmationTarget, FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
33+
use crate::chain::chaininterface::{FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
3434
use crate::chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
3535
use crate::chain::package::{PackageSolvingData, PackageTemplate};
3636
use crate::chain::transaction::MaybeSignedTransaction;
@@ -487,7 +487,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
487487
/// connections, like on mobile.
488488
pub(super) fn rebroadcast_pending_claims<B: Deref, F: Deref, L: Logger>(
489489
&mut self, current_height: u32, feerate_strategy: FeerateStrategy, broadcaster: &B,
490-
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
490+
conf_target: ConfirmationTarget, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
491491
)
492492
where
493493
B::Target: BroadcasterInterface,
@@ -500,7 +500,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
500500
bump_requests.push((*claim_id, request.clone()));
501501
}
502502
for (claim_id, request) in bump_requests {
503-
self.generate_claim(current_height, &request, &feerate_strategy, fee_estimator, logger)
503+
self.generate_claim(current_height, &request, &feerate_strategy, conf_target, fee_estimator, logger)
504504
.map(|(_, new_feerate, claim)| {
505505
let mut bumped_feerate = false;
506506
if let Some(mut_request) = self.pending_claim_requests.get_mut(&claim_id) {
@@ -552,7 +552,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
552552
/// events are not expected to fail, and if they do, we may lose funds.
553553
fn generate_claim<F: Deref, L: Logger>(
554554
&mut self, cur_height: u32, cached_request: &PackageTemplate, feerate_strategy: &FeerateStrategy,
555-
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
555+
conf_target: ConfirmationTarget, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
556556
) -> Option<(u32, u64, OnchainClaim)>
557557
where F::Target: FeeEstimator,
558558
{
@@ -600,7 +600,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
600600
if cached_request.is_malleable() {
601601
if cached_request.requires_external_funding() {
602602
let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
603-
fee_estimator, ConfirmationTarget::OnChainSweep, feerate_strategy,
603+
fee_estimator, conf_target, feerate_strategy,
604604
);
605605
if let Some(htlcs) = cached_request.construct_malleable_package_with_external_funding(self) {
606606
return Some((
@@ -620,7 +620,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
620620
let predicted_weight = cached_request.package_weight(&self.destination_script);
621621
if let Some((output_value, new_feerate)) = cached_request.compute_package_output(
622622
predicted_weight, self.destination_script.minimal_non_dust().to_sat(),
623-
feerate_strategy, fee_estimator, logger,
623+
feerate_strategy, conf_target, fee_estimator, logger,
624624
) {
625625
assert!(new_feerate != 0);
626626

@@ -650,7 +650,6 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
650650
debug_assert_eq!(tx.0.compute_txid(), self.holder_commitment.trust().txid(),
651651
"Holder commitment transaction mismatch");
652652

653-
let conf_target = ConfirmationTarget::OnChainSweep;
654653
let package_target_feerate_sat_per_1000_weight = cached_request
655654
.compute_package_feerate(fee_estimator, conf_target, feerate_strategy);
656655
if let Some(input_amount_sat) = output.funding_amount {
@@ -728,7 +727,8 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
728727
/// `cur_height`, however it must never be higher than `cur_height`.
729728
pub(super) fn update_claims_view_from_requests<B: Deref, F: Deref, L: Logger>(
730729
&mut self, requests: Vec<PackageTemplate>, conf_height: u32, cur_height: u32,
731-
broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
730+
broadcaster: &B, conf_target: ConfirmationTarget,
731+
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
732732
) where
733733
B::Target: BroadcasterInterface,
734734
F::Target: FeeEstimator,
@@ -798,7 +798,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
798798
// height timer expiration (i.e in how many blocks we're going to take action).
799799
for mut req in preprocessed_requests {
800800
if let Some((new_timer, new_feerate, claim)) = self.generate_claim(
801-
cur_height, &req, &FeerateStrategy::ForceBump, &*fee_estimator, &*logger,
801+
cur_height, &req, &FeerateStrategy::ForceBump, conf_target, &*fee_estimator, &*logger,
802802
) {
803803
req.set_timer(new_timer);
804804
req.set_feerate(new_feerate);
@@ -863,7 +863,8 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
863863
/// provided via `cur_height`, however it must never be higher than `cur_height`.
864864
pub(super) fn update_claims_view_from_matched_txn<B: Deref, F: Deref, L: Logger>(
865865
&mut self, txn_matched: &[&Transaction], conf_height: u32, conf_hash: BlockHash,
866-
cur_height: u32, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
866+
cur_height: u32, broadcaster: &B, conf_target: ConfirmationTarget,
867+
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
867868
) where
868869
B::Target: BroadcasterInterface,
869870
F::Target: FeeEstimator,
@@ -1014,7 +1015,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
10141015

10151016
for (claim_id, request) in bump_candidates.iter() {
10161017
if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
1017-
cur_height, &request, &FeerateStrategy::ForceBump, &*fee_estimator, &*logger,
1018+
cur_height, &request, &FeerateStrategy::ForceBump, conf_target, &*fee_estimator, &*logger,
10181019
) {
10191020
match bump_claim {
10201021
OnchainClaim::Tx(bump_tx) => {
@@ -1049,6 +1050,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
10491050
&mut self,
10501051
txid: &Txid,
10511052
broadcaster: B,
1053+
conf_target: ConfirmationTarget,
10521054
fee_estimator: &LowerBoundedFeeEstimator<F>,
10531055
logger: &L,
10541056
) where
@@ -1064,11 +1066,14 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
10641066
}
10651067

10661068
if let Some(height) = height {
1067-
self.block_disconnected(height, broadcaster, fee_estimator, logger);
1069+
self.block_disconnected(height, broadcaster, conf_target, fee_estimator, logger);
10681070
}
10691071
}
10701072

1071-
pub(super) fn block_disconnected<B: Deref, F: Deref, L: Logger>(&mut self, height: u32, broadcaster: B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L)
1073+
pub(super) fn block_disconnected<B: Deref, F: Deref, L: Logger>(
1074+
&mut self, height: u32, broadcaster: B, conf_target: ConfirmationTarget,
1075+
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
1076+
)
10721077
where B::Target: BroadcasterInterface,
10731078
F::Target: FeeEstimator,
10741079
{
@@ -1100,7 +1105,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
11001105
// `height` is the height being disconnected, so our `current_height` is 1 lower.
11011106
let current_height = height - 1;
11021107
if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
1103-
current_height, &request, &FeerateStrategy::ForceBump, fee_estimator, logger
1108+
current_height, &request, &FeerateStrategy::ForceBump, conf_target, fee_estimator, logger
11041109
) {
11051110
request.set_timer(new_timer);
11061111
request.set_feerate(new_feerate);

0 commit comments

Comments
 (0)