Manage wallet db namespaces from wallet package.
This changes the wallet.Open function signature to remove the database namespace parameters. This is done so that the wallet package itself is responsible for the location and opening of these namespaces from the database, rather than requiring the caller to open these ahead of time. A new wallet.Create function has also been added. This function initializes a new wallet in an empty database, using the same namespaces as wallet.Open will eventually use. This relieves the caller from needing to manage wallet database namespaces explicitly. Fixes #397.
This commit is contained in:
parent
b1500ba02b
commit
fcccae3d1a
12 changed files with 177 additions and 149 deletions
|
@ -36,8 +36,19 @@ import (
|
|||
var (
|
||||
pubPassphrase = []byte("pubPassphrase")
|
||||
privPassphrase = []byte("privPassphrase")
|
||||
seed = bytes.Repeat([]byte{0x2a, 0x64, 0xdf, 0x08}, 8)
|
||||
fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
)
|
||||
|
||||
func createWaddrmgr(ns walletdb.Namespace, params *chaincfg.Params) (*waddrmgr.Manager, error) {
|
||||
err := waddrmgr.Create(ns, seed, pubPassphrase, privPassphrase, params,
|
||||
fastScrypt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return waddrmgr.Open(ns, pubPassphrase, params, nil)
|
||||
}
|
||||
|
||||
func ExampleCreate() {
|
||||
// Create a new walletdb.DB. See the walletdb docs for instructions on how
|
||||
// to do that.
|
||||
|
@ -56,10 +67,7 @@ func ExampleCreate() {
|
|||
}
|
||||
|
||||
// Create the address manager.
|
||||
seed := bytes.Repeat([]byte{0x2a, 0x64, 0xdf, 0x08}, 8)
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err := waddrmgr.Create(
|
||||
mgrNamespace, seed, pubPassphrase, privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
mgr, err := createWaddrmgr(mgrNamespace, &chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
@ -269,10 +277,7 @@ func exampleCreateMgrAndDBNamespace() (*waddrmgr.Manager, walletdb.Namespace, fu
|
|||
}
|
||||
|
||||
// Create the address manager
|
||||
seed := bytes.Repeat([]byte{0x2a, 0x64, 0xdf, 0x08}, 8)
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err := waddrmgr.Create(
|
||||
mgrNamespace, seed, pubPassphrase, privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
mgr, err := createWaddrmgr(mgrNamespace, &chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
dbTearDown()
|
||||
return nil, nil, nil, err
|
||||
|
@ -331,7 +336,11 @@ func exampleCreateTxStore() (*wtxmgr.Store, func(), error) {
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
s, err := wtxmgr.Create(wtxmgrNamespace)
|
||||
err = wtxmgr.Create(wtxmgrNamespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
s, err := wtxmgr.Open(wtxmgrNamespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -149,10 +149,14 @@ func TstCreateTxStore(t *testing.T) (store *wtxmgr.Store, tearDown func()) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create walletdb namespace: %v", err)
|
||||
}
|
||||
s, err := wtxmgr.Create(wtxmgrNamespace)
|
||||
err = wtxmgr.Create(wtxmgrNamespace)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create txstore: %v", err)
|
||||
}
|
||||
s, err := wtxmgr.Open(wtxmgrNamespace)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open txstore: %v", err)
|
||||
}
|
||||
return s, func() { os.RemoveAll(dir) }
|
||||
}
|
||||
|
||||
|
@ -345,8 +349,12 @@ func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, po
|
|||
t.Fatalf("Failed to create addr manager DB namespace: %v", err)
|
||||
}
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase, privPassphrase,
|
||||
err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase, privPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
if err == nil {
|
||||
mgr, err = waddrmgr.Open(mgrNamespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, nil)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create addr manager: %v", err)
|
||||
}
|
||||
|
|
|
@ -234,8 +234,12 @@ func setupManager(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager) {
|
|||
_ = os.RemoveAll(dirName)
|
||||
t.Fatalf("createDbNamespace: unexpected error: %v", err)
|
||||
}
|
||||
mgr, err = waddrmgr.Create(namespace, seed, pubPassphrase,
|
||||
err = waddrmgr.Create(namespace, seed, pubPassphrase,
|
||||
privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
if err == nil {
|
||||
mgr, err = waddrmgr.Open(namespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, nil)
|
||||
}
|
||||
if err != nil {
|
||||
db.Close()
|
||||
_ = os.RemoveAll(dirName)
|
||||
|
|
|
@ -2272,11 +2272,11 @@ func Open(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chain
|
|||
return loadManager(namespace, pubPassphrase, chainParams)
|
||||
}
|
||||
|
||||
// Create returns a new locked address manager in the given namespace. The
|
||||
// seed must conform to the standards described in hdkeychain.NewMaster and will
|
||||
// be used to create the master root node from which all hierarchical
|
||||
// deterministic addresses are derived. This allows all chained addresses in
|
||||
// the address manager to be recovered by using the same seed.
|
||||
// Create creates a new address manager in the given namespace. The seed must
|
||||
// conform to the standards described in hdkeychain.NewMaster and will be used
|
||||
// to create the master root node from which all hierarchical deterministic
|
||||
// addresses are derived. This allows all chained addresses in the address
|
||||
// manager to be recovered by using the same seed.
|
||||
//
|
||||
// All private and public keys and information are protected by secret keys
|
||||
// derived from the provided private and public passphrases. The public
|
||||
|
@ -2289,26 +2289,26 @@ func Open(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chain
|
|||
//
|
||||
// A ManagerError with an error code of ErrAlreadyExists will be returned the
|
||||
// address manager already exists in the specified namespace.
|
||||
func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []byte, chainParams *chaincfg.Params, config *ScryptOptions) (*Manager, error) {
|
||||
func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []byte, chainParams *chaincfg.Params, config *ScryptOptions) error {
|
||||
// Return an error if the manager has already been created in the given
|
||||
// database namespace.
|
||||
exists, err := managerExists(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil, managerError(ErrAlreadyExists, errAlreadyExists, nil)
|
||||
return managerError(ErrAlreadyExists, errAlreadyExists, nil)
|
||||
}
|
||||
|
||||
// Ensure the private passphrase is not empty.
|
||||
if len(privPassphrase) == 0 {
|
||||
str := "private passphrase may not be empty"
|
||||
return nil, managerError(ErrEmptyPassphrase, str, nil)
|
||||
return managerError(ErrEmptyPassphrase, str, nil)
|
||||
}
|
||||
|
||||
// Perform the initial bucket creation and database namespace setup.
|
||||
if err := createManagerNS(namespace); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
|
@ -2322,15 +2322,16 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
root, err := hdkeychain.NewMaster(seed, chainParams)
|
||||
if err != nil {
|
||||
str := "failed to derive master extended key"
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
|
||||
// Derive the cointype key according to BIP0044.
|
||||
coinTypeKeyPriv, err := deriveCoinTypeKey(root, chainParams.HDCoinType)
|
||||
if err != nil {
|
||||
str := "failed to derive cointype extended key"
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
defer coinTypeKeyPriv.Zero()
|
||||
|
||||
// Derive the account key for the first account according to BIP0044.
|
||||
acctKeyPriv, err := deriveAccountKey(coinTypeKeyPriv, 0)
|
||||
|
@ -2339,11 +2340,11 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
// required hierarchy can't be derived due to invalid child.
|
||||
if err == hdkeychain.ErrInvalidChild {
|
||||
str := "the provided seed is unusable"
|
||||
return nil, managerError(ErrKeyChain, str,
|
||||
return managerError(ErrKeyChain, str,
|
||||
hdkeychain.ErrUnusableSeed)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the branch keys can be derived for the provided seed according
|
||||
|
@ -2353,18 +2354,18 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
// required hierarchy can't be derived due to invalid child.
|
||||
if err == hdkeychain.ErrInvalidChild {
|
||||
str := "the provided seed is unusable"
|
||||
return nil, managerError(ErrKeyChain, str,
|
||||
return managerError(ErrKeyChain, str,
|
||||
hdkeychain.ErrUnusableSeed)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// The address manager needs the public extended key for the account.
|
||||
acctKeyPub, err := acctKeyPriv.Neuter()
|
||||
if err != nil {
|
||||
str := "failed to convert private key for account 0"
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
|
||||
// Generate new master keys. These master keys are used to protect the
|
||||
|
@ -2372,13 +2373,14 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
masterKeyPub, err := newSecretKey(&pubPassphrase, config)
|
||||
if err != nil {
|
||||
str := "failed to master public key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
masterKeyPriv, err := newSecretKey(&privPassphrase, config)
|
||||
if err != nil {
|
||||
str := "failed to master private key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer masterKeyPriv.Zero()
|
||||
|
||||
// Generate the private passphrase salt. This is used when hashing
|
||||
// passwords to detect whether an unlock can be avoided when the manager
|
||||
|
@ -2387,7 +2389,7 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
_, err = rand.Read(privPassphraseSalt[:])
|
||||
if err != nil {
|
||||
str := "failed to read random source for passphrase salt"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Generate new crypto public, private, and script keys. These keys are
|
||||
|
@ -2396,63 +2398,65 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
cryptoKeyPub, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto public key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyPriv, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto private key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyPriv.Zero()
|
||||
cryptoKeyScript, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto script key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyScript.Zero()
|
||||
|
||||
// Encrypt the crypto keys with the associated master keys.
|
||||
cryptoKeyPubEnc, err := masterKeyPub.Encrypt(cryptoKeyPub.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto public key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyPrivEnc, err := masterKeyPriv.Encrypt(cryptoKeyPriv.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto private key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyScriptEnc, err := masterKeyPriv.Encrypt(cryptoKeyScript.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto script key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Encrypt the cointype keys with the associated crypto keys.
|
||||
coinTypeKeyPub, err := coinTypeKeyPriv.Neuter()
|
||||
if err != nil {
|
||||
str := "failed to convert cointype private key"
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
coinTypePubEnc, err := cryptoKeyPub.Encrypt([]byte(coinTypeKeyPub.String()))
|
||||
if err != nil {
|
||||
str := "failed to encrypt cointype public key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
coinTypePrivEnc, err := cryptoKeyPriv.Encrypt([]byte(coinTypeKeyPriv.String()))
|
||||
if err != nil {
|
||||
str := "failed to encrypt cointype private key"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Encrypt the default account keys with the associated crypto keys.
|
||||
acctPubEnc, err := cryptoKeyPub.Encrypt([]byte(acctKeyPub.String()))
|
||||
if err != nil {
|
||||
str := "failed to encrypt public key for account 0"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
acctPrivEnc, err := cryptoKeyPriv.Encrypt([]byte(acctKeyPriv.String()))
|
||||
if err != nil {
|
||||
str := "failed to encrypt private key for account 0"
|
||||
return nil, managerError(ErrCrypto, str, err)
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Use the genesis block for the passed chain as the created at block
|
||||
|
@ -2523,16 +2527,8 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, maybeConvertDbError(err)
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
// The new address manager is locked by default, so clear the master,
|
||||
// crypto private, crypto script and cointype keys from memory.
|
||||
masterKeyPriv.Zero()
|
||||
cryptoKeyPriv.Zero()
|
||||
cryptoKeyScript.Zero()
|
||||
coinTypeKeyPriv.Zero()
|
||||
return newManager(namespace, chainParams, masterKeyPub, masterKeyPriv,
|
||||
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
|
||||
privPassphraseSalt), nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1706,19 +1706,25 @@ func TestManager(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a new manager.
|
||||
mgr, err := waddrmgr.Create(mgrNamespace, seed, pubPassphrase,
|
||||
err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase,
|
||||
privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
if err != nil {
|
||||
t.Errorf("Create: unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
mgr, err := waddrmgr.Open(mgrNamespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Open: unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE: Not using deferred close here since part of the tests is
|
||||
// explicitly closing the manager and then opening the existing one.
|
||||
|
||||
// Attempt to create the manager again to ensure the expected error is
|
||||
// returned.
|
||||
_, err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase,
|
||||
err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase,
|
||||
privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
if !checkManagerError(t, "Create existing", err, waddrmgr.ErrAlreadyExists) {
|
||||
mgr.Close()
|
||||
|
|
|
@ -11,11 +11,9 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/internal/prompt"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -117,46 +115,14 @@ func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte) (*W
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If a seed was provided, ensure that it is of valid length. Otherwise,
|
||||
// we generate a random seed for the wallet with the recommended seed
|
||||
// length.
|
||||
if seed != nil {
|
||||
if len(seed) < hdkeychain.MinSeedBytes ||
|
||||
len(seed) > hdkeychain.MaxSeedBytes {
|
||||
|
||||
return nil, hdkeychain.ErrInvalidSeedLen
|
||||
}
|
||||
} else {
|
||||
hdSeed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seed = hdSeed
|
||||
}
|
||||
|
||||
// Create the address manager.
|
||||
addrMgrNamespace, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = waddrmgr.Create(addrMgrNamespace, seed, pubPassphrase,
|
||||
privPassphrase, l.chainParams, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create empty transaction manager.
|
||||
txMgrNamespace, err := db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = wtxmgr.Create(txMgrNamespace)
|
||||
// Initialize the newly created database for the wallet before opening.
|
||||
err = Create(db, pubPassphrase, privPassphrase, seed, l.chainParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Open the newly-created wallet.
|
||||
w, err := Open(pubPassphrase, l.chainParams, db, addrMgrNamespace, txMgrNamespace, nil)
|
||||
w, err := Open(db, pubPassphrase, nil, l.chainParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -197,14 +163,6 @@ func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
addrMgrNS, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txMgrNS, err := db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cbs *waddrmgr.OpenCallbacks
|
||||
if canConsolePrompt {
|
||||
cbs = &waddrmgr.OpenCallbacks{
|
||||
|
@ -217,7 +175,7 @@ func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool)
|
|||
ObtainPrivatePass: noConsole,
|
||||
}
|
||||
}
|
||||
w, err := Open(pubPassphrase, l.chainParams, db, addrMgrNS, txMgrNS, cbs)
|
||||
w, err := Open(db, pubPassphrase, cbs, l.chainParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcrpcclient"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
|
@ -2058,27 +2059,77 @@ func (w *Wallet) ChainParams() *chaincfg.Params {
|
|||
return w.chainParams
|
||||
}
|
||||
|
||||
// Create creates an new wallet, writing it to an empty database. If the passed
|
||||
// seed is non-nil, it is used. Otherwise, a secure random seed of the
|
||||
// recommended length is generated.
|
||||
func Create(db walletdb.DB, pubPass, privPass, seed []byte, params *chaincfg.Params) error {
|
||||
// If a seed was provided, ensure that it is of valid length. Otherwise,
|
||||
// we generate a random seed for the wallet with the recommended seed
|
||||
// length.
|
||||
if seed == nil {
|
||||
hdSeed, err := hdkeychain.GenerateSeed(
|
||||
hdkeychain.RecommendedSeedLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
seed = hdSeed
|
||||
}
|
||||
if len(seed) < hdkeychain.MinSeedBytes ||
|
||||
len(seed) > hdkeychain.MaxSeedBytes {
|
||||
return hdkeychain.ErrInvalidSeedLen
|
||||
}
|
||||
|
||||
// Create the address manager.
|
||||
addrMgrNamespace, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = waddrmgr.Create(addrMgrNamespace, seed, pubPass, privPass,
|
||||
params, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create empty transaction manager.
|
||||
txMgrNamespace, err := db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return wtxmgr.Create(txMgrNamespace)
|
||||
}
|
||||
|
||||
// Open loads an already-created wallet from the passed database and namespaces.
|
||||
func Open(pubPass []byte, params *chaincfg.Params, db walletdb.DB, waddrmgrNS, wtxmgrNS walletdb.Namespace, cbs *waddrmgr.OpenCallbacks) (*Wallet, error) {
|
||||
addrMgr, err := waddrmgr.Open(waddrmgrNS, pubPass, params, cbs)
|
||||
func Open(db walletdb.DB, pubPass []byte, cbs *waddrmgr.OpenCallbacks, params *chaincfg.Params) (*Wallet, error) {
|
||||
addrMgrNS, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txMgr, err := wtxmgr.Open(wtxmgrNS)
|
||||
txMgrNS, err := db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
if wtxmgr.IsNoExists(err) {
|
||||
log.Info("No recorded transaction history -- needs full rescan")
|
||||
err = addrMgr.SetSyncedTo(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txMgr, err = wtxmgr.Create(wtxmgrNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
addrMgr, err := waddrmgr.Open(addrMgrNS, pubPass, params, cbs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
noTxMgr, err := walletdb.NamespaceIsEmpty(txMgrNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if noTxMgr {
|
||||
log.Info("No recorded transaction history -- needs full rescan")
|
||||
err = addrMgr.SetSyncedTo(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = wtxmgr.Create(txMgrNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
txMgr, err := wtxmgr.Open(txMgrNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Opened wallet") // TODO: log balance? last sync height?
|
||||
|
|
|
@ -171,6 +171,18 @@ type Namespace interface {
|
|||
Update(fn func(Tx) error) error
|
||||
}
|
||||
|
||||
// NamespaceIsEmpty returns whether the namespace is empty, that is, whether there
|
||||
// are no key/value pairs or nested buckets.
|
||||
func NamespaceIsEmpty(namespace Namespace) (bool, error) {
|
||||
var empty bool
|
||||
err := namespace.View(func(tx Tx) error {
|
||||
k, v := tx.RootBucket().Cursor().First()
|
||||
empty = k == nil && v == nil
|
||||
return nil
|
||||
})
|
||||
return empty, err
|
||||
}
|
||||
|
||||
// DB represents a collection of namespaces which are persisted. All database
|
||||
// access is performed through transactions which are obtained through the
|
||||
// specific Namespace.
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/internal/legacy/keystore"
|
||||
"github.com/btcsuite/btcwallet/internal/prompt"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
|
@ -23,12 +22,6 @@ import (
|
|||
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
||||
)
|
||||
|
||||
// Namespace keys
|
||||
var (
|
||||
waddrmgrNamespaceKey = []byte("waddrmgr")
|
||||
wtxmgrNamespaceKey = []byte("wtxmgr")
|
||||
)
|
||||
|
||||
// networkDir returns the directory name of a network directory to hold wallet
|
||||
// files.
|
||||
func networkDir(dataDir string, chainParams *chaincfg.Params) string {
|
||||
|
@ -214,12 +207,6 @@ func createSimulationWallet(cfg *config) error {
|
|||
// Public passphrase is the default.
|
||||
pubPass := []byte(wallet.InsecurePubPassphrase)
|
||||
|
||||
// Generate a random seed.
|
||||
seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
netDir := networkDir(cfg.DataDir, activeNet.Params)
|
||||
|
||||
// Create the wallet.
|
||||
|
@ -233,20 +220,12 @@ func createSimulationWallet(cfg *config) error {
|
|||
}
|
||||
defer db.Close()
|
||||
|
||||
// Create the address manager.
|
||||
waddrmgrNamespace, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
// Create the wallet.
|
||||
err = wallet.Create(db, pubPass, privPass, nil, activeNet.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
manager, err := waddrmgr.Create(waddrmgrNamespace, seed, []byte(pubPass),
|
||||
[]byte(privPass), activeNet.Params, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
manager.Close()
|
||||
|
||||
fmt.Println("The wallet has been created successfully.")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -155,7 +155,12 @@ func Example_basicUsage() {
|
|||
}
|
||||
|
||||
// Create (or open) the transaction store in the provided namespace.
|
||||
s, err := wtxmgr.Create(ns)
|
||||
err = wtxmgr.Create(ns)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
s, err := wtxmgr.Open(ns)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
|
14
wtxmgr/tx.go
14
wtxmgr/tx.go
|
@ -148,15 +148,11 @@ func Open(namespace walletdb.Namespace) (*Store, error) {
|
|||
return &Store{namespace, nil}, nil // TODO: set callbacks
|
||||
}
|
||||
|
||||
// Create creates and opens a new persistent transaction store in the walletdb
|
||||
// namespace. Creating the store when one already exists in this namespace will
|
||||
// error with ErrAlreadyExists.
|
||||
func Create(namespace walletdb.Namespace) (*Store, error) {
|
||||
err := createStore(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Store{namespace, nil}, nil // TODO: set callbacks
|
||||
// Create creates a new persistent transaction store in the walletdb namespace.
|
||||
// Creating the store when one already exists in this namespace will error with
|
||||
// ErrAlreadyExists.
|
||||
func Create(namespace walletdb.Namespace) error {
|
||||
return createStore(namespace)
|
||||
}
|
||||
|
||||
// moveMinedTx moves a transaction record from the unmined buckets to block
|
||||
|
|
|
@ -75,7 +75,11 @@ func testStore() (*Store, func(), error) {
|
|||
if err != nil {
|
||||
return nil, teardown, err
|
||||
}
|
||||
s, err := Create(ns)
|
||||
err = Create(ns)
|
||||
if err != nil {
|
||||
return nil, teardown, err
|
||||
}
|
||||
s, err := Open(ns)
|
||||
return s, teardown, err
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue