Set funding_seen_onchain=true in filter_block
What changed, and why it matters
This commit fixes a bookkeeping flag in the Lightning channel monitor. The flag `funding_seen_onchain` was not being set when the funding transaction was observed on the blockchain, even though the code already detected it. Setting the flag correctly helps the monitor know the channel is real on-chain and may affect later safety decisions, such as whether to accept certain updates or how to handle edge cases during channel closure.
Treat as a correctness fix worth including in a release. Review all downstream checks that read `funding_seen_onchain` to confirm whether stale state could have led to unsafe behavior, such as accepting revoked commitments or mishandling force-close scenarios. No immediate emergency response is indicated from the diff alone.
Security signals we found
State flag not updated despite on-chain detection
Channel monitor internal consistency fix
Could affect safety checks that depend on funding_seen_onchain
Evidence from the diff
In ChannelMonitorImpl, funding_seen_onchain is a state flag indicating the channel funding transaction has been observed on-chain. Previously, filter_block matched transactions but never set this flag. The patch adds a scan over txdata in block_connected/block_disconnected to set funding_seen_onchain = true when the funding txid (or any pending funding txid) appears. It also changes filter_block from &self to &mut self, though the mutation is actually done in the caller after filter_block returns. The change is small and appears to correct stale state rather than a direct exploit path.
Changed components
lightning/src/chain/channelmonitor.rsChannelMonitorImplfunding_seen_onchain flagfilter_blockblock_connected / block_disconnectedInspect captured patch +14 / −1
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index 06f5212..92f7e9e 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -5332,6 +5332,19 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
L::Target: Logger,
{
let txn_matched = self.filter_block(txdata);
+
+ if !self.funding_seen_onchain {
+ for &(_, tx) in txdata.iter() {
+ let txid = tx.compute_txid();
+ if txid == self.funding.funding_txid() ||
+ self.pending_funding.iter().any(|f| f.funding_txid() == txid)
+ {
+ self.funding_seen_onchain = true;
+ break;
+ }
+ }
+ }
+
for tx in &txn_matched {
let mut output_val = Amount::ZERO;
for out in tx.output.iter() {
@@ -5915,7 +5928,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
/// Filters a block's `txdata` for transactions spending watched outputs or for any child
/// transactions thereof.
#[rustfmt::skip]
- fn filter_block<'a>(&self, txdata: &TransactionData<'a>) -> Vec<&'a Transaction> {
+ fn filter_block<'a>(&mut self, txdata: &TransactionData<'a>) -> Vec<&'a Transaction> {
let mut matched_txn = new_hash_set();
txdata.iter().filter(|&&(_, tx)| {
let mut matches = self.spends_watched_output(tx);
Why this scored 43/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.