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.