Skip to content

Commit 73686c6

Browse files
committed
More flexible fee rate estimates
1 parent 989304e commit 73686c6

File tree

6 files changed

+57
-62
lines changed

6 files changed

+57
-62
lines changed

lightning/src/chain/chaininterface.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,23 @@ pub trait BroadcasterInterface {
4848
/// estimation.
4949
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
5050
pub enum ConfirmationTarget {
51-
/// We'd like a transaction to confirm in the future, but don't want to commit most of the fees
52-
/// required to do so yet. The remaining fees will come via a Child-Pays-For-Parent (CPFP) fee
53-
/// bump of the transaction.
54-
///
55-
/// The feerate returned should be the absolute minimum feerate required to enter most node
56-
/// mempools across the network. Note that if you are not able to obtain this feerate estimate,
57-
/// you should likely use the furthest-out estimate allowed by your fee estimator.
58-
MempoolMinimum,
59-
/// We are happy with a transaction confirming slowly, at least within a day or so worth of
60-
/// blocks.
61-
Background,
62-
/// We'd like a transaction to confirm without major delayed, i.e., within the next 12-24 blocks.
63-
Normal,
64-
/// We'd like a transaction to confirm in the next few blocks.
65-
HighPriority,
51+
/// We need to sweep an HTLC after a force close transaction. This should be a high priority
52+
/// transaction.
53+
HtlcSweep,
54+
/// The highest fee rate we will allow our channel counterparty to have in a non-anchor channel.
55+
/// Having this be a low value can cause force closures. Using 10x your HighPriority fee rate can
56+
/// be a good default.
57+
MaxAllowedNonAnchorChannelRemoteFee,
58+
/// The lowest fee rate we will allow our channel counterparty to have in a channel. This should
59+
/// be at least the mempool minimum.
60+
MinAllowedChannelRemoteFee,
61+
/// Fee rate to use for anchor channels. This is safe to just be the mempool minimum.
62+
AnchorChannelFee,
63+
/// Fee rate to use for non-anchor channels. A good estimate is within the next 12-24 blocks.
64+
NonAnchorChannelFee,
65+
/// When cooperative closing channel, the minimum fee rate we will accept. Recommended at least
66+
/// within a day or so worth of blocks.
67+
ChannelCloseMinimum,
6668
}
6769

6870
/// A trait which should be implemented to provide feerate information on a number of time
@@ -135,7 +137,7 @@ mod tests {
135137
let test_fee_estimator = &TestFeeEstimator { sat_per_kw };
136138
let fee_estimator = LowerBoundedFeeEstimator::new(test_fee_estimator);
137139

138-
assert_eq!(fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background), FEERATE_FLOOR_SATS_PER_KW);
140+
assert_eq!(fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee), FEERATE_FLOOR_SATS_PER_KW);
139141
}
140142

141143
#[test]
@@ -144,6 +146,6 @@ mod tests {
144146
let test_fee_estimator = &TestFeeEstimator { sat_per_kw };
145147
let fee_estimator = LowerBoundedFeeEstimator::new(test_fee_estimator);
146148

147-
assert_eq!(fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background), sat_per_kw);
149+
assert_eq!(fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee), sat_per_kw);
148150
}
149151
}

lightning/src/chain/onchaintx.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
580580
if cached_request.is_malleable() {
581581
if cached_request.requires_external_funding() {
582582
let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
583-
fee_estimator, ConfirmationTarget::HighPriority, force_feerate_bump
583+
fee_estimator, ConfirmationTarget::HtlcSweep, force_feerate_bump
584584
);
585585
if let Some(htlcs) = cached_request.construct_malleable_package_with_external_funding(self) {
586586
return Some((
@@ -631,7 +631,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
631631
debug_assert_eq!(tx.txid(), self.holder_commitment.trust().txid(),
632632
"Holder commitment transaction mismatch");
633633

634-
let conf_target = ConfirmationTarget::HighPriority;
634+
let conf_target = ConfirmationTarget::HtlcSweep;
635635
let package_target_feerate_sat_per_1000_weight = cached_request
636636
.compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
637637
if let Some(input_amount_sat) = output.funding_amount {

lightning/src/chain/package.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1111,13 +1111,14 @@ fn compute_fee_from_spent_amounts<F: Deref, L: Deref>(input_amounts: u64, predic
11111111
where F::Target: FeeEstimator,
11121112
L::Target: Logger,
11131113
{
1114-
let mut updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
1114+
let mut updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HtlcSweep) as u64;
1115+
let min_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::ChannelCloseMinimum) as u64;
11151116
let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
11161117
if input_amounts <= fee {
1117-
updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
1118+
updated_feerate = cmp::max(min_feerate, updated_feerate / 2);
11181119
fee = updated_feerate * (predicted_weight as u64) / 1000;
11191120
if input_amounts <= fee {
1120-
updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
1121+
updated_feerate = cmp::max(min_feerate, updated_feerate / 2);
11211122
fee = updated_feerate * (predicted_weight as u64) / 1000;
11221123
if input_amounts <= fee {
11231124
log_error!(logger, "Failed to generate an on-chain punishment tx as even low priority fee ({} sat) was more than the entire claim balance ({} sat)",

lightning/src/ln/channel.rs

+11-18
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
11681168
match self.config.options.max_dust_htlc_exposure {
11691169
MaxDustHTLCExposure::FeeRateMultiplier(multiplier) => {
11701170
let feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(
1171-
ConfirmationTarget::HighPriority);
1171+
ConfirmationTarget::HtlcSweep);
11721172
feerate_per_kw as u64 * multiplier
11731173
},
11741174
MaxDustHTLCExposure::FixedLimitMsat(limit) => limit,
@@ -2155,23 +2155,14 @@ impl<SP: Deref> Channel<SP> where
21552155
// apply to channels supporting anchor outputs since HTLC transactions are pre-signed with a
21562156
// zero fee, so their fee is no longer considered to determine dust limits.
21572157
if !channel_type.supports_anchors_zero_fee_htlc_tx() {
2158-
let upper_limit = cmp::max(250 * 25,
2159-
fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 10);
2158+
let upper_limit =
2159+
fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee) as u64;
21602160
if feerate_per_kw as u64 > upper_limit {
21612161
return Err(ChannelError::Close(format!("Peer's feerate much too high. Actual: {}. Our expected upper limit: {}", feerate_per_kw, upper_limit)));
21622162
}
21632163
}
21642164

2165-
// We can afford to use a lower bound with anchors than previously since we can now bump
2166-
// fees when broadcasting our commitment. However, we must still make sure we meet the
2167-
// minimum mempool feerate, until package relay is deployed, such that we can ensure the
2168-
// commitment transaction propagates throughout node mempools on its own.
2169-
let lower_limit_conf_target = if channel_type.supports_anchors_zero_fee_htlc_tx() {
2170-
ConfirmationTarget::MempoolMinimum
2171-
} else {
2172-
ConfirmationTarget::Background
2173-
};
2174-
let lower_limit = fee_estimator.bounded_sat_per_1000_weight(lower_limit_conf_target);
2165+
let lower_limit = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MinAllowedChannelRemoteFee);
21752166
// Some fee estimators round up to the next full sat/vbyte (ie 250 sats per kw), causing
21762167
// occasional issues with feerate disagreements between an initiator that wants a feerate
21772168
// of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250
@@ -4155,8 +4146,10 @@ impl<SP: Deref> Channel<SP> where
41554146
// Propose a range from our current Background feerate to our Normal feerate plus our
41564147
// force_close_avoidance_max_fee_satoshis.
41574148
// If we fail to come to consensus, we'll have to force-close.
4158-
let mut proposed_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background);
4159-
let normal_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
4149+
let mut proposed_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::ChannelCloseMinimum);
4150+
// Use NonAnchorChannelFee because this should be an estimate for a channel close
4151+
// that we don't expect to be need fee bumping
4152+
let normal_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
41604153
let mut proposed_max_feerate = if self.context.is_outbound() { normal_feerate } else { u32::max_value() };
41614154

41624155
// The spec requires that (when the channel does not have anchors) we only send absolute
@@ -5727,9 +5720,9 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
57275720
debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
57285721

57295722
let commitment_conf_target = if channel_type.supports_anchors_zero_fee_htlc_tx() {
5730-
ConfirmationTarget::MempoolMinimum
5723+
ConfirmationTarget::AnchorChannelFee
57315724
} else {
5732-
ConfirmationTarget::Normal
5725+
ConfirmationTarget::NonAnchorChannelFee
57335726
};
57345727
let commitment_feerate = fee_estimator.bounded_sat_per_1000_weight(commitment_conf_target);
57355728

@@ -6019,7 +6012,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60196012
// whatever reason.
60206013
if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() {
60216014
self.context.channel_type.clear_anchors_zero_fee_htlc_tx();
6022-
self.context.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
6015+
self.context.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
60236016
assert!(!self.context.channel_transaction_parameters.channel_type_features.supports_anchors_nonzero_fee_htlc_tx());
60246017
} else if self.context.channel_type.supports_scid_privacy() {
60256018
self.context.channel_type.clear_scid_privacy();

lightning/src/ln/channelmanager.rs

+16-17
Original file line numberDiff line numberDiff line change
@@ -2638,9 +2638,9 @@ where
26382638
/// will be accepted on the given channel, and after additional timeout/the closing of all
26392639
/// pending HTLCs, the channel will be closed on chain.
26402640
///
2641-
/// * If we are the channel initiator, we will pay between our [`Background`] and
2642-
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`] plus our [`Normal`] fee
2643-
/// estimate.
2641+
/// * If we are the channel initiator, we will pay between our [`ChannelCloseMinimum`] and
2642+
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`] plus our [`NonAnchorChannelFee`]
2643+
/// fee estimate.
26442644
/// * If our counterparty is the channel initiator, we will require a channel closing
26452645
/// transaction feerate of at least our [`Background`] feerate or the feerate which
26462646
/// would appear on a force-closure transaction, whichever is lower. We will allow our
@@ -2654,8 +2654,8 @@ where
26542654
/// channel.
26552655
///
26562656
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis
2657-
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
2658-
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
2657+
/// [`ChannelCloseMinimum`]: crate::chain::chaininterface::ConfirmationTarget::ChannelCloseMinimum
2658+
/// [`NonAnchorChannelFee`]: crate::chain::chaininterface::ConfirmationTarget::NonAnchorChannelFee
26592659
/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
26602660
pub fn close_channel(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey) -> Result<(), APIError> {
26612661
self.close_channel_internal(channel_id, counterparty_node_id, None, None)
@@ -2669,8 +2669,8 @@ where
26692669
/// the channel being closed or not:
26702670
/// * If we are the channel initiator, we will pay at least this feerate on the closing
26712671
/// transaction. The upper-bound is set by
2672-
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`] plus our [`Normal`] fee
2673-
/// estimate (or `target_feerate_sat_per_1000_weight`, if it is greater).
2672+
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`] plus our [`NonAnchorChannelFee`]
2673+
/// fee estimate (or `target_feerate_sat_per_1000_weight`, if it is greater).
26742674
/// * If our counterparty is the channel initiator, we will refuse to accept a channel closure
26752675
/// transaction feerate below `target_feerate_sat_per_1000_weight` (or the feerate which
26762676
/// will appear on a force-closure transaction, whichever is lower).
@@ -2688,8 +2688,7 @@ where
26882688
/// channel.
26892689
///
26902690
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis
2691-
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
2692-
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
2691+
/// [`NonAnchorChannelFee`]: crate::chain::chaininterface::ConfirmationTarget::NonAnchorChannelFee
26932692
/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
26942693
pub fn close_channel_with_feerate_and_script(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
26952694
self.close_channel_internal(channel_id, counterparty_node_id, target_feerate_sats_per_1000_weight, shutdown_script)
@@ -4752,8 +4751,8 @@ where
47524751
PersistenceNotifierGuard::optionally_notify(self, || {
47534752
let mut should_persist = NotifyOption::SkipPersistNoEvents;
47544753

4755-
let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
4756-
let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
4754+
let non_anchor_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
4755+
let anchor_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee);
47574756

47584757
let per_peer_state = self.per_peer_state.read().unwrap();
47594758
for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
@@ -4763,9 +4762,9 @@ where
47634762
|(chan_id, phase)| if let ChannelPhase::Funded(chan) = phase { Some((chan_id, chan)) } else { None }
47644763
) {
47654764
let new_feerate = if chan.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4766-
min_mempool_feerate
4765+
anchor_feerate
47674766
} else {
4768-
normal_feerate
4767+
non_anchor_feerate
47694768
};
47704769
let chan_needs_persist = self.update_channel_fee(chan_id, chan, new_feerate);
47714770
if chan_needs_persist == NotifyOption::DoPersist { should_persist = NotifyOption::DoPersist; }
@@ -4797,8 +4796,8 @@ where
47974796
PersistenceNotifierGuard::optionally_notify(self, || {
47984797
let mut should_persist = NotifyOption::SkipPersistNoEvents;
47994798

4800-
let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
4801-
let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
4799+
let non_anchor_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
4800+
let anchor_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee);
48024801

48034802
let mut handle_errors: Vec<(Result<(), _>, _)> = Vec::new();
48044803
let mut timed_out_mpp_htlcs = Vec::new();
@@ -4845,9 +4844,9 @@ where
48454844
match phase {
48464845
ChannelPhase::Funded(chan) => {
48474846
let new_feerate = if chan.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4848-
min_mempool_feerate
4847+
anchor_feerate
48494848
} else {
4850-
normal_feerate
4849+
non_anchor_feerate
48514850
};
48524851
let chan_needs_persist = self.update_channel_fee(chan_id, chan, new_feerate);
48534852
if chan_needs_persist == NotifyOption::DoPersist { should_persist = NotifyOption::DoPersist; }

lightning/src/util/config.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -438,20 +438,20 @@ pub struct ChannelConfig {
438438
/// funder/initiator.
439439
///
440440
/// When we are the funder, because we have to pay the channel closing fee, we bound the
441-
/// acceptable fee by our [`Background`] and [`Normal`] fees, with the upper bound increased by
441+
/// acceptable fee by our [`ChannelCloseMinimum`] and [`NonAnchorChannelFee`] fees, with the upper bound increased by
442442
/// this value. Because the on-chain fee we'd pay to force-close the channel is kept near our
443-
/// [`Normal`] feerate during normal operation, this value represents the additional fee we're
443+
/// [`NonAnchorChannelFee`] feerate during normal operation, this value represents the additional fee we're
444444
/// willing to pay in order to avoid waiting for our counterparty's to_self_delay to reclaim our
445445
/// funds.
446446
///
447447
/// When we are not the funder, we require the closing transaction fee pay at least our
448-
/// [`Background`] fee estimate, but allow our counterparty to pay as much fee as they like.
448+
/// [`ChannelCloseMinimum`] fee estimate, but allow our counterparty to pay as much fee as they like.
449449
/// Thus, this value is ignored when we are not the funder.
450450
///
451451
/// Default value: 1000 satoshis.
452452
///
453-
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
454-
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
453+
/// [`NonAnchorChannelFee`]: crate::chain::chaininterface::ConfirmationTarget::NonAnchorChannelFee
454+
/// [`ChannelCloseMinimum`]: crate::chain::chaininterface::ConfirmationTarget::ChannelCloseMinimum
455455
pub force_close_avoidance_max_fee_satoshis: u64,
456456
/// If set, allows this channel's counterparty to skim an additional fee off this node's inbound
457457
/// HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.

0 commit comments

Comments
 (0)