From b98d7b8a6253a71e01ed854aeaa7cb33903087de Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sun, 12 Apr 2026 23:25:03 +0000 Subject: [PATCH] Use `saturating_mul` when multiplying feerates by the fee spike buf In theory a channel's feerate could be set to some absurd value (millions of satoshis per vB) and we'd overflow the fee spike buffer, accepting the absurd fee and ignoring our fee spike buffer check. This is harmless - the counterparty has much easier ways of bricking the channel if they want, and paying several BTC in fees is probably not the best way. Our commitment transaction and dust fee exposure logic all correctly map the `u32` to a `u64` before multiplying, making them overflow-safe. Still, its good to fix overflows because it is a remotely-reachable crash in debug builds. Reported by Jordan Mecom of Block's Security Team --- lightning/src/ln/channel.rs | 5 +++-- lightning/src/sign/tx_builder.rs | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 55d4a84eb91..b80ea76cf10 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -5847,7 +5847,7 @@ impl ChannelContext { 1 }; // Note that the feerate is 0 in zero-fee commitment channels, so this statement is a noop - let spiked_feerate = feerate * fee_spike_multiple; + let spiked_feerate = feerate.saturating_mul(fee_spike_multiple); let (remote_stats, _remote_htlcs) = self .get_next_remote_commitment_stats( funding, @@ -13333,7 +13333,8 @@ where let feerate_per_kw = if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() { // Similar to HTLC additions, require the funder to have enough funds reserved for // fees such that the feerate can jump without rendering the channel useless. - self.context.feerate_per_kw * FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32 + let spike_mul = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32; + self.context.feerate_per_kw.saturating_mul(spike_mul) } else { self.context.feerate_per_kw }; diff --git a/lightning/src/sign/tx_builder.rs b/lightning/src/sign/tx_builder.rs index a54f8f70f8d..f51759db5e9 100644 --- a/lightning/src/sign/tx_builder.rs +++ b/lightning/src/sign/tx_builder.rs @@ -336,12 +336,13 @@ fn get_available_balances( if channel_type.supports_anchor_zero_fee_commitments() { 0 } else { 1 }; // Note that the feerate is 0 in zero-fee commitment channels, so this statement is a noop - let spiked_feerate = feerate_per_kw - * if is_outbound_from_holder && !channel_type.supports_anchors_zero_fee_htlc_tx() { + let spiked_feerate = feerate_per_kw.saturating_mul( + if is_outbound_from_holder && !channel_type.supports_anchors_zero_fee_htlc_tx() { crate::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32 } else { 1 - }; + }, + ); let local_nondust_htlc_count = pending_htlcs .iter()