Allow multiple RBF splice candidates in channel monitor
What changed, and why it matters
This change fixes a logic bug in how Bitcoin Lightning channels handle 'splicing' (a way to resize a channel's on-chain funds). Previously, the code blocked all new funding entries while any splice was still pending, which accidentally prevented valid 'Replace-By-Fee' (RBF) attempts—multiple competing versions of the same splice meant to speed up confirmation. The patch relaxes the rule so only splices that spend from a *different* parent funding transaction are rejected. This is a correctness/functional fix rather than a clear-cut security vulnerability, but the overly strict check could have caused operational failures around unconfirmed splices.
Review as a functional/correctness fix. Verify that the new `has_different_parent` check correctly preserves the intended invariant (no concurrent splices from different funding sources) and that RBF candidates with identical parent txids cannot be abused to evade confirmation requirements. No immediate emergency response indicated absent additional incident evidence.
Security signals we found
Logic relaxation in channel monitor validation
Splicing / RBF candidate handling
Pending funding state check changed from 'any pending' to 'different parent pending'
No explicit security framing in commit message
Evidence from the diff
In ChannelMonitorImpl::provide_latest_holder_commitment_tx, the monitor validates a new pending funding entry. The old code rejected any new pending funding if self.pending_funding was non-empty. The new code instead scans existing pending funding entries and rejects only if any existing entry has a different splice_parent_funding_txid. This allows multiple RBF candidates for the same splice (same parent txid) while still preventing concurrent splices from different funding sources. The change is small (10 insertions, 3 deletions) and localized to lightning/src/chain/channelmonitor.rs.
Changed components
lightning/src/chain/channelmonitor.rsChannelMonitorImpl::provide_latest_holder_commitment_txRBF splice candidate handlingInspect captured patch +10 / −3
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index a8d055a..02a3a42 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -4039,9 +4039,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
}
if let Some(parent_funding_txid) = channel_parameters.splice_parent_funding_txid.as_ref() {
- // Only one splice can be negotiated at a time after we've exchanged `channel_ready`
- // (implying our funding is confirmed) that spends our currently locked funding.
- if !self.pending_funding.is_empty() {
+ // Multiple RBF candidates for the same splice are allowed (they share the same
+ // parent funding txid). A new splice with a different parent while one is pending
+ // is not allowed. This also ensures a dual-funded channel has exchanged
+ // `channel_ready` (implying funding is confirmed) before allowing a splice,
+ // since unconfirmed initial funding has no splice parent.
+ let has_different_parent = self.pending_funding.iter().any(|funding| {
+ funding.channel_parameters.splice_parent_funding_txid.as_ref()
+ != Some(parent_funding_txid)
+ });
+ if has_different_parent {
log_error!(
logger,
"Negotiated splice while channel is pending channel_ready/splice_locked"
Why this scored 29/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.