#36245 wallet: start descriptor top up at range_start instead of index 0

full analysis

https://github.com/bitcoin/bitcoin/pull/36245 · kriss39 · +43/-3 in 2 files, 1 commits · labels: Wallet

Goal

  • Prevent wallet balance inconsistencies across reloads when importing descriptors with non-zero range starts
  • Avoid massive derivation delays and memory exhaustion when importing descriptors with high start indices

Fixes descriptor expansion during import by starting cache top up at the descriptor's range_start rather than index 0. Also corrects `m_max_cached_index` tracking in both `TopUpWithDB()` and `Load()` so the cached index matches the actual derived range rather than assuming a zero-based offset.

Problem: When importing a descriptor with a non-zero range start `[N, M]`, the wallet derives every index from 0 to M, causing O(M) derivation delays or memory exhaustion on large indices. Furthermore, scriptPubKeys below N are temporarily treated as `ismine` during initial rescan but vanish after the wallet is reloaded, leading to inconsistent balances.

Category: Wallet (#2 of 84)

P2 · bug fix

  • P2 because it fixes inconsistent balances where transactions vanish after reloading an imported wallet
  • Eliminates severe latency and memory exhaustion when importing descriptors starting at high indices

Fixes a noticeable bug where imported ranged descriptors produce inconsistent balances across wallet reloads: 'Load() only expands [range_start, range_end), so those scriptPubKeys stop being IsMine the next time the wallet is opened, and a transaction picked up for one of them during the import rescan is no longer credited to the wallet' (author kriss39). It also addresses severe latency and potential memory exhaustion on high range starts, dropping import time for index 600k from 19.5s to 0.09s.

Membership: Modifies `src/wallet/scriptpubkeyman.cpp` and adds a functional test in `test/functional/wallet_importdescriptors.py`.

Factors: security/stability 1, bug 2, performance 2, user value 2, leverage 0

Reviewability: Ready

  • Ready for review
  • Clean patch with passing CI and functional test coverage

The patch is small, cleanly rebased, passes CI, and includes functional test coverage.

Author status: active

Agreement: Crickets

  • No reviews or comments yet

Crickets: no reviews or comments yet.

The pull request was recently submitted and has not yet received comments or reviews.

Review verdicts (DrahtBot): 0

Files

37 lines under test/bench/ci.

  • test/functional/wallet_importdescriptors.py +37/-0
  • src/wallet/scriptpubkeyman.cpp +6/-3

Card

This PR fixes descriptor top-up during imports with a non-zero range_start so derivation begins at the range start rather than index 0. Currently, importing a descriptor with range [N, M] derives and caches all indices in [0, M), leading to O(M) latency and marking keys below N as ismine during import only for them to vanish upon wallet reload. The fix aligns TopUpWithDB() with Load() and updates m_max_cached_index tracking accordingly. The PR is ready for review with no comments or reviews recorded yet.

Data

dossier JSON · extract JSON · model openrouter/google/gemini-3.8-flash, generated 2026-09-17T16:24, confidence high, input hash c7aa96a297924cea