From 52b3a06733d9eca00a6bb4ff42bda3a702172f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Tigerstr=C3=B6m?= Date: Tue, 24 Sep 2024 17:58:08 +0200 Subject: [PATCH] lnd: allow shutdown signal during `IsSynced` check Prior to this commit, lnd could become unresponsive to shutdown signals during the `IsSynced` check. Since the `IsSynced` check can occasionally take a long time to complete, this could result in lnd failing to shut down promptly. --- docs/release-notes/release-notes-0.19.0.md | 5 ++ lnd.go | 59 ++++++++++++++++------ 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 47562b074..49e313cf4 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -27,6 +27,10 @@ cause a nil pointer dereference during the probing of a payment request that does not contain a payment address. +* [Fix a bug](https://github.com/lightningnetwork/lnd/pull/9137) that prevented + a graceful shutdown of LND during the main chain backend sync check in certain + cases. + # New Features ## Functional Enhancements ## RPC Additions @@ -75,4 +79,5 @@ * CharlieZKSmith * Elle Mouton * Pins +* Viktor Tigerström * Ziggie diff --git a/lnd.go b/lnd.go index b69383a89..849e1f574 100644 --- a/lnd.go +++ b/lnd.go @@ -667,25 +667,54 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg, ltndLog.Infof("Waiting for chain backend to finish sync, "+ "start_height=%v", bestHeight) + type syncResult struct { + synced bool + bestBlockTime int64 + err error + } + + var syncedResChan = make(chan syncResult, 1) + for { - if !interceptor.Alive() { + // We check if the wallet is synced in a separate goroutine as + // the call is blocking, and we want to be able to interrupt it + // if the daemon is shutting down. + go func() { + synced, bestBlockTime, err := activeChainControl.Wallet. + IsSynced() + syncedResChan <- syncResult{synced, bestBlockTime, err} + }() + + select { + case <-interceptor.ShutdownChannel(): return nil + + case res := <-syncedResChan: + if res.err != nil { + return mkErr("unable to determine if wallet "+ + "is synced: %v", res.err) + } + + ltndLog.Debugf("Syncing to block timestamp: %v, is "+ + "synced=%v", time.Unix(res.bestBlockTime, 0), + res.synced) + + if res.synced { + break + } + + // If we're not yet synced, we'll wait for a second + // before checking again. + select { + case <-interceptor.ShutdownChannel(): + return nil + + case <-time.After(time.Second): + continue + } } - synced, ts, err := activeChainControl.Wallet.IsSynced() - if err != nil { - return mkErr("unable to determine if wallet is "+ - "synced: %v", err) - } - - ltndLog.Debugf("Syncing to block timestamp: %v, is synced=%v", - time.Unix(ts, 0), synced) - - if synced { - break - } - - time.Sleep(time.Second * 1) + break } _, bestHeight, err = activeChainControl.ChainIO.GetBestBlock()