waddrmgr: add support for wallet birthday for creating new wallet

TODO: support for wallet upgrades and key imports
This commit is contained in:
Alex 2017-09-19 15:53:38 -06:00 committed by Olaoluwa Osuntokun
parent 44f94c4ca5
commit 555bd5d583
3 changed files with 68 additions and 2 deletions

View file

@ -194,6 +194,7 @@ var (
// Sync related key names (sync bucket).
syncedToName = []byte("syncedto")
startBlockName = []byte("startblock")
birthdayName = []byte("birthday")
// Account related key names (account bucket).
acctNumAcctsName = []byte("numaccts")
@ -1489,6 +1490,37 @@ func putStartBlock(ns walletdb.ReadWriteBucket, bs *BlockStamp) error {
return nil
}
// fetchBirthday loads the manager's bithday timestamp from the database.
func fetchBirthday(ns walletdb.ReadBucket) (time.Time, error) {
bucket := ns.NestedReadBucket(syncBucketName)
var t time.Time
buf := bucket.Get(birthdayName)
if len(buf) != 8 {
str := "malformed birthday stored in database"
return t, managerError(ErrDatabase, str, nil)
}
t = time.Unix(int64(binary.BigEndian.Uint64(buf)), 0)
return t, nil
}
// putBirthday stores the provided birthday timestamp to the database.
func putBirthday(ns walletdb.ReadWriteBucket, t time.Time) error {
bucket := ns.NestedReadWriteBucket(syncBucketName)
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(t.Unix()))
err := bucket.Put(birthdayName, buf)
if err != nil {
str := "failed to store birthday"
return managerError(ErrDatabase, str, err)
}
return nil
}
// managerExists returns whether or not the manager has already been created
// in the given database namespace.
func managerExists(ns walletdb.ReadBucket) bool {

View file

@ -9,6 +9,7 @@ import (
"crypto/sha512"
"fmt"
"sync"
"time"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
@ -249,6 +250,7 @@ type Manager struct {
chainParams *chaincfg.Params
addrs map[addrKey]ManagedAddress
syncState syncState
birthday time.Time
watchingOnly bool
locked bool
closed bool
@ -1985,12 +1987,13 @@ func (m *Manager) Decrypt(keyType CryptoKeyType, in []byte) ([]byte, error) {
func newManager(chainParams *chaincfg.Params, masterKeyPub *snacl.SecretKey,
masterKeyPriv *snacl.SecretKey, cryptoKeyPub EncryptorDecryptor,
cryptoKeyPrivEncrypted, cryptoKeyScriptEncrypted []byte, syncInfo *syncState,
privPassphraseSalt [saltSize]byte) *Manager {
birthday time.Time, privPassphraseSalt [saltSize]byte) *Manager {
return &Manager{
chainParams: chainParams,
addrs: make(map[addrKey]ManagedAddress),
syncState: *syncInfo,
birthday: birthday,
locked: true,
acctInfo: make(map[uint32]*accountInfo),
masterKeyPub: masterKeyPub,
@ -2124,6 +2127,10 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte, chainParams *chai
if err != nil {
return nil, maybeConvertDbError(err)
}
birthday, err := fetchBirthday(ns)
if err != nil {
return nil, maybeConvertDbError(err)
}
// When not a watching-only manager, set the master private key params,
// but don't derive it now since the manager starts off locked.
@ -2174,7 +2181,7 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte, chainParams *chai
// call to new with the values loaded from the database.
mgr := newManager(chainParams, &masterKeyPub, &masterKeyPriv,
cryptoKeyPub, cryptoKeyPrivEnc, cryptoKeyScriptEnc, syncInfo,
privPassphraseSalt)
birthday, privPassphraseSalt)
mgr.watchingOnly = watchingOnly
return mgr, nil
}
@ -2438,6 +2445,11 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
if err != nil {
return err
}
// Use 48 hours as margin of safety for wallet birthday.
err = putBirthday(ns, time.Now().Add(-48*time.Hour))
if err != nil {
return err
}
// Save the information for the imported account to the database.
err = putAccountInfo(ns, ImportedAddrAccount, nil,

View file

@ -5,6 +5,8 @@
package waddrmgr
import (
"time"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcwallet/walletdb"
)
@ -87,3 +89,23 @@ func (m *Manager) BlockHash(ns walletdb.ReadBucket, height int32) (
return fetchBlockHash(ns, height)
}
// Birthday returns the birthday, or earliest time a key could have been used,
// for the manager.
func (m *Manager) Birthday() time.Time {
m.mtx.Lock()
defer m.mtx.Unlock()
return m.birthday
}
// SetBirthday sets the birthday, or earliest time a key could have been used,
// for the manager.
func (m *Manager) SetBirthday(ns walletdb.ReadWriteBucket,
birthday time.Time) error {
m.mtx.Lock()
defer m.mtx.Unlock()
m.birthday = birthday
return putBirthday(ns, birthday)
}