Rescan, Account Discovery, and default Passphhrase #38
1 changed files with 27 additions and 44 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue