feat(fullnode): auto-reconcile wallet after bootstrap; runtime rescan for pruned nodes
A wallet bootstrapped from a snapshot keeps its wallet.dat but never rescans, so its spent-state is stale and the first send tries to spend already-spent notes and is rejected. The startup -rescan flag can't fix it either: the snapshot lacks the pre-snapshot block history -rescan needs, so it errors. The working fix is a runtime rescanblockchain RPC from a height the snapshot actually has. - Add App::runtimeRescan(startHeight): runs rescanblockchain via the worker, drives the rescanning UI state, and owns completion via the RPC callback (getrescaninfo is unavailable on this daemon). Suppresses the per-second mining/rescan pollers and the Core/balance/tx refreshes while the daemon holds cs_main for the scan. - Add App::detectLowestAvailableBlockHeight(): async binary search via getblock for the lowest height whose block data is on disk → the snapshot base, and whether the node still has full history. - Auto-reconcile after bootstrap: both completion sites (wizard + Settings download dialog) mark a pending rescan; once the daemon is back up and the tip is known, detect the base and runtimeRescan() from it (or -rescan restart on a full node). - Settings "Rescan Blockchain" now probes first: full-history nodes get the existing -rescan restart; bootstrapped/pruned nodes get a prompt pre-filled with the detected base height that runs the runtime rescan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
21
src/app.h
21
src/app.h
@@ -305,7 +305,19 @@ public:
|
||||
bool isEmbeddedDaemonRunning() const;
|
||||
bool isUsingEmbeddedDaemon() const { return supportsEmbeddedDaemon() && use_embedded_daemon_; }
|
||||
void setUseEmbeddedDaemon(bool use) { use_embedded_daemon_ = use && supportsEmbeddedDaemon(); }
|
||||
void rescanBlockchain(); // restart daemon with -rescan flag
|
||||
void rescanBlockchain(); // restart daemon with -rescan flag (full-history nodes)
|
||||
// Runtime rescanblockchain RPC starting at a snapshot-available height. Unlike the
|
||||
// -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.
|
||||
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; }
|
||||
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
|
||||
void deleteBlockchainData(); // stop daemon, delete chain data, restart fresh
|
||||
@@ -616,6 +628,13 @@ private:
|
||||
// Gates the "rescan complete" detection so a getrescaninfo poll that hits the still-running
|
||||
// pre-restart daemon (which reports rescanning=false) can't fire a false "complete" instantly.
|
||||
bool rescan_confirmed_active_ = false;
|
||||
// A runtime rescanblockchain RPC is in flight (vs the -rescan daemon restart). While set,
|
||||
// the per-second mining/rescan-status pollers are suppressed (the daemon holds cs_main for
|
||||
// the whole scan and would block them); completion is signalled by the rescan RPC callback.
|
||||
bool runtime_rescan_active_ = false;
|
||||
// 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 opid_poll_in_progress_ = false;
|
||||
// Consecutive Core-refresh cycles where BOTH core RPCs failed → likely a dead
|
||||
// connection. After kCoreFailuresBeforeDisconnect, tear down and reconnect.
|
||||
|
||||
Reference in New Issue
Block a user