Skip to content

Commit d0cf6c8

Browse files
committed
Use TxBuilder::get_next_commitment_stats to get AvailableBalances
Also move things around to make the move in the next commit as straightforward as possible. We take the conservative route here and include all pending HTLCs, including those in the holding cell, no matter their state.
1 parent e3ee0c0 commit d0cf6c8

File tree

2 files changed

+53
-39
lines changed

2 files changed

+53
-39
lines changed

lightning/src/ln/channel.rs

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5090,57 +5090,73 @@ where
50905090
where
50915091
F::Target: FeeEstimator,
50925092
{
5093-
let context = &self;
5093+
use crate::sign::tx_builder::get_dust_buffer_feerate;
5094+
50945095
let holder_channel_constraints = self.get_holder_channel_constraints(funding);
50955096
let counterparty_channel_constraints = self.get_counterparty_channel_constraints(funding);
50965097
// Note that we have to handle overflow due to the case mentioned in the docs in general
50975098
// here.
50985099

5100+
let pending_outbound_htlcs = self.pending_outbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: true });
5101+
let pending_inbound_htlcs = self.pending_inbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: false });
5102+
let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| {
5103+
if let &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } = htlc {
5104+
Some(HTLCAmountDirection { outbound: true, amount_msat })
5105+
} else {
5106+
None
5107+
}
5108+
});
5109+
5110+
let mut pending_htlcs: Vec<HTLCAmountDirection> = Vec::with_capacity(self.pending_outbound_htlcs.len() + self.pending_inbound_htlcs.len() + self.holding_cell_htlc_updates.len());
5111+
pending_htlcs.extend(pending_outbound_htlcs.chain(pending_inbound_htlcs).chain(holding_cell_htlcs));
5112+
let pending_htlcs = &pending_htlcs;
5113+
50995114
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
51005115
&fee_estimator, funding.get_channel_type(),
51015116
);
5102-
let htlc_stats = context.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
5117+
let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
51035118

5104-
// Subtract any non-HTLC outputs from the local and remote balances
5105-
let (local_balance_before_fee_msat, remote_balance_before_fee_msat) = SpecTxBuilder {}.subtract_non_htlc_outputs(
5106-
funding.is_outbound(),
5107-
funding.value_to_self_msat.saturating_sub(htlc_stats.pending_outbound_htlcs_value_msat),
5108-
(funding.get_value_satoshis() * 1000).checked_sub(funding.value_to_self_msat).unwrap().saturating_sub(htlc_stats.pending_inbound_htlcs_value_msat),
5109-
funding.get_channel_type(),
5110-
);
5119+
let is_outbound_from_holder = funding.is_outbound();
5120+
let channel_value_satoshis = funding.get_value_satoshis();
5121+
let value_to_holder_msat = funding.get_value_to_self_msat();
5122+
let feerate_per_kw = self.feerate_per_kw;
5123+
let channel_type = funding.get_channel_type();
5124+
5125+
let fee_spike_buffer_htlc = if channel_type.supports_anchor_zero_fee_commitments() {
5126+
0
5127+
} else {
5128+
1
5129+
};
5130+
5131+
let local_stats_max_fee = SpecTxBuilder {}.get_next_commitment_stats(true, is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, fee_spike_buffer_htlc + 1, feerate_per_kw, dust_exposure_limiting_feerate, holder_channel_constraints.dust_limit_satoshis, channel_type);
5132+
let local_stats_min_fee = SpecTxBuilder {}.get_next_commitment_stats(true, is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, fee_spike_buffer_htlc, feerate_per_kw, dust_exposure_limiting_feerate, holder_channel_constraints.dust_limit_satoshis, channel_type);
5133+
let remote_stats = SpecTxBuilder {}.get_next_commitment_stats(false, is_outbound_from_holder, channel_value_satoshis, value_to_holder_msat, pending_htlcs, 1, feerate_per_kw, dust_exposure_limiting_feerate, counterparty_channel_constraints.dust_limit_satoshis, channel_type);
51115134

5112-
let outbound_capacity_msat = local_balance_before_fee_msat
5135+
let outbound_capacity_msat = local_stats_max_fee.holder_balance_before_fee_msat.unwrap_or(0)
51135136
.saturating_sub(
51145137
holder_channel_constraints.channel_reserve_satoshis * 1000);
51155138

51165139
let mut available_capacity_msat = outbound_capacity_msat;
51175140
let (real_htlc_success_tx_fee_sat, real_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5118-
funding.get_channel_type(), context.feerate_per_kw,
5141+
channel_type, feerate_per_kw
51195142
);
51205143

5121-
if funding.is_outbound() {
5144+
if is_outbound_from_holder {
51225145
// We should mind channel commit tx fee when computing how much of the available capacity
51235146
// can be used in the next htlc. Mirrors the logic in send_htlc.
51245147
//
51255148
// The fee depends on whether the amount we will be sending is above dust or not,
51265149
// and the answer will in turn change the amount itself — making it a circular
51275150
// dependency.
51285151
// This complicates the computation around dust-values, up to the one-htlc-value.
5129-
let fee_spike_buffer_htlc = if funding.get_channel_type().supports_anchor_zero_fee_commitments() {
5130-
None
5131-
} else {
5132-
Some(())
5133-
};
51345152

51355153
let real_dust_limit_timeout_sat = real_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
5136-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
5137-
let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_above_dust, fee_spike_buffer_htlc);
5138-
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
5139-
let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_dust, fee_spike_buffer_htlc);
5154+
let mut max_reserved_commit_tx_fee_msat = local_stats_max_fee.commit_tx_fee_sat * 1000;
5155+
let mut min_reserved_commit_tx_fee_msat = local_stats_min_fee.commit_tx_fee_sat * 1000;
51405156

5141-
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5142-
max_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5143-
min_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5157+
if !channel_type.supports_anchors_zero_fee_htlc_tx() {
5158+
max_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5159+
min_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
51445160
}
51455161

51465162
// We will first subtract the fee as if we were above-dust. Then, if the resulting
@@ -5157,11 +5173,10 @@ where
51575173
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
51585174
// sending a new HTLC won't reduce their balance below our reserve threshold.
51595175
let real_dust_limit_success_sat = real_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
5160-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
5161-
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, Some(htlc_above_dust), None);
5176+
let max_reserved_commit_tx_fee_msat = remote_stats.commit_tx_fee_sat * 1000;
51625177

51635178
let holder_selected_chan_reserve_msat = counterparty_channel_constraints.channel_reserve_satoshis * 1000;
5164-
if remote_balance_before_fee_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
5179+
if remote_stats.counterparty_balance_before_fee_msat.unwrap_or(0) < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
51655180
// If another HTLC's fee would reduce the remote's balance below the reserve limit
51665181
// we've selected for them, we can only send dust HTLCs.
51675182
available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1);
@@ -5176,35 +5191,34 @@ where
51765191
// send above the dust limit (as the router can always overpay to meet the dust limit).
51775192
let mut remaining_msat_below_dust_exposure_limit = None;
51785193
let mut dust_exposure_dust_limit_msat = 0;
5179-
let max_dust_htlc_exposure_msat = context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
51805194

5181-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
5195+
let dust_buffer_feerate = get_dust_buffer_feerate(feerate_per_kw);
51825196
let (buffer_htlc_success_tx_fee_sat, buffer_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5183-
funding.get_channel_type(), dust_buffer_feerate,
5197+
channel_type, dust_buffer_feerate,
51845198
);
51855199
let buffer_dust_limit_success_sat = buffer_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
51865200
let buffer_dust_limit_timeout_sat = buffer_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
51875201

5188-
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
5202+
if let Some(extra_htlc_dust_exposure) = remote_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
51895203
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
51905204
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
51915205
// send any non-dust HTLCs.
51925206
available_capacity_msat = cmp::min(available_capacity_msat, buffer_dust_limit_success_sat * 1000);
51935207
}
51945208
}
51955209

5196-
if htlc_stats.on_counterparty_tx_dust_exposure_msat.saturating_add(buffer_dust_limit_success_sat * 1000) > max_dust_htlc_exposure_msat.saturating_add(1) {
5210+
if remote_stats.dust_exposure_msat.saturating_add(buffer_dust_limit_success_sat * 1000) > max_dust_htlc_exposure_msat.saturating_add(1) {
51975211
// Note that we don't use the `counterparty_tx_dust_exposure` (with
51985212
// `htlc_dust_exposure_msat`) here as it only applies to non-dust HTLCs.
51995213
remaining_msat_below_dust_exposure_limit =
5200-
Some(max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_counterparty_tx_dust_exposure_msat));
5214+
Some(max_dust_htlc_exposure_msat.saturating_sub(remote_stats.dust_exposure_msat));
52015215
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_success_sat * 1000);
52025216
}
52035217

5204-
if htlc_stats.on_holder_tx_dust_exposure_msat as i64 + buffer_dust_limit_timeout_sat as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) {
5218+
if local_stats_max_fee.dust_exposure_msat as i64 + buffer_dust_limit_timeout_sat as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) {
52055219
remaining_msat_below_dust_exposure_limit = Some(cmp::min(
52065220
remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
5207-
max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_holder_tx_dust_exposure_msat)));
5221+
max_dust_htlc_exposure_msat.saturating_sub(local_stats_max_fee.dust_exposure_msat)));
52085222
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_timeout_sat * 1000);
52095223
}
52105224

@@ -5217,15 +5231,15 @@ where
52175231
}
52185232

52195233
available_capacity_msat = cmp::min(available_capacity_msat,
5220-
counterparty_channel_constraints.max_htlc_value_in_flight_msat - htlc_stats.pending_outbound_htlcs_value_msat);
5234+
counterparty_channel_constraints.max_htlc_value_in_flight_msat - pending_htlcs.iter().filter(|htlc| htlc.outbound).map(|htlc| htlc.amount_msat).sum::<u64>());
52215235

5222-
if htlc_stats.pending_outbound_htlcs + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
5236+
if pending_htlcs.iter().filter(|htlc| htlc.outbound).count() + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
52235237
available_capacity_msat = 0;
52245238
}
52255239

52265240
#[allow(deprecated)] // TODO: Remove once balance_msat is removed.
52275241
AvailableBalances {
5228-
inbound_capacity_msat: remote_balance_before_fee_msat.saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
5242+
inbound_capacity_msat: remote_stats.counterparty_balance_before_fee_msat.unwrap_or(0).saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
52295243
outbound_capacity_msat,
52305244
next_outbound_htlc_limit_msat: available_capacity_msat,
52315245
next_outbound_htlc_minimum_msat,

lightning/src/sign/tx_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn subtract_addl_outputs(
106106
(local_balance_before_fee_msat, remote_balance_before_fee_msat)
107107
}
108108

109-
fn get_dust_buffer_feerate(feerate_per_kw: u32) -> u32 {
109+
pub(crate) fn get_dust_buffer_feerate(feerate_per_kw: u32) -> u32 {
110110
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
111111
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
112112
// whichever is higher. This ensures that we aren't suddenly exposed to significantly

0 commit comments

Comments
 (0)