Skip to content

Commit db1b4af

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 f8f43c8 commit db1b4af

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
@@ -5085,57 +5085,73 @@ where
50855085
where
50865086
F::Target: FeeEstimator,
50875087
{
5088-
let context = &self;
5088+
use crate::sign::tx_builder::get_dust_buffer_feerate;
5089+
50895090
let holder_channel_constraints = self.get_holder_channel_constraints(funding);
50905091
let counterparty_channel_constraints = self.get_counterparty_channel_constraints(funding);
50915092
// Note that we have to handle overflow due to the case mentioned in the docs in general
50925093
// here.
50935094

5095+
let pending_outbound_htlcs = self.pending_outbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: true });
5096+
let pending_inbound_htlcs = self.pending_inbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: false });
5097+
let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| {
5098+
if let &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } = htlc {
5099+
Some(HTLCAmountDirection { outbound: true, amount_msat })
5100+
} else {
5101+
None
5102+
}
5103+
});
5104+
5105+
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());
5106+
pending_htlcs.extend(pending_outbound_htlcs.chain(pending_inbound_htlcs).chain(holding_cell_htlcs));
5107+
let pending_htlcs = &pending_htlcs;
5108+
50945109
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
50955110
&fee_estimator, funding.get_channel_type(),
50965111
);
5097-
let htlc_stats = context.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
5112+
let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
50985113

5099-
// Subtract any non-HTLC outputs from the local and remote balances
5100-
let (local_balance_before_fee_msat, remote_balance_before_fee_msat) = SpecTxBuilder {}.subtract_non_htlc_outputs(
5101-
funding.is_outbound(),
5102-
funding.value_to_self_msat.saturating_sub(htlc_stats.pending_outbound_htlcs_value_msat),
5103-
(funding.get_value_satoshis() * 1000).checked_sub(funding.value_to_self_msat).unwrap().saturating_sub(htlc_stats.pending_inbound_htlcs_value_msat),
5104-
funding.get_channel_type(),
5105-
);
5114+
let is_outbound_from_holder = funding.is_outbound();
5115+
let channel_value_satoshis = funding.get_value_satoshis();
5116+
let value_to_holder_msat = funding.get_value_to_self_msat();
5117+
let feerate_per_kw = self.feerate_per_kw;
5118+
let channel_type = funding.get_channel_type();
5119+
5120+
let fee_spike_buffer_htlc = if channel_type.supports_anchor_zero_fee_commitments() {
5121+
0
5122+
} else {
5123+
1
5124+
};
5125+
5126+
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);
5127+
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);
5128+
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);
51065129

5107-
let outbound_capacity_msat = local_balance_before_fee_msat
5130+
let outbound_capacity_msat = local_stats_max_fee.holder_balance_before_fee_msat.unwrap_or(0)
51085131
.saturating_sub(
51095132
holder_channel_constraints.channel_reserve_satoshis * 1000);
51105133

51115134
let mut available_capacity_msat = outbound_capacity_msat;
51125135
let (real_htlc_success_tx_fee_sat, real_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5113-
funding.get_channel_type(), context.feerate_per_kw,
5136+
channel_type, feerate_per_kw
51145137
);
51155138

5116-
if funding.is_outbound() {
5139+
if is_outbound_from_holder {
51175140
// We should mind channel commit tx fee when computing how much of the available capacity
51185141
// can be used in the next htlc. Mirrors the logic in send_htlc.
51195142
//
51205143
// The fee depends on whether the amount we will be sending is above dust or not,
51215144
// and the answer will in turn change the amount itself — making it a circular
51225145
// dependency.
51235146
// This complicates the computation around dust-values, up to the one-htlc-value.
5124-
let fee_spike_buffer_htlc = if funding.get_channel_type().supports_anchor_zero_fee_commitments() {
5125-
None
5126-
} else {
5127-
Some(())
5128-
};
51295147

51305148
let real_dust_limit_timeout_sat = real_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
5131-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
5132-
let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_above_dust, fee_spike_buffer_htlc);
5133-
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
5134-
let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_dust, fee_spike_buffer_htlc);
5149+
let mut max_reserved_commit_tx_fee_msat = local_stats_max_fee.commit_tx_fee_sat * 1000;
5150+
let mut min_reserved_commit_tx_fee_msat = local_stats_min_fee.commit_tx_fee_sat * 1000;
51355151

5136-
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5137-
max_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5138-
min_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5152+
if !channel_type.supports_anchors_zero_fee_htlc_tx() {
5153+
max_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5154+
min_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
51395155
}
51405156

51415157
// We will first subtract the fee as if we were above-dust. Then, if the resulting
@@ -5152,11 +5168,10 @@ where
51525168
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
51535169
// sending a new HTLC won't reduce their balance below our reserve threshold.
51545170
let real_dust_limit_success_sat = real_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
5155-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
5156-
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, Some(htlc_above_dust), None);
5171+
let max_reserved_commit_tx_fee_msat = remote_stats.commit_tx_fee_sat * 1000;
51575172

51585173
let holder_selected_chan_reserve_msat = counterparty_channel_constraints.channel_reserve_satoshis * 1000;
5159-
if remote_balance_before_fee_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
5174+
if remote_stats.counterparty_balance_before_fee_msat.unwrap_or(0) < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
51605175
// If another HTLC's fee would reduce the remote's balance below the reserve limit
51615176
// we've selected for them, we can only send dust HTLCs.
51625177
available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1);
@@ -5171,35 +5186,34 @@ where
51715186
// send above the dust limit (as the router can always overpay to meet the dust limit).
51725187
let mut remaining_msat_below_dust_exposure_limit = None;
51735188
let mut dust_exposure_dust_limit_msat = 0;
5174-
let max_dust_htlc_exposure_msat = context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
51755189

5176-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
5190+
let dust_buffer_feerate = get_dust_buffer_feerate(feerate_per_kw);
51775191
let (buffer_htlc_success_tx_fee_sat, buffer_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5178-
funding.get_channel_type(), dust_buffer_feerate,
5192+
channel_type, dust_buffer_feerate,
51795193
);
51805194
let buffer_dust_limit_success_sat = buffer_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
51815195
let buffer_dust_limit_timeout_sat = buffer_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
51825196

5183-
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
5197+
if let Some(extra_htlc_dust_exposure) = remote_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
51845198
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
51855199
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
51865200
// send any non-dust HTLCs.
51875201
available_capacity_msat = cmp::min(available_capacity_msat, buffer_dust_limit_success_sat * 1000);
51885202
}
51895203
}
51905204

5191-
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) {
5205+
if remote_stats.dust_exposure_msat.saturating_add(buffer_dust_limit_success_sat * 1000) > max_dust_htlc_exposure_msat.saturating_add(1) {
51925206
// Note that we don't use the `counterparty_tx_dust_exposure` (with
51935207
// `htlc_dust_exposure_msat`) here as it only applies to non-dust HTLCs.
51945208
remaining_msat_below_dust_exposure_limit =
5195-
Some(max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_counterparty_tx_dust_exposure_msat));
5209+
Some(max_dust_htlc_exposure_msat.saturating_sub(remote_stats.dust_exposure_msat));
51965210
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_success_sat * 1000);
51975211
}
51985212

5199-
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()) {
5213+
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()) {
52005214
remaining_msat_below_dust_exposure_limit = Some(cmp::min(
52015215
remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
5202-
max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_holder_tx_dust_exposure_msat)));
5216+
max_dust_htlc_exposure_msat.saturating_sub(local_stats_max_fee.dust_exposure_msat)));
52035217
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_timeout_sat * 1000);
52045218
}
52055219

@@ -5212,15 +5226,15 @@ where
52125226
}
52135227

52145228
available_capacity_msat = cmp::min(available_capacity_msat,
5215-
counterparty_channel_constraints.max_htlc_value_in_flight_msat - htlc_stats.pending_outbound_htlcs_value_msat);
5229+
counterparty_channel_constraints.max_htlc_value_in_flight_msat - pending_htlcs.iter().filter(|htlc| htlc.outbound).map(|htlc| htlc.amount_msat).sum::<u64>());
52165230

5217-
if htlc_stats.pending_outbound_htlcs + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
5231+
if pending_htlcs.iter().filter(|htlc| htlc.outbound).count() + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
52185232
available_capacity_msat = 0;
52195233
}
52205234

52215235
#[allow(deprecated)] // TODO: Remove once balance_msat is removed.
52225236
AvailableBalances {
5223-
inbound_capacity_msat: remote_balance_before_fee_msat.saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
5237+
inbound_capacity_msat: remote_stats.counterparty_balance_before_fee_msat.unwrap_or(0).saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
52245238
outbound_capacity_msat,
52255239
next_outbound_htlc_limit_msat: available_capacity_msat,
52265240
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)