Don't broadcast manual-funded chan closing txn on HTLC timeouts
What changed, and why it matters
This patch fixes a follow-up bug in the Lightning Dev Kit's channel monitor. For channels where the user manually broadcasts the funding transaction, the software could incorrectly try to broadcast a force-closing transaction before the funding transaction had actually appeared on-chain—specifically when HTLC payments timed out. This could lead to wasted transaction fees, failed broadcasts, or unnecessary on-chain activity. The fix applies the same safety gate already used for normal commitment broadcasts to the HTLC-timeout force-close path.
Review related force-close and timeout paths for similar missing gating. Add regression tests covering manual-broadcast channels with HTLC timeouts before funding is seen on-chain. Consider centralizing the broadcast-gating check to reduce future inconsistency.
Security signals we found
Denial-of-service-like resource waste via spurious transaction broadcast attempts
Potential fee loss from premature or invalid transaction submission
Inconsistent safety gating across force-close code paths
Follow-up fix to a prior broadcast-gating commit
Evidence from the diff
In channelmonitor.rs, the HTLC timeout force-close path now checks !self.is_manual_broadcast || self.funding_seen_onchain before appending claimable outpoints and watch outputs. This mirrors the gating introduced in commit 6c5ef049b8d0ec174d7368d48b7b429efffb4a61 for commitment transaction broadcast. Without the gate, a manual-broadcast channel whose funding tx is not yet on-chain would generate and attempt to broadcast a holder commitment close tx on HTLC timeout, causing spurious fee bumps or unbroadcastable transactions.
Changed components
lightning/src/chain/channelmonitor.rsHTLC timeout handling in ChannelMonitorImplManual-broadcast channel flowInspect captured patch +6 / −2
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index 3b0b393..5182679 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -5664,8 +5664,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
let (mut new_outpoints, mut new_outputs) =
self.generate_claimable_outpoints_and_watch_outputs(Some(reason), false);
- claimable_outpoints.append(&mut new_outpoints);
- watch_outputs.append(&mut new_outputs);
+ if !self.is_manual_broadcast || self.funding_seen_onchain {
+ claimable_outpoints.append(&mut new_outpoints);
+ watch_outputs.append(&mut new_outputs);
+ } else {
+ log_info!(logger, "Not broadcasting holder commitment for manual-broadcast channel before funding appears on-chain");
+ }
}
}
Why this scored 44/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.