From ce9ccd3f14e7a95886071d10463177958662cd6c Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 7 Jun 2021 13:15:10 +0200 Subject: [PATCH] rpcserver: prevent shutdown during wallet recovery If the wallet recovery chain rescan was aborted before it finished, the user would need to remember to use a positive recovery_window value the next time they unlock the wallet for the rescan to continue. Because forgetting to do so could lead to an incomplete wallet state (and therefore potential missing funds) we rather don't allow shutting down lnd through the RPC while a rescan is in progress. This won't prevent any user from manually signaling Ctrl+C to kill lnd. But that user might also check the log and see there's still something going on that's preventing lnd from shutting down. --- rpcserver.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rpcserver.go b/rpcserver.go index 9c6d182f..7a2df67d 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5531,8 +5531,24 @@ func (r *rpcServer) GetNetworkInfo(ctx context.Context, // StopDaemon will send a shutdown request to the interrupt handler, triggering // a graceful shutdown of the daemon. -func (r *rpcServer) StopDaemon(ctx context.Context, +func (r *rpcServer) StopDaemon(_ context.Context, _ *lnrpc.StopRequest) (*lnrpc.StopResponse, error) { + + // Before we even consider a shutdown, are we currently in recovery + // mode? We don't want to allow shutting down during recovery because + // that would mean the user would have to manually continue the rescan + // process next time by using `lncli unlock --recovery_window X` + // otherwise some funds wouldn't be picked up. + isRecoveryMode, progress, err := r.server.cc.Wallet.GetRecoveryInfo() + if err != nil { + return nil, fmt.Errorf("unable to get wallet recovery info: %v", + err) + } + if isRecoveryMode && progress < 1 { + return nil, fmt.Errorf("wallet recovery in progress, cannot " + + "shut down, please wait until rescan finishes") + } + r.interceptor.RequestShutdown() return &lnrpc.StopResponse{}, nil }