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:
31
src/app.cpp
31
src/app.cpp
@@ -2144,6 +2144,7 @@ void App::render()
|
||||
renderPinDialogs();
|
||||
renderSwitchStopDaemonDialog();
|
||||
renderBlockDbReindexDialog();
|
||||
renderWalletRecoveredDialog();
|
||||
|
||||
// Render notifications (toast messages)
|
||||
ui::Notifications::instance().render();
|
||||
@@ -4281,6 +4282,36 @@ void App::renderAntivirusHelpDialog()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Auto-shown when the node auto-recovered (salvaged) wallet.dat: the real wallet is safe in a
|
||||
// wallet.<timestamp>.bak, but a possibly-incomplete salvaged copy is now loaded — warn loudly and point
|
||||
// the user at the datadir so they can restore the original instead of mistaking it for fund loss.
|
||||
void App::renderWalletRecoveredDialog()
|
||||
{
|
||||
if (!show_wallet_recovered_dialog_) return;
|
||||
|
||||
ui::material::OverlayDialogSpec ov;
|
||||
ov.title = TR("wallet_recovered_title");
|
||||
ov.p_open = &show_wallet_recovered_dialog_;
|
||||
ov.style = ui::material::OverlayStyle::BlurFloat;
|
||||
ov.cardWidth = 560.0f;
|
||||
ov.idSuffix = "walletrecovered";
|
||||
if (!ui::material::BeginOverlayDialog(ov)) return;
|
||||
const float dp = ui::Layout::dpiScale();
|
||||
|
||||
ui::material::DialogWarningHeader(TR("wallet_recovered_warn"));
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
|
||||
ImGui::TextWrapped("%s", TR("wallet_recovered_body"));
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingMd()));
|
||||
if (ui::material::TactileButton(TR("wallet_recovered_open_folder"), ImVec2(240.0f * dp, 0))) {
|
||||
util::Platform::openFolder(util::Platform::getDragonXDataDir());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ui::material::TactileButton(TR("wallet_recovered_dismiss"), ImVec2(150.0f * dp, 0))) {
|
||||
show_wallet_recovered_dialog_ = false; // acknowledged; keeps the salvaged wallet loaded
|
||||
}
|
||||
ui::material::EndOverlayDialog();
|
||||
}
|
||||
|
||||
// Auto-shown when the embedded node aborts on an unreadable block database — offers the one-click
|
||||
// -reindex rebuild instead of leaving the wallet stuck on a silent zero balance.
|
||||
void App::renderBlockDbReindexDialog()
|
||||
|
||||
Reference in New Issue
Block a user