Skip to content

Commit 177e51d

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 86ffea1 commit 177e51d

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;
@@ -834,6 +834,10 @@ struct HTLCStats {
834834
pending_inbound_htlcs_value_msat: u64,
835835
pending_outbound_htlcs_value_msat: u64,
836836
on_counterparty_tx_dust_exposure_msat: u64,
837+
// If the counterparty sets a feerate on the channel in excess of our dust_exposure_limiting_feerate,
838+
// this will be set to the dust exposure that would result from us adding an additional nondust outbound
839+
// htlc on the counterparty's commitment transaction.
840+
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat: Option<u64>,
837841
on_holder_tx_dust_exposure_msat: u64,
838842
outbound_holding_cell_msat: u64,
839843
on_holder_tx_outbound_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included
@@ -3705,27 +3709,21 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37053709
.or(self.pending_update_fee.map(|(fee, _)| fee))
37063710
.unwrap_or(self.feerate_per_kw)
37073711
.checked_sub(dust_exposure_limiting_feerate);
3708-
if let Some(excess_feerate) = excess_feerate_opt {
3709-
let on_counterparty_tx_nondust_htlcs =
3710-
on_counterparty_tx_accepted_nondust_htlcs + on_counterparty_tx_offered_nondust_htlcs;
3711-
on_counterparty_tx_dust_exposure_msat +=
3712-
commit_tx_fee_sat(excess_feerate, on_counterparty_tx_nondust_htlcs, &self.channel_type) * 1000;
3713-
if !self.channel_type.supports_anchors_zero_fee_htlc_tx() {
3714-
on_counterparty_tx_dust_exposure_msat +=
3715-
on_counterparty_tx_accepted_nondust_htlcs as u64 * htlc_success_tx_weight(&self.channel_type)
3716-
* excess_feerate as u64 / 1000;
3717-
on_counterparty_tx_dust_exposure_msat +=
3718-
on_counterparty_tx_offered_nondust_htlcs as u64 * htlc_timeout_tx_weight(&self.channel_type)
3719-
* excess_feerate as u64 / 1000;
3720-
}
3721-
}
3712+
let extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat = excess_feerate_opt.map(|excess_feerate| {
3713+
let extra_htlc_dust_exposure = on_counterparty_tx_dust_exposure_msat
3714+
+ 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;
3715+
on_counterparty_tx_dust_exposure_msat
3716+
+= 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;
3717+
extra_htlc_dust_exposure
3718+
});
37223719

37233720
HTLCStats {
37243721
pending_inbound_htlcs: self.pending_inbound_htlcs.len(),
37253722
pending_outbound_htlcs,
37263723
pending_inbound_htlcs_value_msat,
37273724
pending_outbound_htlcs_value_msat,
37283725
on_counterparty_tx_dust_exposure_msat,
3726+
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat,
37293727
on_holder_tx_dust_exposure_msat,
37303728
outbound_holding_cell_msat,
37313729
on_holder_tx_outbound_holding_cell_htlcs_count,
@@ -3930,13 +3928,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
39303928
context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000)
39313929
};
39323930

3933-
let excess_feerate_opt = self.feerate_per_kw.checked_sub(dust_exposure_limiting_feerate);
3934-
if let Some(excess_feerate) = excess_feerate_opt {
3935-
let htlc_dust_exposure_msat =
3936-
per_outbound_htlc_counterparty_commit_tx_fee_msat(excess_feerate, &context.channel_type);
3937-
let nondust_htlc_counterparty_tx_dust_exposure =
3938-
htlc_stats.on_counterparty_tx_dust_exposure_msat.saturating_add(htlc_dust_exposure_msat);
3939-
if nondust_htlc_counterparty_tx_dust_exposure > max_dust_htlc_exposure_msat {
3931+
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
3932+
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
39403933
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
39413934
// send any non-dust HTLCs.
39423935
available_capacity_msat = cmp::min(available_capacity_msat, htlc_success_dust_limit * 1000);

0 commit comments

Comments
 (0)