Skip to content

Commit 88e5f89

Browse files
author
Antoine Riard
committed
Check we won't overflow max_dust_htlc_exposure_msat at outbound feerate update
1 parent 925ca17 commit 88e5f89

File tree

1 file changed

+40
-22
lines changed

1 file changed

+40
-22
lines changed

lightning/src/ln/channel.rs

Lines changed: 40 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);
@@ -3091,6 +3091,21 @@ impl<Signer: Sign> Channel<Signer> {
30913091
return None;
30923092
}
30933093

3094+
// If the new outbound feerate is inferior to the dust buffer feerate, pending HTLCs
3095+
// have been already evaluated with the dust buffer feerate and as such the proposed
3096+
// feerate is not affecting our dust exposure.
3097+
if feerate_per_kw > self.get_dust_buffer_feerate(None) {
3098+
// Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
3099+
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
3100+
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
3101+
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
3102+
return None;
3103+
}
3104+
if counterparty_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
3105+
return None;
3106+
}
3107+
}
3108+
30943109
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 {
30953110
self.holding_cell_update_fee = Some(feerate_per_kw);
30963111
return None;
@@ -3270,16 +3285,16 @@ impl<Signer: Sign> Channel<Signer> {
32703285
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
32713286
}
32723287
Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
3273-
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate();
3288+
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None);
32743289

32753290
self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
32763291
self.update_time_counter += 1;
32773292
// If the feerate has increased over the previous dust buffer (note that
32783293
// `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we
32793294
// won't be pushed over our dust exposure limit by the feerate increase.
32803295
if feerate_over_dust_buffer {
3281-
let inbound_stats = self.get_inbound_pending_htlc_stats();
3282-
let outbound_stats = self.get_outbound_pending_htlc_stats();
3296+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
3297+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
32833298
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
32843299
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
32853300
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
@@ -3980,7 +3995,7 @@ impl<Signer: Sign> Channel<Signer> {
39803995
self.feerate_per_kw
39813996
}
39823997

3983-
pub fn get_dust_buffer_feerate(&self) -> u32 {
3998+
pub fn get_dust_buffer_feerate(&self, outbound_feerate_update: Option<u32>) -> u32 {
39843999
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
39854000
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
39864001
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
@@ -3992,6 +4007,9 @@ impl<Signer: Sign> Channel<Signer> {
39924007
if let Some((feerate, _)) = self.pending_update_fee {
39934008
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
39944009
}
4010+
if let Some(feerate) = outbound_feerate_update {
4011+
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
4012+
}
39954013
cmp::max(2530, feerate_per_kw * 1250 / 1000)
39964014
}
39974015

@@ -4654,8 +4672,8 @@ impl<Signer: Sign> Channel<Signer> {
46544672
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
46554673
}
46564674

4657-
let inbound_stats = self.get_inbound_pending_htlc_stats();
4658-
let outbound_stats = self.get_outbound_pending_htlc_stats();
4675+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
4676+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
46594677
if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 {
46604678
return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs)));
46614679
}
@@ -4676,7 +4694,7 @@ impl<Signer: Sign> Channel<Signer> {
46764694
}
46774695
}
46784696

4679-
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
4697+
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
46804698
if amount_msat / 1000 < exposure_dust_limit_success_sats {
46814699
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;
46824700
if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -4685,7 +4703,7 @@ impl<Signer: Sign> Channel<Signer> {
46854703
}
46864704
}
46874705

4688-
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
4706+
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
46894707
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
46904708
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;
46914709
if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {

0 commit comments

Comments
 (0)