Skip to content

Commit 6e356d4

Browse files
author
Antoine Riard
committed
Check we won't overflow max_dust_htlc_exposure_msat at outbound feerate update
1 parent 71f7be1 commit 6e356d4

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

lightning/src/ln/channel.rs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,16 +1904,16 @@ impl<Signer: Sign> Channel<Signer> {
19041904
}
19051905

19061906
/// Returns a HTLCStats about inbound pending htlcs
1907-
fn get_inbound_pending_htlc_stats(&self) -> HTLCStats {
1907+
fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
19081908
let mut stats = HTLCStats {
19091909
pending_htlcs: self.pending_inbound_htlcs.len() as u32,
19101910
pending_htlcs_value_msat: 0,
19111911
on_counterparty_tx_dust_exposure_msat: 0,
19121912
on_holder_tx_dust_exposure_msat: 0,
19131913
};
19141914

1915-
let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
1916-
let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
1915+
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;
1916+
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;
19171917
for ref htlc in self.pending_inbound_htlcs.iter() {
19181918
stats.pending_htlcs_value_msat += htlc.amount_msat;
19191919
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
@@ -1927,16 +1927,16 @@ impl<Signer: Sign> Channel<Signer> {
19271927
}
19281928

19291929
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
1930-
fn get_outbound_pending_htlc_stats(&self) -> HTLCStats {
1930+
fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
19311931
let mut stats = HTLCStats {
19321932
pending_htlcs: self.pending_outbound_htlcs.len() as u32,
19331933
pending_htlcs_value_msat: 0,
19341934
on_counterparty_tx_dust_exposure_msat: 0,
19351935
on_holder_tx_dust_exposure_msat: 0,
19361936
};
19371937

1938-
let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
1939-
let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
1938+
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;
1939+
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;
19401940
for ref htlc in self.pending_outbound_htlcs.iter() {
19411941
stats.pending_htlcs_value_msat += htlc.amount_msat;
19421942
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
@@ -1971,11 +1971,11 @@ impl<Signer: Sign> Channel<Signer> {
19711971
(
19721972
cmp::max(self.channel_value_satoshis as i64 * 1000
19731973
- self.value_to_self_msat as i64
1974-
- self.get_inbound_pending_htlc_stats().pending_htlcs_value_msat as i64
1974+
- self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
19751975
- Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000,
19761976
0) as u64,
19771977
cmp::max(self.value_to_self_msat as i64
1978-
- self.get_outbound_pending_htlc_stats().pending_htlcs_value_msat as i64
1978+
- self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
19791979
- self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000,
19801980
0) as u64
19811981
)
@@ -2187,8 +2187,8 @@ impl<Signer: Sign> Channel<Signer> {
21872187
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)));
21882188
}
21892189

2190-
let inbound_stats = self.get_inbound_pending_htlc_stats();
2191-
let outbound_stats = self.get_outbound_pending_htlc_stats();
2190+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
2191+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
21922192
if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
21932193
return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
21942194
}
@@ -2217,7 +2217,7 @@ impl<Signer: Sign> Channel<Signer> {
22172217
}
22182218
}
22192219

2220-
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
2220+
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
22212221
if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
22222222
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;
22232223
if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -2227,7 +2227,7 @@ impl<Signer: Sign> Channel<Signer> {
22272227
}
22282228
}
22292229

2230-
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
2230+
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
22312231
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
22322232
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;
22332233
if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -2963,6 +2963,20 @@ impl<Signer: Sign> Channel<Signer> {
29632963
}
29642964
}
29652965

2966+
if feerate_per_kw > self.get_dust_buffer_feerate(None) {
2967+
// Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
2968+
let inbound_stats = self.get_inbound_pending_htlc_stats(Some(feerate_per_kw));
2969+
let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw));
2970+
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
2971+
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
2972+
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
2973+
return None;
2974+
}
2975+
if counterparty_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
2976+
return None;
2977+
}
2978+
}
2979+
29662980
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 {
29672981
self.holding_cell_update_fee = Some(feerate_per_kw);
29682982
return None;
@@ -3130,16 +3144,16 @@ impl<Signer: Sign> Channel<Signer> {
31303144
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
31313145
}
31323146
Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
3133-
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate();
3147+
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None);
31343148

31353149
self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
31363150
self.update_time_counter += 1;
31373151
// If the feerate has increased over the previous dust buffer (note that
31383152
// `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we
31393153
// won't be pushed over our dust exposure limit by the feerate increase.
31403154
if feerate_over_dust_buffer {
3141-
let inbound_stats = self.get_inbound_pending_htlc_stats();
3142-
let outbound_stats = self.get_outbound_pending_htlc_stats();
3155+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
3156+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
31433157
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
31443158
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
31453159
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
@@ -3840,7 +3854,7 @@ impl<Signer: Sign> Channel<Signer> {
38403854
self.feerate_per_kw
38413855
}
38423856

3843-
pub fn get_dust_buffer_feerate(&self) -> u32 {
3857+
pub fn get_dust_buffer_feerate(&self, outbound_feerate_update: Option<u32>) -> u32 {
38443858
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
38453859
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
38463860
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
@@ -3852,6 +3866,9 @@ impl<Signer: Sign> Channel<Signer> {
38523866
if let Some((feerate, _)) = self.pending_update_fee {
38533867
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
38543868
}
3869+
if let Some(feerate) = outbound_feerate_update {
3870+
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
3871+
}
38553872
cmp::max(2530, feerate_per_kw * 1250 / 1000)
38563873
}
38573874

@@ -4509,8 +4526,8 @@ impl<Signer: Sign> Channel<Signer> {
45094526
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
45104527
}
45114528

4512-
let inbound_stats = self.get_inbound_pending_htlc_stats();
4513-
let outbound_stats = self.get_outbound_pending_htlc_stats();
4529+
let inbound_stats = self.get_inbound_pending_htlc_stats(None);
4530+
let outbound_stats = self.get_outbound_pending_htlc_stats(None);
45144531
if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 {
45154532
return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs)));
45164533
}
@@ -4530,7 +4547,7 @@ impl<Signer: Sign> Channel<Signer> {
45304547
}
45314548
}
45324549

4533-
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
4550+
let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
45344551
if amount_msat / 1000 < exposure_dust_limit_success_sats {
45354552
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;
45364553
if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
@@ -4539,7 +4556,7 @@ impl<Signer: Sign> Channel<Signer> {
45394556
}
45404557
}
45414558

4542-
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
4559+
let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
45434560
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
45444561
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;
45454562
if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {

0 commit comments

Comments
 (0)