fix(rescan): probe the node's block range off the UI thread

Finding the lowest block a node still has (Settings > Rescan, and the
automatic reconcile after a bootstrap) ran a binary search of about 42
synchronous getblockhash/getblock calls on the UI thread, each waiting
for the RPC connection behind any wallet scan (10-20 s on a big wallet)
and each with a 30 s timeout. The window froze for that long.

It now runs as one task on the wallet RPC worker, bounded to 90 s, and
the answer comes back on the UI thread; meanwhile the dialog shows
"Checking which blocks..." with Rescan disabled. An answer from an
earlier connection counts as "could not tell", and one for an earlier
opening of the dialog is dropped. The search probes block 1 first, so a
full-history node answers in one probe, and it answers "could not tell"
at once while a runtime rescan holds the lane.

Fixed along the way: any probe error (timeout, busy node) read as "block
missing", so a busy node could get a bogus "bootstrapped, rescan from
the tip"; and a non-string getblockhash reply never called back, leaving
the dialog on "Checking..." for good. Only the daemon's "can't read
block" error now counts as missing; anything else means "could not
tell".

User-visible:
- after a bootstrap, a probe that cannot tell is tried up to 6 times,
  30 s apart and only while the node is not busy, then a toast points
  to Settings > Rescan, instead of falling back to the -rescan
  restart, which fails on a bootstrapped node;
- the Settings Rescan dialog warns when the probe could not tell.

Two new strings, translated into all eight languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 21:09:48 -05:00
co-authored by Claude Opus 5.5
parent ad0f60a747
commit 2618744e59
16 changed files with 275 additions and 32 deletions
+2
View File
@@ -873,6 +873,7 @@ void I18n::loadBuiltinEnglish()
strings_["confirm_rescan_msg"] = "This restarts the daemon and re-scans the entire blockchain for your wallet's transactions. It can take a long time and the wallet stays offline until it finishes.";
strings_["confirm_rescan_safe"] = "Your wallet.dat and blockchain data are not deleted — only re-scanned.";
strings_["rescan_detecting"] = "Checking which blocks your node has on disk…";
strings_["rescan_probe_failed"] = "Couldn't check which blocks your node has on disk (it is busy or a request timed out). If this node was restored from a bootstrap, cancel and try again in a minute: the full -rescan restart below fails on a bootstrapped node.";
strings_["rescan_bootstrapped_msg"] = "Your node was bootstrapped, so blocks below the snapshot aren't on disk and a rescan from genesis would fail. Rescan from a height your snapshot includes to reconcile your wallet's spent balance. Your wallet.dat and chain data are not deleted.";
strings_["rescan_from_height"] = "Rescan from block height:";
strings_["repair_wallet"] = "Repair";
@@ -2716,6 +2717,7 @@ void I18n::loadBuiltinEnglish()
strings_["appx_miner_stopped_prefix"] = "Miner stopped: ";
strings_["appx_pool_miner_connected_and_hashing"] = "Pool miner connected and hashing.";
strings_["appx_bootstrap_complete_reconciling"] = "Bootstrap complete — reconciling your wallet with the new chain data.";
strings_["appx_bootstrap_reconcile_probe_failed"] = "Couldn't reconcile your wallet with the bootstrapped chain data: the node stayed too busy to check which blocks it has. Run Rescan from Settings once it has caught up.";
strings_["appx_blockchain_data_deleted"] = "Blockchain data deleted (%d items). The daemon is restarting to re-sync from the network.";
strings_["appx_invalid_payment_uri_prefix"] = "Invalid payment URI: ";
strings_["appx_payment_request_loaded"] = "Payment request loaded";