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:
parent
e59e51f8e1
commit
177e31c0b3
6 changed files with 36 additions and 36 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue