Skip to content

Commit 2c89d30

Browse files
committed
For the candidate outbound htlc, sum weights, then sum fees
Previously, we calculated the fee of the commitment transaction with n htlcs, and the fee due to the candidate htlc, rounded the two fees to the lower satoshi, and then summed the fees. This is not equal to how fees of commitment transactions are calculated, which is to add up the total weight of the (n+1) htlc commitment transaction, convert to fee, then round to the lower satoshi. This commit corrects this delta by running the full fee calculation twice, once for the n htlc, and once for the (n+1) htlc counterparty commitment transactions.
1 parent bb658c2 commit 2c89d30

File tree

2 files changed

+24
-30
lines changed

2 files changed

+24
-30
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,16 @@ pub(crate) fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_t
196196
/ 1000
197197
}
198198

199-
pub(crate) fn per_outbound_htlc_counterparty_commit_tx_fee_msat(feerate_per_kw: u32, channel_type_features: &ChannelTypeFeatures) -> u64 {
200-
// Note that we need to divide before multiplying to round properly,
201-
// since the lowest denomination of bitcoin on-chain is the satoshi.
202-
let commitment_tx_fee = COMMITMENT_TX_WEIGHT_PER_HTLC * feerate_per_kw as u64 / 1000 * 1000;
203-
if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
204-
commitment_tx_fee + htlc_success_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000
199+
pub(crate) fn commit_and_htlc_tx_fees_sat(feerate_per_kw: u32, num_accepted_htlcs: usize, num_offered_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 {
200+
let num_htlcs = num_accepted_htlcs + num_offered_htlcs;
201+
let commit_tx_fees_sat = commit_tx_fee_sat(feerate_per_kw, num_htlcs, channel_type_features);
202+
let htlc_tx_fees_sat = if !channel_type_features.supports_anchors_zero_fee_htlc_tx() {
203+
num_accepted_htlcs as u64 * htlc_success_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000
204+
+ num_offered_htlcs as u64 * htlc_timeout_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000
205205
} else {
206-
commitment_tx_fee
207-
}
206+
0
207+
};
208+
commit_tx_fees_sat + htlc_tx_fees_sat
208209
}
209210

210211
// Various functions for key derivation and transaction creation for use within channels. Primarily

lightning/src/ln/channel.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::ln::chan_utils::{
4646
HolderCommitmentTransaction, ChannelTransactionParameters,
4747
CounterpartyChannelTransactionParameters, MAX_HTLCS,
4848
get_commitment_transaction_number_obscure_factor,
49-
ClosingTransaction, commit_tx_fee_sat, per_outbound_htlc_counterparty_commit_tx_fee_msat,
49+
ClosingTransaction, commit_tx_fee_sat,
5050
};
5151
use crate::ln::chan_utils;
5252
use crate::ln::onion_utils::HTLCFailReason;
@@ -833,6 +833,10 @@ struct HTLCStats {
833833
pending_inbound_htlcs_value_msat: u64,
834834
pending_outbound_htlcs_value_msat: u64,
835835
on_counterparty_tx_dust_exposure_msat: u64,
836+
// If the counterparty sets a feerate on the channel in excess of our dust_exposure_limiting_feerate,
837+
// this will be set to the dust exposure that would result from us adding an additional nondust outbound
838+
// htlc on the counterparty's commitment transaction.
839+
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat: Option<u64>,
836840
on_holder_tx_dust_exposure_msat: u64,
837841
outbound_holding_cell_msat: u64,
838842
on_holder_tx_outbound_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included
@@ -3661,27 +3665,21 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
36613665
.or(self.pending_update_fee.map(|(fee, _)| fee))
36623666
.unwrap_or(self.feerate_per_kw)
36633667
.checked_sub(dust_exposure_limiting_feerate);
3664-
if let Some(excess_feerate) = excess_feerate_opt {
3665-
let on_counterparty_tx_nondust_htlcs =
3666-
on_counterparty_tx_accepted_nondust_htlcs + on_counterparty_tx_offered_nondust_htlcs;
3667-
on_counterparty_tx_dust_exposure_msat +=
3668-
commit_tx_fee_sat(excess_feerate, on_counterparty_tx_nondust_htlcs, &self.channel_type) * 1000;
3669-
if !self.channel_type.supports_anchors_zero_fee_htlc_tx() {
3670-
on_counterparty_tx_dust_exposure_msat +=
3671-
on_counterparty_tx_accepted_nondust_htlcs as u64 * htlc_success_tx_weight(&self.channel_type)
3672-
* excess_feerate as u64 / 1000;
3673-
on_counterparty_tx_dust_exposure_msat +=
3674-
on_counterparty_tx_offered_nondust_htlcs as u64 * htlc_timeout_tx_weight(&self.channel_type)
3675-
* excess_feerate as u64 / 1000;
3676-
}
3677-
}
3668+
let extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat = excess_feerate_opt.map(|excess_feerate| {
3669+
let extra_htlc_dust_exposure = on_counterparty_tx_dust_exposure_msat
3670+
+ chan_utils::commit_and_htlc_tx_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs + 1, on_counterparty_tx_offered_nondust_htlcs, &self.channel_type) * 1000;
3671+
on_counterparty_tx_dust_exposure_msat
3672+
+= chan_utils::commit_and_htlc_tx_fees_sat(excess_feerate, on_counterparty_tx_accepted_nondust_htlcs, on_counterparty_tx_offered_nondust_htlcs, &self.channel_type) * 1000;
3673+
extra_htlc_dust_exposure
3674+
});
36783675

36793676
HTLCStats {
36803677
pending_inbound_htlcs: self.pending_inbound_htlcs.len(),
36813678
pending_outbound_htlcs,
36823679
pending_inbound_htlcs_value_msat,
36833680
pending_outbound_htlcs_value_msat,
36843681
on_counterparty_tx_dust_exposure_msat,
3682+
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat,
36853683
on_holder_tx_dust_exposure_msat,
36863684
outbound_holding_cell_msat,
36873685
on_holder_tx_outbound_holding_cell_htlcs_count,
@@ -3884,13 +3882,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38843882
context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000)
38853883
};
38863884

3887-
let excess_feerate_opt = self.feerate_per_kw.checked_sub(dust_exposure_limiting_feerate);
3888-
if let Some(excess_feerate) = excess_feerate_opt {
3889-
let htlc_dust_exposure_msat =
3890-
per_outbound_htlc_counterparty_commit_tx_fee_msat(excess_feerate, &context.channel_type);
3891-
let nondust_htlc_counterparty_tx_dust_exposure =
3892-
htlc_stats.on_counterparty_tx_dust_exposure_msat.saturating_add(htlc_dust_exposure_msat);
3893-
if nondust_htlc_counterparty_tx_dust_exposure > max_dust_htlc_exposure_msat {
3885+
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
3886+
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
38943887
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
38953888
// send any non-dust HTLCs.
38963889
available_capacity_msat = cmp::min(available_capacity_msat, htlc_success_dust_limit * 1000);

0 commit comments

Comments
 (0)