diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 47562b07413..49e313cf48f 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 b69383a8932..849e1f57481 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 - } - synced, ts, err := activeChainControl.Wallet.IsSynced() - if err != nil { - return mkErr("unable to determine if wallet is "+ - "synced: %v", err) - } + 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(ts, 0), synced) + ltndLog.Debugf("Syncing to block timestamp: %v, is "+ + "synced=%v", time.Unix(res.bestBlockTime, 0), + res.synced) - if synced { - break + 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 + } } - time.Sleep(time.Second * 1) + break } _, bestHeight, err = activeChainControl.ChainIO.GetBestBlock()