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:
@@ -645,13 +645,18 @@ public:
|
||||
// -rescan restart, this works on bootstrapped/pruned nodes (which lack pre-snapshot
|
||||
// block data), reconciling the wallet's stale spent-state without a daemon restart.
|
||||
void runtimeRescan(int startHeight);
|
||||
// Async binary-search probe for the lowest block height the node still has on disk.
|
||||
// cb(ok, lowestHeight, fullHistory): fullHistory==true when genesis is present (a normal,
|
||||
// non-bootstrapped node). Runs on the UI thread via the RPC worker callbacks.
|
||||
// Probe for the lowest block height the node still has on disk, on worker_ (never on the UI thread).
|
||||
// cb(ok, lowestHeight, fullHistory) runs on the UI thread: from worker_->drainResults(), or synchronously
|
||||
// when there is nothing to probe. fullHistory==true when block 1 is readable (a normal, non-bootstrapped
|
||||
// node). ok==false means "could not tell" (busy node, timeout, reconnect): never "blocks are missing".
|
||||
void detectLowestAvailableBlockHeight(std::function<void(bool ok, int lowestHeight, bool fullHistory)> cb);
|
||||
// Flag that a bootstrap just finished so the wallet auto-reconciles spent-state once the
|
||||
// daemon is back up (consumed in update()).
|
||||
void markPostBootstrapRescanPending() { post_bootstrap_rescan_pending_ = true; }
|
||||
void markPostBootstrapRescanPending() {
|
||||
post_bootstrap_rescan_pending_ = true;
|
||||
post_bootstrap_probe_attempts_ = 0;
|
||||
post_bootstrap_probe_retry_at_ = {};
|
||||
}
|
||||
bool runtimeRescanActive() const { return runtime_rescan_active_; }
|
||||
void repairWallet(); // restart daemon with -zapwallettxes=2 (wipe & rebuild wallet tx records)
|
||||
void reinstallBundledDaemon(); // stop daemon, overwrite installed binary with the bundled one, restart
|
||||
@@ -1720,6 +1725,9 @@ private:
|
||||
// Set when a bootstrap completes; consumed once the daemon is connected to auto-run a rescan
|
||||
// that reconciles the preserved wallet.dat against the freshly-imported chain.
|
||||
bool post_bootstrap_rescan_pending_ = false;
|
||||
bool post_bootstrap_probe_in_flight_ = false; // its detectLowestAvailableBlockHeight() is on worker_
|
||||
int post_bootstrap_probe_attempts_ = 0; // probes that could not tell; gives up after 6
|
||||
std::chrono::steady_clock::time_point post_bootstrap_probe_retry_at_{};
|
||||
// Largest "blocks remaining" seen during the current witness-rebuild phase. The daemon's
|
||||
// "Building Witnesses for block" fraction resets every call (it's re-invoked per connected
|
||||
// block, each walking from its own start height to the tip), so we derive a stable, monotonic
|
||||
|
||||
Reference in New Issue
Block a user