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:
@@ -38,6 +38,7 @@
|
||||
#include "data/seed_migration_resume.h"
|
||||
#include "util/address_validation.h"
|
||||
#include "util/seed_phrase.h"
|
||||
#include "daemon/daemon_startup_diagnosis.h"
|
||||
#include "util/amount_format.h"
|
||||
#include "util/payment_uri.h"
|
||||
#include "util/platform.h"
|
||||
@@ -6114,6 +6115,32 @@ void testSeedPhraseHelpers()
|
||||
EXPECT_EQ(normalizeSeedPhrase(words24).find("\xC2\xA0"), std::string::npos);
|
||||
}
|
||||
|
||||
// Block-DB abort detection: classify a crashed daemon's console output so the app can offer a
|
||||
// one-click reindex instead of silently showing a zero balance (a daemon-vs-chaindata format break).
|
||||
void testBlockDbOutputDiagnosis()
|
||||
{
|
||||
using dragonx::daemon::blockDbOutputLooksBroken;
|
||||
|
||||
// The exact abort sequence we observed on a format-mismatched datadir.
|
||||
EXPECT_TRUE(blockDbOutputLooksBroken(
|
||||
"Opened LevelDB successfully\n"
|
||||
"GetValue: CDataStream error - non-canonical optional discriminant: iostream error\n"
|
||||
"ERROR: LoadBlockIndex() : failed to read value\n"
|
||||
": Error loading block database.\n"
|
||||
"Aborted block database rebuild. Exiting.\n"));
|
||||
// Each individual fatal marker also trips it (partial capture / different phrasing).
|
||||
EXPECT_TRUE(blockDbOutputLooksBroken("... : Error loading block database."));
|
||||
EXPECT_TRUE(blockDbOutputLooksBroken("Aborted block database rebuild. Exiting."));
|
||||
EXPECT_TRUE(blockDbOutputLooksBroken("ERROR: LoadBlockIndex() : failed to read value"));
|
||||
|
||||
// Normal startup / other failures must NOT be misread as a block-DB problem (no false reindex offer).
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken(
|
||||
"Loading block index...\nVerifying blocks...\nLoading wallet...\nRescanning...\nDone loading\n"));
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken("Error loading wallet")); // wallet corruption → salvage, not reindex
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken("Error: Could not find any asmap file!"));
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken(""));
|
||||
}
|
||||
|
||||
// Live probe of a real lite server (env-gated). Validates CONNECT_ONLY latency + IP capture.
|
||||
void testLiteServerProbeLive()
|
||||
{
|
||||
@@ -7363,6 +7390,7 @@ int main()
|
||||
testAddressChecksumValidation();
|
||||
testPrivateKeyImportRecognition();
|
||||
testSeedPhraseHelpers();
|
||||
testBlockDbOutputDiagnosis();
|
||||
testLiteServerProbeLive();
|
||||
testXmrigLiveInstall();
|
||||
testGeneratedResourceBehavior();
|
||||
|
||||
Reference in New Issue
Block a user