mirror of
https://github.com/muun/recovery.git
synced 2025-11-11 06:20:16 -05:00
Release v0.3.0
This commit is contained in:
386
vendor/github.com/btcsuite/btcwallet/waddrmgr/manager.go
generated
vendored
386
vendor/github.com/btcsuite/btcwallet/waddrmgr/manager.go
generated
vendored
@@ -123,6 +123,14 @@ var DefaultScryptOptions = ScryptOptions{
|
||||
P: 1,
|
||||
}
|
||||
|
||||
// FastScryptOptions are the scrypt options that should be used for testing
|
||||
// purposes only where speed is more important than security.
|
||||
var FastScryptOptions = ScryptOptions{
|
||||
N: 16,
|
||||
R: 8,
|
||||
P: 1,
|
||||
}
|
||||
|
||||
// addrKey is used to uniquely identify an address even when those addresses
|
||||
// would end up being the same bitcoin address (as is the case for
|
||||
// pay-to-pubkey and pay-to-pubkey-hash style of addresses).
|
||||
@@ -430,53 +438,61 @@ func (m *Manager) Close() {
|
||||
//
|
||||
// TODO(roasbeef): addrtype of raw key means it'll look in scripts to possibly
|
||||
// mark as gucci?
|
||||
func (m *Manager) NewScopedKeyManager(ns walletdb.ReadWriteBucket, scope KeyScope,
|
||||
addrSchema ScopeAddrSchema) (*ScopedKeyManager, error) {
|
||||
func (m *Manager) NewScopedKeyManager(ns walletdb.ReadWriteBucket,
|
||||
scope KeyScope, addrSchema ScopeAddrSchema) (*ScopedKeyManager, error) {
|
||||
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
// If the manager is locked, then we can't create a new scoped manager.
|
||||
if m.locked {
|
||||
return nil, managerError(ErrLocked, errLocked, nil)
|
||||
}
|
||||
var rootPriv *hdkeychain.ExtendedKey
|
||||
if !m.watchingOnly {
|
||||
// If the manager is locked, then we can't create a new scoped
|
||||
// manager.
|
||||
if m.locked {
|
||||
return nil, managerError(ErrLocked, errLocked, nil)
|
||||
}
|
||||
|
||||
// Now that we know the manager is unlocked, we'll need to fetch the
|
||||
// root master HD private key. This is required as we'll be attempting
|
||||
// the following derivation: m/purpose'/cointype'
|
||||
//
|
||||
// Note that the path to the coin type is requires hardened derivation,
|
||||
// therefore this can only be done if the wallet's root key hasn't been
|
||||
// neutered.
|
||||
masterRootPrivEnc, _, err := fetchMasterHDKeys(ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Now that we know the manager is unlocked, we'll need to
|
||||
// fetch the root master HD private key. This is required as
|
||||
// we'll be attempting the following derivation:
|
||||
// m/purpose'/cointype'
|
||||
//
|
||||
// Note that the path to the coin type is requires hardened
|
||||
// derivation, therefore this can only be done if the wallet's
|
||||
// root key hasn't been neutered.
|
||||
masterRootPrivEnc, _, err := fetchMasterHDKeys(ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the master root private key isn't found within the database, but
|
||||
// we need to bail here as we can't create the cointype key without the
|
||||
// master root private key.
|
||||
if masterRootPrivEnc == nil {
|
||||
return nil, managerError(ErrWatchingOnly, "", nil)
|
||||
}
|
||||
// If the master root private key isn't found within the
|
||||
// database, but we need to bail here as we can't create the
|
||||
// cointype key without the master root private key.
|
||||
if masterRootPrivEnc == nil {
|
||||
return nil, managerError(ErrWatchingOnly, "", nil)
|
||||
}
|
||||
|
||||
// Before we can derive any new scoped managers using this key, we'll
|
||||
// need to fully decrypt it.
|
||||
serializedMasterRootPriv, err := m.cryptoKeyPriv.Decrypt(masterRootPrivEnc)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to decrypt master root serialized private key")
|
||||
return nil, managerError(ErrLocked, str, err)
|
||||
}
|
||||
// Before we can derive any new scoped managers using this
|
||||
// key, we'll need to fully decrypt it.
|
||||
serializedMasterRootPriv, err :=
|
||||
m.cryptoKeyPriv.Decrypt(masterRootPrivEnc)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to decrypt master root " +
|
||||
"serialized private key")
|
||||
return nil, managerError(ErrLocked, str, err)
|
||||
}
|
||||
|
||||
// Now that we know the root priv is within the database, we'll decode
|
||||
// it into a usable object.
|
||||
rootPriv, err := hdkeychain.NewKeyFromString(
|
||||
string(serializedMasterRootPriv),
|
||||
)
|
||||
zero.Bytes(serializedMasterRootPriv)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to create master extended private key")
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
// Now that we know the root priv is within the database,
|
||||
// we'll decode it into a usable object.
|
||||
rootPriv, err = hdkeychain.NewKeyFromString(
|
||||
string(serializedMasterRootPriv),
|
||||
)
|
||||
zero.Bytes(serializedMasterRootPriv)
|
||||
if err != nil {
|
||||
str := fmt.Sprintf("failed to create master extended " +
|
||||
"private key")
|
||||
return nil, managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have the root private key, we'll fetch the scope bucket
|
||||
@@ -498,19 +514,21 @@ func (m *Manager) NewScopedKeyManager(ns walletdb.ReadWriteBucket, scope KeyScop
|
||||
}
|
||||
scopeKey := scopeToBytes(&scope)
|
||||
schemaBytes := scopeSchemaToBytes(&addrSchema)
|
||||
err = scopeSchemas.Put(scopeKey[:], schemaBytes)
|
||||
err := scopeSchemas.Put(scopeKey[:], schemaBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// With the database state created, we'll now derive the cointype key
|
||||
// using the master HD private key, then encrypt it along with the
|
||||
// first account using our crypto keys.
|
||||
err = createManagerKeyScope(
|
||||
ns, scope, rootPriv, m.cryptoKeyPub, m.cryptoKeyPriv,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if !m.watchingOnly {
|
||||
// With the database state created, we'll now derive the
|
||||
// cointype key using the master HD private key, then encrypt
|
||||
// it along with the first account using our crypto keys.
|
||||
err = createManagerKeyScope(
|
||||
ns, scope, rootPriv, m.cryptoKeyPub, m.cryptoKeyPriv,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we'll register this new scoped manager with the root
|
||||
@@ -730,6 +748,43 @@ func (m *Manager) ForEachActiveAddress(ns walletdb.ReadBucket, fn func(addr btcu
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForEachRelevantActiveAddress invokes the given closure on each active
|
||||
// address relevant to the wallet. Ideally, only addresses within the default
|
||||
// key scopes would be relevant, but due to a bug (now fixed) in which change
|
||||
// addresses could be created outside of the default key scopes, we now need to
|
||||
// check for those as well.
|
||||
func (m *Manager) ForEachRelevantActiveAddress(ns walletdb.ReadBucket,
|
||||
fn func(addr btcutil.Address) error) error {
|
||||
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
|
||||
for _, scopedMgr := range m.scopedManagers {
|
||||
// If the manager is for a default key scope, we'll return all
|
||||
// addresses, otherwise we'll only return internal addresses, as
|
||||
// that's the branch used for change addresses.
|
||||
isDefaultKeyScope := false
|
||||
for _, defaultKeyScope := range DefaultKeyScopes {
|
||||
if scopedMgr.Scope() == defaultKeyScope {
|
||||
isDefaultKeyScope = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if isDefaultKeyScope {
|
||||
err = scopedMgr.ForEachActiveAddress(ns, fn)
|
||||
} else {
|
||||
err = scopedMgr.ForEachInternalActiveAddress(ns, fn)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForEachAccountAddress calls the given function with each address of
|
||||
// the given account stored in the manager, breaking early on error.
|
||||
func (m *Manager) ForEachAccountAddress(ns walletdb.ReadBucket, account uint32,
|
||||
@@ -1253,7 +1308,7 @@ func newManager(chainParams *chaincfg.Params, masterKeyPub *snacl.SecretKey,
|
||||
masterKeyPriv *snacl.SecretKey, cryptoKeyPub EncryptorDecryptor,
|
||||
cryptoKeyPrivEncrypted, cryptoKeyScriptEncrypted []byte, syncInfo *syncState,
|
||||
birthday time.Time, privPassphraseSalt [saltSize]byte,
|
||||
scopedManagers map[KeyScope]*ScopedKeyManager) *Manager {
|
||||
scopedManagers map[KeyScope]*ScopedKeyManager, watchingOnly bool) *Manager {
|
||||
|
||||
m := &Manager{
|
||||
chainParams: chainParams,
|
||||
@@ -1271,6 +1326,7 @@ func newManager(chainParams *chaincfg.Params, masterKeyPub *snacl.SecretKey,
|
||||
scopedManagers: scopedManagers,
|
||||
externalAddrSchemas: make(map[AddressType][]KeyScope),
|
||||
internalAddrSchemas: make(map[AddressType][]KeyScope),
|
||||
watchingOnly: watchingOnly,
|
||||
}
|
||||
|
||||
for _, sMgr := range m.scopedManagers {
|
||||
@@ -1495,9 +1551,8 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
|
||||
mgr := newManager(
|
||||
chainParams, &masterKeyPub, &masterKeyPriv,
|
||||
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
|
||||
birthday, privPassphraseSalt, scopedManagers,
|
||||
birthday, privPassphraseSalt, scopedManagers, watchingOnly,
|
||||
)
|
||||
mgr.watchingOnly = watchingOnly
|
||||
|
||||
for _, scopedManager := range scopedManagers {
|
||||
scopedManager.rootManager = mgr
|
||||
@@ -1631,27 +1686,40 @@ func createManagerKeyScope(ns walletdb.ReadWriteBucket,
|
||||
)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Create creates a new address manager in the given namespace.
|
||||
//
|
||||
// All private and public keys and information are protected by secret keys
|
||||
// derived from the provided private and public passphrases. The public
|
||||
// passphrase is required on subsequent opens of the address manager, and the
|
||||
// private passphrase is required to unlock the address manager in order to
|
||||
// gain access to any private keys and information.
|
||||
// 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.
|
||||
//
|
||||
// If a config structure is passed to the function, that configuration will
|
||||
// override the defaults.
|
||||
// If the provided seed value is nil the address manager will be
|
||||
// created in watchingOnly mode in which case no default accounts or
|
||||
// scoped managers are created - it is up to the caller to create a
|
||||
// new one with NewAccountWatchingOnly and NewScopedKeyManager.
|
||||
//
|
||||
// A ManagerError with an error code of ErrAlreadyExists will be returned the
|
||||
// address manager already exists in the specified namespace.
|
||||
func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []byte,
|
||||
// All private and public keys and information are protected by secret
|
||||
// keys derived from the provided private and public passphrases. The
|
||||
// public passphrase is required on subsequent opens of the address
|
||||
// manager, and the private passphrase is required to unlock the
|
||||
// address manager in order to gain access to any private keys and
|
||||
// information.
|
||||
//
|
||||
// If a config structure is passed to the function, that configuration
|
||||
// will override the defaults.
|
||||
//
|
||||
// A ManagerError with an error code of ErrAlreadyExists will be
|
||||
// returned the address manager already exists in the specified
|
||||
// namespace.
|
||||
func Create(ns walletdb.ReadWriteBucket,
|
||||
seed, pubPassphrase, privPassphrase []byte,
|
||||
chainParams *chaincfg.Params, config *ScryptOptions,
|
||||
birthday time.Time) error {
|
||||
|
||||
// If the seed argument is nil we create in watchingOnly mode.
|
||||
isWatchingOnly := seed == nil
|
||||
|
||||
// Return an error if the manager has already been created in
|
||||
// the given database namespace.
|
||||
exists := managerExists(ns)
|
||||
@@ -1660,13 +1728,17 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
|
||||
}
|
||||
|
||||
// Ensure the private passphrase is not empty.
|
||||
if len(privPassphrase) == 0 {
|
||||
if !isWatchingOnly && len(privPassphrase) == 0 {
|
||||
str := "private passphrase may not be empty"
|
||||
return managerError(ErrEmptyPassphrase, str, nil)
|
||||
}
|
||||
|
||||
// Perform the initial bucket creation and database namespace setup.
|
||||
if err := createManagerNS(ns, ScopeAddrMap); err != nil {
|
||||
defaultScopes := map[KeyScope]ScopeAddrSchema{}
|
||||
if !isWatchingOnly {
|
||||
defaultScopes = ScopeAddrMap
|
||||
}
|
||||
if err := createManagerNS(ns, defaultScopes); err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
@@ -1681,22 +1753,6 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
|
||||
str := "failed to master public key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
masterKeyPriv, err := newSecretKey(&privPassphrase, config)
|
||||
if err != nil {
|
||||
str := "failed to master private key"
|
||||
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
|
||||
// is already unlocked.
|
||||
var privPassphraseSalt [saltSize]byte
|
||||
_, err = rand.Read(privPassphraseSalt[:])
|
||||
if err != nil {
|
||||
str := "failed to read random source for passphrase salt"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Generate new crypto public, private, and script keys. These keys are
|
||||
// used to protect the actual public and private data such as addresses,
|
||||
@@ -1706,18 +1762,6 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
|
||||
str := "failed to generate crypto public key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyPriv, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyPriv.Zero()
|
||||
cryptoKeyScript, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto script key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyScript.Zero()
|
||||
|
||||
// Encrypt the crypto keys with the associated master keys.
|
||||
cryptoKeyPubEnc, err := masterKeyPub.Encrypt(cryptoKeyPub.Bytes())
|
||||
@@ -1725,70 +1769,120 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
|
||||
str := "failed to encrypt crypto public key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyPrivEnc, err := masterKeyPriv.Encrypt(cryptoKeyPriv.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyScriptEnc, err := masterKeyPriv.Encrypt(cryptoKeyScript.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto script key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Use the genesis block for the passed chain as the created at block
|
||||
// for the default.
|
||||
createdAt := &BlockStamp{Hash: *chainParams.GenesisHash, Height: 0}
|
||||
createdAt := &BlockStamp{
|
||||
Hash: *chainParams.GenesisHash,
|
||||
Height: 0,
|
||||
Timestamp: chainParams.GenesisBlock.Header.Timestamp,
|
||||
}
|
||||
|
||||
// Create the initial sync state.
|
||||
syncInfo := newSyncState(createdAt, createdAt)
|
||||
|
||||
// Save the master key params to the database.
|
||||
pubParams := masterKeyPub.Marshal()
|
||||
privParams := masterKeyPriv.Marshal()
|
||||
err = putMasterKeyParams(ns, pubParams, privParams)
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
// Generate the BIP0044 HD key structure to ensure the provided seed
|
||||
// can generate the required structure with no issues.
|
||||
var privParams []byte = nil
|
||||
var masterKeyPriv *snacl.SecretKey
|
||||
var cryptoKeyPrivEnc []byte = nil
|
||||
var cryptoKeyScriptEnc []byte = nil
|
||||
if !isWatchingOnly {
|
||||
masterKeyPriv, err = newSecretKey(&privPassphrase, config)
|
||||
if err != nil {
|
||||
str := "failed to master private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer masterKeyPriv.Zero()
|
||||
|
||||
// Derive the master extended key from the seed.
|
||||
rootKey, err := hdkeychain.NewMaster(seed, chainParams)
|
||||
if err != nil {
|
||||
str := "failed to derive master extended key"
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
rootPubKey, err := rootKey.Neuter()
|
||||
if err != nil {
|
||||
str := "failed to neuter master extended key"
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
// Generate the private passphrase salt. This is used when
|
||||
// hashing passwords to detect whether an unlock can be
|
||||
// avoided when the manager is already unlocked.
|
||||
var privPassphraseSalt [saltSize]byte
|
||||
_, err = rand.Read(privPassphraseSalt[:])
|
||||
if err != nil {
|
||||
str := "failed to read random source for passphrase salt"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Next, for each registers default manager scope, we'll create the
|
||||
// hardened cointype key for it, as well as the first default account.
|
||||
for _, defaultScope := range DefaultKeyScopes {
|
||||
err := createManagerKeyScope(
|
||||
ns, defaultScope, rootKey, cryptoKeyPub, cryptoKeyPriv,
|
||||
)
|
||||
cryptoKeyPriv, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyPriv.Zero()
|
||||
cryptoKeyScript, err := newCryptoKey()
|
||||
if err != nil {
|
||||
str := "failed to generate crypto script key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
defer cryptoKeyScript.Zero()
|
||||
|
||||
cryptoKeyPrivEnc, err =
|
||||
masterKeyPriv.Encrypt(cryptoKeyPriv.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
cryptoKeyScriptEnc, err =
|
||||
masterKeyPriv.Encrypt(cryptoKeyScript.Bytes())
|
||||
if err != nil {
|
||||
str := "failed to encrypt crypto script key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
}
|
||||
|
||||
// Generate the BIP0044 HD key structure to ensure the
|
||||
// provided seed can generate the required structure with no
|
||||
// issues.
|
||||
|
||||
// Derive the master extended key from the seed.
|
||||
rootKey, err := hdkeychain.NewMaster(seed, chainParams)
|
||||
if err != nil {
|
||||
str := "failed to derive master extended key"
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
rootPubKey, err := rootKey.Neuter()
|
||||
if err != nil {
|
||||
str := "failed to neuter master extended key"
|
||||
return managerError(ErrKeyChain, str, err)
|
||||
}
|
||||
|
||||
// Next, for each registers default manager scope, we'll
|
||||
// create the hardened cointype key for it, as well as the
|
||||
// first default account.
|
||||
for _, defaultScope := range DefaultKeyScopes {
|
||||
err := createManagerKeyScope(
|
||||
ns, defaultScope, rootKey, cryptoKeyPub, cryptoKeyPriv,
|
||||
)
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Before we proceed, we'll also store the root master private
|
||||
// key within the database in an encrypted format. This is
|
||||
// required as in the future, we may need to create additional
|
||||
// scoped key managers.
|
||||
masterHDPrivKeyEnc, err :=
|
||||
cryptoKeyPriv.Encrypt([]byte(rootKey.String()))
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
masterHDPubKeyEnc, err :=
|
||||
cryptoKeyPub.Encrypt([]byte(rootPubKey.String()))
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
err = putMasterHDKeys(ns, masterHDPrivKeyEnc, masterHDPubKeyEnc)
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
privParams = masterKeyPriv.Marshal()
|
||||
}
|
||||
|
||||
// Before we proceed, we'll also store the root master private key
|
||||
// within the database in an encrypted format. This is required as in
|
||||
// the future, we may need to create additional scoped key managers.
|
||||
masterHDPrivKeyEnc, err := cryptoKeyPriv.Encrypt([]byte(rootKey.String()))
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
masterHDPubKeyEnc, err := cryptoKeyPub.Encrypt([]byte(rootPubKey.String()))
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
err = putMasterHDKeys(ns, masterHDPrivKeyEnc, masterHDPubKeyEnc)
|
||||
// Save the master key params to the database.
|
||||
err = putMasterKeyParams(ns, pubParams, privParams)
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
@@ -1800,9 +1894,9 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
// Save the fact this is not a watching-only address manager to the
|
||||
// Save the watching-only mode of the address manager to the
|
||||
// database.
|
||||
err = putWatchingOnly(ns, false)
|
||||
err = putWatchingOnly(ns, isWatchingOnly)
|
||||
if err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user