diff --git a/lnd.go b/lnd.go index c7986dad..238ad535 100644 --- a/lnd.go +++ b/lnd.go @@ -318,6 +318,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { var ( walletInitParams WalletUnlockParams + shutdownUnlocker = func() {} privateWalletPw = lnwallet.DefaultPrivatePassphrase publicWalletPw = lnwallet.DefaultPublicPassphrase ) @@ -377,7 +378,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { // started with the --noseedbackup flag, we use the default password // for wallet encryption. if !cfg.NoSeedBackup { - params, err := waitForWalletPassword( + params, shutdown, err := waitForWalletPassword( cfg, cfg.RESTListeners, serverOpts, restDialOpts, restProxyDest, tlsCfg, walletUnlockerListeners, ) @@ -389,6 +390,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { } walletInitParams = *params + shutdownUnlocker = shutdown privateWalletPw = walletInitParams.Password publicWalletPw = walletInitParams.Password defer func() { @@ -443,6 +445,10 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { } } + // Now we're definitely done with the unlocker, shut it down so we can + // start the main RPC service later. + shutdownUnlocker() + // With the information parsed from the configuration, create valid // instances of the pertinent interfaces required to operate the // Lightning Network Daemon. @@ -1041,7 +1047,7 @@ type WalletUnlockParams struct { func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, serverOpts []grpc.ServerOption, restDialOpts []grpc.DialOption, restProxyDest string, tlsConf *tls.Config, - getListeners rpcListeners) (*WalletUnlockParams, error) { + getListeners rpcListeners) (*WalletUnlockParams, func(), error) { chainConfig := cfg.Bitcoin if cfg.registeredChains.PrimaryChain() == chainreg.LitecoinChain { @@ -1064,16 +1070,23 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, // Set up a new PasswordService, which will listen for passwords // provided over RPC. grpcServer := grpc.NewServer(serverOpts...) - defer grpcServer.GracefulStop() lnrpc.RegisterWalletUnlockerServer(grpcServer, pwService) + var shutdownFuncs []func() + shutdown := func() { + for _, shutdownFn := range shutdownFuncs { + shutdownFn() + } + } + shutdownFuncs = append(shutdownFuncs, grpcServer.GracefulStop) + // Start a gRPC server listening for HTTP/2 connections, solely used // for getting the encryption password from the client. listeners, cleanup, err := getListeners() if err != nil { - return nil, err + return nil, shutdown, err } - defer cleanup() + shutdownFuncs = append(shutdownFuncs, cleanup) // Use a WaitGroup so we can be sure the instructions on how to input the // password is the last thing to be printed to the console. @@ -1082,21 +1095,21 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, for _, lis := range listeners { wg.Add(1) go func(lis *ListenerWithSignal) { - rpcsLog.Infof("password RPC server listening on %s", + rpcsLog.Infof("Password RPC server listening on %s", lis.Addr()) // Close the ready chan to indicate we are listening. close(lis.Ready) wg.Done() - grpcServer.Serve(lis) + _ = grpcServer.Serve(lis) }(lis) } // Start a REST proxy for our gRPC server above. ctx := context.Background() ctx, cancel := context.WithCancel(ctx) - defer cancel() + shutdownFuncs = append(shutdownFuncs, cancel) mux := proxy.NewServeMux() @@ -1104,7 +1117,7 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, ctx, mux, restProxyDest, restDialOpts, ) if err != nil { - return nil, err + return nil, shutdown, err } srv := &http.Server{Handler: allowCORS(mux, cfg.RestCORS)} @@ -1112,22 +1125,24 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, for _, restEndpoint := range restEndpoints { lis, err := lncfg.TLSListenOnAddress(restEndpoint, tlsConf) if err != nil { - ltndLog.Errorf( - "password gRPC proxy unable to listen on %s", - restEndpoint, - ) - return nil, err + ltndLog.Errorf("Password gRPC proxy unable to listen "+ + "on %s", restEndpoint) + return nil, shutdown, err } - defer lis.Close() + shutdownFuncs = append(shutdownFuncs, func() { + err := lis.Close() + if err != nil { + rpcsLog.Errorf("Error closing listener: %v", + err) + } + }) wg.Add(1) go func() { - rpcsLog.Infof( - "password gRPC proxy started at %s", - lis.Addr(), - ) + rpcsLog.Infof("Password gRPC proxy started at %s", + lis.Addr()) wg.Done() - srv.Serve(lis) + _ = srv.Serve(lis) }() } @@ -1158,8 +1173,8 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, // version, then we'll return an error as we don't understand // this. if cipherSeed.InternalVersion != keychain.KeyDerivationVersion { - return nil, fmt.Errorf("invalid internal seed version "+ - "%v, current version is %v", + return nil, shutdown, fmt.Errorf("invalid internal "+ + "seed version %v, current version is %v", cipherSeed.InternalVersion, keychain.KeyDerivationVersion) } @@ -1185,7 +1200,7 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, ltndLog.Errorf("Could not unload new "+ "wallet: %v", err) } - return nil, err + return nil, shutdown, err } return &WalletUnlockParams{ @@ -1195,7 +1210,7 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, Wallet: newWallet, ChansToRestore: initMsg.ChanBackups, UnloadWallet: loader.UnloadWallet, - }, nil + }, shutdown, nil // The wallet has already been created in the past, and is simply being // unlocked. So we'll just return these passphrases. @@ -1206,10 +1221,10 @@ func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr, Wallet: unlockMsg.Wallet, ChansToRestore: unlockMsg.ChanBackups, UnloadWallet: unlockMsg.UnloadWallet, - }, nil + }, shutdown, nil case <-signal.ShutdownChannel(): - return nil, fmt.Errorf("shutting down") + return nil, shutdown, fmt.Errorf("shutting down") } }