misc: add ability to store the wallet in the remote DB

This commit is contained in:
Andras Banki-Horvath committed 2021-05-04 17:33:11 +02:00
1 parent 08be03367a
commit b6a620e6b2
7 files changed
+203 -57

No files matched your search

+113 -6
View File
@@ -19,12 +19,14 @@ import (
"github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet"
base "github.com/btcsuite/btcwallet/wallet"
"github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wallet/txrules"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/channeldb/kvdb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
@@ -37,6 +39,13 @@ const (
// UnconfirmedHeight is the special case end height that is used to
// obtain unconfirmed transactions from ListTransactionDetails.
UnconfirmedHeight int32 = -1
// walletMetaBucket is used to store wallet metadata.
walletMetaBucket = "lnwallet"
// walletReadyKey is used to indicate that the wallet has been
// initialized.
walletReadyKey = "ready"
)
var (
@@ -87,9 +96,6 @@ var _ lnwallet.BlockChainIO = (*BtcWallet)(nil)
// New returns a new fully initialized instance of BtcWallet given a valid
// configuration struct.
func New(cfg Config, blockCache *blockcache.BlockCache) (*BtcWallet, error) {
// Ensure the wallet exists or create it when the create flag is set.
netDir := NetworkDir(cfg.DataDir, cfg.NetParams)
// Create the key scope for the coin type being managed by this wallet.
chainKeyScope := waddrmgr.KeyScope{
Purpose: keychain.BIP0043Purpose,
@@ -108,10 +114,13 @@ func New(cfg Config, blockCache *blockcache.BlockCache) (*BtcWallet, error) {
} else {
pubPass = cfg.PublicPass
}
loader := base.NewLoader(
cfg.NetParams, netDir, cfg.NoFreelistSync,
cfg.DBTimeOut, cfg.RecoveryWindow,
loader, err := NewWalletLoader(
cfg.NetParams, cfg.RecoveryWindow, cfg.LoaderOptions...,
)
if err != nil {
return nil, err
}
walletExists, err := loader.WalletExists()
if err != nil {
return nil, err
@@ -149,6 +158,104 @@ func New(cfg Config, blockCache *blockcache.BlockCache) (*BtcWallet, error) {
}, nil
}
// loaderCfg holds optional wallet loader configuration.
type loaderCfg struct {
dbDirPath string
noFreelistSync bool
dbTimeout time.Duration
useLocalDB bool
externalDB kvdb.Backend
}
// LoaderOption is a functional option to update the optional loader config.
type LoaderOption func(*loaderCfg)
// LoaderWithLocalWalletDB configures the wallet loader to use the local db.
func LoaderWithLocalWalletDB(dbDirPath string, noFreelistSync bool,
dbTimeout time.Duration) LoaderOption {
return func(cfg *loaderCfg) {
cfg.dbDirPath = dbDirPath
cfg.noFreelistSync = noFreelistSync
cfg.dbTimeout = dbTimeout
cfg.useLocalDB = true
}
}
// LoaderWithExternalWalletDB configures the wallet loadr to use an external db.
func LoaderWithExternalWalletDB(db kvdb.Backend) LoaderOption {
return func(cfg *loaderCfg) {
cfg.externalDB = db
}
}
// NewWalletLoader constructs a wallet loader.
func NewWalletLoader(chainParams *chaincfg.Params, recoveryWindow uint32,
opts ...LoaderOption) (*wallet.Loader, error) {
cfg := &loaderCfg{}
// Apply all functional options.
for _, o := range opts {
o(cfg)
}
if cfg.externalDB != nil && cfg.useLocalDB {
return nil, fmt.Errorf("wallet can either be in the local or " +
"an external db")
}
if cfg.externalDB != nil {
loader, err := base.NewLoaderWithDB(
chainParams, recoveryWindow, cfg.externalDB,
func() (bool, error) {
return externalWalletExists(cfg.externalDB)
},
)
if err != nil {
return nil, err
}
// Decorate wallet db with out own key such that we
// can always check whether the wallet exists or not.
loader.OnWalletCreated(onWalletCreated)
return loader, nil
}
return base.NewLoader(
chainParams, cfg.dbDirPath, cfg.noFreelistSync,
cfg.dbTimeout, recoveryWindow,
), nil
}
// externalWalletExists is a helper function that we use to template btcwallet's
// Loader in order to be able check if the wallet database has been initialized
// in an external DB.
func externalWalletExists(db kvdb.Backend) (bool, error) {
exists := false
err := kvdb.View(db, func(tx kvdb.RTx) error {
metaBucket := tx.ReadBucket([]byte(walletMetaBucket))
if metaBucket != nil {
walletReady := metaBucket.Get([]byte(walletReadyKey))
exists = string(walletReady) == walletReadyKey
}
return nil
}, func() {})
return exists, err
}
// onWalletCreated is executed when btcwallet creates the wallet the first time.
func onWalletCreated(tx kvdb.RwTx) error {
metaBucket, err := tx.CreateTopLevelBucket([]byte(walletMetaBucket))
if err != nil {
return err
}
return metaBucket.Put([]byte(walletReadyKey), []byte(walletReadyKey))
}
// BackEnd returns the underlying ChainService's name as a string.
//
// This is a part of the WalletController interface.
+2 -12
View File
@@ -28,10 +28,6 @@ var (
// Config is a struct which houses configuration parameters which modify the
// instance of BtcWallet generated by the New() function.
type Config struct {
// DataDir is the name of the directory where the wallet's persistent
// state should be stored.
DataDir string
// LogDir is the name of the directory which should be used to store
// generated log files.
LogDir string
@@ -76,14 +72,8 @@ type Config struct {
// normally when creating the BtcWallet.
Wallet *wallet.Wallet
// NoFreelistSync, if true, prevents the database from syncing its
// freelist to disk, resulting in improved performance at the expense of
// increased startup time.
NoFreelistSync bool
// DBTimeOut specifies the timeout value to use when opening the wallet
// database.
DBTimeOut time.Duration
// LoaderOptions holds functional wallet db loader options.
LoaderOptions []LoaderOption
}
// NetworkDir returns the directory name of a network directory to hold wallet
+10 -2
View File
@@ -3427,12 +3427,16 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
aliceWalletConfig := &btcwallet.Config{
PrivatePass: []byte("alice-pass"),
HdSeed: aliceSeedBytes,
DataDir: tempTestDirAlice,
NetParams: netParams,
ChainSource: aliceClient,
CoinType: keychain.CoinTypeTestnet,
// wallet starts in recovery mode
RecoveryWindow: 2,
LoaderOptions: []btcwallet.LoaderOption{
btcwallet.LoaderWithLocalWalletDB(
tempTestDirAlice, false, time.Minute,
),
},
}
aliceWalletController, err = walletDriver.New(
aliceWalletConfig, blockCache,
@@ -3454,12 +3458,16 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
bobWalletConfig := &btcwallet.Config{
PrivatePass: []byte("bob-pass"),
HdSeed: bobSeedBytes,
DataDir: tempTestDirBob,
NetParams: netParams,
ChainSource: bobClient,
CoinType: keychain.CoinTypeTestnet,
// wallet starts without recovery mode
RecoveryWindow: 0,
LoaderOptions: []btcwallet.LoaderOption{
btcwallet.LoaderWithLocalWalletDB(
tempTestDirBob, false, time.Minute,
),
},
}
bobWalletController, err = walletDriver.New(
bobWalletConfig, blockCache,