waddrmgr+cmd/dropwtxmgr: start rescan from birthday block

In this commit, we modify the dropwtxmgr tool to force a rescan upon
restart from the wallet's birthday block, rather than the chain's
genesis block. We can safely do this as we expect that no on-chain
events relevant to the wallet should happen before this block.  For
older wallets which do not have their birthday block set, the rescan
should start from the genesis block.
This commit is contained in:
Wilmer Paulino 2019-01-08 09:44:44 -08:00 committed by Olaoluwa Osuntokun
parent e59e51f8e1
commit 177e31c0b3
6 changed files with 36 additions and 36 deletions

View file

@ -6,12 +6,12 @@ package main
import (
"bufio"
"encoding/binary"
"fmt"
"os"
"path/filepath"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/walletdb"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
"github.com/btcsuite/btcwallet/wtxmgr"
@ -40,14 +40,8 @@ func init() {
var (
// Namespace keys.
syncBucketName = []byte("sync")
waddrmgrNamespace = []byte("waddrmgr")
wtxmgrNamespace = []byte("wtxmgr")
// Sync related key names (sync bucket).
syncedToName = []byte("syncedto")
startBlockName = []byte("startblock")
recentBlocksName = []byte("recentblocks")
)
func yes(s string) bool {
@ -111,7 +105,9 @@ func mainInt() int {
return 1
}
defer db.Close()
fmt.Println("Dropping wtxmgr namespace")
fmt.Println("Dropping btcwallet transaction history")
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
err := tx.DeleteTopLevelBucket(wtxmgrNamespace)
if err != nil && err != walletdb.ErrBucketNotFound {
@ -125,17 +121,21 @@ func mainInt() int {
if err != nil {
return err
}
ns = tx.ReadWriteBucket(waddrmgrNamespace).NestedReadWriteBucket(syncBucketName)
startBlock := ns.Get(startBlockName)
err = ns.Put(syncedToName, startBlock)
ns = tx.ReadWriteBucket(waddrmgrNamespace)
birthdayBlock, err := waddrmgr.FetchBirthdayBlock(ns)
if err != nil {
return err
fmt.Println("Wallet does not have a birthday block " +
"set, falling back to rescan from genesis")
startBlock, err := waddrmgr.FetchStartBlock(ns)
if err != nil {
return err
}
return waddrmgr.PutSyncedTo(ns, startBlock)
}
recentBlocks := make([]byte, 40)
copy(recentBlocks[0:4], startBlock[0:4])
copy(recentBlocks[8:], startBlock[4:])
binary.LittleEndian.PutUint32(recentBlocks[4:8], uint32(1))
return ns.Put(recentBlocksName, recentBlocks)
return waddrmgr.PutSyncedTo(ns, &birthdayBlock)
})
if err != nil {
fmt.Println("Failed to drop and re-create namespace:", err)

View file

@ -1830,8 +1830,8 @@ func fetchSyncedTo(ns walletdb.ReadBucket) (*BlockStamp, error) {
return &bs, nil
}
// putSyncedTo stores the provided synced to blockstamp to the database.
func putSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) error {
// PutSyncedTo stores the provided synced to blockstamp to the database.
func PutSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) error {
bucket := ns.NestedReadWriteBucket(syncBucketName)
errStr := fmt.Sprintf("failed to store sync information %v", bs.Hash)
@ -1893,9 +1893,9 @@ func fetchBlockHash(ns walletdb.ReadBucket, height int32) (*chainhash.Hash, erro
return &hash, nil
}
// fetchStartBlock loads the start block stamp for the manager from the
// FetchStartBlock loads the start block stamp for the manager from the
// database.
func fetchStartBlock(ns walletdb.ReadBucket) (*BlockStamp, error) {
func FetchStartBlock(ns walletdb.ReadBucket) (*BlockStamp, error) {
bucket := ns.NestedReadBucket(syncBucketName)
// The serialized start block format is:
@ -1964,13 +1964,13 @@ func putBirthday(ns walletdb.ReadWriteBucket, t time.Time) error {
return nil
}
// fetchBirthdayBlock retrieves the birthday block from the database.
// 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) {
func FetchBirthdayBlock(ns walletdb.ReadBucket) (BlockStamp, error) {
var block BlockStamp
bucket := ns.NestedReadBucket(syncBucketName)

View file

@ -1405,7 +1405,7 @@ func loadManager(ns walletdb.ReadBucket, pubPassphrase []byte,
if err != nil {
return nil, maybeConvertDbError(err)
}
startBlock, err := fetchStartBlock(ns)
startBlock, err := FetchStartBlock(ns)
if err != nil {
return nil, maybeConvertDbError(err)
}
@ -1800,7 +1800,7 @@ func Create(ns walletdb.ReadWriteBucket, seed, pubPassphrase, privPassphrase []b
}
// Save the initial synced to state.
err = putSyncedTo(ns, &syncInfo.syncedTo)
err = PutSyncedTo(ns, &syncInfo.syncedTo)
if err != nil {
return maybeConvertDbError(err)
}

View file

@ -365,10 +365,10 @@ func resetSyncedBlockToBirthday(ns walletdb.ReadWriteBucket) error {
return errors.New("sync bucket does not exist")
}
birthdayBlock, err := fetchBirthdayBlock(ns)
birthdayBlock, err := FetchBirthdayBlock(ns)
if err != nil {
return err
}
return putSyncedTo(ns, &birthdayBlock)
return PutSyncedTo(ns, &birthdayBlock)
}

View file

@ -81,7 +81,7 @@ func TestMigrationPopulateBirthdayBlock(t *testing.T) {
block.Height = i
blockHash := bytes.Repeat([]byte(string(i)), 32)
copy(block.Hash[:], blockHash)
if err := putSyncedTo(ns, block); err != nil {
if err := PutSyncedTo(ns, block); err != nil {
return err
}
}
@ -100,7 +100,7 @@ func TestMigrationPopulateBirthdayBlock(t *testing.T) {
// Finally, since the migration has not yet started, we should
// not be able to find the birthday block within the database.
_, err := fetchBirthdayBlock(ns)
_, err := FetchBirthdayBlock(ns)
if !IsError(err, ErrBirthdayBlockNotSet) {
return fmt.Errorf("expected ErrBirthdayBlockNotSet, "+
"got %v", err)
@ -112,7 +112,7 @@ func TestMigrationPopulateBirthdayBlock(t *testing.T) {
// After the migration has completed, we should see that the birthday
// block now exists and is set to the correct expected height.
afterMigration := func(ns walletdb.ReadWriteBucket) error {
birthdayBlock, err := fetchBirthdayBlock(ns)
birthdayBlock, err := FetchBirthdayBlock(ns)
if err != nil {
return err
}
@ -151,7 +151,7 @@ func TestMigrationPopulateBirthdayBlockEstimateTooFar(t *testing.T) {
block.Height = i
blockHash := bytes.Repeat([]byte(string(i)), 32)
copy(block.Hash[:], blockHash)
if err := putSyncedTo(ns, block); err != nil {
if err := PutSyncedTo(ns, block); err != nil {
return err
}
}
@ -184,7 +184,7 @@ func TestMigrationPopulateBirthdayBlockEstimateTooFar(t *testing.T) {
// Finally, since the migration has not yet started, we should
// not be able to find the birthday block within the database.
_, err := fetchBirthdayBlock(ns)
_, err := FetchBirthdayBlock(ns)
if !IsError(err, ErrBirthdayBlockNotSet) {
return fmt.Errorf("expected ErrBirthdayBlockNotSet, "+
"got %v", err)
@ -196,7 +196,7 @@ func TestMigrationPopulateBirthdayBlockEstimateTooFar(t *testing.T) {
// After the migration has completed, we should see that the birthday
// block now exists and is set to the correct expected height.
afterMigration := func(ns walletdb.ReadWriteBucket) error {
birthdayBlock, err := fetchBirthdayBlock(ns)
birthdayBlock, err := FetchBirthdayBlock(ns)
if err != nil {
return err
}
@ -230,7 +230,7 @@ func TestMigrationResetSyncedBlockToBirthday(t *testing.T) {
block.Height = i
blockHash := bytes.Repeat([]byte(string(i)), 32)
copy(block.Hash[:], blockHash)
if err := putSyncedTo(ns, block); err != nil {
if err := PutSyncedTo(ns, block); err != nil {
return err
}
}

View file

@ -59,7 +59,7 @@ func (m *Manager) SetSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) error
}
// Update the database.
err := putSyncedTo(ns, bs)
err := PutSyncedTo(ns, bs)
if err != nil {
return err
}
@ -115,7 +115,7 @@ func (m *Manager) SetBirthday(ns walletdb.ReadWriteBucket,
// been used, for the manager. A boolean is also returned to indicate whether
// the birthday block has been verified as correct.
func (m *Manager) BirthdayBlock(ns walletdb.ReadBucket) (BlockStamp, bool, error) {
birthdayBlock, err := fetchBirthdayBlock(ns)
birthdayBlock, err := FetchBirthdayBlock(ns)
if err != nil {
return BlockStamp{}, false, err
}