From e9d24382d683cb0bbc8f645672535a4e30001337 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 5 Nov 2018 17:02:26 -0800 Subject: [PATCH] waddrmgr/db: add birthday block within syncBucket In this commit, we add a new key/value pair within the waddrmgr's syncBucket that will represent the birthday block of the wallet. This can then be used to force rescans from this point, rather than from the genesis block. --- waddrmgr/db.go | 77 ++++++++++++++++++++++++++++++++++++++--------- waddrmgr/error.go | 4 +++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/waddrmgr/db.go b/waddrmgr/db.go index 851410b..1765cd4 100644 --- a/waddrmgr/db.go +++ b/waddrmgr/db.go @@ -252,9 +252,10 @@ var ( watchingOnlyName = []byte("watchonly") // Sync related key names (sync bucket). - syncedToName = []byte("syncedto") - startBlockName = []byte("startblock") - birthdayName = []byte("birthday") + syncedToName = []byte("syncedto") + startBlockName = []byte("startblock") + birthdayName = []byte("birthday") + birthdayBlockName = []byte("birthdayblock") ) // uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in @@ -1929,32 +1930,80 @@ func putStartBlock(ns walletdb.ReadWriteBucket, bs *BlockStamp) error { // 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 { + bucket := ns.NestedReadBucket(syncBucketName) + birthdayTimestamp := bucket.Get(birthdayName) + if len(birthdayTimestamp) != 8 { str := "malformed birthday stored in database" return t, managerError(ErrDatabase, str, nil) } - t = time.Unix(int64(binary.BigEndian.Uint64(buf)), 0) + t = time.Unix(int64(binary.BigEndian.Uint64(birthdayTimestamp)), 0) + return t, nil } // putBirthday stores the provided birthday timestamp to the database. func putBirthday(ns walletdb.ReadWriteBucket, t time.Time) error { + var birthdayTimestamp [8]byte + binary.BigEndian.PutUint64(birthdayTimestamp[:], uint64(t.Unix())) + bucket := ns.NestedReadWriteBucket(syncBucketName) - - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, uint64(t.Unix())) - - err := bucket.Put(birthdayName, buf) - if err != nil { + if err := bucket.Put(birthdayName, birthdayTimestamp[:]); err != nil { str := "failed to store birthday" return managerError(ErrDatabase, str, err) } + + return nil +} + +// fetchBirthdayBlock retrieves the birthday block from the database. +// +// The block is serialized as follows: +// [0:4] block height +// [4:36] block hash +// [36:44] block timestamp +func fetchBirthdayBlock(ns walletdb.ReadBucket) (BlockStamp, error) { + var block BlockStamp + + bucket := ns.NestedReadBucket(syncBucketName) + birthdayBlock := bucket.Get(birthdayBlockName) + if birthdayBlock == nil { + str := "birthday block not set" + return block, managerError(ErrBirthdayBlockNotSet, str, nil) + } + if len(birthdayBlock) != 44 { + str := "malformed birthday block stored in database" + return block, managerError(ErrDatabase, str, nil) + } + + block.Height = int32(binary.BigEndian.Uint32(birthdayBlock[:4])) + copy(block.Hash[:], birthdayBlock[4:36]) + t := int64(binary.BigEndian.Uint64(birthdayBlock[36:])) + block.Timestamp = time.Unix(t, 0) + + return block, nil +} + +// putBirthdayBlock stores the provided birthday block to the database. +// +// The block is serialized as follows: +// [0:4] block height +// [4:36] block hash +// [36:44] block timestamp +func putBirthdayBlock(ns walletdb.ReadWriteBucket, block BlockStamp) error { + var birthdayBlock [44]byte + binary.BigEndian.PutUint32(birthdayBlock[:4], uint32(block.Height)) + copy(birthdayBlock[4:36], block.Hash[:]) + binary.BigEndian.PutUint64(birthdayBlock[36:], uint64(block.Timestamp.Unix())) + + bucket := ns.NestedReadWriteBucket(syncBucketName) + if err := bucket.Put(birthdayBlockName, birthdayBlock[:]); err != nil { + str := "failed to store birthday block" + return managerError(ErrDatabase, str, err) + } + return nil } diff --git a/waddrmgr/error.go b/waddrmgr/error.go index 5a66882..0ff575c 100644 --- a/waddrmgr/error.go +++ b/waddrmgr/error.go @@ -131,6 +131,10 @@ const ( // ErrScopeNotFound is returned when a target scope cannot be found // within the database. ErrScopeNotFound + + // ErrBirthdayBlockNotSet is returned when we attempt to retrieve the + // wallet's birthday but it has not been set yet. + ErrBirthdayBlockNotSet ) // Map of ErrorCode values back to their constant names for pretty printing.