Don't process alternative funding confirmations duplicatively
What changed, and why it matters
This patch fixes a bug where the Lightning node could re-process the same alternative funding transaction more than once. Reprocessing could trigger an internal assertion (a safety check that crashes the program), potentially causing the node to panic and stop running. The fix adds a check to skip the transaction if it was already recorded as confirmed.
Apply the patch. Users running nodes that monitor on-chain channel closes should upgrade to avoid a potential panic if a previously confirmed alternative funding spend is reprocessed, for example during chain reorgs or block replays.
Security signals we found
Assertion bypass / panic condition in channel monitor transaction reprocessing
Missing duplicate detection for alternative funding confirmation path
Denial-of-service vector: node panic triggered by on-chain transaction replay
Evidence from the diff
In ChannelMonitorImpl, when processing confirmed transactions that spend the funding output, the code already skipped reprocessing if the txid matched funding_spend_confirmed. However, it did not check alternative_funding_confirmed, which stores a confirmed alternative funding spend. Reprocessing such a transaction would later hit an assertion expecting no prior alternative funding confirmation. The patch adds an early duplicate-detection guard for alternative_funding_confirmed before the existing funding_spend_confirmed guard.
Changed components
lightning/src/chain/channelmonitor.rsChannelMonitorImpl transaction confirmation handlingalternative_funding_confirmed stateInspect captured patch +4 / −0
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index b34016b..d0aa0ee 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -5164,6 +5164,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
let txid = tx.compute_txid();
log_trace!(logger, "Transaction {} confirmed in block {}", txid , block_hash);
// If a transaction has already been confirmed, ensure we don't bother processing it duplicatively.
+ if self.alternative_funding_confirmed.map(|(alternative_funding_txid, _)| alternative_funding_txid == txid).unwrap_or(false) {
+ log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid);
+ continue 'tx_iter;
+ }
if Some(txid) == self.funding_spend_confirmed {
log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid);
continue 'tx_iter;
Why this scored 49/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.