Return early on duplicate calls to `funding_transaction_signed`
What changed, and why it matters
This change makes a Lightning channel funding API more forgiving. Previously, if a user already signed a funding transaction and then accidentally called the signing function again—perhaps because the app showed the same request twice after a peer reconnection—the library would return an error. Now it silently returns early instead. This is a robustness fix that prevents harmless duplicate calls from being treated as failures, which could confuse or break wallet software.
Treat as a low-risk robustness improvement. Reviewers should confirm that returning early in both branches does not skip any required post-processing (e.g., broadcasting or persisting state) and that the duplicate detection conditions are precise enough to avoid masking unrelated errors. No urgent security response is indicated.
Security signals we found
API misuse error downgraded to silent success on duplicate input
Duplicate event handling path made idempotent
No cryptographic or state-machine weakening evident in diff
Evidence from the diff
The commit modifies Channel::funding_transaction_signed in lightning/src/ln/channel.rs to return Ok((None, None)) instead of an APIMisuseError when duplicate signatures are supplied. Two duplicate cases are handled: (1) an in-memory signing session already contains holder transaction signatures, and (2) the funding transaction ID matches the already-locked funding transaction but the signing session is no longer present. The change makes the API idempotent in these paths.
Changed components
lightning/src/ln/channel.rsChannel::funding_transaction_signedFundingTransactionReadyForSigning event handlingInspect captured patch +11 / −0
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index f063c62..2a8fd8e 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -8678,8 +8678,19 @@ where
.unwrap_or(false));
}
+ if signing_session.holder_tx_signatures().is_some() {
+ // Our `tx_signatures` either should've been the first time we processed them,
+ // or we're waiting for our counterparty to send theirs first.
+ return Ok((None, None));
+ }
+
signing_session
} else {
+ if Some(funding_txid_signed) == self.funding.get_funding_txid() {
+ // We may be handling a duplicate call and the funding was already locked so we
+ // no longer have the signing session present.
+ return Ok((None, None));
+ }
let err =
format!("Channel {} not expecting funding signatures", self.context.channel_id);
return Err(APIError::APIMisuseError { err });
Why this scored 32/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.