wallet: perform recovery on all registered key scopes
In similar fashion to the previous commit, due to a no longer existing bug within the wallet, it was possible for change addresses to be created outside of their intended key scope (the default), so wallets affected by this now need to ensure upon recovery that they scan the chain for _all_ existing key scopes, rather than just the default ones, to reflect their proper balance. Through manual testing, it was shown that the impact of recovering the additional key scopes is negligible in most cases for both full nodes and light clients.
This commit is contained in:
parent
1285049923
commit
31c027e19f
1 changed files with 14 additions and 48 deletions
|
@ -637,13 +637,15 @@ func (w *Wallet) recovery(chainClient chain.Interface,
|
|||
)
|
||||
|
||||
// In the event that this recovery is being resumed, we will need to
|
||||
// repopulate all found addresses from the database. For basic recovery,
|
||||
// we will only do so for the default scopes.
|
||||
scopedMgrs, err := w.defaultScopeManagers()
|
||||
if err != nil {
|
||||
return err
|
||||
// repopulate all found addresses from the database. Ideally, for basic
|
||||
// recovery, we would only do so for the default scopes, but due to a
|
||||
// bug in which the wallet would create change addresses outside of the
|
||||
// default scopes, it's necessary to attempt all registered key scopes.
|
||||
scopedMgrs := make(map[waddrmgr.KeyScope]*waddrmgr.ScopedKeyManager)
|
||||
for _, scopedMgr := range w.Manager.ActiveScopedKeyManagers() {
|
||||
scopedMgrs[scopedMgr.Scope()] = scopedMgr
|
||||
}
|
||||
err = walletdb.View(w.db, func(tx walletdb.ReadTx) error {
|
||||
err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
|
||||
txMgrNS := tx.ReadBucket(wtxmgrNamespaceKey)
|
||||
credits, err := w.TxStore.UnspentOutputs(txMgrNS)
|
||||
if err != nil {
|
||||
|
@ -712,9 +714,9 @@ func (w *Wallet) recovery(chainClient chain.Interface,
|
|||
return err
|
||||
}
|
||||
}
|
||||
return w.recoverDefaultScopes(
|
||||
return w.recoverScopedAddresses(
|
||||
chainClient, tx, ns, recoveryBatch,
|
||||
recoveryMgr.State(),
|
||||
recoveryMgr.State(), scopedMgrs,
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -737,48 +739,10 @@ func (w *Wallet) recovery(chainClient chain.Interface,
|
|||
return nil
|
||||
}
|
||||
|
||||
// defaultScopeManagers fetches the ScopedKeyManagers from the wallet using the
|
||||
// default set of key scopes.
|
||||
func (w *Wallet) defaultScopeManagers() (
|
||||
map[waddrmgr.KeyScope]*waddrmgr.ScopedKeyManager, error) {
|
||||
|
||||
scopedMgrs := make(map[waddrmgr.KeyScope]*waddrmgr.ScopedKeyManager)
|
||||
for _, scope := range waddrmgr.DefaultKeyScopes {
|
||||
scopedMgr, err := w.Manager.FetchScopedKeyManager(scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scopedMgrs[scope] = scopedMgr
|
||||
}
|
||||
|
||||
return scopedMgrs, nil
|
||||
}
|
||||
|
||||
// recoverDefaultScopes attempts to recover any addresses belonging to any
|
||||
// active scoped key managers known to the wallet. Recovery of each scope's
|
||||
// default account will be done iteratively against the same batch of blocks.
|
||||
// TODO(conner): parallelize/pipeline/cache intermediate network requests
|
||||
func (w *Wallet) recoverDefaultScopes(
|
||||
chainClient chain.Interface,
|
||||
tx walletdb.ReadWriteTx,
|
||||
ns walletdb.ReadWriteBucket,
|
||||
batch []wtxmgr.BlockMeta,
|
||||
recoveryState *RecoveryState) error {
|
||||
|
||||
scopedMgrs, err := w.defaultScopeManagers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return w.recoverScopedAddresses(
|
||||
chainClient, tx, ns, batch, recoveryState, scopedMgrs,
|
||||
)
|
||||
}
|
||||
|
||||
// recoverAccountAddresses scans a range of blocks in attempts to recover any
|
||||
// recoverScopedAddresses scans a range of blocks in attempts to recover any
|
||||
// previously used addresses for a particular account derivation path. At a high
|
||||
// level, the algorithm works as follows:
|
||||
//
|
||||
// 1) Ensure internal and external branch horizons are fully expanded.
|
||||
// 2) Filter the entire range of blocks, stopping if a non-zero number of
|
||||
// address are contained in a particular block.
|
||||
|
@ -786,6 +750,8 @@ func (w *Wallet) recoverDefaultScopes(
|
|||
// 4) Record any outpoints found in the block that should be watched for spends
|
||||
// 5) Trim the range of blocks up to and including the one reporting the addrs.
|
||||
// 6) Repeat from (1) if there are still more blocks in the range.
|
||||
//
|
||||
// TODO(conner): parallelize/pipeline/cache intermediate network requests
|
||||
func (w *Wallet) recoverScopedAddresses(
|
||||
chainClient chain.Interface,
|
||||
tx walletdb.ReadWriteTx,
|
||||
|
|
Loading…
Add table
Reference in a new issue