Skip to content

Commit 1a8ed2e

Browse files
committed
Abstract the weight of HTLC transactions away from channel
Hence, we let `TxBuilder` set the total endogenous fees spent on a set of HTLC transactions via `htlc_txs_endogenous_fees_sat`. Furthermore, we also let `TxBuilder` set the dust limit for offered and accepted HTLCs on commitment transactions; channel will use those limits when sorting dust HTLCs from non-dust HTLCs. These limits are a function of the weight of HTLC transactions in legacy channels. As a result of this commit, implementers of `TxBuilder` may now set arbitrary dust limits for HTLCs on commitment transactions.
1 parent 42085b9 commit 1a8ed2e

File tree

3 files changed

+69
-139
lines changed

3 files changed

+69
-139
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,6 @@ pub(crate) fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_t
233233
/ 1000
234234
}
235235

236-
#[rustfmt::skip]
237-
pub(crate) fn htlc_tx_fees_sat(feerate_per_kw: u32, num_accepted_htlcs: usize, num_offered_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 {
238-
let htlc_tx_fees_sat = if !channel_type_features.supports_anchors_zero_fee_htlc_tx() {
239-
num_accepted_htlcs as u64 * htlc_success_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000
240-
+ num_offered_htlcs as u64 * htlc_timeout_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000
241-
} else {
242-
0
243-
};
244-
htlc_tx_fees_sat
245-
}
246-
247236
// Various functions for key derivation and transaction creation for use within channels. Primarily
248237
// used in Channel and ChannelMonitor.
249238

lightning/src/ln/channel.rs

Lines changed: 25 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ use crate::ln::chan_utils;
4141
#[cfg(splicing)]
4242
use crate::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
4343
use crate::ln::chan_utils::{
44-
get_commitment_transaction_number_obscure_factor, htlc_success_tx_weight,
45-
htlc_timeout_tx_weight, max_htlcs, ChannelPublicKeys, ChannelTransactionParameters,
46-
ClosingTransaction, CommitmentTransaction, CounterpartyChannelTransactionParameters,
47-
CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HolderCommitmentTransaction,
44+
get_commitment_transaction_number_obscure_factor, max_htlcs, ChannelPublicKeys,
45+
ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction,
46+
CounterpartyChannelTransactionParameters, CounterpartyCommitmentSecrets,
47+
HTLCOutputInCommitment, HolderCommitmentTransaction,
4848
};
4949
use crate::ln::channel_state::{
5050
ChannelShutdownState, CounterpartyForwardingInfo, InboundHTLCDetails, InboundHTLCStateDetails,
@@ -284,27 +284,6 @@ struct InboundHTLCOutput {
284284
state: InboundHTLCState,
285285
}
286286

287-
impl InboundHTLCOutput {
288-
fn is_dust(
289-
&self, local: bool, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
290-
features: &ChannelTypeFeatures,
291-
) -> bool {
292-
let htlc_tx_fee_sat = if features.supports_anchors_zero_fee_htlc_tx() {
293-
0
294-
} else {
295-
let htlc_tx_weight = if !local {
296-
// this is an offered htlc
297-
htlc_timeout_tx_weight(features)
298-
} else {
299-
htlc_success_tx_weight(features)
300-
};
301-
// As required by the spec, round down
302-
feerate_per_kw as u64 * htlc_tx_weight / 1000
303-
};
304-
self.amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
305-
}
306-
}
307-
308287
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
309288
enum OutboundHTLCState {
310289
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
@@ -430,27 +409,6 @@ struct OutboundHTLCOutput {
430409
send_timestamp: Option<Duration>,
431410
}
432411

433-
impl OutboundHTLCOutput {
434-
fn is_dust(
435-
&self, local: bool, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
436-
features: &ChannelTypeFeatures,
437-
) -> bool {
438-
let htlc_tx_fee_sat = if features.supports_anchors_zero_fee_htlc_tx() {
439-
0
440-
} else {
441-
let htlc_tx_weight = if local {
442-
// this is an offered htlc
443-
htlc_timeout_tx_weight(features)
444-
} else {
445-
htlc_success_tx_weight(features)
446-
};
447-
// As required by the spec, round down
448-
feerate_per_kw as u64 * htlc_tx_weight / 1000
449-
};
450-
self.amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
451-
}
452-
}
453-
454412
/// See AwaitingRemoteRevoke ChannelState for more info
455413
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
456414
enum HTLCUpdateAwaitingACK {
@@ -4378,14 +4336,9 @@ where
43784336
on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
43794337
return Err(LocalHTLCFailureReason::DustLimitCounterparty)
43804338
}
4381-
let htlc_success_dust_limit = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4382-
0
4383-
} else {
4384-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
4385-
dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000
4386-
};
4387-
let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
4388-
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
4339+
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
4340+
let (exposure_dust_limit_success_sat, _) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, self.holder_dust_limit_satoshis, funding.get_channel_type());
4341+
if msg.amount_msat / 1000 < exposure_dust_limit_success_sat {
43894342
let on_holder_tx_dust_htlc_exposure_msat = htlc_stats.on_holder_tx_dust_exposure_msat;
43904343
if on_holder_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
43914344
log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
@@ -4466,10 +4419,11 @@ where
44664419
let mut value_to_remote_claimed_msat = 0;
44674420

44684421
let feerate_per_kw = feerate_per_kw.unwrap_or_else(|| self.get_commitment_feerate(funding, generated_by_local));
4422+
let (dust_limit_success_sat, dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type());
44694423

44704424
for htlc in self.pending_inbound_htlcs.iter() {
44714425
if htlc.state.included_in_commitment(generated_by_local) {
4472-
if !htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type()) {
4426+
if htlc.amount_msat >= if local { dust_limit_success_sat } else { dust_limit_timeout_sat } * 1000 {
44734427
nondust_htlc_count += 1;
44744428
}
44754429
remote_htlc_total_msat += htlc.amount_msat;
@@ -4482,7 +4436,7 @@ where
44824436

44834437
for htlc in self.pending_outbound_htlcs.iter() {
44844438
if htlc.state.included_in_commitment(generated_by_local) {
4485-
if !htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type()) {
4439+
if htlc.amount_msat >= if local { dust_limit_timeout_sat } else { dust_limit_success_sat } * 1000 {
44864440
nondust_htlc_count += 1;
44874441
}
44884442
local_htlc_total_msat += htlc.amount_msat;
@@ -4707,15 +4661,10 @@ where
47074661
dust_exposure_limiting_feerate: u32,
47084662
) -> HTLCStats {
47094663
let context = self;
4710-
let uses_0_htlc_fee_anchors = funding.get_channel_type().supports_anchors_zero_fee_htlc_tx();
47114664

47124665
let dust_buffer_feerate = context.get_dust_buffer_feerate(outbound_feerate_update);
4713-
let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if uses_0_htlc_fee_anchors {
4714-
(0, 0)
4715-
} else {
4716-
(dust_buffer_feerate as u64 * htlc_timeout_tx_weight(funding.get_channel_type()) / 1000,
4717-
dust_buffer_feerate as u64 * htlc_success_tx_weight(funding.get_channel_type()) / 1000)
4718-
};
4666+
let (counterparty_dust_limit_success_sat, counterparty_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, context.counterparty_dust_limit_satoshis, funding.get_channel_type());
4667+
let (holder_dust_limit_success_sat, holder_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, context.holder_dust_limit_satoshis, funding.get_channel_type());
47194668

47204669
let mut on_holder_tx_dust_exposure_msat = 0;
47214670
let mut on_counterparty_tx_dust_exposure_msat = 0;
@@ -4726,8 +4675,6 @@ where
47264675
let mut pending_inbound_htlcs_value_msat = 0;
47274676

47284677
{
4729-
let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis;
4730-
let holder_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis;
47314678
for htlc in context.pending_inbound_htlcs.iter() {
47324679
pending_inbound_htlcs_value_msat += htlc.amount_msat;
47334680
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
@@ -4746,8 +4693,6 @@ where
47464693
let mut on_holder_tx_outbound_holding_cell_htlcs_count = 0;
47474694
let mut pending_outbound_htlcs = self.pending_outbound_htlcs.len();
47484695
{
4749-
let counterparty_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis;
4750-
let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.holder_dust_limit_satoshis;
47514696
for htlc in context.pending_outbound_htlcs.iter() {
47524697
pending_outbound_htlcs_value_msat += htlc.amount_msat;
47534698
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
@@ -4786,10 +4731,10 @@ where
47864731
.checked_sub(dust_exposure_limiting_feerate);
47874732
let extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat = excess_feerate_opt.map(|excess_feerate| {
47884733
let extra_htlc_commit_tx_fee_sat = SpecTxBuilder {}.commit_tx_fee_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs + 1 + on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
4789-
let extra_htlc_htlc_tx_fees_sat = chan_utils::htlc_tx_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs + 1, on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
4734+
let extra_htlc_htlc_tx_fees_sat = SpecTxBuilder {}.htlc_txs_endogenous_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs + 1, on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
47904735

47914736
let commit_tx_fee_sat = SpecTxBuilder {}.commit_tx_fee_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs + on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
4792-
let htlc_tx_fees_sat = chan_utils::htlc_tx_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs, on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
4737+
let htlc_tx_fees_sat = SpecTxBuilder {}.htlc_txs_endogenous_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs, on_counterparty_tx_offered_nondust_htlcs, funding.get_channel_type());
47934738

47944739
let extra_htlc_dust_exposure = on_counterparty_tx_dust_exposure_msat + (extra_htlc_commit_tx_fee_sat + extra_htlc_htlc_tx_fees_sat) * 1000;
47954740
on_counterparty_tx_dust_exposure_msat += (commit_tx_fee_sat + htlc_tx_fees_sat) * 1000;
@@ -4838,13 +4783,8 @@ where
48384783
}
48394784
}
48404785
let mut inbound_details = Vec::new();
4841-
let htlc_success_dust_limit = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4842-
0
4843-
} else {
4844-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
4845-
dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000
4846-
};
4847-
let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
4786+
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
4787+
let (holder_dust_limit_success_sat, _) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, self.holder_dust_limit_satoshis, funding.get_channel_type());
48484788
for htlc in self.pending_inbound_htlcs.iter() {
48494789
if let Some(state_details) = (&htlc.state).into() {
48504790
inbound_details.push(InboundHTLCDetails{
@@ -4864,13 +4804,8 @@ where
48644804
#[rustfmt::skip]
48654805
pub fn get_pending_outbound_htlc_details(&self, funding: &FundingScope) -> Vec<OutboundHTLCDetails> {
48664806
let mut outbound_details = Vec::new();
4867-
let htlc_timeout_dust_limit = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4868-
0
4869-
} else {
4870-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
4871-
dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000
4872-
};
4873-
let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
4807+
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
4808+
let (_, holder_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, self.holder_dust_limit_satoshis, funding.get_channel_type());
48744809
for htlc in self.pending_outbound_htlcs.iter() {
48754810
outbound_details.push(OutboundHTLCDetails{
48764811
htlc_id: Some(htlc.htlc_id),
@@ -4932,6 +4867,8 @@ where
49324867

49334868
let mut available_capacity_msat = outbound_capacity_msat;
49344869

4870+
let (real_dust_limit_success_sat, real_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(context.feerate_per_kw, context.holder_dust_limit_satoshis, funding.get_channel_type());
4871+
49354872
if funding.is_outbound() {
49364873
// We should mind channel commit tx fee when computing how much of the available capacity
49374874
// can be used in the next htlc. Mirrors the logic in send_htlc.
@@ -4940,10 +4877,6 @@ where
49404877
// and the answer will in turn change the amount itself — making it a circular
49414878
// dependency.
49424879
// This complicates the computation around dust-values, up to the one-htlc-value.
4943-
let mut real_dust_limit_timeout_sat = context.holder_dust_limit_satoshis;
4944-
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4945-
real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(funding.get_channel_type()) / 1000;
4946-
}
49474880

49484881
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
49494882
let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(funding, htlc_above_dust, Some(()));
@@ -4971,11 +4904,6 @@ where
49714904
} else {
49724905
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
49734906
// sending a new HTLC won't reduce their balance below our reserve threshold.
4974-
let mut real_dust_limit_success_sat = context.counterparty_dust_limit_satoshis;
4975-
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4976-
real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(funding.get_channel_type()) / 1000;
4977-
}
4978-
49794907
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
49804908
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, Some(htlc_above_dust), None);
49814909

@@ -4997,13 +4925,9 @@ where
49974925
let mut dust_exposure_dust_limit_msat = 0;
49984926
let max_dust_htlc_exposure_msat = context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
49994927

5000-
let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5001-
(context.counterparty_dust_limit_satoshis, context.holder_dust_limit_satoshis)
5002-
} else {
5003-
let dust_buffer_feerate = context.get_dust_buffer_feerate(None) as u64;
5004-
(context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000,
5005-
context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(funding.get_channel_type()) / 1000)
5006-
};
4928+
let dust_buffer_feerate = context.get_dust_buffer_feerate(None);
4929+
let (htlc_success_dust_limit, _) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, context.counterparty_dust_limit_satoshis, funding.get_channel_type());
4930+
let (_, htlc_timeout_dust_limit) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(dust_buffer_feerate, context.holder_dust_limit_satoshis, funding.get_channel_type());
50074931

50084932
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
50094933
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
@@ -5069,14 +4993,7 @@ where
50694993
let context = self;
50704994
assert!(funding.is_outbound());
50714995

5072-
let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5073-
(0, 0)
5074-
} else {
5075-
(context.feerate_per_kw as u64 * htlc_success_tx_weight(funding.get_channel_type()) / 1000,
5076-
context.feerate_per_kw as u64 * htlc_timeout_tx_weight(funding.get_channel_type()) / 1000)
5077-
};
5078-
let real_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis;
5079-
let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.holder_dust_limit_satoshis;
4996+
let (real_dust_limit_success_sat, real_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(context.feerate_per_kw, context.holder_dust_limit_satoshis, funding.get_channel_type());
50804997

50814998
let mut addl_htlcs = 0;
50824999
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
@@ -5178,14 +5095,7 @@ where
51785095
let context = self;
51795096
assert!(!funding.is_outbound());
51805097

5181-
let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5182-
(0, 0)
5183-
} else {
5184-
(context.feerate_per_kw as u64 * htlc_success_tx_weight(funding.get_channel_type()) / 1000,
5185-
context.feerate_per_kw as u64 * htlc_timeout_tx_weight(funding.get_channel_type()) / 1000)
5186-
};
5187-
let real_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis;
5188-
let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis;
5098+
let (real_dust_limit_success_sat, real_dust_limit_timeout_sat) = SpecTxBuilder {}.htlc_success_timeout_dust_limits(context.feerate_per_kw, context.counterparty_dust_limit_satoshis, funding.get_channel_type());
51895099

51905100
let mut addl_htlcs = 0;
51915101
if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }

lightning/src/sign/tx_builder.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ use crate::types::features::ChannelTypeFeatures;
1414
use crate::util::logger::Logger;
1515

1616
pub(crate) trait TxBuilder {
17+
fn htlc_success_timeout_dust_limits(
18+
&self, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
19+
channel_type: &ChannelTypeFeatures,
20+
) -> (u64, u64);
1721
fn commit_tx_fee_sat(
1822
&self, feerate_per_kw: u32, nondust_htlc_count: usize, channel_type: &ChannelTypeFeatures,
1923
) -> u64;
24+
fn htlc_txs_endogenous_fees_sat(
25+
&self, feerate_per_kw: u32, num_accepted_htlcs: usize, num_offered_htlcs: usize,
26+
channel_type_features: &ChannelTypeFeatures,
27+
) -> u64;
2028
fn subtract_non_htlc_outputs(
2129
&self, is_outbound_from_holder: bool, value_to_self_after_htlcs: u64,
2230
value_to_remote_after_htlcs: u64, channel_type: &ChannelTypeFeatures,
@@ -34,11 +42,44 @@ pub(crate) trait TxBuilder {
3442
pub(crate) struct SpecTxBuilder {}
3543

3644
impl TxBuilder for SpecTxBuilder {
45+
fn htlc_success_timeout_dust_limits(
46+
&self, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
47+
channel_type: &ChannelTypeFeatures,
48+
) -> (u64, u64) {
49+
let (htlc_timeout_dust_limit, htlc_success_dust_limit) =
50+
if channel_type.supports_anchors_zero_fee_htlc_tx() {
51+
(0, 0)
52+
} else {
53+
(
54+
feerate_per_kw as u64 * htlc_timeout_tx_weight(channel_type) / 1000,
55+
feerate_per_kw as u64 * htlc_success_tx_weight(channel_type) / 1000,
56+
)
57+
};
58+
(
59+
broadcaster_dust_limit_sat + htlc_success_dust_limit,
60+
broadcaster_dust_limit_sat + htlc_timeout_dust_limit,
61+
)
62+
}
3763
fn commit_tx_fee_sat(
3864
&self, feerate_per_kw: u32, nondust_htlc_count: usize, channel_type: &ChannelTypeFeatures,
3965
) -> u64 {
4066
commit_tx_fee_sat(feerate_per_kw, nondust_htlc_count, channel_type)
4167
}
68+
fn htlc_txs_endogenous_fees_sat(
69+
&self, feerate_per_kw: u32, num_accepted_htlcs: usize, num_offered_htlcs: usize,
70+
channel_type: &ChannelTypeFeatures,
71+
) -> u64 {
72+
let htlc_tx_fees_sat = if !channel_type.supports_anchors_zero_fee_htlc_tx() {
73+
num_accepted_htlcs as u64 * htlc_success_tx_weight(channel_type) * feerate_per_kw as u64
74+
/ 1000 + num_offered_htlcs as u64
75+
* htlc_timeout_tx_weight(channel_type)
76+
* feerate_per_kw as u64
77+
/ 1000
78+
} else {
79+
0
80+
};
81+
htlc_tx_fees_sat
82+
}
4283
fn subtract_non_htlc_outputs(
4384
&self, is_outbound_from_holder: bool, value_to_self_after_htlcs: u64,
4485
value_to_remote_after_htlcs: u64, channel_type: &ChannelTypeFeatures,
@@ -81,21 +122,11 @@ impl TxBuilder for SpecTxBuilder {
81122
{
82123
let mut local_htlc_total_msat = 0;
83124
let mut remote_htlc_total_msat = 0;
84-
let channel_type = &channel_parameters.channel_type_features;
125+
126+
let (dust_limit_success_sat, dust_limit_timeout_sat) = self.htlc_success_timeout_dust_limits(feerate_per_kw, broadcaster_dust_limit_sat, &channel_parameters.channel_type_features);
85127

86128
let is_dust = |offered: bool, amount_msat: u64| -> bool {
87-
let htlc_tx_fee_sat = if channel_type.supports_anchors_zero_fee_htlc_tx() {
88-
0
89-
} else {
90-
let htlc_tx_weight = if offered {
91-
htlc_timeout_tx_weight(channel_type)
92-
} else {
93-
htlc_success_tx_weight(channel_type)
94-
};
95-
// As required by the spec, round down
96-
feerate_per_kw as u64 * htlc_tx_weight / 1000
97-
};
98-
amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
129+
amount_msat / 1000 < if offered { dust_limit_timeout_sat } else { dust_limit_success_sat }
99130
};
100131

101132
// Trim dust htlcs

0 commit comments

Comments
 (0)