wallet: include addresses from relevant key scopes in rescan
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 they scan the chain for all addresses within the default key scopes (as expected), and all _internal_ addresses (branch used for change addresses) within any other registered key scopes to reflect their proper balance.
This commit is contained in:
parent
43e19da868
commit
1285049923
3 changed files with 70 additions and 4 deletions
|
@ -738,6 +738,43 @@ func (m *Manager) ForEachActiveAddress(ns walletdb.ReadBucket, fn func(addr btcu
|
|||
return nil
|
||||
}
|
||||
|
||||
// ForEachRelevantActiveAddress invokes the given closure on each active
|
||||
// address relevant to the wallet. Ideally, only addresses within the default
|
||||
// key scopes would be relevant, but due to a bug (now fixed) in which change
|
||||
// addresses could be created outside of the default key scopes, we now need to
|
||||
// check for those as well.
|
||||
func (m *Manager) ForEachRelevantActiveAddress(ns walletdb.ReadBucket,
|
||||
fn func(addr btcutil.Address) error) error {
|
||||
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
|
||||
for _, scopedMgr := range m.scopedManagers {
|
||||
// If the manager is for a default key scope, we'll return all
|
||||
// addresses, otherwise we'll only return internal addresses, as
|
||||
// that's the branch used for change addresses.
|
||||
isDefaultKeyScope := false
|
||||
for _, defaultKeyScope := range DefaultKeyScopes {
|
||||
if scopedMgr.Scope() == defaultKeyScope {
|
||||
isDefaultKeyScope = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if isDefaultKeyScope {
|
||||
err = scopedMgr.ForEachActiveAddress(ns, fn)
|
||||
} else {
|
||||
err = scopedMgr.ForEachInternalActiveAddress(ns, fn)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForEachAccountAddress calls the given function with each address of
|
||||
// the given account stored in the manager, breaking early on error.
|
||||
func (m *Manager) ForEachAccountAddress(ns walletdb.ReadBucket, account uint32,
|
||||
|
|
|
@ -1760,3 +1760,30 @@ func (s *ScopedKeyManager) ForEachActiveAddress(ns walletdb.ReadBucket,
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForEachInternalActiveAddress invokes the given closure on each _internal_
|
||||
// active address belonging to the scoped key manager, breaking early on error.
|
||||
func (s *ScopedKeyManager) ForEachInternalActiveAddress(ns walletdb.ReadBucket,
|
||||
fn func(addr btcutil.Address) error) error {
|
||||
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
addrFn := func(rowInterface interface{}) error {
|
||||
managedAddr, err := s.rowInterfaceToManaged(ns, rowInterface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip any non-internal branch addresses.
|
||||
if !managedAddr.Internal() {
|
||||
return nil
|
||||
}
|
||||
return fn(managedAddr.Address())
|
||||
}
|
||||
|
||||
if err := forEachActiveAddress(ns, &s.scope, addrFn); err != nil {
|
||||
return maybeConvertDbError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -311,10 +311,12 @@ func (w *Wallet) activeData(dbtx walletdb.ReadTx) ([]btcutil.Address, []wtxmgr.C
|
|||
txmgrNs := dbtx.ReadBucket(wtxmgrNamespaceKey)
|
||||
|
||||
var addrs []btcutil.Address
|
||||
err := w.Manager.ForEachActiveAddress(addrmgrNs, func(addr btcutil.Address) error {
|
||||
err := w.Manager.ForEachRelevantActiveAddress(
|
||||
addrmgrNs, func(addr btcutil.Address) error {
|
||||
addrs = append(addrs, addr)
|
||||
return nil
|
||||
})
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue