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:
parent
71ba2a8e60
commit
b685a97fcd
67
lnd.go
67
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")
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user