feat(node): detect an unreadable block DB on startup and offer a one-click reindex
When a daemon update changes the block-index on-disk format (or the index is
corrupt), dragonxd aborts at startup — "non-canonical optional discriminant" →
"Error loading block database. Aborted." — and the wallet silently shows a zero
balance. Previously the connect loop just crash-restarted into the same abort up
to 3x and then reported a bare "Daemon crashed N times", with no path forward.
Now:
- daemon/daemon_startup_diagnosis.h: pure blockDbOutputLooksBroken() classifies
the crashed node's captured console output (the fatal block-DB markers).
- The connect loop detects it on the FIRST abort, STOPS crash-restarting into the
same failure (each retry reloads the whole index — wasteful), and offers a fix.
- A one-shot -reindex flag (EmbeddedDaemon::setReindexOnNextStart → DaemonController
forwarder → args) rebuilds the block index + chainstate from the intact raw
blocks; App::reindexBlockDatabase() arms it and un-gates the loop to restart.
- An auto-shown dialog (renderBlockDbReindexDialog) + a notification explain the
situation ("your coins are safe; the node just can't load the chain") and offer
a one-click "Rebuild block database". Full-node only (gated), lite-safe.
This is the exact trap behind a real "big wallet shows no funds" report: a
post-format-change daemon over pre-change chaindata. Reindex also fixes a plain
corrupt index.
Adds testBlockDbOutputDiagnosis (the abort sequence + individual markers trip it;
normal startup / wallet-corruption / asmap errors do not). Suite green (1/1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#include "wallet/lite_diagnostics.h" // liteLog — chat note-buffer coordinator diagnostics
|
||||
#include "config/version.h"
|
||||
#include "daemon/daemon_controller.h"
|
||||
#include "daemon/daemon_startup_diagnosis.h"
|
||||
#include "daemon/embedded_daemon.h"
|
||||
#include "daemon/seed_wallet_creator.h"
|
||||
#include "daemon/xmrig_manager.h"
|
||||
@@ -501,8 +502,21 @@ void App::tryConnect()
|
||||
VERBOSE_LOGF("[connect #%d] RPC connection failed — no daemon starting, no external detected\n", attempt);
|
||||
|
||||
if (isUsingEmbeddedDaemon() && !isEmbeddedDaemonRunning()) {
|
||||
// If the node aborted because its BLOCK DATABASE is unreadable (a daemon-vs-chaindata
|
||||
// format mismatch after an update, or a corrupt index), crash-restarting just repeats
|
||||
// the same abort — and each attempt reloads the whole index (wasteful). Detect it once
|
||||
// and offer a one-click reindex instead of silently looping into a zero-balance node.
|
||||
if (!block_db_reindex_available_ && daemon_controller_ && daemon_controller_->daemon() &&
|
||||
daemon::blockDbOutputLooksBroken(daemon_controller_->daemon()->getOutput())) {
|
||||
block_db_reindex_available_ = true;
|
||||
show_block_db_reindex_confirm_ = true;
|
||||
ui::Notifications::instance().error(TR("block_db_reindex_notify"), 20.0f);
|
||||
VERBOSE_LOGF("[connect #%d] Block database unreadable — offering a one-click reindex\n", attempt);
|
||||
}
|
||||
// Prevent infinite crash-restart loop
|
||||
if (daemon_controller_ && daemon_controller_->crashCount() >= 3) {
|
||||
if (block_db_reindex_available_) {
|
||||
connection_status_ = TR("sb_block_db_unreadable"); // hold; awaiting the rebuild choice
|
||||
} else if (daemon_controller_ && daemon_controller_->crashCount() >= 3) {
|
||||
if (wallet_switch_pending_confirm_.load()) {
|
||||
// The just-switched-to wallet's daemon keeps crashing (e.g. a wallet that
|
||||
// fails LATE in init, past the fast start grace) — revert to the previous
|
||||
|
||||
Reference in New Issue
Block a user