Detect splice out as local contribution
What changed, and why it matters
This change fixes a logic bug in how LDK decides whether a user must sign a splicing transaction. Previously, LDK only checked if the local side had inputs to sign. A 'splice out' adds a local output (money going back to the user) but no local input, so LDK would skip the signing callback and the shared splice input would never get signed. That could leave a splice transaction stuck or incomplete. The patch now also counts local outputs, so splice-outs correctly trigger the signing step.
Treat as a bug fix with possible availability/integrity implications for splicing users. Review related splice-in/splice-out paths for similar conditions that depend only on inputs. No immediate emergency response is indicated, but users relying on splicing should upgrade to a release containing this fix.
Security signals we found
Logic error in transaction signing flow
Missing event emission for splice-out path
Incomplete state transition in interactive transaction protocol
Evidence from the diff
In channelmanager.rs, the code that emits a funding_transaction_signed event used signing_session.local_inputs_count() > 0 to decide whether the local party still had something to sign. For a splice out, the local node contributes no new inputs but does add a local output, so the condition was false and the signing event was not produced. The patch adds local_outputs_count() in interactivetxs.rs and a new has_local_contribution() helper that returns true if either local inputs or local outputs exist. channelmanager.rs now uses that helper, ensuring splice outs reach the signing callback for the shared splice input.
Changed components
lightning/src/ln/channelmanager.rslightning/src/ln/interactivetxs.rsLDK interactive transaction / splicing signing flowInspect captured patch +19 / −2
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 90e6a30..11f8d86 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -9034,8 +9034,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
.and_then(|_| channel.interactive_tx_signing_session.as_mut())
.filter(|signing_session| signing_session.holder_tx_signatures().is_none())
{
- let local_inputs_count = signing_session.local_inputs_count();
- if local_inputs_count > 0 {
+ if signing_session.has_local_contribution() {
let mut pending_events = self.pending_events.lock().unwrap();
let unsigned_transaction = signing_session.unsigned_tx().build_unsigned_tx();
let event_action = (
diff --git a/lightning/src/ln/interactivetxs.rs b/lightning/src/ln/interactivetxs.rs
index 563a894..d199b37 100644
--- a/lightning/src/ln/interactivetxs.rs
+++ b/lightning/src/ln/interactivetxs.rs
@@ -561,6 +561,24 @@ impl InteractiveTxSigningSession {
.count()
}
+ fn local_outputs_count(&self) -> usize {
+ self.unsigned_tx
+ .outputs
+ .iter()
+ .enumerate()
+ .filter(|(_, output)| {
+ !is_serial_id_valid_for_counterparty(
+ self.unsigned_tx.holder_is_initiator,
+ output.serial_id,
+ )
+ })
+ .count()
+ }
+
+ pub fn has_local_contribution(&self) -> bool {
+ self.local_inputs_count() > 0 || self.local_outputs_count() > 0
+ }
+
pub fn shared_input(&self) -> Option<&NegotiatedTxInput> {
self.unsigned_tx
.shared_input_index
Why this scored 35/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.