Use SignedAmount::unsigned_abs to avoid overflow
What changed, and why it matters
This commit fixes a potential integer overflow bug in the Lightning Dev Kit's channel splicing code. The bug occurs when converting a negative Bitcoin amount to its absolute value in debug builds, which could crash the program. The fix uses a safer method that cannot overflow. The practical security impact is limited because the overflow only happens in debug mode and the affected values are normally constrained by protocol rules.
Apply the patch. It is a low-risk defensive fix. No immediate incident response is warranted, but consider whether any other SignedAmount::abs() calls in the codebase have the same overflow risk and audit them similarly.
Security signals we found
Integer overflow in debug mode on signed-to-absolute conversion
Use of safer unsigned_abs API to eliminate panic path
Validation of funding contributions in splicing logic
No explicit security advisory or CVE referenced in commit
Evidence from the diff
The patch replaces calls to SignedAmount::abs() with SignedAmount::unsigned_abs() in two locations within lightning/src/ln/channel.rs. The original code could panic in debug builds due to an integer overflow when SignedAmount::MIN (i64::MIN) was passed, because abs() on i64::MIN cannot be represented as a positive i64. The new code converts directly to an unsigned Amount, which has no overflow issue. The comparisons against MAX_MONEY remain functionally equivalent. One occurrence is in a debug_assert, the other in runtime validation of splice contributions.
Changed components
lightning/src/ln/channel.rsFundingScope::new_for_next_fundingvalidate_splice_contributionsInspect captured patch +4 / −4
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 042b388..a50365c 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -2664,8 +2664,8 @@ impl FundingScope {
their_funding_contribution: SignedAmount, counterparty_funding_pubkey: PublicKey,
our_new_holder_keys: ChannelPublicKeys,
) -> Self {
- debug_assert!(our_funding_contribution.abs() <= SignedAmount::MAX_MONEY);
- debug_assert!(their_funding_contribution.abs() <= SignedAmount::MAX_MONEY);
+ debug_assert!(our_funding_contribution.unsigned_abs() <= Amount::MAX_MONEY);
+ debug_assert!(their_funding_contribution.unsigned_abs() <= Amount::MAX_MONEY);
let post_channel_value = prev_funding.compute_post_splice_value(
our_funding_contribution.to_sat(),
@@ -12155,7 +12155,7 @@ where
fn validate_splice_contributions(
&self, our_funding_contribution: SignedAmount, their_funding_contribution: SignedAmount,
) -> Result<(), String> {
- if our_funding_contribution.abs() > SignedAmount::MAX_MONEY {
+ if our_funding_contribution.unsigned_abs() > Amount::MAX_MONEY {
return Err(format!(
"Channel {} cannot be spliced; our {} contribution exceeds the total bitcoin supply",
self.context.channel_id(),
@@ -12163,7 +12163,7 @@ where
));
}
- if their_funding_contribution.abs() > SignedAmount::MAX_MONEY {
+ if their_funding_contribution.unsigned_abs() > Amount::MAX_MONEY {
return Err(format!(
"Channel {} cannot be spliced; their {} contribution exceeds the total bitcoin supply",
self.context.channel_id(),
Why this scored 34/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.