Skip to content

Commit c877709

Browse files
committed
wallettool: Add a salvage command
1 parent 448bdff commit c877709

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

src/bitcoin-wallet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static void SetupWalletToolArgs()
3131

3232
gArgs.AddArg("info", "Get wallet info", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
3333
gArgs.AddArg("create", "Create new wallet file", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
34+
gArgs.AddArg("salvage", "Attempt to recover private keys from a corrupt wallet", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
3435
}
3536

3637
static bool WalletAppInit(int argc, char* argv[])

src/wallet/wallettool.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,29 @@ static void WalletShowInfo(CWallet* wallet_instance)
103103
tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
104104
}
105105

106+
static bool SalvageWallet(const fs::path& path)
107+
{
108+
// Create a Database handle to allow for the db to be initialized before recovery
109+
std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(path);
110+
111+
// Initialize the environment before recovery
112+
bilingual_str error_string;
113+
try {
114+
WalletBatch::VerifyEnvironment(path, error_string);
115+
} catch (const fs::filesystem_error& e) {
116+
error_string = Untranslated(strprintf("Error loading wallet. %s", fsbridge::get_filesystem_error_message(e)));
117+
}
118+
if (!error_string.original.empty()) {
119+
tfm::format(std::cerr, "Failed to open wallet for salvage :%s\n", error_string.original);
120+
return false;
121+
}
122+
123+
// Perform the recovery
124+
CWallet dummy_wallet(nullptr, WalletLocation(), WalletDatabase::CreateDummy());
125+
std::string backup_filename;
126+
return WalletBatch::Recover(path, (void*)&dummy_wallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename);
127+
}
128+
106129
bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
107130
{
108131
fs::path path = fs::absolute(name, GetWalletDir());
@@ -113,7 +136,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
113136
WalletShowInfo(wallet_instance.get());
114137
wallet_instance->Flush(true);
115138
}
116-
} else if (command == "info") {
139+
} else if (command == "info" || command == "salvage") {
117140
if (!fs::exists(path)) {
118141
tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
119142
return false;
@@ -123,10 +146,15 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
123146
tfm::format(std::cerr, "%s\nError loading %s. Is wallet being used by other process?\n", error.original, name);
124147
return false;
125148
}
126-
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
127-
if (!wallet_instance) return false;
128-
WalletShowInfo(wallet_instance.get());
129-
wallet_instance->Flush(true);
149+
150+
if (command == "info") {
151+
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
152+
if (!wallet_instance) return false;
153+
WalletShowInfo(wallet_instance.get());
154+
wallet_instance->Flush(true);
155+
} else if (command == "salvage") {
156+
return SalvageWallet(path);
157+
}
130158
} else {
131159
tfm::format(std::cerr, "Invalid command: %s\n", command);
132160
return false;

0 commit comments

Comments
 (0)