Refactor wallet opening.
Rather than the main package being responsible for opening the address and transaction managers, the namespaces of these components are passed as parameters to the wallet.Open function. Additionally, the address manager Options struct has been split into two: ScryptOptions which holds the scrypt parameters needed during passphrase key derivation, and OpenCallbacks which is only passed to the Open function to allow the caller to provide additional details during upgrades. These changes are being done in preparation for a notification server in the wallet package, with callbacks passed to the Open and Create functions in waddrmgr and wtxmgr. Before this could happen, the wallet package had to be responsible for actually opening the managers from their namespaces.
This commit is contained in:
parent
edde89cd4c
commit
d714bf3310
12 changed files with 125 additions and 192 deletions
|
@ -69,12 +69,12 @@ func walletMain() error {
|
|||
|
||||
// Load the wallet database. It must have been created with the
|
||||
// --create option already or this will return an appropriate error.
|
||||
wallet, err := openWallet()
|
||||
wallet, db, err := openWallet()
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return err
|
||||
}
|
||||
defer wallet.Db().Close()
|
||||
defer db.Close()
|
||||
|
||||
// Create and start HTTP server to serve wallet client connections.
|
||||
// This will be updated with the wallet and chain server RPC client
|
||||
|
|
|
@ -57,7 +57,7 @@ func ExampleCreate() {
|
|||
|
||||
// Create the address manager.
|
||||
seed := bytes.Repeat([]byte{0x2a, 0x64, 0xdf, 0x08}, 8)
|
||||
var fastScrypt = &waddrmgr.Options{ScryptN: 16, ScryptR: 8, ScryptP: 1}
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err := waddrmgr.Create(
|
||||
mgrNamespace, seed, pubPassphrase, privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
if err != nil {
|
||||
|
@ -270,7 +270,7 @@ func exampleCreateMgrAndDBNamespace() (*waddrmgr.Manager, walletdb.Namespace, fu
|
|||
|
||||
// Create the address manager
|
||||
seed := bytes.Repeat([]byte{0x2a, 0x64, 0xdf, 0x08}, 8)
|
||||
var fastScrypt = &waddrmgr.Options{ScryptN: 16, ScryptR: 8, ScryptP: 1}
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err := waddrmgr.Create(
|
||||
mgrNamespace, seed, pubPassphrase, privPassphrase, &chaincfg.MainNetParams, fastScrypt)
|
||||
if err != nil {
|
||||
|
|
|
@ -344,7 +344,7 @@ func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, po
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create addr manager DB namespace: %v", err)
|
||||
}
|
||||
var fastScrypt = &waddrmgr.Options{ScryptN: 16, ScryptR: 8, ScryptP: 1}
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
|
||||
mgr, err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase, privPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
if err != nil {
|
||||
|
|
|
@ -45,10 +45,10 @@ var (
|
|||
|
||||
// fastScrypt are parameters used throughout the tests to speed up the
|
||||
// scrypt operations.
|
||||
fastScrypt = &waddrmgr.Options{
|
||||
ScryptN: 16,
|
||||
ScryptR: 8,
|
||||
ScryptP: 1,
|
||||
fastScrypt = &waddrmgr.ScryptOptions{
|
||||
N: 16,
|
||||
R: 8,
|
||||
P: 1,
|
||||
}
|
||||
|
||||
// waddrmgrNamespaceKey is the namespace key for the waddrmgr package.
|
||||
|
|
|
@ -1662,7 +1662,7 @@ func upgradeToVersion2(namespace walletdb.Namespace) error {
|
|||
|
||||
// upgradeManager upgrades the data in the provided manager namespace to newer
|
||||
// versions as neeeded.
|
||||
func upgradeManager(namespace walletdb.Namespace, pubPassPhrase []byte, chainParams *chaincfg.Params, config *Options) error {
|
||||
func upgradeManager(namespace walletdb.Namespace, pubPassPhrase []byte, chainParams *chaincfg.Params, cbs *OpenCallbacks) error {
|
||||
var version uint32
|
||||
err := namespace.View(func(tx walletdb.Tx) error {
|
||||
var err error
|
||||
|
@ -1715,16 +1715,16 @@ func upgradeManager(namespace walletdb.Namespace, pubPassPhrase []byte, chainPar
|
|||
}
|
||||
|
||||
if version < 3 {
|
||||
if config.ObtainSeed == nil || config.ObtainPrivatePass == nil {
|
||||
if cbs == nil || cbs.ObtainSeed == nil || cbs.ObtainPrivatePass == nil {
|
||||
str := "failed to obtain seed and private passphrase required for upgrade"
|
||||
return managerError(ErrDatabase, str, err)
|
||||
}
|
||||
|
||||
seed, err := config.ObtainSeed()
|
||||
seed, err := cbs.ObtainSeed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privPassPhrase, err := config.ObtainPrivatePass()
|
||||
privPassPhrase, err := cbs.ObtainPrivatePass()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1769,7 +1769,7 @@ func upgradeToVersion3(namespace walletdb.Namespace, seed, privPassPhrase, pubPa
|
|||
currentMgrVersion := uint32(3)
|
||||
rootBucket := tx.RootBucket()
|
||||
|
||||
woMgr, err := loadManager(namespace, pubPassPhrase, chainParams, nil)
|
||||
woMgr, err := loadManager(namespace, pubPassPhrase, chainParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func TstRunWithReplacedNewSecretKey(callback func()) {
|
|||
defer func() {
|
||||
newSecretKey = orig
|
||||
}()
|
||||
newSecretKey = func(passphrase *[]byte, config *Options) (*snacl.SecretKey, error) {
|
||||
newSecretKey = func(passphrase *[]byte, config *ScryptOptions) (*snacl.SecretKey, error) {
|
||||
return nil, snacl.ErrDecryptFailed
|
||||
}
|
||||
callback()
|
||||
|
|
|
@ -107,11 +107,16 @@ func isReservedAccountNum(acct uint32) bool {
|
|||
return acct == ImportedAddrAccount
|
||||
}
|
||||
|
||||
// Options is used to hold the optional parameters passed to Create or Load.
|
||||
type Options struct {
|
||||
ScryptN int
|
||||
ScryptR int
|
||||
ScryptP int
|
||||
// ScryptOptions is used to hold the scrypt parameters needed when deriving new
|
||||
// passphrase keys.
|
||||
type ScryptOptions struct {
|
||||
N, R, P int
|
||||
}
|
||||
|
||||
// OpenCallbacks houses caller-provided callbacks that may be called when
|
||||
// opening an existing manager. The open blocks on the execution of these
|
||||
// functions.
|
||||
type OpenCallbacks struct {
|
||||
// ObtainSeed is a callback function that is potentially invoked during
|
||||
// upgrades. It is intended to be used to request the wallet seed
|
||||
// from the user (or any other mechanism the caller deems fit).
|
||||
|
@ -123,12 +128,12 @@ type Options struct {
|
|||
ObtainPrivatePass ObtainUserInputFunc
|
||||
}
|
||||
|
||||
// defaultConfig is an instance of the Options struct initialized with default
|
||||
// DefaultConfig is an instance of the Options struct initialized with default
|
||||
// configuration options.
|
||||
var defaultConfig = &Options{
|
||||
ScryptN: 262144, // 2^18
|
||||
ScryptR: 8,
|
||||
ScryptP: 1,
|
||||
var DefaultScryptOptions = ScryptOptions{
|
||||
N: 262144, // 2^18
|
||||
R: 8,
|
||||
P: 1,
|
||||
}
|
||||
|
||||
// addrKey is used to uniquely identify an address even when those addresses
|
||||
|
@ -170,9 +175,8 @@ type unlockDeriveInfo struct {
|
|||
}
|
||||
|
||||
// defaultNewSecretKey returns a new secret key. See newSecretKey.
|
||||
func defaultNewSecretKey(passphrase *[]byte, config *Options) (*snacl.SecretKey, error) {
|
||||
return snacl.NewSecretKey(passphrase, config.ScryptN, config.ScryptR,
|
||||
config.ScryptP)
|
||||
func defaultNewSecretKey(passphrase *[]byte, config *ScryptOptions) (*snacl.SecretKey, error) {
|
||||
return snacl.NewSecretKey(passphrase, config.N, config.R, config.P)
|
||||
}
|
||||
|
||||
// newSecretKey is used as a way to replace the new secret key generation
|
||||
|
@ -294,9 +298,6 @@ type Manager struct {
|
|||
// order to encrypt it.
|
||||
deriveOnUnlock []*unlockDeriveInfo
|
||||
|
||||
// config holds overridable options, such as scrypt parameters.
|
||||
config *Options
|
||||
|
||||
// privPassphraseSalt and hashedPrivPassphrase allow for the secure
|
||||
// detection of a correct passphrase on manager unlock when the
|
||||
// manager is already unlocked. The hash is zeroed each lock.
|
||||
|
@ -709,8 +710,11 @@ func (m *Manager) AddrAccount(address btcutil.Address) (uint32, error) {
|
|||
|
||||
// ChangePassphrase changes either the public or private passphrase to the
|
||||
// provided value depending on the private flag. In order to change the private
|
||||
// password, the address manager must not be watching-only.
|
||||
func (m *Manager) ChangePassphrase(oldPassphrase, newPassphrase []byte, private bool) error {
|
||||
// password, the address manager must not be watching-only. The new passphrase
|
||||
// keys are derived using the scrypt parameters in the options, so changing the
|
||||
// passphrase may be used to bump the computational difficulty needed to brute
|
||||
// force the passphrase.
|
||||
func (m *Manager) ChangePassphrase(oldPassphrase, newPassphrase []byte, private bool, config *ScryptOptions) error {
|
||||
// No private passphrase to change for a watching-only address manager.
|
||||
if private && m.watchingOnly {
|
||||
return managerError(ErrWatchingOnly, errWatchingOnly, nil)
|
||||
|
@ -746,7 +750,7 @@ func (m *Manager) ChangePassphrase(oldPassphrase, newPassphrase []byte, private
|
|||
|
||||
// Generate a new master key from the passphrase which is used to secure
|
||||
// the actual secret keys.
|
||||
newMasterKey, err := newSecretKey(&newPassphrase, m.config)
|
||||
newMasterKey, err := newSecretKey(&newPassphrase, config)
|
||||
if err != nil {
|
||||
str := "failed to create new master private key"
|
||||
return managerError(ErrCrypto, str, err)
|
||||
|
@ -1990,7 +1994,7 @@ func newManager(namespace walletdb.Namespace, chainParams *chaincfg.Params,
|
|||
masterKeyPub *snacl.SecretKey, masterKeyPriv *snacl.SecretKey,
|
||||
cryptoKeyPub EncryptorDecryptor, cryptoKeyPrivEncrypted,
|
||||
cryptoKeyScriptEncrypted []byte, syncInfo *syncState,
|
||||
config *Options, privPassphraseSalt [saltSize]byte) *Manager {
|
||||
privPassphraseSalt [saltSize]byte) *Manager {
|
||||
|
||||
return &Manager{
|
||||
namespace: namespace,
|
||||
|
@ -2006,7 +2010,6 @@ func newManager(namespace walletdb.Namespace, chainParams *chaincfg.Params,
|
|||
cryptoKeyPriv: &cryptoKey{},
|
||||
cryptoKeyScriptEncrypted: cryptoKeyScriptEncrypted,
|
||||
cryptoKeyScript: &cryptoKey{},
|
||||
config: config,
|
||||
privPassphraseSalt: privPassphraseSalt,
|
||||
}
|
||||
}
|
||||
|
@ -2088,7 +2091,7 @@ func checkBranchKeys(acctKey *hdkeychain.ExtendedKey) error {
|
|||
// loadManager returns a new address manager that results from loading it from
|
||||
// the passed opened database. The public passphrase is required to decrypt the
|
||||
// public keys.
|
||||
func loadManager(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chaincfg.Params, config *Options) (*Manager, error) {
|
||||
func loadManager(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chaincfg.Params) (*Manager, error) {
|
||||
// Perform all database lookups in a read-only view.
|
||||
var watchingOnly bool
|
||||
var masterKeyPubParams, masterKeyPrivParams []byte
|
||||
|
@ -2184,7 +2187,7 @@ func loadManager(namespace walletdb.Namespace, pubPassphrase []byte, chainParams
|
|||
// call to new with the values loaded from the database.
|
||||
mgr := newManager(namespace, chainParams, &masterKeyPub, &masterKeyPriv,
|
||||
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
|
||||
config, privPassphraseSalt)
|
||||
privPassphraseSalt)
|
||||
mgr.watchingOnly = watchingOnly
|
||||
return mgr, nil
|
||||
}
|
||||
|
@ -2199,7 +2202,7 @@ func loadManager(namespace walletdb.Namespace, pubPassphrase []byte, chainParams
|
|||
//
|
||||
// A ManagerError with an error code of ErrNoExist will be returned if the
|
||||
// passed manager does not exist in the specified namespace.
|
||||
func Open(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chaincfg.Params, config *Options) (*Manager, error) {
|
||||
func Open(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chaincfg.Params, cbs *OpenCallbacks) (*Manager, error) {
|
||||
// Return an error if the manager has NOT already been created in the
|
||||
// given database namespace.
|
||||
exists, err := managerExists(namespace)
|
||||
|
@ -2212,15 +2215,11 @@ func Open(namespace walletdb.Namespace, pubPassphrase []byte, chainParams *chain
|
|||
}
|
||||
|
||||
// Upgrade the manager to the latest version as needed.
|
||||
if err := upgradeManager(namespace, pubPassphrase, chainParams, config); err != nil {
|
||||
if err := upgradeManager(namespace, pubPassphrase, chainParams, cbs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
config = defaultConfig
|
||||
}
|
||||
|
||||
return loadManager(namespace, pubPassphrase, chainParams, config)
|
||||
return loadManager(namespace, pubPassphrase, chainParams)
|
||||
}
|
||||
|
||||
// Create returns a new locked address manager in the given namespace. The
|
||||
|
@ -2240,7 +2239,7 @@ 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 *Options) (*Manager, error) {
|
||||
func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []byte, chainParams *chaincfg.Params, config *ScryptOptions) (*Manager, error) {
|
||||
// Return an error if the manager has already been created in the given
|
||||
// database namespace.
|
||||
exists, err := managerExists(namespace)
|
||||
|
@ -2257,7 +2256,7 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
}
|
||||
|
||||
if config == nil {
|
||||
config = defaultConfig
|
||||
config = &DefaultScryptOptions
|
||||
}
|
||||
|
||||
// Generate the BIP0044 HD key structure to ensure the provided seed
|
||||
|
@ -2479,5 +2478,5 @@ func Create(namespace walletdb.Namespace, seed, pubPassphrase, privPassphrase []
|
|||
coinTypeKeyPriv.Zero()
|
||||
return newManager(namespace, chainParams, masterKeyPub, masterKeyPriv,
|
||||
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
|
||||
config, privPassphraseSalt), nil
|
||||
privPassphraseSalt), nil
|
||||
}
|
||||
|
|
|
@ -1002,7 +1002,7 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
|
||||
var err error
|
||||
waddrmgr.TstRunWithReplacedNewSecretKey(func() {
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase, pubPassphrase2, false)
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase, pubPassphrase2, false, fastScrypt)
|
||||
})
|
||||
if !checkManagerError(tc.t, testName, err, waddrmgr.ErrCrypto) {
|
||||
return false
|
||||
|
@ -1010,14 +1010,14 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
|
||||
// Attempt to change public passphrase with invalid old passphrase.
|
||||
testName = "ChangePassphrase (public) with invalid old passphrase"
|
||||
err = tc.manager.ChangePassphrase([]byte("bogus"), pubPassphrase2, false)
|
||||
err = tc.manager.ChangePassphrase([]byte("bogus"), pubPassphrase2, false, fastScrypt)
|
||||
if !checkManagerError(tc.t, testName, err, waddrmgr.ErrWrongPassphrase) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Change the public passphrase.
|
||||
testName = "ChangePassphrase (public)"
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase, pubPassphrase2, false)
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase, pubPassphrase2, false, fastScrypt)
|
||||
if err != nil {
|
||||
tc.t.Errorf("%s: unexpected error: %v", testName, err)
|
||||
return false
|
||||
|
@ -1030,7 +1030,7 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
}
|
||||
|
||||
// Change the private passphrase back to what it was.
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase2, pubPassphrase, false)
|
||||
err = tc.manager.ChangePassphrase(pubPassphrase2, pubPassphrase, false, fastScrypt)
|
||||
if err != nil {
|
||||
tc.t.Errorf("%s: unexpected error: %v", testName, err)
|
||||
return false
|
||||
|
@ -1040,7 +1040,7 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
// The error should be ErrWrongPassphrase or ErrWatchingOnly depending
|
||||
// on the type of the address manager.
|
||||
testName = "ChangePassphrase (private) with invalid old passphrase"
|
||||
err = tc.manager.ChangePassphrase([]byte("bogus"), privPassphrase2, true)
|
||||
err = tc.manager.ChangePassphrase([]byte("bogus"), privPassphrase2, true, fastScrypt)
|
||||
wantErrCode := waddrmgr.ErrWrongPassphrase
|
||||
if tc.watchingOnly {
|
||||
wantErrCode = waddrmgr.ErrWatchingOnly
|
||||
|
@ -1059,7 +1059,7 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
|
||||
// Change the private passphrase.
|
||||
testName = "ChangePassphrase (private)"
|
||||
err = tc.manager.ChangePassphrase(privPassphrase, privPassphrase2, true)
|
||||
err = tc.manager.ChangePassphrase(privPassphrase, privPassphrase2, true, fastScrypt)
|
||||
if err != nil {
|
||||
tc.t.Errorf("%s: unexpected error: %v", testName, err)
|
||||
return false
|
||||
|
@ -1076,7 +1076,7 @@ func testChangePassphrase(tc *testContext) bool {
|
|||
|
||||
// Change the private passphrase back to what it was while the manager
|
||||
// is unlocked to ensure that path works properly as well.
|
||||
err = tc.manager.ChangePassphrase(privPassphrase2, privPassphrase, true)
|
||||
err = tc.manager.ChangePassphrase(privPassphrase2, privPassphrase, true, fastScrypt)
|
||||
if err != nil {
|
||||
tc.t.Errorf("%s: unexpected error: %v", testName, err)
|
||||
return false
|
||||
|
@ -1388,7 +1388,7 @@ func testWatchingOnly(tc *testContext) bool {
|
|||
|
||||
// Open the manager using the namespace and convert it to watching-only.
|
||||
mgr, err := waddrmgr.Open(namespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
&chaincfg.MainNetParams, nil)
|
||||
if err != nil {
|
||||
tc.t.Errorf("%v", err)
|
||||
return false
|
||||
|
@ -1412,7 +1412,7 @@ func testWatchingOnly(tc *testContext) bool {
|
|||
|
||||
// Open the watching-only manager and run all the tests again.
|
||||
mgr, err = waddrmgr.Open(namespace, pubPassphrase, &chaincfg.MainNetParams,
|
||||
fastScrypt)
|
||||
nil)
|
||||
if err != nil {
|
||||
tc.t.Errorf("Open Watching-Only: unexpected error: %v", err)
|
||||
return false
|
||||
|
@ -1696,7 +1696,7 @@ func TestManager(t *testing.T) {
|
|||
// Open manager that does not exist to ensure the expected error is
|
||||
// returned.
|
||||
_, err = waddrmgr.Open(mgrNamespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
&chaincfg.MainNetParams, nil)
|
||||
if !checkManagerError(t, "Open non-existant", err, waddrmgr.ErrNoExist) {
|
||||
return
|
||||
}
|
||||
|
@ -1737,7 +1737,7 @@ func TestManager(t *testing.T) {
|
|||
// constant is bumped without writing code to actually do the upgrade.
|
||||
*waddrmgr.TstLatestMgrVersion++
|
||||
_, err = waddrmgr.Open(mgrNamespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
&chaincfg.MainNetParams, nil)
|
||||
if !checkManagerError(t, "Upgrade needed", err, waddrmgr.ErrUpgrade) {
|
||||
return
|
||||
}
|
||||
|
@ -1746,7 +1746,7 @@ func TestManager(t *testing.T) {
|
|||
// Open the manager and run all the tests again in open mode which
|
||||
// avoids reinserting new addresses like the create mode tests do.
|
||||
mgr, err = waddrmgr.Open(mgrNamespace, pubPassphrase,
|
||||
&chaincfg.MainNetParams, fastScrypt)
|
||||
&chaincfg.MainNetParams, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Open: unexpected error: %v", err)
|
||||
return
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The btcsuite developers
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
)
|
||||
|
||||
// Config is a structure used to initialize a Wallet
|
||||
// All values are required for successfully opening a Wallet
|
||||
type Config struct {
|
||||
ChainParams *chaincfg.Params
|
||||
Db *walletdb.DB
|
||||
TxStore *wtxmgr.Store
|
||||
Waddrmgr *waddrmgr.Manager
|
||||
}
|
|
@ -50,10 +50,10 @@ var (
|
|||
|
||||
// fastScrypt are options to passed to the wallet address manager to speed up
|
||||
// the scrypt derivations.
|
||||
var fastScrypt = &waddrmgr.Options{
|
||||
ScryptN: 16,
|
||||
ScryptR: 8,
|
||||
ScryptP: 1,
|
||||
var fastScrypt = &waddrmgr.ScryptOptions{
|
||||
N: 16,
|
||||
R: 8,
|
||||
P: 1,
|
||||
}
|
||||
|
||||
func Test_addOutputs(t *testing.T) {
|
||||
|
|
|
@ -110,37 +110,10 @@ type Wallet struct {
|
|||
notificationLock sync.Locker
|
||||
|
||||
chainParams *chaincfg.Params
|
||||
Config *Config
|
||||
wg sync.WaitGroup
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// newWallet creates a new Wallet structure with the provided address manager
|
||||
// and transaction store.
|
||||
func newWallet(mgr *waddrmgr.Manager, txs *wtxmgr.Store, db *walletdb.DB) *Wallet {
|
||||
return &Wallet{
|
||||
db: *db,
|
||||
Manager: mgr,
|
||||
TxStore: txs,
|
||||
chainSvrLock: new(sync.Mutex),
|
||||
lockedOutpoints: map[wire.OutPoint]struct{}{},
|
||||
FeeIncrement: defaultFeeIncrement,
|
||||
rescanAddJob: make(chan *RescanJob),
|
||||
rescanBatch: make(chan *rescanBatch),
|
||||
rescanNotifications: make(chan interface{}),
|
||||
rescanProgress: make(chan *RescanProgressMsg),
|
||||
rescanFinished: make(chan *RescanFinishedMsg),
|
||||
createTxRequests: make(chan createTxRequest),
|
||||
unlockRequests: make(chan unlockRequest),
|
||||
lockRequests: make(chan struct{}),
|
||||
holdUnlockRequests: make(chan chan HeldUnlock),
|
||||
lockState: make(chan bool),
|
||||
changePassphrase: make(chan changePassphraseRequest),
|
||||
notificationLock: new(sync.Mutex),
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrDuplicateListen is returned for any attempts to listen for the same
|
||||
// notification more than once. If callers must pass along a notifiation to
|
||||
// multiple places, they must broadcast it themself.
|
||||
|
@ -574,7 +547,8 @@ out:
|
|||
continue
|
||||
|
||||
case req := <-w.changePassphrase:
|
||||
err := w.Manager.ChangePassphrase(req.old, req.new, true)
|
||||
err := w.Manager.ChangePassphrase(req.old, req.new, true,
|
||||
&waddrmgr.DefaultScryptOptions)
|
||||
req.err <- err
|
||||
continue
|
||||
|
||||
|
@ -1617,15 +1591,51 @@ func (w *Wallet) TotalReceivedForAddr(addr btcutil.Address, minConf int32) (btcu
|
|||
return amount, err
|
||||
}
|
||||
|
||||
// Db returns wallet db being used by a wallet
|
||||
func (w *Wallet) Db() walletdb.DB {
|
||||
return w.db
|
||||
}
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Open opens a wallet from disk.
|
||||
func Open(config *Config) *Wallet {
|
||||
wallet := newWallet(config.Waddrmgr, config.TxStore, config.Db)
|
||||
wallet.chainParams = config.ChainParams
|
||||
txMgr, err := wtxmgr.Open(wtxmgrNS)
|
||||
if err != nil {
|
||||
if !wtxmgr.IsNoExists(err) {
|
||||
return nil, 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
|
||||
}
|
||||
}
|
||||
|
||||
return wallet
|
||||
log.Infof("Opened wallet") // TODO: log balance? last sync height?
|
||||
w := &Wallet{
|
||||
db: db,
|
||||
Manager: addrMgr,
|
||||
TxStore: txMgr,
|
||||
chainSvrLock: new(sync.Mutex),
|
||||
lockedOutpoints: map[wire.OutPoint]struct{}{},
|
||||
FeeIncrement: defaultFeeIncrement,
|
||||
rescanAddJob: make(chan *RescanJob),
|
||||
rescanBatch: make(chan *rescanBatch),
|
||||
rescanNotifications: make(chan interface{}),
|
||||
rescanProgress: make(chan *RescanProgressMsg),
|
||||
rescanFinished: make(chan *RescanFinishedMsg),
|
||||
createTxRequests: make(chan createTxRequest),
|
||||
unlockRequests: make(chan unlockRequest),
|
||||
lockRequests: make(chan struct{}),
|
||||
holdUnlockRequests: make(chan chan HeldUnlock),
|
||||
lockState: make(chan bool),
|
||||
changePassphrase: make(chan changePassphraseRequest),
|
||||
notificationLock: new(sync.Mutex),
|
||||
chainParams: params,
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import (
|
|||
"github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/btcsuite/golangcrypto/ssh/terminal"
|
||||
)
|
||||
|
||||
|
@ -594,73 +593,31 @@ func openDb(directory string, dbname string) (walletdb.DB, error) {
|
|||
return walletdb.Open("bdb", dbPath)
|
||||
}
|
||||
|
||||
// openManagers opens and returns the wallet address and transaction managers.
|
||||
// If the transaction store does not already exist, the manager is marked
|
||||
// unsynced so the wallet will sync with a full rescan.
|
||||
//
|
||||
// It prompts for seed and private passphrase required in case of upgrades
|
||||
func openManagers(db walletdb.DB, pass string) (*waddrmgr.Manager, *wtxmgr.Store, error) {
|
||||
// Get the namespace for the address manager.
|
||||
namespace, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
config := &waddrmgr.Options{
|
||||
ObtainSeed: promptSeed,
|
||||
ObtainPrivatePass: promptPrivPassPhrase,
|
||||
}
|
||||
addrMgr, err := waddrmgr.Open(namespace, []byte(pass), activeNet.Params, config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
namespace, err = db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
txMgr, err := wtxmgr.Open(namespace)
|
||||
if err != nil {
|
||||
if !wtxmgr.IsNoExists(err) {
|
||||
return nil, nil, err
|
||||
}
|
||||
log.Info("No recorded transaction history -- needs full rescan")
|
||||
err = addrMgr.SetSyncedTo(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
txMgr, err = wtxmgr.Create(namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return addrMgr, txMgr, nil
|
||||
}
|
||||
|
||||
// openWallet returns a wallet. The function handles opening an existing wallet
|
||||
// database, the address manager and the transaction store and uses the values
|
||||
// to open a wallet.Wallet
|
||||
func openWallet() (*wallet.Wallet, error) {
|
||||
func openWallet() (*wallet.Wallet, walletdb.DB, error) {
|
||||
netdir := networkDir(cfg.DataDir, activeNet.Params)
|
||||
|
||||
db, err := openDb(netdir, walletDbName)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return nil, err
|
||||
log.Errorf("Failed to open database: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mgr, txs, err := openManagers(db, cfg.WalletPass)
|
||||
addrMgrNS, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
walletConfig := &wallet.Config{
|
||||
Db: &db, // TODO: Remove the pointer
|
||||
TxStore: txs,
|
||||
Waddrmgr: mgr,
|
||||
ChainParams: activeNet.Params,
|
||||
txMgrNS, err := db.Namespace(wtxmgrNamespaceKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
log.Infof("Opened wallet files") // TODO: log balance? last sync height?
|
||||
w := wallet.Open(walletConfig)
|
||||
|
||||
return w, nil
|
||||
cbs := &waddrmgr.OpenCallbacks{
|
||||
ObtainSeed: promptSeed,
|
||||
ObtainPrivatePass: promptPrivPassPhrase,
|
||||
}
|
||||
w, err := wallet.Open([]byte(cfg.WalletPass), activeNet.Params, db,
|
||||
addrMgrNS, txMgrNS, cbs)
|
||||
return w, db, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue