diff --git a/btcwallet.go b/btcwallet.go index daee36c..dd84eb2 100644 --- a/btcwallet.go +++ b/btcwallet.go @@ -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 diff --git a/votingpool/example_test.go b/votingpool/example_test.go index a44b4f9..3697494 100644 --- a/votingpool/example_test.go +++ b/votingpool/example_test.go @@ -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 { diff --git a/votingpool/factory_test.go b/votingpool/factory_test.go index b3e5d4b..4cb6a9e 100644 --- a/votingpool/factory_test.go +++ b/votingpool/factory_test.go @@ -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 { diff --git a/waddrmgr/common_test.go b/waddrmgr/common_test.go index 977991c..25ed7ca 100644 --- a/waddrmgr/common_test.go +++ b/waddrmgr/common_test.go @@ -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. diff --git a/waddrmgr/db.go b/waddrmgr/db.go index 41db9bd..62a036c 100644 --- a/waddrmgr/db.go +++ b/waddrmgr/db.go @@ -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 } diff --git a/waddrmgr/internal_test.go b/waddrmgr/internal_test.go index fc83cc2..801b555 100644 --- a/waddrmgr/internal_test.go +++ b/waddrmgr/internal_test.go @@ -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() diff --git a/waddrmgr/manager.go b/waddrmgr/manager.go index d79f13e..9642655 100644 --- a/waddrmgr/manager.go +++ b/waddrmgr/manager.go @@ -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 } diff --git a/waddrmgr/manager_test.go b/waddrmgr/manager_test.go index 6f0feee..958acf3 100644 --- a/waddrmgr/manager_test.go +++ b/waddrmgr/manager_test.go @@ -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 diff --git a/wallet/config.go b/wallet/config.go deleted file mode 100644 index b47f127..0000000 --- a/wallet/config.go +++ /dev/null @@ -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 -} diff --git a/wallet/createtx_test.go b/wallet/createtx_test.go index 7650e9b..1be9fc7 100644 --- a/wallet/createtx_test.go +++ b/wallet/createtx_test.go @@ -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) { diff --git a/wallet/wallet.go b/wallet/wallet.go index f697452..b77b007 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -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 } diff --git a/walletsetup.go b/walletsetup.go index 916275a..ccf5315 100644 --- a/walletsetup.go +++ b/walletsetup.go @@ -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 }