Skip to content

Commit ee40e9a

Browse files
committed
Improve prediction of commitment stats in can_send_update_fee
`ChannelContext::get_pending_htlc_stats` predicts that the set of HTLCs on the next commitment will be all the HTLCs in `ChannelContext.pending_inbound_htlcs`, and `ChannelContext.pending_outbound_htlcs`, as well as all the outbound HTLC adds in the holding cell. This is an overestimate: * Outbound HTLC removals which have been ACK'ed by the counterparty will certainly not be present in any *next* commitment, even though they remain in `pending_outbound_htlcs` (I refer to states `AwaitingRemoteRevokeToRemove` and `AwaitingRemovedRemoteRevoke`). * Outbound HTLCs in the `RemoteRemoved` state, will not be present in the next *local* commitment. * Inbound HTLCs in the `LocalRemoved` state will not be present in the next *remote* commitment. `ChannelContext::build_commitment_stats(funding, true, true, ..)` makes these errors when predicting the HTLC count on the remote commitment: * Inbound HTLCs in the state `RemoteAnnounced` are not included, but they will be in the next remote commitment transaction if the local ACK's the addition before producing the next remote commitment. * Inbound HTLCs in the state `AwaitingRemoteRevokeToAnnounce` are not included, even though the local has ACK'ed the addition. * Outbound HTLCs in the state `AwaitingRemoteRevokeToRemove` are counted, even though the local party has ACK'ed the removal. This commit replaces these functions in favor of the newly added `ChannelContext::get_next_{local, remote}_commitment_stats` methods, and fixes the issues described above. We now always calculate dust exposure using a buffer from `msg.feerate_per_kw`, and not from `max(feerate_per_kw, self.feerate_per_kw, self.pending_update_fee)`.
1 parent 0edb8a1 commit ee40e9a

File tree

1 file changed

+9
-15
lines changed

1 file changed

+9
-15
lines changed

lightning/src/ln/channel.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,6 @@ struct HTLCStats {
11121112
// htlc on the counterparty's commitment transaction.
11131113
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat: Option<u64>,
11141114
on_holder_tx_dust_exposure_msat: u64,
1115-
outbound_holding_cell_msat: u64,
1116-
on_holder_tx_outbound_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included
11171115
}
11181116

11191117
/// A struct gathering data on a commitment, either local or remote.
@@ -4466,23 +4464,26 @@ where
44664464
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
44674465
&fee_estimator, funding.get_channel_type(),
44684466
);
4469-
let htlc_stats = self.get_pending_htlc_stats(funding, Some(feerate_per_kw), dust_exposure_limiting_feerate);
4470-
let stats = self.build_commitment_stats(funding, true, true, Some(feerate_per_kw), Some(htlc_stats.on_holder_tx_outbound_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize));
4471-
let holder_balance_msat = stats.local_balance_before_fee_msat - htlc_stats.outbound_holding_cell_msat;
4467+
// Include outbound update_add_htlc's in the holding cell, and those which haven't yet been ACK'ed by the counterparty (ie. LocalAnnounced HTLCs)
4468+
let include_counterparty_unknown_htlcs = true;
4469+
let next_remote_commitment_stats = self.get_next_remote_commitment_stats(funding, None, include_counterparty_unknown_htlcs, CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, feerate_per_kw, dust_exposure_limiting_feerate);
4470+
let holder_balance_msat = next_remote_commitment_stats.holder_balance_before_fee_msat.expect("The holder's balance before fees should never underflow.");
44724471
// Note that `stats.commit_tx_fee_sat` accounts for any HTLCs that transition from non-dust to dust under a higher feerate (in the case where HTLC-transactions pay endogenous fees).
4473-
if holder_balance_msat < stats.commit_tx_fee_sat * 1000 + funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
4472+
if holder_balance_msat < next_remote_commitment_stats.commit_tx_fee_sat * 1000 + funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
44744473
//TODO: auto-close after a number of failures?
44754474
log_debug!(logger, "Cannot afford to send new feerate at {}", feerate_per_kw);
44764475
return false;
44774476
}
44784477

44794478
// Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
44804479
let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
4481-
if htlc_stats.on_holder_tx_dust_exposure_msat > max_dust_htlc_exposure_msat {
4480+
if next_remote_commitment_stats.dust_exposure_msat > max_dust_htlc_exposure_msat {
44824481
log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
44834482
return false;
44844483
}
4485-
if htlc_stats.on_counterparty_tx_dust_exposure_msat > max_dust_htlc_exposure_msat {
4484+
4485+
let next_local_commitment_stats = self.get_next_local_commitment_stats(funding, None, include_counterparty_unknown_htlcs, CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, feerate_per_kw, dust_exposure_limiting_feerate);
4486+
if next_local_commitment_stats.dust_exposure_msat > max_dust_htlc_exposure_msat {
44864487
log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
44874488
return false;
44884489
}
@@ -4848,8 +4849,6 @@ where
48484849
}
48494850

48504851
let mut pending_outbound_htlcs_value_msat = 0;
4851-
let mut outbound_holding_cell_msat = 0;
4852-
let mut on_holder_tx_outbound_holding_cell_htlcs_count = 0;
48534852
let mut pending_outbound_htlcs = self.pending_outbound_htlcs.len();
48544853
{
48554854
let counterparty_dust_limit_success_sat = htlc_success_tx_fee_sat + context.counterparty_dust_limit_satoshis;
@@ -4870,16 +4869,13 @@ where
48704869
if let &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } = update {
48714870
pending_outbound_htlcs += 1;
48724871
pending_outbound_htlcs_value_msat += amount_msat;
4873-
outbound_holding_cell_msat += amount_msat;
48744872
if *amount_msat / 1000 < counterparty_dust_limit_success_sat {
48754873
on_counterparty_tx_dust_exposure_msat += amount_msat;
48764874
} else {
48774875
on_counterparty_tx_accepted_nondust_htlcs += 1;
48784876
}
48794877
if *amount_msat / 1000 < holder_dust_limit_timeout_sat {
48804878
on_holder_tx_dust_exposure_msat += amount_msat;
4881-
} else {
4882-
on_holder_tx_outbound_holding_cell_htlcs_count += 1;
48834879
}
48844880
}
48854881
}
@@ -4917,8 +4913,6 @@ where
49174913
on_counterparty_tx_dust_exposure_msat,
49184914
extra_nondust_htlc_on_counterparty_tx_dust_exposure_msat,
49194915
on_holder_tx_dust_exposure_msat,
4920-
outbound_holding_cell_msat,
4921-
on_holder_tx_outbound_holding_cell_htlcs_count,
49224916
}
49234917
}
49244918

0 commit comments

Comments
 (0)