multi: extract key ring creation from chain control

To make it possible to supply our own implementation of a secret key
ring, we extract that part from the chain control and split the whole
chain control creation into two parts.
This commit is contained in:
Oliver Gugger
2021-10-14 15:42:47 +02:00
parent 1309c6afea
commit 9fa9dd8e43
4 changed files with 103 additions and 68 deletions

View File

@ -86,15 +86,24 @@ type DatabaseBuilder interface {
BuildDatabase(ctx context.Context) (*DatabaseInstances, func(), error)
}
// WalletConfigBuilder is an interface that must be satisfied by a custom wallet
// implementation.
type WalletConfigBuilder interface {
// BuildWalletConfig is responsible for creating or unlocking and then
// fully initializing a wallet.
BuildWalletConfig(context.Context, *DatabaseInstances,
*rpcperms.InterceptorChain,
[]*ListenerWithSignal) (*chainreg.PartialChainControl,
*btcwallet.Config, func(), error)
}
// ChainControlBuilder is an interface that must be satisfied by a custom wallet
// implementation.
type ChainControlBuilder interface {
// BuildChainControl is responsible for creating or unlocking and then
// fully initializing a wallet and returning it as part of a fully
// populated chain control instance.
BuildChainControl(context.Context, *DatabaseInstances,
*rpcperms.InterceptorChain,
[]*ListenerWithSignal) (*chainreg.ChainControl, func(), error)
// BuildChainControl is responsible for creating a fully populated chain
// control instance from a wallet.
BuildChainControl(*chainreg.PartialChainControl,
*btcwallet.Config) (*chainreg.ChainControl, func(), error)
}
// ImplementationCfg is a struct that holds all configuration items for
@ -116,6 +125,10 @@ type ImplementationCfg struct {
// backend instances.
DatabaseBuilder
// WalletConfigBuilder is a type that can provide a wallet configuration
// with a fully loaded and unlocked wallet.
WalletConfigBuilder
// ChainControlBuilder is a type that can provide a custom wallet
// implementation.
ChainControlBuilder
@ -195,15 +208,14 @@ func (d *DefaultWalletImpl) Permissions() map[string][]bakery.Op {
return nil
}
// BuildChainControl is responsible for creating or unlocking and then fully
// initializing a wallet and returning it as part of a fully populated chain
// control instance.
// BuildWalletConfig is responsible for creating or unlocking and then
// fully initializing a wallet.
//
// NOTE: This is part of the ChainControlBuilder interface.
func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
// NOTE: This is part of the WalletConfigBuilder interface.
func (d *DefaultWalletImpl) BuildWalletConfig(ctx context.Context,
dbs *DatabaseInstances, interceptorChain *rpcperms.InterceptorChain,
grpcListeners []*ListenerWithSignal) (*chainreg.ChainControl, func(),
error) {
grpcListeners []*ListenerWithSignal) (*chainreg.PartialChainControl,
*btcwallet.Config, func(), error) {
// Keep track of our various cleanup functions. We use a defer function
// as well to not repeat ourselves with every return statement.
@ -245,7 +257,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
err := fmt.Errorf("unable to initialize neutrino "+
"backend: %v", err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
cleanUpTasks = append(cleanUpTasks, neutrinoCleanUp)
neutrinoCS = neutrinoBackend
@ -270,7 +282,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
d.pwService.SetMacaroonDB(dbs.MacaroonDB)
walletExists, err := d.pwService.WalletExists()
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
if !walletExists {
@ -287,9 +299,9 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
if d.cfg.WalletUnlockPasswordFile != "" && !walletExists &&
!d.cfg.WalletUnlockAllowCreate {
return nil, nil, fmt.Errorf("wallet unlock password file was " +
"specified but wallet does not exist; initialize the " +
"wallet before using auto unlocking")
return nil, nil, nil, fmt.Errorf("wallet unlock password file " +
"was specified but wallet does not exist; initialize " +
"the wallet before using auto unlocking")
}
// What wallet mode are we running in? We've already made sure the no
@ -306,8 +318,8 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
"password provided in file")
pwBytes, err := ioutil.ReadFile(d.cfg.WalletUnlockPasswordFile)
if err != nil {
return nil, nil, fmt.Errorf("error reading password "+
"from file %s: %v",
return nil, nil, nil, fmt.Errorf("error reading "+
"password from file %s: %v",
d.cfg.WalletUnlockPasswordFile, err)
}
@ -322,8 +334,8 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
pwBytes, 0,
)
if err != nil {
return nil, nil, fmt.Errorf("error unlocking wallet "+
"with password from file: %v", err)
return nil, nil, nil, fmt.Errorf("error unlocking "+
"wallet with password from file: %v", err)
}
cleanUpTasks = append(cleanUpTasks, func() {
@ -343,7 +355,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
// over RPC.
default:
if err := d.interceptor.Notifier.NotifyReady(false); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
params, err := waitForWalletPassword(
@ -354,7 +366,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
err := fmt.Errorf("unable to set up wallet password "+
"listeners: %v", err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
walletInitParams = *params
@ -386,7 +398,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
err := fmt.Errorf("unable to set up macaroon "+
"authentication: %v", err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
cleanUpTasks = append(cleanUpTasks, func() {
if err := macaroonService.Close(); err != nil {
@ -402,7 +414,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
if err != nil && err != macaroons.ErrAlreadyUnlocked {
err := fmt.Errorf("unable to unlock macaroons: %v", err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
// In case we actually needed to unlock the wallet, we now need
@ -415,7 +427,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
ctx, macaroonService, adminPermissions(),
)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
// The channel is buffered by one element so writing
@ -446,7 +458,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
err := fmt.Errorf("unable to create macaroons "+
"%v", err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
}
@ -538,7 +550,7 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
err := fmt.Errorf("unable to create partial chain control: %v",
err)
d.logger.Error(err)
return nil, nil, err
return nil, nil, nil, err
}
walletConfig := &btcwallet.Config{
@ -562,23 +574,60 @@ func (d *DefaultWalletImpl) BuildChainControl(ctx context.Context,
walletConfig.CoinSelectionStrategy = wallet.CoinSelectionRandom
default:
return nil, nil, fmt.Errorf("unknown coin selection strategy "+
"%v", d.cfg.CoinSelectionStrategy)
return nil, nil, nil, fmt.Errorf("unknown coin selection "+
"strategy %v", d.cfg.CoinSelectionStrategy)
}
earlyExit = false
return partialChainControl, walletConfig, cleanUp, nil
}
// BuildChainControl is responsible for creating a fully populated chain
// control instance from a wallet.
//
// NOTE: This is part of the ChainControlBuilder interface.
func (d *DefaultWalletImpl) BuildChainControl(
partialChainControl *chainreg.PartialChainControl,
walletConfig *btcwallet.Config) (*chainreg.ChainControl, func(), error) {
walletController, err := btcwallet.New(
*walletConfig, partialChainControl.Cfg.BlockCache,
)
if err != nil {
fmt.Printf("unable to create wallet controller: %v\n", err)
d.logger.Error(err)
return nil, nil, err
}
keyRing := keychain.NewBtcWalletKeyRing(
walletController.InternalWallet(), walletConfig.CoinType,
)
// Create, and start the lnwallet, which handles the core payment
// channel logic, and exposes control via proxy state machines.
lnWalletConfig := lnwallet.Config{
Database: partialChainControl.Cfg.ChanStateDB,
Notifier: partialChainControl.ChainNotifier,
WalletController: walletController,
Signer: walletController,
FeeEstimator: partialChainControl.FeeEstimator,
SecretKeyRing: keyRing,
ChainIO: walletController,
DefaultConstraints: partialChainControl.ChannelConstraints,
NetParams: *walletConfig.NetParams,
}
// We've created the wallet configuration now, so we can finish
// initializing the main chain control.
activeChainControl, ccCleanup, err := chainreg.NewChainControl(
walletConfig, partialChainControl,
activeChainControl, cleanUp, err := chainreg.NewChainControl(
lnWalletConfig, walletController, partialChainControl,
)
cleanUpTasks = append(cleanUpTasks, ccCleanup)
if err != nil {
err := fmt.Errorf("unable to create chain control: %v", err)
d.logger.Error(err)
return nil, nil, err
}
earlyExit = false
return activeChainControl, cleanUp, nil
}