multi: make macaroon DB remote compatible

The macaroon root keys should also be stored to the remote database if a
replicated backend such as etcd is used.
This commit refactors the macaroons service and wallet unlocker to
accept a kvdb backend directly instead of creating the bolt instance
automatically.
This commit is contained in:
Oliver Gugger
2021-08-03 09:57:30 +02:00
parent 0d3647d715
commit f7b17df452
8 changed files with 121 additions and 104 deletions

View File

@@ -13,6 +13,7 @@ import (
"github.com/lightningnetwork/lnd/aezeed"
"github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
@@ -124,30 +125,28 @@ type UnlockerService struct {
// the WalletUnlocker service.
MacResponseChan chan []byte
chainDir string
noFreelistSync bool
netParams *chaincfg.Params
netParams *chaincfg.Params
// macaroonFiles is the path to the three generated macaroons with
// different access permissions. These might not exist in a stateless
// initialization of lnd.
macaroonFiles []string
// dbTimeout specifies the timeout value to use when opening the wallet
// database.
dbTimeout time.Duration
// resetWalletTransactions indicates that the wallet state should be
// reset on unlock to force a full chain rescan.
resetWalletTransactions bool
// LoaderOpts holds the functional options for the wallet loader.
loaderOpts []btcwallet.LoaderOption
// macaroonDB is an instance of a database backend that stores all
// macaroon root keys. This will be nil on initialization and must be
// set using the SetMacaroonDB method as soon as it's available.
macaroonDB kvdb.Backend
}
// New creates and returns a new UnlockerService.
func New(chainDir string, params *chaincfg.Params, noFreelistSync bool,
macaroonFiles []string, dbTimeout time.Duration,
func New(params *chaincfg.Params, macaroonFiles []string,
resetWalletTransactions bool,
loaderOpts []btcwallet.LoaderOption) *UnlockerService {
@@ -158,11 +157,8 @@ func New(chainDir string, params *chaincfg.Params, noFreelistSync bool,
// Make sure we buffer the channel is buffered so the main lnd
// goroutine isn't blocking on writing to it.
MacResponseChan: make(chan []byte, 1),
chainDir: chainDir,
netParams: params,
macaroonFiles: macaroonFiles,
dbTimeout: dbTimeout,
noFreelistSync: noFreelistSync,
resetWalletTransactions: resetWalletTransactions,
loaderOpts: loaderOpts,
}
@@ -174,6 +170,12 @@ func (u *UnlockerService) SetLoaderOpts(loaderOpts []btcwallet.LoaderOption) {
u.loaderOpts = loaderOpts
}
// SetMacaroonDB can be used to inject the macaroon database after the unlocker
// service has been hooked to the main RPC server.
func (u *UnlockerService) SetMacaroonDB(macaroonDB kvdb.Backend) {
u.macaroonDB = macaroonDB
}
func (u *UnlockerService) newLoader(recoveryWindow uint32) (*wallet.Loader,
error) {
@@ -607,9 +609,8 @@ func (u *UnlockerService) ChangePassword(ctx context.Context,
// then close it again.
// Attempt to open the macaroon DB, unlock it and then change
// the passphrase.
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
macaroonService, err := macaroons.NewService(
netDir, "lnd", in.StatelessInit, u.dbTimeout,
u.macaroonDB, "lnd", in.StatelessInit,
)
if err != nil {
return nil, err

View File

@@ -113,7 +113,7 @@ func openOrCreateTestMacStore(tempDir string, pw *[]byte,
return nil, err
}
db, err := kvdb.Create(
kvdb.BoltBackendName, path.Join(netDir, macaroons.DBFilename),
kvdb.BoltBackendName, path.Join(netDir, "macaroons.db"),
true, kvdb.DefaultDBTimeout,
)
if err != nil {
@@ -154,8 +154,7 @@ func TestGenSeed(t *testing.T) {
}()
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, nil, false, testLoaderOpts(testDir),
)
// Now that the service has been created, we'll ask it to generate a
@@ -192,8 +191,7 @@ func TestGenSeedGenerateEntropy(t *testing.T) {
_ = os.RemoveAll(testDir)
}()
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, nil, false, testLoaderOpts(testDir),
)
// Now that the service has been created, we'll ask it to generate a
@@ -229,8 +227,7 @@ func TestGenSeedInvalidEntropy(t *testing.T) {
_ = os.RemoveAll(testDir)
}()
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, nil, false, testLoaderOpts(testDir),
)
// Now that the service has been created, we'll ask it to generate a
@@ -263,8 +260,7 @@ func TestInitWallet(t *testing.T) {
// Create new UnlockerService.
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, nil, false, testLoaderOpts(testDir),
)
// Once we have the unlocker service created, we'll now instantiate a
@@ -352,8 +348,7 @@ func TestCreateWalletInvalidEntropy(t *testing.T) {
// Create new UnlockerService.
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, nil, false, testLoaderOpts(testDir),
)
// We'll attempt to init the wallet with an invalid cipher seed and
@@ -385,8 +380,7 @@ func TestUnlockWallet(t *testing.T) {
// Create new UnlockerService that'll also drop the wallet's history on
// unlock.
service := walletunlocker.New(
testDir, testNetParams, true, nil, kvdb.DefaultDBTimeout,
true, testLoaderOpts(testDir),
testNetParams, nil, true, testLoaderOpts(testDir),
)
ctx := context.Background()
@@ -477,9 +471,9 @@ func TestChangeWalletPasswordNewRootkey(t *testing.T) {
// Create a new UnlockerService with our temp files.
service := walletunlocker.New(
testDir, testNetParams, true, tempFiles, kvdb.DefaultDBTimeout,
false, testLoaderOpts(testDir),
testNetParams, tempFiles, false, testLoaderOpts(testDir),
)
service.SetMacaroonDB(store.Backend)
ctx := context.Background()
newPassword := []byte("hunter2???")
@@ -588,10 +582,11 @@ func TestChangeWalletPasswordStateless(t *testing.T) {
// Create a new UnlockerService with our temp files.
service := walletunlocker.New(
testDir, testNetParams, true, []string{
testNetParams, []string{
tempMacFile, nonExistingFile,
}, kvdb.DefaultDBTimeout, false, testLoaderOpts(testDir),
}, false, testLoaderOpts(testDir),
)
service.SetMacaroonDB(store.Backend)
// Create a wallet we can try to unlock. We use the default password
// so we can check that the unlocker service defaults to this when