Skip to content

Commit

Permalink
Added Wallet and Loader watching-only wallet creation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ksedgwic committed Mar 25, 2020
1 parent 52afd8c commit b97681b
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 23 deletions.
36 changes: 31 additions & 5 deletions wallet/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@ func (l *Loader) RunAfterLoad(fn func(*Wallet)) {
func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte,
bday time.Time) (*Wallet, error) {

return l.createNewWalletInternal(
pubPassphrase, privPassphrase, seed, bday, false,
)
}

// CreateNewWatchingOnlyWallet creates a new wallet using the provided
// public passphrase. No seed or private passphrase may be provided
// since the wallet is watching-only.
func (l *Loader) CreateNewWatchingOnlyWallet(pubPassphrase []byte,
bday time.Time) (*Wallet, error) {

return l.createNewWalletInternal(
pubPassphrase, nil, nil, bday, true,
)
}

func (l *Loader) createNewWalletInternal(pubPassphrase, privPassphrase,
seed []byte, bday time.Time, isWatchingOnly bool) (*Wallet, error) {

defer l.mu.Unlock()
l.mu.Lock()

Expand Down Expand Up @@ -127,11 +146,18 @@ func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte,
}

// Initialize the newly created database for the wallet before opening.
err = Create(
db, pubPassphrase, privPassphrase, seed, l.chainParams, bday,
)
if err != nil {
return nil, err
if isWatchingOnly {
err = CreateWatchingOnly(db, pubPassphrase, l.chainParams, bday)
if err != nil {
return nil, err
}
} else {
err = Create(
db, pubPassphrase, privPassphrase, seed, l.chainParams, bday,
)
if err != nil {
return nil, err
}
}

// Open the newly-created wallet.
Expand Down
57 changes: 39 additions & 18 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3620,23 +3620,45 @@ func (w *Wallet) Database() walletdb.DB {
// 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,
birthday time.Time) 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
func Create(db walletdb.DB, pubPass, privPass, seed []byte,
params *chaincfg.Params, birthday time.Time) error {

return createInternal(
db, pubPass, privPass, seed, params, birthday, false,
)
}

// CreateWatchingOnly creates an new watch-only wallet, writing it to
// an empty database. No seed can be provided as this wallet will be
// watching only. Likewise no private passphrase may be provided
// either.
func CreateWatchingOnly(db walletdb.DB, pubPass []byte,
params *chaincfg.Params, birthday time.Time) error {

return createInternal(
db, pubPass, nil, nil, params, birthday, true,
)
}

func createInternal(db walletdb.DB, pubPass, privPass, seed []byte,
params *chaincfg.Params, birthday time.Time, isWatchingOnly bool) error {

if !isWatchingOnly {
// 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
}
seed = hdSeed
}
if len(seed) < hdkeychain.MinSeedBytes ||
len(seed) > hdkeychain.MaxSeedBytes {
return hdkeychain.ErrInvalidSeedLen
}

return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
Expand All @@ -3650,8 +3672,7 @@ func Create(db walletdb.DB, pubPass, privPass, seed []byte, params *chaincfg.Par
}

err = waddrmgr.Create(
addrmgrNs, seed, pubPass, privPass, params, nil,
birthday,
addrmgrNs, seed, pubPass, privPass, params, nil, birthday,
)
if err != nil {
return err
Expand Down
34 changes: 34 additions & 0 deletions wallet/watchingonly_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2018 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package wallet

import (
"io/ioutil"
"os"
"testing"
"time"

"github.com/btcsuite/btcd/chaincfg"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
)

// TestCreateWatchingOnly checks that we can construct a watching-only
// wallet.
func TestCreateWatchingOnly(t *testing.T) {
// Set up a wallet.
dir, err := ioutil.TempDir("", "watchingonly_test")
if err != nil {
t.Fatalf("Failed to create db dir: %v", err)
}
defer os.RemoveAll(dir)

pubPass := []byte("hello")

loader := NewLoader(&chaincfg.TestNet3Params, dir, true, 250)
_, err = loader.CreateNewWatchingOnlyWallet(pubPass, time.Now())
if err != nil {
t.Fatalf("unable to create wallet: %v", err)
}
}

0 comments on commit b97681b

Please sign in to comment.