feat(node): one-click "Restore original wallet" after a daemon auto-recovery

Adds the restore action to the wallet-auto-recovery warning: undo the daemon's
salvage by swapping the untouched original (wallet.<ts>.bak) back over the
salvaged copy and clearing the stale BDB env that triggered the false recovery,
then restarting. Modeled on beginAdoptSeedWallet (stop daemon → file ops →
restart on a worker; result pumped to the main thread for notifications).

Safety (fund-adjacent file ops on a real wallet — copy/rename only, never delete
user data):
- picks the newest wallet.<unixtime>.bak via the pure, unit-tested
  newestWalletSalvageBak(); aborts if none.
- verifies the .bak is a real Berkeley DB (probeWalletFile) before touching
  anything — won't overwrite a working wallet with a bad backup.
- stops the daemon first (stopDaemonForWalletSwitch) so wallet.dat is released.
- moves the salvaged copy aside to wallet.dat.salvaged-<ts>.dat (kept), COPIES
  the .bak into place (the .bak stays), moves database/ aside to
  database.pre-restore-<ts>.bak (kept), and drops only the transient __db.*
  BDB region files. Rolls back the move if the copy fails.
- relaunches the node even on failure so it's never left down.

The warning dialog now offers Restore original wallet / Open data folder /
Keep salvaged copy. Full-node only; lite-safe. Build clean, suite green (1/1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-10 00:45:47 -05:00
parent 3b7423f3a1
commit 384d64ea5d
4 changed files with 149 additions and 2 deletions

View File

@@ -1199,7 +1199,18 @@ void I18n::loadBuiltinEnglish()
strings_["wallet_recovered_body"] = "On startup the node decided your wallet.dat looked damaged and recovered it automatically. Your ORIGINAL wallet was NOT deleted — it was renamed to \"wallet.<numbers>.bak\" in your data folder, and a salvaged copy is loaded now.\n\nThe salvaged copy may be incomplete, so the balance shown here could be wrong — don't treat it as final.\n\nThis is often a false alarm caused by leftover database files (e.g. after moving the wallet between machines). To restore your original: quit the wallet, then in the data folder rename the current wallet.dat aside, rename \"wallet.<numbers>.bak\" back to \"wallet.dat\", delete the \"database\" folder and any \"__db.*\" files, and reopen.";
strings_["wallet_recovered_open_folder"] = "Open data folder";
strings_["wallet_recovered_dismiss"] = "Keep salvaged copy";
strings_["wallet_recovered_restore"] = "Restore original wallet";
strings_["wallet_recovered_notify"] = "The node recovered your wallet and moved the original to a .bak — your shown balance may be incomplete. See the prompt to restore it.";
// One-click "Restore original wallet" flow.
strings_["wallet_restore_started"] = "Restoring your original wallet and restarting the node…";
strings_["wallet_restore_busy"] = "The node is busy restarting — try again in a moment.";
strings_["wallet_restore_ok"] = "Original wallet restored. The node is loading it now.";
strings_["wallet_restore_no_backup"] = "Couldn't find a wallet.<timestamp>.bak to restore. Nothing was changed.";
strings_["wallet_restore_bad_backup"] = "The backup wallet file looks unreadable, so it was NOT restored — your current wallet is unchanged. Restore from your own backup instead.";
strings_["wallet_restore_stop_failed"] = "The node didn't stop in time, so nothing was changed. Try again.";
strings_["wallet_restore_move_failed"] = "Couldn't set the current wallet aside — nothing was changed.";
strings_["wallet_restore_copy_failed"] = "Couldn't install the backup wallet; your current wallet was left in place.";
strings_["wallet_restore_no_restart"] = "Your original wallet was restored, but the node didn't restart — start it from Settings.";
// Receive Tab
strings_["receiving_addresses"] = "Your Receiving Addresses";