wallet/wallet: start initial rescan from birthday block
This commit is contained in:
parent
dfa3a88529
commit
0c5c8d7f9e
1 changed files with 50 additions and 13 deletions
|
@ -345,6 +345,13 @@ func (w *Wallet) syncWithChain() error {
|
||||||
isRecovery := w.recoveryWindow > 0
|
isRecovery := w.recoveryWindow > 0
|
||||||
isInitialSync := len(addrs) == 0 && len(unspent) == 0 &&
|
isInitialSync := len(addrs) == 0 && len(unspent) == 0 &&
|
||||||
startHeight == 0
|
startHeight == 0
|
||||||
|
birthday := w.Manager.Birthday()
|
||||||
|
|
||||||
|
// If an initial sync is attempted, we will try and find the block stamp
|
||||||
|
// of the first block past our birthday. This will be fed into the
|
||||||
|
// rescan to ensure we catch transactions that are sent while performing
|
||||||
|
// the initial sync.
|
||||||
|
var birthdayStamp *waddrmgr.BlockStamp
|
||||||
|
|
||||||
// TODO(jrick): How should this handle a synced height earlier than
|
// TODO(jrick): How should this handle a synced height earlier than
|
||||||
// the chain server best block?
|
// the chain server best block?
|
||||||
|
@ -470,15 +477,37 @@ func (w *Wallet) syncWithChain() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if this header's timestamp has surpassed
|
// Check to see if this header's timestamp has surpassed
|
||||||
// our birthday. If we are in recovery mode and the
|
// our birthday or if we've surpassed one previously.
|
||||||
// check passes, we will add this block to our list of
|
|
||||||
// blocks to scan for recovered addresses.
|
|
||||||
timestamp := header.Timestamp
|
timestamp := header.Timestamp
|
||||||
if isRecovery && timestamp.After(w.Manager.Birthday()) {
|
if timestamp.After(birthday) || birthdayStamp != nil {
|
||||||
|
// If this is the first block past our birthday,
|
||||||
|
// record the block stamp so that we can use
|
||||||
|
// this as the starting point for the rescan.
|
||||||
|
// This will ensure we don't miss transactions
|
||||||
|
// that are sent to the wallet during an initial
|
||||||
|
// sync.
|
||||||
|
//
|
||||||
|
// NOTE: The birthday persisted by the wallet is
|
||||||
|
// two days before the actual wallet birthday,
|
||||||
|
// to deal with potentially inaccurate header
|
||||||
|
// timestamps.
|
||||||
|
if birthdayStamp == nil {
|
||||||
|
birthdayStamp = &waddrmgr.BlockStamp{
|
||||||
|
Height: height,
|
||||||
|
Hash: *hash,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are in recovery mode and the check
|
||||||
|
// passes, we will add this block to our list of
|
||||||
|
// blocks to scan for recovered addresses.
|
||||||
|
if isRecovery {
|
||||||
recoveryMgr.AddToBlockBatch(
|
recoveryMgr.AddToBlockBatch(
|
||||||
hash, height, timestamp,
|
hash, height, timestamp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = w.Manager.SetSyncedTo(ns, &waddrmgr.BlockStamp{
|
err = w.Manager.SetSyncedTo(ns, &waddrmgr.BlockStamp{
|
||||||
Hash: *hash,
|
Hash: *hash,
|
||||||
|
@ -566,11 +595,11 @@ func (w *Wallet) syncWithChain() error {
|
||||||
// Compare previously-seen blocks against the chain server. If any of
|
// Compare previously-seen blocks against the chain server. If any of
|
||||||
// these blocks no longer exist, rollback all of the missing blocks
|
// these blocks no longer exist, rollback all of the missing blocks
|
||||||
// before catching up with the rescan.
|
// before catching up with the rescan.
|
||||||
|
rollback := false
|
||||||
|
rollbackStamp := w.Manager.SyncedTo()
|
||||||
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
|
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
|
||||||
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
|
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
|
||||||
txmgrNs := tx.ReadWriteBucket(wtxmgrNamespaceKey)
|
txmgrNs := tx.ReadWriteBucket(wtxmgrNamespaceKey)
|
||||||
rollback := false
|
|
||||||
rollbackStamp := w.Manager.SyncedTo()
|
|
||||||
for height := rollbackStamp.Height; true; height-- {
|
for height := rollbackStamp.Height; true; height-- {
|
||||||
hash, err := w.Manager.BlockHash(addrmgrNs, height)
|
hash, err := w.Manager.BlockHash(addrmgrNs, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -594,14 +623,15 @@ func (w *Wallet) syncWithChain() error {
|
||||||
}
|
}
|
||||||
rollback = true
|
rollback = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if rollback {
|
if rollback {
|
||||||
err := w.Manager.SetSyncedTo(addrmgrNs, &rollbackStamp)
|
err := w.Manager.SetSyncedTo(addrmgrNs, &rollbackStamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Rollback unconfirms transactions at and beyond the passed
|
// Rollback unconfirms transactions at and beyond the
|
||||||
// height, so add one to the new synced-to height to prevent
|
// passed height, so add one to the new synced-to height
|
||||||
// unconfirming txs from the synced-to block.
|
// to prevent unconfirming txs from the synced-to block.
|
||||||
err = w.TxStore.Rollback(txmgrNs, rollbackStamp.Height+1)
|
err = w.TxStore.Rollback(txmgrNs, rollbackStamp.Height+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -613,6 +643,13 @@ func (w *Wallet) syncWithChain() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a birthday stamp was found during the initial sync and the
|
||||||
|
// rollback causes us to revert it, update the birthday stamp so that it
|
||||||
|
// points at the new tip.
|
||||||
|
if birthdayStamp != nil && rollbackStamp.Height <= birthdayStamp.Height {
|
||||||
|
birthdayStamp = &rollbackStamp
|
||||||
|
}
|
||||||
|
|
||||||
// Request notifications for connected and disconnected blocks.
|
// Request notifications for connected and disconnected blocks.
|
||||||
//
|
//
|
||||||
// TODO(jrick): Either request this notification only once, or when
|
// TODO(jrick): Either request this notification only once, or when
|
||||||
|
@ -626,7 +663,7 @@ func (w *Wallet) syncWithChain() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.Rescan(addrs, unspent)
|
return w.rescanWithTarget(addrs, unspent, birthdayStamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultScopeManagers fetches the ScopedKeyManagers from the wallet using the
|
// defaultScopeManagers fetches the ScopedKeyManagers from the wallet using the
|
||||||
|
|
Loading…
Reference in a new issue