Skip to content

Commit 9a7e1dc

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 addbe07 commit 9a7e1dc

File tree

2 files changed

+56
-46
lines changed

2 files changed

+56
-46
lines changed

lightning/src/ln/channel.rs

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5689,57 +5689,71 @@ where
56895689
where
56905690
F::Target: FeeEstimator,
56915691
{
5692-
let context = &self;
5692+
use crate::sign::tx_builder::get_dust_buffer_feerate;
5693+
56935694
let holder_channel_constraints = self.get_holder_channel_constraints(funding);
56945695
let counterparty_channel_constraints = self.get_counterparty_channel_constraints(funding);
56955696
// Note that we have to handle overflow due to the case mentioned in the docs in general
56965697
// here.
56975698

5699+
let pending_outbound_htlcs = self.pending_outbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: true });
5700+
let pending_inbound_htlcs = self.pending_inbound_htlcs.iter().map(|htlc| HTLCAmountDirection { amount_msat: htlc.amount_msat, outbound: false });
5701+
let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| {
5702+
if let &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } = htlc {
5703+
Some(HTLCAmountDirection { outbound: true, amount_msat })
5704+
} else {
5705+
None
5706+
}
5707+
});
5708+
5709+
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());
5710+
pending_htlcs.extend(pending_outbound_htlcs.chain(pending_inbound_htlcs).chain(holding_cell_htlcs));
5711+
let pending_htlcs = &pending_htlcs;
5712+
56985713
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
56995714
&fee_estimator, funding.get_channel_type(),
57005715
);
5701-
let htlc_stats = context.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
5716+
let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
57025717

5703-
// Subtract any non-HTLC outputs from the local and remote balances
5704-
let (local_balance_before_fee_msat, remote_balance_before_fee_msat) = SpecTxBuilder {}.subtract_non_htlc_outputs(
5705-
funding.is_outbound(),
5706-
funding.value_to_self_msat.saturating_sub(htlc_stats.pending_outbound_htlcs_value_msat),
5707-
(funding.get_value_satoshis() * 1000).checked_sub(funding.value_to_self_msat).unwrap().saturating_sub(htlc_stats.pending_inbound_htlcs_value_msat),
5708-
funding.get_channel_type(),
5709-
);
5718+
let is_outbound_from_holder = funding.is_outbound();
5719+
let channel_value_satoshis = funding.get_value_satoshis();
5720+
let value_to_holder_msat = funding.get_value_to_self_msat();
5721+
let feerate_per_kw = self.feerate_per_kw;
5722+
let channel_type = funding.get_channel_type();
5723+
5724+
let fee_spike_buffer_htlc = if channel_type.supports_anchor_zero_fee_commitments() {
5725+
0
5726+
} else {
5727+
1
5728+
};
57105729

5711-
let outbound_capacity_msat = local_balance_before_fee_msat
5712-
.saturating_sub(
5713-
holder_channel_constraints.channel_reserve_satoshis * 1000);
5730+
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).unwrap();
5731+
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).unwrap();
5732+
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).unwrap();
5733+
5734+
let outbound_capacity_msat = local_stats_max_fee.holder_balance_before_fee_msat.saturating_sub(holder_channel_constraints.channel_reserve_satoshis * 1000);
57145735

57155736
let mut available_capacity_msat = outbound_capacity_msat;
57165737
let (real_htlc_success_tx_fee_sat, real_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5717-
funding.get_channel_type(), context.feerate_per_kw,
5738+
channel_type, feerate_per_kw
57185739
);
57195740

5720-
if funding.is_outbound() {
5741+
if is_outbound_from_holder {
57215742
// We should mind channel commit tx fee when computing how much of the available capacity
57225743
// can be used in the next htlc. Mirrors the logic in send_htlc.
57235744
//
57245745
// The fee depends on whether the amount we will be sending is above dust or not,
57255746
// and the answer will in turn change the amount itself — making it a circular
57265747
// dependency.
57275748
// This complicates the computation around dust-values, up to the one-htlc-value.
5728-
let fee_spike_buffer_htlc = if funding.get_channel_type().supports_anchor_zero_fee_commitments() {
5729-
None
5730-
} else {
5731-
Some(())
5732-
};
57335749

57345750
let real_dust_limit_timeout_sat = real_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
5735-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
5736-
let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_above_dust, fee_spike_buffer_htlc);
5737-
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
5738-
let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(&funding, htlc_dust, fee_spike_buffer_htlc);
5751+
let mut max_reserved_commit_tx_fee_msat = local_stats_max_fee.commit_tx_fee_sat * 1000;
5752+
let mut min_reserved_commit_tx_fee_msat = local_stats_min_fee.commit_tx_fee_sat * 1000;
57395753

5740-
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5741-
max_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5742-
min_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5754+
if !channel_type.supports_anchors_zero_fee_htlc_tx() {
5755+
max_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
5756+
min_reserved_commit_tx_fee_msat *= crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
57435757
}
57445758

57455759
// We will first subtract the fee as if we were above-dust. Then, if the resulting
@@ -5756,11 +5770,10 @@ where
57565770
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
57575771
// sending a new HTLC won't reduce their balance below our reserve threshold.
57585772
let real_dust_limit_success_sat = real_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
5759-
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
5760-
let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, Some(htlc_above_dust), None);
5773+
let max_reserved_commit_tx_fee_msat = remote_stats.commit_tx_fee_sat * 1000;
57615774

57625775
let holder_selected_chan_reserve_msat = counterparty_channel_constraints.channel_reserve_satoshis * 1000;
5763-
if remote_balance_before_fee_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
5776+
if remote_stats.counterparty_balance_before_fee_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
57645777
// If another HTLC's fee would reduce the remote's balance below the reserve limit
57655778
// we've selected for them, we can only send dust HTLCs.
57665779
available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1);
@@ -5775,35 +5788,32 @@ where
57755788
// send above the dust limit (as the router can always overpay to meet the dust limit).
57765789
let mut remaining_msat_below_dust_exposure_limit = None;
57775790
let mut dust_exposure_dust_limit_msat = 0;
5778-
let max_dust_htlc_exposure_msat = context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
57795791

5780-
let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
5792+
let dust_buffer_feerate = get_dust_buffer_feerate(feerate_per_kw);
57815793
let (buffer_htlc_success_tx_fee_sat, buffer_htlc_timeout_tx_fee_sat) = second_stage_tx_fees_sat(
5782-
funding.get_channel_type(), dust_buffer_feerate,
5794+
channel_type, dust_buffer_feerate,
57835795
);
57845796
let buffer_dust_limit_success_sat = buffer_htlc_success_tx_fee_sat + counterparty_channel_constraints.dust_limit_satoshis;
57855797
let buffer_dust_limit_timeout_sat = buffer_htlc_timeout_tx_fee_sat + holder_channel_constraints.dust_limit_satoshis;
57865798

5787-
if let Some(extra_htlc_dust_exposure) = htlc_stats.extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat {
5788-
if extra_htlc_dust_exposure > max_dust_htlc_exposure_msat {
5789-
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
5790-
// send any non-dust HTLCs.
5791-
available_capacity_msat = cmp::min(available_capacity_msat, buffer_dust_limit_success_sat * 1000);
5792-
}
5799+
if remote_stats.extra_accepted_htlc_dust_exposure_msat > max_dust_htlc_exposure_msat {
5800+
// If adding an extra HTLC would put us over the dust limit in total fees, we cannot
5801+
// send any non-dust HTLCs.
5802+
available_capacity_msat = cmp::min(available_capacity_msat, buffer_dust_limit_success_sat * 1000);
57935803
}
57945804

5795-
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) {
5805+
if remote_stats.dust_exposure_msat.saturating_add(buffer_dust_limit_success_sat * 1000) > max_dust_htlc_exposure_msat.saturating_add(1) {
57965806
// Note that we don't use the `counterparty_tx_dust_exposure` (with
57975807
// `htlc_dust_exposure_msat`) here as it only applies to non-dust HTLCs.
57985808
remaining_msat_below_dust_exposure_limit =
5799-
Some(max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_counterparty_tx_dust_exposure_msat));
5809+
Some(max_dust_htlc_exposure_msat.saturating_sub(remote_stats.dust_exposure_msat));
58005810
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_success_sat * 1000);
58015811
}
58025812

5803-
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()) {
5813+
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()) {
58045814
remaining_msat_below_dust_exposure_limit = Some(cmp::min(
58055815
remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()),
5806-
max_dust_htlc_exposure_msat.saturating_sub(htlc_stats.on_holder_tx_dust_exposure_msat)));
5816+
max_dust_htlc_exposure_msat.saturating_sub(local_stats_max_fee.dust_exposure_msat)));
58075817
dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, buffer_dust_limit_timeout_sat * 1000);
58085818
}
58095819

@@ -5816,15 +5826,15 @@ where
58165826
}
58175827

58185828
available_capacity_msat = cmp::min(available_capacity_msat,
5819-
counterparty_channel_constraints.max_htlc_value_in_flight_msat - htlc_stats.pending_outbound_htlcs_value_msat);
5829+
counterparty_channel_constraints.max_htlc_value_in_flight_msat - pending_htlcs.iter().filter(|htlc| htlc.outbound).map(|htlc| htlc.amount_msat).sum::<u64>());
58205830

5821-
if htlc_stats.pending_outbound_htlcs + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
5831+
if pending_htlcs.iter().filter(|htlc| htlc.outbound).count() + 1 > counterparty_channel_constraints.max_accepted_htlcs as usize {
58225832
available_capacity_msat = 0;
58235833
}
58245834

58255835
#[allow(deprecated)] // TODO: Remove once balance_msat is removed.
58265836
AvailableBalances {
5827-
inbound_capacity_msat: remote_balance_before_fee_msat.saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
5837+
inbound_capacity_msat: remote_stats.counterparty_balance_before_fee_msat.saturating_sub(counterparty_channel_constraints.channel_reserve_satoshis * 1000),
58285838
outbound_capacity_msat,
58295839
next_outbound_htlc_limit_msat: available_capacity_msat,
58305840
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
@@ -144,7 +144,7 @@ fn subtract_addl_outputs(
144144
}
145145
}
146146

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

0 commit comments

Comments
 (0)