Skip to content

Commit ab11f45

Browse files
author
Antoine Riard
committed
Check we won't overflow max_dust_htlc_exposure_msat at outbound feerate update
1 parent 31975c5 commit ab11f45

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

lightning/src/ln/channel.rs

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,7 +1998,7 @@ impl<Signer: Sign> Channel<Signer> {
19981998
}
19991999

20002000
/// Returns a HTLCStats about inbound pending htlcs
2001-
fn get_inbound_pending_htlc_stats(&self) -> HTLCStats {
2001+
fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
20022002
let mut stats = HTLCStats {
20032003
pending_htlcs: self.pending_inbound_htlcs.len() as u32,
20042004
pending_htlcs_value_msat: 0,
@@ -2007,8 +2007,8 @@ impl<Signer: Sign> Channel<Signer> {
20072007
holding_cell_msat: 0,
20082008
};
20092009

2010-
let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2011-
let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
2010+
let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2011+
let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
20122012
for ref htlc in self.pending_inbound_htlcs.iter() {
20132013
stats.pending_htlcs_value_msat += htlc.amount_msat;
20142014
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
@@ -2022,7 +2022,7 @@ impl<Signer: Sign> Channel<Signer> {
20222022
}
20232023

20242024
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
2025-
fn get_outbound_pending_htlc_stats(&self) -> HTLCStats {
2025+
fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
20262026
let mut stats = HTLCStats {
20272027
pending_htlcs: self.pending_outbound_htlcs.len() as u32,
20282028
pending_htlcs_value_msat: 0,
@@ -2031,8 +2031,8 @@ impl<Signer: Sign> Channel<Signer> {
20312031
holding_cell_msat: 0,
20322032
};
20332033

2034-
let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2035-
let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
2034+
let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2035+
let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
20362036
for ref htlc in self.pending_outbound_htlcs.iter() {
20372037
stats.pending_htlcs_value_msat += htlc.amount_msat;
20382038
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
@@ -2068,11 +2068,11 @@ impl<Signer: Sign> Channel<Signer> {
20682068
(
20692069
cmp::max(self.channel_value_satoshis as i64 * 1000
20702070
- self.value_to_self_msat as i64
2071-
- self.get_inbound_pending_htlc_stats().pending_htlcs_value_msat as i64
2071+
- self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
20722072
- Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000,
20732073
0) as u64,
20742074
cmp::max(self.value_to_self_msat as i64
2075-
- self.get_outbound_pending_htlc_stats().pending_htlcs_value_msat as i64
2075+
- self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
20762076
- self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000,
20772077
0) as u64
20782078
)
@@ -2291,8 +2291,8 @@ impl<Signer: Sign> Channel<Signer> {
22912291
return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.holder_htlc_minimum_msat, msg.amount_msat)));
22922292
}
22932293

2294-
let inbound_stats = self.get_inbound_pending_htlc_stats();
2295-
let outbound_stats = self.get_outbound_pending_htlc_stats();
2294+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
2295+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
22962296
if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
22972297
return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
22982298
}
@@ -2321,7 +2321,7 @@ impl<Signer: Sign> Channel<Signer> {
23212321
}
23222322
}
23232323

2324-
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2324+
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
23252325
if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
23262326
let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
23272327
if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -2331,7 +2331,7 @@ impl<Signer: Sign> Channel<Signer> {
23312331
}
23322332
}
23332333

2334-
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
2334+
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
23352335
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
23362336
let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
23372337
if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -3080,8 +3080,8 @@ impl<Signer: Sign> Channel<Signer> {
30803080
}
30813081

30823082
// Before proposing a feerate update, check that we can actually afford the new fee.
3083-
let inbound_stats = self.get_inbound_pending_htlc_stats();
3084-
let outbound_stats = self.get_outbound_pending_htlc_stats();
3083+
let inbound_stats = self.get_inbound_pending_htlc_stats(Some(feerate_per_kw));
3084+
let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw));
30853085
let keys = if let Ok(keys) = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number) { keys } else { return None; };
30863086
let (_, _, num_htlcs, _, holder_balance_msat, _) = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger);
30873087
let total_fee_sat = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, num_htlcs + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize);
@@ -3092,6 +3092,18 @@ impl<Signer: Sign> Channel<Signer> {
30923092
return None;
30933093
}
30943094

3095+
// Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
3096+
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
3097+
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
3098+
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
3099+
log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
3100+
return None;
3101+
}
3102+
if counterparty_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
3103+
log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
3104+
return None;
3105+
}
3106+
30953107
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 {
30963108
self.holding_cell_update_fee = Some(feerate_per_kw);
30973109
return None;
@@ -3271,16 +3283,16 @@ impl<Signer: Sign> Channel<Signer> {
32713283
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
32723284
}
32733285
Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
3274-
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate();
3286+
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None);
32753287

32763288
self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
32773289
self.update_time_counter += 1;
32783290
// If the feerate has increased over the previous dust buffer (note that
32793291
// `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we
32803292
// won't be pushed over our dust exposure limit by the feerate increase.
32813293
if feerate_over_dust_buffer {
3282-
let inbound_stats = self.get_inbound_pending_htlc_stats();
3283-
let outbound_stats = self.get_outbound_pending_htlc_stats();
3294+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
3295+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
32843296
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
32853297
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
32863298
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
@@ -3981,7 +3993,7 @@ impl<Signer: Sign> Channel<Signer> {
39813993
self.feerate_per_kw
39823994
}
39833995

3984-
pub fn get_dust_buffer_feerate(&self) -> u32 {
3996+
pub fn get_dust_buffer_feerate(&self, outbound_feerate_update: Option<u32>) -> u32 {
39853997
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
39863998
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
39873999
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
@@ -3993,6 +4005,9 @@ impl<Signer: Sign> Channel<Signer> {
39934005
if let Some((feerate, _)) = self.pending_update_fee {
39944006
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
39954007
}
4008+
if let Some(feerate) = outbound_feerate_update {
4009+
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
4010+
}
39964011
cmp::max(2530, feerate_per_kw * 1250 / 1000)
39974012
}
39984013

@@ -4655,8 +4670,8 @@ impl<Signer: Sign> Channel<Signer> {
46554670
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
46564671
}
46574672

4658-
let inbound_stats = self.get_inbound_pending_htlc_stats();
4659-
let outbound_stats = self.get_outbound_pending_htlc_stats();
4673+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
4674+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
46604675
if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 {
46614676
return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs)));
46624677
}
@@ -4677,7 +4692,7 @@ impl<Signer: Sign> Channel<Signer> {
46774692
}
46784693
}
46794694

4680-
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
4695+
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
46814696
if amount_msat / 1000 < exposure_dust_limit_success_sats {
46824697
let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + amount_msat;
46834698
if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -4686,7 +4701,7 @@ impl<Signer: Sign> Channel<Signer> {
46864701
}
46874702
}
46884703

4689-
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
4704+
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
46904705
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
46914706
let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + amount_msat;
46924707
if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {

0 commit comments

Comments
 (0)