diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -38,6 +38,9 @@ OptionsCategory::COMMANDS); gArgs.AddArg("create", "Create new wallet file", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); + gArgs.AddArg("salvage", + "Attempt to recover private keys from a corrupt wallet", + ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); } static bool WalletAppInit(int argc, char *argv[]) { diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -123,6 +123,35 @@ wallet_instance->m_address_book.size()); } +static bool SalvageWallet(const fs::path &path) { + // Create a Database handle to allow for the db to be initialized before + // recovery + std::unique_ptr database = WalletDatabase::Create(path); + + // Initialize the environment before recovery + bilingual_str error_string; + try { + WalletBatch::VerifyEnvironment(path, error_string); + } catch (const fs::filesystem_error &e) { + error_string = + Untranslated(strprintf("Error loading wallet. %s", + fsbridge::get_filesystem_error_message(e))); + } + if (!error_string.original.empty()) { + tfm::format(std::cerr, "Failed to open wallet for salvage :%s\n", + error_string.original); + return false; + } + + // Perform the recovery + CWallet dummy_wallet(Params(), nullptr, WalletLocation(), + WalletDatabase::CreateDummy()); + std::string backup_filename; + return WalletBatch::Recover(path, (void *)&dummy_wallet, + WalletBatch::RecoverKeysOnlyFilter, + backup_filename); +} + bool ExecuteWalletToolFunc(const std::string &command, const std::string &name) { fs::path path = fs::absolute(name, GetWalletDir()); @@ -133,7 +162,7 @@ WalletShowInfo(wallet_instance.get()); wallet_instance->Flush(true); } - } else if (command == "info") { + } else if (command == "info" || command == "salvage") { if (!fs::exists(path)) { tfm::format(std::cerr, "Error: no wallet file at %s\n", name); return false; @@ -146,12 +175,17 @@ error.original, name); return false; } - std::shared_ptr wallet_instance = LoadWallet(name, path); - if (!wallet_instance) { - return false; + + if (command == "info") { + std::shared_ptr wallet_instance = LoadWallet(name, path); + if (!wallet_instance) { + return false; + } + WalletShowInfo(wallet_instance.get()); + wallet_instance->Flush(true); + } else if (command == "salvage") { + return SalvageWallet(path); } - WalletShowInfo(wallet_instance.get()); - wallet_instance->Flush(true); } else { tfm::format(std::cerr, "Invalid command: %s\n", command); return false;