Use `next_splice_out_maximum_sat` to validate `funding_contributed`
What changed, and why it matters
This commit changes how a Lightning channel validates splice-out funding contributions. Instead of a more general reserve check, it now uses a dedicated 'next splice-out maximum' calculation to decide whether a proposed splice-out is too large, and reports a clearer error message to the user. The change appears to be a refinement of validation logic rather than a fix for a known exploit, but the commit message references a previous commit with added debug assertions, suggesting it hardens an earlier correction.
Review the previous commit referenced in the message to understand what the debug assertions were protecting against, and confirm that `get_next_splice_out_maximum` enforces equivalent or stronger guarantees than the removed `validate_splice_contributions` call. Consider whether the new error message exposes any internal state that could aid an attacker.
Security signals we found
Replaces a broader reserve validation with a specific splice-out maximum check
Uses `checked_add_signed` to prevent signed-amount overflow when validating contributions
Commit message references a prior commit with added debug assertions, implying a hardening or follow-up fix
Error message now exposes the exact splice-out maximum to the caller
No explicit CVE, security advisory, or researcher attribution in commit or supplied references
Evidence from the diff
The patch replaces calls to validate_splice_contributions with a direct check using get_next_splice_out_maximum. It computes whether our_funding_contribution can be added to the splice-out maximum without overflow, and if not, returns a precise error: ‘Our splice-out value of X is greater than the maximum Y’. The test expectation is updated to match the new error wording. The commit message states this is ‘equivalent to the previous commit’ and that the new approach gives users a more actionable maximum value.
Changed components
lightning/src/ln/channel.rslightning/src/ln/splicing_tests.rsInspect captured patch +18 / −15
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index e850d83..f7c4ca2 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -12605,13 +12605,14 @@ where
}
let our_funding_contribution = contribution.net_value();
-
- if let Err(e) = self.validate_splice_contributions(
- our_funding_contribution,
- SignedAmount::ZERO,
- self.funding.get_counterparty_pubkeys().funding_pubkey,
- self.funding.get_holder_pubkeys().clone(),
- ) {
+ let unsigned_contribution = our_funding_contribution.unsigned_abs();
+ if let Err(e) = self.get_next_splice_out_maximum(&self.funding)
+ .and_then(|splice_max| splice_max
+ .to_sat()
+ .checked_add_signed(our_funding_contribution.to_sat())
+ .ok_or(format!("Our splice-out value of {unsigned_contribution} is greater than the maximum {splice_max}"))
+ )
+ {
log_error!(logger, "Channel {} cannot be funded: {}", self.context.channel_id(), e);
return Err(QuiescentError::FailSplice(self.splice_funding_failed_for(contribution)));
}
@@ -14232,12 +14233,14 @@ where
// balance. If invalid, disconnect and return the contribution so
// the user can reclaim their inputs.
let our_funding_contribution = contribution.net_value();
- if let Err(e) = self.validate_splice_contributions(
- our_funding_contribution,
- SignedAmount::ZERO,
- self.funding.get_counterparty_pubkeys().funding_pubkey,
- self.funding.get_holder_pubkeys().clone(),
- ) {
+ let unsigned_contribution = our_funding_contribution.unsigned_abs();
+ if let Err(e) = self.get_next_splice_out_maximum(&self.funding)
+ .and_then(|splice_max| splice_max
+ .to_sat()
+ .checked_add_signed(our_funding_contribution.to_sat())
+ .ok_or(format!("Our splice-out value of {unsigned_contribution} is greater than the maximum {splice_max}"))
+ )
+ {
let failed = self.splice_funding_failed_for(contribution);
return Err((
ChannelError::WarnAndDisconnect(format!(
diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs
index b2cb1ed..33483e4 100644
--- a/lightning/src/ln/splicing_tests.rs
+++ b/lightning/src/ln/splicing_tests.rs
@@ -4264,8 +4264,8 @@ fn do_test_splice_pending_htlcs(config: UserConfig) {
format!("Channel {} cannot accept funding contribution", channel_id);
assert_eq!(error, APIError::APIMisuseError { err: cannot_accept_contribution });
let cannot_be_funded = format!(
- "Channel {} cannot be funded: Channel {} cannot be spliced out; our post-splice channel balance {} is smaller than their selected v2 reserve {}",
- channel_id, channel_id, post_splice_reserve - Amount::ONE_SAT, post_splice_reserve
+ "Channel {} cannot be funded: Our splice-out value of {} is greater than the maximum {}",
+ channel_id, splice_out_incl_fees + Amount::ONE_SAT, splice_out_incl_fees,
);
initiator.logger.assert_log("lightning::ln::channel", cannot_be_funded, 1);
Why this scored 41/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.