wallet, rpc: add verify_balance option to importdescriptors #36236

pull musaHaruna wants to merge 4 commits into bitcoin:master from musaHaruna:wallet/importdescriptors-utxo-check changing 11 files +570 −46
  1. musaHaruna commented at 7:23 AM on September 13, 2026: contributor

    Another Attempt to fix #28898

    When importing descriptors, users may provide a timestamp that is too recent. This causes the rescan to miss older payments, leaving the wallet with an incomplete balance.

    This PR adds an optional verify_balance argument to importdescriptors, which is false by default.

    When enabled, it scans the chainstate UTXO set once for outputs belonging to the wallet’s known scripts. If it finds outputs missing from the wallet, it uses the earliest missing output’s block height to extend the rescan backwards where needed, then scans forward. An earlier requested timestamp is still respected so older transaction history is scanned as well.

    After rescanning, it compares the wallet’s confirmed mature UTXO outpoints with those collected from the initial chainstate scan. The response includes an info object showing the verification result, UTXO counts and scan details.

    For example:

    bitcoin-cli -rpcwallet=restore importdescriptors \
      '[{"desc":"<descriptor>","timestamp":"now"}]' true
    

    <details> <summary><strong>Example response when verification recovers payments:</strong></summary>

    [
      {
        "success": true,
        "info": {
          "status": "matched after recovery",
          "utxo_check": true,
          "scanned_blocks": 22,
          "wallet_utxos": 2,
          "chain_utxos": 2,
          "scan_start_height": 101,
          "snapshot_block": "0000000000000001234..01f",
          "snapshot_height": 122,
          "recovery_start_height": 101
        }
      }
    ]
    

    </details>

    If the sets still differ, verification reports "utxo_check": false with an error explaining the mismatch. For example, the info object may contain:

    <details> <summary><strong>Failure Response</strong></summary>

    {
      "status": "unmatched",
      "utxo_check": false,
      "scanned_blocks": 22,
      "wallet_utxos": 2,
      "chain_utxos": 1,
      "scan_start_height": 101,
      "snapshot_block": "00000000000000001234...01f",
      "snapshot_height": 122,
      "recovery_start_height": 101
    }
    

    </details>

    Verification failures leave the descriptors imported and keep any transactions already discovered. Required blocks being unavailable is reported explicitly. No automatic retry or fallback rescan is performed.

    A match verifies the compared UTXO sets; it does not guarantee complete transaction history. Older spent transactions still require an appropriate timestamp or a full rescan. Changes to relevant UTXOs during verification can also cause a mismatch because the final wallet check is compared with the initial chainstate scan.

    Functional tests cover recovery with recent timestamps, preserving older requested history, mismatches, mempool transactions, invalid requests and unavailable blocks.

  2. DrahtBot commented at 7:24 AM on September 13, 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/36236.

    <!--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 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35989.svg"></sub> (wallet: fix crash on importdescriptors with a range ending at 2^31-1 by shuv-amp)
    • #35377 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35377.svg"></sub> (wallet: Allow importing of descriptors without private keys when the wallet has the private keys by achow101)

    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-->

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • This error could potentially caused by data corruption. -> This error could potentially be caused by data corruption. [missing “be”; current wording is grammatically broken]

    Possible places where comparison-specific test macros should replace generic comparisons:

    • [test/functional/wallet_importdescriptors.py] assert result["info"]["scan_start_height"] <= first_header["height"] -> replace with assert_greater_than_or_equal(first_header["height"], result["info"]["scan_start_height"])
    • [test/functional/wallet_importdescriptors.py] assert node.pruneblockchain(funding_height) >= funding_height -> replace with assert_greater_than_or_equal(node.pruneblockchain(funding_height), funding_height)

    <sup>2026-09-17 20:08:47</sup>

  3. DrahtBot added the label CI failed on Sep 13, 2026
  4. DrahtBot commented at 8:26 AM on September 13, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task iwyu: https://github.com/bitcoin/bitcoin/actions/runs/34745132536/job/103691544345</sub> <sub>LLM reason (✨ experimental): CI failed because the IWYU (include-what-you-use) check reported missing/incorrect includes and exited with “Failure generated from IWYU.”</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  5. musaHaruna force-pushed on Sep 13, 2026
  6. DrahtBot removed the label CI failed on Sep 13, 2026
  7. DrahtBot added the label Needs rebase on Sep 14, 2026
  8. musaHaruna force-pushed on Sep 15, 2026
  9. DrahtBot removed the label Needs rebase on Sep 15, 2026
  10. DrahtBot added the label Needs rebase on Sep 17, 2026
  11. node: add chainstate UTXO scan by output script
    Add an interface function to scan the chainstate for coins matching
    the requested output scripts, fill the output map with matching
    coins, and set the best block of the scanned snapshot.
    53ca5f924f
  12. wallet: add UTXO scan for known wallet scripts
    Collect unique scripts from the wallet's script managers and scan
    chainstate for matching unspent outputs. Filter out coinbase outputs
    that are immature at the scanned block height.
    
    Return the matching coins, searched scripts, and the scan's block hash
    and height so callers can identify missing outputs and report which
    chainstate was scanned.
    51716fcd6f
  13. wallet, rpc: add verify_balance option to importdescriptors
    Add an optional verify_balance argument to check the wallet's confirmed
    mature UTXOs against a chainstate scan for known wallet scripts.
    
    If the wallet is missing outputs, extend the rescan to the earliest
    missing output when it is before the requested scan start. Keep the
    requested timestamp range so older transaction history is still scanned.
    
    Return the comparison result, UTXO counts and scan details. Verification
    failures leave descriptors and any discovered transactions in the wallet.
    The option defaults to false.
    4937b319e4
  14. test: cover importdescriptors UTXO verification
    Cover missing UTXO recovery, timestamp handling, mismatch reporting and mempool transactions.
    
    Check that pruned blocks fail verification without removing the
    imported descriptor.
    4da013f50b
  15. musaHaruna force-pushed on Sep 17, 2026
  16. musaHaruna commented at 8:15 PM on September 17, 2026: contributor

    Rebased on the latest master and resolved the conflict with #34861.

    Since #34861 moved descriptor importing and rescanning into the shared importer, I moved the UTXO verification scan into src/wallet/imports.cpp as well. The RPC now passes verify_balance to ProcessDescriptorsImport(...), and backup.cpp only handles parsing the RPC argument and formatting the result. compare

  17. DrahtBot removed the label Needs rebase on Sep 17, 2026
  18. DrahtBot added the label Needs rebase on Oct 9, 2026
  19. DrahtBot commented at 1:25 AM on October 9, 2026: contributor

    <!--cf906140f33d8803c4a75a2196329ecb-->

    🐙 This pull request conflicts with the target branch and needs rebase.


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-10-11 10:51 UTC

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