lbcwallet/waddrmgr/sync.go
Wilmer Paulino f710cd4a92
cmd/dropwtxmgr+waddrmgr: handle constraint when resetting synced state
We update the dropwtxmgr utility tool to take into account that the
wallet only stores MaxReorgDepth blocks, which introduced an additional
constraint when updating the wallet's synced state. The constraint
ensures that the previous block exists when updating the wallet's synced
state, but this does not hold for the birthday block since it's the
first block we'll store.
2019-07-08 13:26:43 -07:00

136 lines
4.3 KiB
Go

// Copyright (c) 2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package waddrmgr
import (
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcwallet/walletdb"
)
// BlockStamp defines a block (by height and a unique hash) and is used to mark
// a point in the blockchain that an address manager element is
// synced to.
type BlockStamp struct {
Height int32
Hash chainhash.Hash
Timestamp time.Time
}
// syncState houses the sync state of the manager. It consists of the recently
// seen blocks as height, as well as the start and current sync block stamps.
type syncState struct {
// startBlock is the first block that can be safely used to start a
// rescan. It is either the block the manager was created with, or the
// earliest block provided with imported addresses or scripts.
startBlock BlockStamp
// syncedTo is the current block the addresses in the manager are known
// to be synced against.
syncedTo BlockStamp
}
// newSyncState returns a new sync state with the provided parameters.
func newSyncState(startBlock, syncedTo *BlockStamp) *syncState {
return &syncState{
startBlock: *startBlock,
syncedTo: *syncedTo,
}
}
// SetSyncedTo marks the address manager to be in sync with the recently-seen
// block described by the blockstamp. When the provided blockstamp is nil, the
// oldest blockstamp of the block the manager was created at and of all
// imported addresses will be used. This effectively allows the manager to be
// marked as unsynced back to the oldest known point any of the addresses have
// appeared in the block chain.
func (m *Manager) SetSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) error {
m.mtx.Lock()
defer m.mtx.Unlock()
// Use the stored start blockstamp and reset recent hashes and height
// when the provided blockstamp is nil.
if bs == nil {
bs = &m.syncState.startBlock
}
// Update the database.
err := PutSyncedTo(ns, bs)
if err != nil {
return err
}
// Update memory now that the database is updated.
m.syncState.syncedTo = *bs
return nil
}
// SyncedTo returns details about the block height and hash that the address
// manager is synced through at the very least. The intention is that callers
// can use this information for intelligently initiating rescans to sync back to
// the best chain from the last known good block.
func (m *Manager) SyncedTo() BlockStamp {
m.mtx.RLock()
defer m.mtx.RUnlock()
return m.syncState.syncedTo
}
// BlockHash returns the block hash at a particular block height. This
// information is useful for comparing against the chain back-end to see if a
// reorg is taking place and how far back it goes.
func (m *Manager) BlockHash(ns walletdb.ReadBucket, height int32) (
*chainhash.Hash, error) {
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.RLock()
defer m.mtx.RUnlock()
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)
}
// BirthdayBlock returns the birthday block, or earliest block a key could have
// 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)
if err != nil {
return BlockStamp{}, false, err
}
return birthdayBlock, fetchBirthdayBlockVerification(ns), nil
}
// SetBirthdayBlock sets the birthday block, or earliest time a key could have
// been used, for the manager. The verified boolean can be used to specify
// whether this birthday block should be sanity checked to determine if there
// exists a better candidate to prevent less block fetching.
func (m *Manager) SetBirthdayBlock(ns walletdb.ReadWriteBucket,
block BlockStamp, verified bool) error {
if err := PutBirthdayBlock(ns, block); err != nil {
return err
}
return putBirthdayBlockVerification(ns, verified)
}