lnd: shutdown wallet unlocker after macaroon creation

Because we'll need to return the macaroon through the wallet unlocker
we cannot shut down its service before we have done so, otherwise
we'll end up in a deadlock. That's why we collect all shutdown
tasks and return them as a function that can be called after we've
initialized the macaroon service.
This commit is contained in:
Oliver Gugger 2020-10-06 17:23:36 +02:00
parent 71ba2a8e60
commit b685a97fcd
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

67
lnd.go
View File

@ -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")
}
}