From 51b362d7c515211bcd47348de847cf6ed075abe2 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 24 Jan 2020 15:18:09 -0800 Subject: [PATCH] waddrmgr+wallet: only watch addresses within default key scopes It was discovered that the wallet can scan the chain for unnecessary additional addresses that are derived by higher-level applications using custom key scopes. This isn't much of an issue for full nodes, but it can cause light clients to scan more than what's required, triggering more false positive matches which lead to block retrieval. Now, we'll only scan the chain for addresses that exist within the default key scopes, as those are the only ones the wallet should be concerned about. --- waddrmgr/manager.go | 23 +++++++++++++++++++++++ wallet/wallet.go | 20 ++++++++++++-------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/waddrmgr/manager.go b/waddrmgr/manager.go index 85d034d..0540a4b 100644 --- a/waddrmgr/manager.go +++ b/waddrmgr/manager.go @@ -748,6 +748,29 @@ func (m *Manager) ForEachAccountAddress(ns walletdb.ReadBucket, account uint32, return nil } +// ForEachDefaultScopeActiveAddress calls the given function with each active +// address stored in the manager within the default scopes, breaking early on +// error. +func (m *Manager) ForEachDefaultScopeActiveAddress(ns walletdb.ReadBucket, + fn func(addr btcutil.Address) error) error { + + m.mtx.RLock() + defer m.mtx.RUnlock() + + for _, keyScope := range DefaultKeyScopes { + scopedMgr, ok := m.scopedManagers[keyScope] + if !ok { + return fmt.Errorf("manager for default key scope with "+ + "purpose %v not found", keyScope.Purpose) + } + if err := scopedMgr.ForEachActiveAddress(ns, fn); err != nil { + return err + } + } + + return nil +} + // ChainParams returns the chain parameters for this address manager. func (m *Manager) ChainParams() *chaincfg.Params { // NOTE: No need for mutex here since the net field does not change diff --git a/wallet/wallet.go b/wallet/wallet.go index 49e8e20..2309b69 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -303,18 +303,22 @@ func (w *Wallet) SetChainSynced(synced bool) { w.chainClientSyncMtx.Unlock() } -// activeData returns the currently-active receiving addresses and all unspent -// outputs. This is primarely intended to provide the parameters for a -// rescan request. -func (w *Wallet) activeData(dbtx walletdb.ReadTx) ([]btcutil.Address, []wtxmgr.Credit, error) { +// activeData returns the currently-active receiving addresses that exist within +// the wallet's default key scopes and all unspent outputs. This is primarily +// intended to provide the parameters for a rescan request. +func (w *Wallet) activeData(dbtx walletdb.ReadTx) ([]btcutil.Address, + []wtxmgr.Credit, error) { + addrmgrNs := dbtx.ReadBucket(waddrmgrNamespaceKey) txmgrNs := dbtx.ReadBucket(wtxmgrNamespaceKey) var addrs []btcutil.Address - err := w.Manager.ForEachActiveAddress(addrmgrNs, func(addr btcutil.Address) error { - addrs = append(addrs, addr) - return nil - }) + err := w.Manager.ForEachDefaultScopeActiveAddress( + addrmgrNs, func(addr btcutil.Address) error { + addrs = append(addrs, addr) + return nil + }, + ) if err != nil { return nil, nil, err }