Rescan, Account Discovery, and default Passphhrase #38

Merged
roylee17 merged 4 commits from separate-rescan-and-account-discovery into master 2022-11-01 03:53:17 +01:00
Showing only changes of commit fe6f28d469 - Show all commits

View file

@ -26,7 +26,6 @@ import (
btcutil "github.com/lbryio/lbcutil" btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/hdkeychain" "github.com/lbryio/lbcutil/hdkeychain"
"github.com/lbryio/lbcwallet/chain" "github.com/lbryio/lbcwallet/chain"
"github.com/lbryio/lbcwallet/internal/prompt"
"github.com/lbryio/lbcwallet/waddrmgr" "github.com/lbryio/lbcwallet/waddrmgr"
"github.com/lbryio/lbcwallet/wallet/txauthor" "github.com/lbryio/lbcwallet/wallet/txauthor"
"github.com/lbryio/lbcwallet/wallet/txrules" "github.com/lbryio/lbcwallet/wallet/txrules"
@ -407,7 +406,7 @@ func (w *Wallet) syncWithChain(birthdayStamp *waddrmgr.BlockStamp) error {
// If the wallet requested an on-chain recovery of its funds, we'll do // If the wallet requested an on-chain recovery of its funds, we'll do
// so now. // so now.
if w.recoveryWindow > 0 { if w.recoveryWindow > 0 {
if err := w.recovery(chainClient, birthdayStamp); err != nil { if err := w.Recovery(chainClient); err != nil {
return fmt.Errorf("unable to perform wallet recovery: "+ return fmt.Errorf("unable to perform wallet recovery: "+
"%v", err) "%v", err)
} }
@ -638,13 +637,12 @@ func locateBirthdayBlock(chainClient chainConn,
return birthdayBlock, nil return birthdayBlock, nil
} }
// recovery attempts to recover any unspent outputs that pay to any of our // Recovery attempts to recover any unspent outputs that pay to any of our
// addresses starting from our birthday, or the wallet's tip (if higher), which // addresses starting from our birthday, or the wallet's tip (if higher), which
// would indicate resuming a recovery after a restart. // would indicate resuming a recovery after a restart.
func (w *Wallet) recovery(chainClient chain.Interface, func (w *Wallet) Recovery(chainClient chain.Interface) error {
birthdayBlock *waddrmgr.BlockStamp) error {
log.Infof("RECOVERY MODE ENABLED -- rescanning for used addresses "+ log.Infof("Recovery for used addresses "+
"with recovery_window=%d", w.recoveryWindow) "with recovery_window=%d", w.recoveryWindow)
// We'll initialize the recovery manager with a default batch size of // We'll initialize the recovery manager with a default batch size of
@ -672,44 +670,36 @@ func (w *Wallet) recovery(chainClient chain.Interface,
return err return err
} }
// Fetch the best height from the backend to determine when we should return nil
// stop. }
_, bestHeight, err := chainClient.GetBestBlock()
if err != nil {
return err
}
// Now we can begin scanning the chain from the wallet's current tip to func (w *Wallet) RescanBlockchain(chainClient chain.Interface,
// ensure we properly handle restarts. Since the recovery process itself startHeight int32, stopHeight int32) (int32, int32, error) {
// acts as rescan, we'll also update our wallet's synced state along the
// way to reflect the blocks we process and prevent rescanning them
// later on.
//
// NOTE: We purposefully don't update our best height since we assume
// that a wallet rescan will be performed from the wallet's tip, which
// will be of bestHeight after completing the recovery process.
pass, err := prompt.Passphrase(false) log.Infof("Rescanning blockchain from block %d to %d "+
if err != nil { "with recovery_window=%d", startHeight, stopHeight,
return err w.recoveryWindow)
}
err = w.Unlock(pass, nil) defer log.Infof("Rescan blockchain done")
if err != nil {
return err recoveryMgr := NewRecoveryManager(
w.recoveryWindow, recoveryBatchSize, w.chainParams,
)
scopedMgrs := make(map[waddrmgr.KeyScope]*waddrmgr.ScopedKeyManager)
for _, scopedMgr := range w.Manager.ActiveScopedKeyManagers() {
scopedMgrs[scopedMgr.Scope()] = scopedMgr
} }
defer w.Lock()
var blocks []*waddrmgr.BlockStamp var blocks []*waddrmgr.BlockStamp
startHeight := w.Manager.SyncedTo().Height + 1 for height := startHeight; height <= stopHeight; height++ {
for height := startHeight; height <= bestHeight; height++ {
hash, err := chainClient.GetBlockHash(int64(height)) hash, err := chainClient.GetBlockHash(int64(height))
if err != nil { if err != nil {
return err return startHeight, stopHeight, err
} }
header, err := chainClient.GetBlockHeader(hash) header, err := chainClient.GetBlockHeader(hash)
if err != nil { if err != nil {
return err return startHeight, stopHeight, err
} }
blocks = append(blocks, &waddrmgr.BlockStamp{ blocks = append(blocks, &waddrmgr.BlockStamp{
Hash: *hash, Hash: *hash,
@ -720,7 +710,7 @@ func (w *Wallet) recovery(chainClient chain.Interface,
// It's possible for us to run into blocks before our birthday // It's possible for us to run into blocks before our birthday
// if our birthday is after our reorg safe height, so we'll make // if our birthday is after our reorg safe height, so we'll make
// sure to not add those to the batch. // sure to not add those to the batch.
if height >= birthdayBlock.Height { if height >= startHeight {
recoveryMgr.AddToBlockBatch( recoveryMgr.AddToBlockBatch(
hash, height, header.Timestamp, hash, height, header.Timestamp,
) )
@ -731,18 +721,12 @@ func (w *Wallet) recovery(chainClient chain.Interface,
// the recovery batch size, so we can proceed to commit our // the recovery batch size, so we can proceed to commit our
// state to disk. // state to disk.
recoveryBatch := recoveryMgr.BlockBatch() recoveryBatch := recoveryMgr.BlockBatch()
if len(recoveryBatch) != recoveryBatchSize && height != bestHeight { if len(recoveryBatch) != recoveryBatchSize && height != stopHeight {
continue continue
} }
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error { err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey) ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
for _, block := range blocks {
err = w.Manager.SetSyncedTo(ns, block)
if err != nil {
return err
}
}
for scope, scopedMgr := range scopedMgrs { for scope, scopedMgr := range scopedMgrs {
scopeState := recoveryMgr.State().StateForScope(scope) scopeState := recoveryMgr.State().StateForScope(scope)
err = expandScopeHorizons(ns, scopedMgr, scopeState) err = expandScopeHorizons(ns, scopedMgr, scopeState)
@ -755,7 +739,7 @@ func (w *Wallet) recovery(chainClient chain.Interface,
) )
}) })
if err != nil { if err != nil {
return err return startHeight, stopHeight, err
} }
if len(recoveryBatch) > 0 { if len(recoveryBatch) > 0 {
@ -769,8 +753,7 @@ func (w *Wallet) recovery(chainClient chain.Interface,
blocks = blocks[:0] blocks = blocks[:0]
recoveryMgr.ResetBlockBatch() recoveryMgr.ResetBlockBatch()
} }
return startHeight, stopHeight, nil
return nil
} }
// recoverScopedAddresses scans a range of blocks in attempts to recover any // recoverScopedAddresses scans a range of blocks in attempts to recover any