#36245 wallet: start descriptor top up at range_start instead of index 0
| Reviewability | Reviews | Agreement | Size | ||||
|---|---|---|---|---|---|---|---|
| #36245 wallet: start descriptor top up at range_start instead of index 0 | Ready | 0 | Crickets | 6 + 37 tests | |||
|
|
|
|
| |||
Reviewability: ReadyStalePaused Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs. Size: lines added or modified outside tests, then in tests; greener = smaller. | |||||||
Goal
Restricts descriptor expansion in `DescriptorScriptPubKeyMan::TopUpWithDB()` to start at `range_start` instead of index 0, and records the derived index directly rather than incrementing an offset from -1. Also aligns `DescriptorScriptPubKeyMan::Load()` to set `m_max_cached_index` to the actual index loaded.
Problem: When importing a descriptor with range `[N, M]`, the wallet expands and tracks keys starting from index 0 instead of `N`. This causes import times to scale with M rather than the range size M - N, falsely treats scriptPubKeys below N as `IsMine` until wallet restart (causing rescanned transactions below N to lose ownership on reload), can trigger derivation of up to 2^31 keys for high range starts, and causes redundant re-expansions on active wallet reload due to miscalculated `m_max_cached_index`.
Evidence of importance:
- Author benchmark: 'Importing wpkh(xpub/0/*) with "range": [600000, 600009] into a blank watch-only wallet goes from 19.5s to 0.09s on this machine.' (PR description)
- Author notes vulnerability to excessive derivation: 'Since ParseDescriptorRange() only bounds the size of the range and not its start, "range": [2146483648, 2147483647] is accepted and expands 2^31 indexes into m_map_script_pub_keys before the RPC returns.' (PR description)
Risk of a mistake: medium (wallet). Flaws in descriptor address derivation or caching could cause wallets to fail to detect incoming transactions or misreport wallet ownership.
Changed since the previous assessment: No functional differences; patch rebased or re-formatted.
Reviewability
Ready
Nothing known that would invalidate a review now.
Agreement
Crickets
no substantive comment either way
Objections, suggestions, and questions: none recorded.
Files
37 lines under test/bench/ci.
- test/functional/wallet_importdescriptors.py +37/-0
- src/wallet/scriptpubkeyman.cpp +6/-3
Card
The short text the ranking pass compares across PRs.
Bounds descriptor key expansion during import top-ups to start at range_start rather than index 0, and records the derived index directly. Currently, importing a descriptor with range [N, M] derives and caches all keys from 0 to M, making import cost O(M) instead of O(M - N) and causing keys below N to appear as owned during import only to disappear when the wallet is reloaded. The author reports that importing a 10-key range starting at index 600,000 drops from 19.5 seconds to 0.09 seconds, and prevents pathological large range starts from attempting to derive up to 2^31 keys.
Data
Discussion read under schema 1 rules: suggestions and questions may be missing, and an objection may combine several harms (schema history).
labels: Wallet
Categories
Wallet
P2 · bug fix
Fixes a correctness and reliability bug where ranged descriptor imports starting at index N derive keys from 0, causing import times to scale with M rather than M - N (benchmark: 19.5s to 0.09s for [600000, 600009]), potential memory exhaustion on high range starts up to 2^31, and inconsistent `IsMine` tracking across restarts.
Membership: Matches Wallet label, modifies `src/wallet/scriptpubkeyman.cpp` descriptor expansion logic and adds functional test in `test/functional/wallet_importdescriptors.py`.
Factors: security/stability 2, bug 2, performance 2, user value 1, leverage 0