peer: send out a notification after the 1st conf, then wait for the rest
What changed, and why it matters
This commit changes how LND notifies wallets and user interfaces about a cooperative channel close. Previously, LND waited for a variable number of confirmations based on the channel's capacity before sending any success notification. Now it sends an initial notification after just one confirmation, then a final notification after the full required confirmations. It also adds a hidden configuration override for testing. The change is described as a UI-compatibility improvement, not a security fix.
Review the full change (including any unshown second notification path) to confirm the first update is clearly marked as provisional and that consumers do not treat it as final. Verify the ChannelCloseConfs override is only exposed in test configurations and cannot be set in production.
Security signals we found
Confirmation-policy change for cooperative close notifications
New test-only config override for confirmation count
Potential premature action by consumers on single-confirmation close update
No explicit security claim in commit message or diff
Evidence from the diff
In peer/brontide.go, finalizeChanClosure now reads a ChannelCloseConfs override from peer config (UnwrapOrFunc) and still calls WaitForChanToClose with the resulting numConfs. The diff only shows the override plumbing and formatting/comment changes; the actual ‘send notification after 1st conf, then wait for the rest’ logic is referenced in the commit message but is not visible in the supplied diff hunk. The change reduces the chance that a UI/wallet times out waiting for the first update, but also means subsystems may act on a close that is not yet fully confirmed according to the capacity-scaled policy.
Changed components
peer/brontide.gofinalizeChanClosureWaitForChanToCloseChannelCloseUpdate notification flowInspect captured patch +27 / −18
diff --git a/peer/brontide.go b/peer/brontide.go
index ac91f00..13c8220 100644
--- a/peer/brontide.go
+++ b/peer/brontide.go
@@ -4471,19 +4471,27 @@ func (p *Brontide) finalizeChanClosure(chanCloser *chancloser.ChanCloser) {
localOut := chanCloser.LocalCloseOutput()
remoteOut := chanCloser.RemoteCloseOutput()
auxOut := chanCloser.AuxOutputs()
- // Determine the number of confirmations to wait before
- // signaling a successful cooperative close, scaled by
- // channel capacity (see CloseConfsForCapacity).
- numConfs := lnwallet.CloseConfsForCapacity(chanCloser.Channel().Capacity)
-
- go WaitForChanToClose(
- chanCloser.NegotiationHeight(), notifier, errChan,
- &chanPoint, &closingTxid, closingTx.TxOut[0].PkScript, numConfs, func() {
- // Respond to the local subsystem which requested the
- // channel closure.
- if closeReq != nil {
- closeReq.Updates <- &ChannelCloseUpdate{
- ClosingTxid: closingTxid[:],
+
+ // Determine the number of confirmations to wait before signaling a
+ // successful cooperative close, scaled by channel capacity (see
+ // CloseConfsForCapacity). Check if we have a config override for
+ // testing purposes.
+ chanCapacity := chanCloser.Channel().Capacity
+ numConfs := p.cfg.ChannelCloseConfs.UnwrapOrFunc(func() uint32 {
+ // No override, use normal capacity-based scaling.
+ return lnwallet.CloseConfsForCapacity(chanCapacity)
+ })
+
+ // Register for full confirmation to send the final update.
+ closeScript := closingTx.TxOut[0].PkScript
+ go WaitForChanToClose(
+ chanCloser.NegotiationHeight(), notifier, errChan,
+ &chanPoint, &closingTxid, closeScript, numConfs, func() {
+ // Respond to the local subsystem which requested the
+ // channel closure.
+ if closeReq != nil {
+ closeReq.Updates <- &ChannelCloseUpdate{
+ ClosingTxid: closingTxid[:],
Success: true,
LocalCloseOutput: localOut,
RemoteCloseOutput: remoteOut,
@@ -4500,15 +4508,16 @@ func (p *Brontide) finalizeChanClosure(chanCloser *chancloser.ChanCloser) {
// finally the callback will be executed. If any error is encountered within
// the function, then it will be sent over the errChan.
func WaitForChanToClose(bestHeight uint32, notifier chainntnfs.ChainNotifier,
- errChan chan error, chanPoint *wire.OutPoint,
- closingTxID *chainhash.Hash, closeScript []byte, numConfs uint32, cb func()) {
+ errChan chan error, chanPoint *wire.OutPoint,
+ closingTxID *chainhash.Hash, closeScript []byte, numConfs uint32,
+ cb func()) {
peerLog.Infof("Waiting for confirmation of close of ChannelPoint(%v) "+
"with txid: %v", chanPoint, closingTxID)
- confNtfn, err := notifier.RegisterConfirmationsNtfn(
- closingTxID, closeScript, numConfs, bestHeight,
- )
+ confNtfn, err := notifier.RegisterConfirmationsNtfn(
+ closingTxID, closeScript, numConfs, bestHeight,
+ )
if err != nil {
if errChan != nil {
errChan <- err
Why this scored 26/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.