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 9 files +584 −47
  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 (wallet: fix crash on importdescriptors with a range ending at 2^31-1 by shuv-amp)
    • #35377 (wallet: Allow importing of descriptors without private keys when the wallet has the private keys by achow101)
    • #34861 (wallet: Add importdescriptors interface by polespinasa)
    • #31668 (Added rescan option for import descriptors by saikiran57)

    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 places where comparison-specific test macros should replace generic comparisons:

    • [test/functional/wallet_importdescriptors.py] assert result["info"]["scan_start_height"] <= first_header["height"] -> 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 -> assert_greater_than_or_equal(node.pruneblockchain(funding_height), funding_height)

    <sup>2026-09-15 12:41:09</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. 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.
    96c1ea40ca
  9. 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.
    e46d1ba1d5
  10. 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.
    cbfd1c15d8
  11. 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.
    3eccd3463c
  12. musaHaruna force-pushed on Sep 15, 2026
  13. DrahtBot removed the label Needs rebase on Sep 15, 2026
  14. DrahtBot commented at 2:27 AM on September 17, 2026: contributor

    <!--cf906140f33d8803c4a75a2196329ecb-->

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

  15. DrahtBot added the label Needs rebase on Sep 17, 2026

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-17 18:51 UTC

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