feat(node): warn when the daemon auto-recovers (salvages) wallet.dat
dragonxd auto-recovers a wallet.dat that fails BDB verification on startup — no flag needed (CWallet::Verify → CDBEnv::Verify(walletFile, CWalletDB::Recover)): it moves the original to wallet.<timestamp>.bak, salvages readable keys into a fresh wallet.dat, and keeps running. The salvage can be incomplete (or the whole thing a FALSE POSITIVE from stale/cross-platform BDB env state — __db.* / the database/ dir carried between machines), so the node silently comes up on a possibly-empty wallet. To the user that reads as fund loss, with no warning. Detect it and warn loudly instead: - daemon/daemon_startup_diagnosis.h: pure walletAutoRecovered() (the salvage / "Original wallet.dat saved as wallet.<ts>.bak" markers) + newestWalletSalvageBak() (picks the wallet.<unixtime>.bak the recovery just made). - onConnected() scans the node's captured output once per session; on a match it shows a warning dialog + notification: the ORIGINAL is safe in wallet.<ts>.bak, the shown balance may be incomplete, and here are the exact steps to restore it (rename the .bak back + delete the stale database/ + __db.* env). One-click "Open data folder" jumps straight there. Full-node only; lite-safe. Deliberately does NOT auto-swap the wallet files (untested per-platform file manipulation on a real wallet is not worth the risk) — it informs + guides. Adds walletAutoRecovered / newestWalletSalvageBak coverage to testBlockDbOutputDiagnosis. Suite green (1/1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6139,6 +6139,23 @@ void testBlockDbOutputDiagnosis()
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken("Error loading wallet")); // wallet corruption → salvage, not reindex
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken("Error: Could not find any asmap file!"));
|
||||
EXPECT_FALSE(blockDbOutputLooksBroken(""));
|
||||
|
||||
// Wallet auto-recovery detection: the node salvaged wallet.dat (moved the original to a .bak).
|
||||
using dragonx::daemon::walletAutoRecovered;
|
||||
EXPECT_TRUE(walletAutoRecovered(
|
||||
"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.1786300000.bak in ..."));
|
||||
EXPECT_TRUE(walletAutoRecovered("wallet.dat corrupt, salvage failed"));
|
||||
EXPECT_FALSE(walletAutoRecovered("Loading wallet...\nWallet completed loading\n")); // normal load
|
||||
EXPECT_FALSE(walletAutoRecovered(": Error loading block database.")); // block-DB abort != salvage
|
||||
EXPECT_FALSE(walletAutoRecovered(""));
|
||||
|
||||
// Newest salvage backup picker (the "wallet.<unixtime>.bak" the recovery just made).
|
||||
using dragonx::daemon::newestWalletSalvageBak;
|
||||
EXPECT_EQ(newestWalletSalvageBak({"wallet.dat", "wallet.1786200000.bak", "wallet.1786300000.bak", "peers.dat"}),
|
||||
std::string("wallet.1786300000.bak")); // highest timestamp wins
|
||||
EXPECT_EQ(newestWalletSalvageBak({"wallet.dat", "wallet.dat.encrypted.bak", "notes.txt"}),
|
||||
std::string("")); // no wallet.<digits>.bak present
|
||||
EXPECT_EQ(newestWalletSalvageBak({}), std::string(""));
|
||||
}
|
||||
|
||||
// Live probe of a real lite server (env-gated). Validates CONNECT_ONLY latency + IP capture.
|
||||
|
||||
Reference in New Issue
Block a user