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

pull kriss39 wants to merge 1 commits into bitcoin:master from kriss39:fix-topup-cache-from-range-start changing 2 files +43 −3
  1. kriss39 commented at 8:34 AM on September 14, 2026: contributor

    DescriptorScriptPubKeyMan::TopUpWithDB() expands the descriptor from m_max_cached_index + 1, which is 0 for a freshly imported descriptor regardless of its range_start. Importing a descriptor with "range": [N, M] therefore derives and watches every index in [0, M), so the cost of an import is O(M) rather than O(M - N) and the wallet treats scriptPubKeys below N as its own. 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.

    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.

    Start the top up loop at range_start and record the index that was actually cached instead of counting from -1, so that Load() and TopUpWithDB() agree on m_max_cached_index for descriptors with a non-zero range_start. Before this change Load() left m_max_cached_index at range_end - range_start - 1 for such descriptors, which made the first top up after opening the wallet re-expand the stored range.

    Importing wpkh(xpub/0/*) with "range": [600000, 600009] into a blank watch-only wallet goes from 19.5s to 0.09s on this machine.

  2. wallet: start descriptor top up at range_start instead of index 0
    DescriptorScriptPubKeyMan::TopUpWithDB() expands the descriptor from
    m_max_cached_index + 1, which is 0 for a freshly imported descriptor
    regardless of its range_start. Importing a descriptor with
    "range": [N, M] therefore derives and watches every index in [0, M),
    so the cost of an import is O(M) rather than O(M - N) and the wallet
    treats scriptPubKeys below N as its own. 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.
    
    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.
    
    Start the top up loop at range_start and record the index that was
    actually cached instead of counting from -1, so that Load() and
    TopUpWithDB() agree on m_max_cached_index for descriptors with a
    non-zero range_start. Before this change Load() left m_max_cached_index
    at range_end - range_start - 1 for such descriptors, which made the
    first top up after opening the wallet re-expand the stored range.
    
    Importing wpkh(xpub/0/*) with "range": [600000, 600009] into a blank
    watch-only wallet goes from 19.5s to 0.09s on this machine.
    4d2dc3c327
  3. DrahtBot added the label Wallet on Sep 14, 2026
  4. DrahtBot commented at 8:34 AM on September 14, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/36245.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process. A summary of reviews will appear here.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35989 (wallet: fix crash on importdescriptors with a range ending at 2^31-1 by shuv-amp)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

Contributors
Labels

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-09-15 19:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me