misc: add ability to store the wallet in the remote DB
This commit is contained in:
7 files changed
+203
-57
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user