From 06e263a4e368671ebb4e4a77c1447ebd5104a488 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 6 Jul 2020 14:32:17 -0400 Subject: [PATCH 1/3] Call RecoverDatabaseFile directly from wallettool When using the salvage command, call RecoverDatabaseFile directly instead of SalvageWallet. Also removes SalvageWallet as it is no longer needed. SalvageWallet was doing an additional verify on the database which would caause the salvage to sometimes fail. This is not needed. --- src/wallet/wallettool.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 8a45d81456f..1e699658e47 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -104,27 +104,6 @@ static void WalletShowInfo(CWallet* wallet_instance) tfm::format(std::cout, "Address Book: %zu\n", 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 = CreateWalletDatabase(path); - - // Initialize the environment before recovery - bilingual_str error_string; - try { - database->Verify(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 - return RecoverDatabaseFile(path); -} - bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) { fs::path path = fs::absolute(name, GetWalletDir()); @@ -147,7 +126,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) WalletShowInfo(wallet_instance.get()); wallet_instance->Flush(true); } else if (command == "salvage") { - return SalvageWallet(path); + return RecoverDatabaseFile(path); } } else { tfm::format(std::cerr, "Invalid command: %s\n", command); From 9f536d4fe949666f14a0bf5b814522cecde71f56 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 6 Jul 2020 14:34:49 -0400 Subject: [PATCH 2/3] wallettool: Have RecoverDatabaseFile return errors and warnings Instead of logging or printing these errors and warnings, return them to the caller. --- src/wallet/salvage.cpp | 27 +++++++++++---------------- src/wallet/salvage.h | 4 +++- src/wallet/wallettool.cpp | 13 ++++++++++++- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index af57210f01c..c0755db7518 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -16,14 +16,12 @@ static const char *HEADER_END = "HEADER=END"; static const char *DATA_END = "DATA=END"; typedef std::pair, std::vector > KeyValPair; -bool RecoverDatabaseFile(const fs::path& file_path) +bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector& warnings) { std::string filename; std::shared_ptr env = GetWalletEnv(file_path, filename); - bilingual_str open_err; - if (!env->Open(open_err)) { - tfm::format(std::cerr, "%s\n", open_err.original); + if (!env->Open(error)) { return false; } @@ -39,11 +37,9 @@ bool RecoverDatabaseFile(const fs::path& file_path) int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr, newFilename.c_str(), DB_AUTO_COMMIT); - if (result == 0) - LogPrintf("Renamed %s to %s\n", filename, newFilename); - else + if (result != 0) { - LogPrintf("Failed to rename %s to %s\n", filename, newFilename); + error = strprintf(Untranslated("Failed to rename %s to %s"), filename, newFilename); return false; } @@ -60,10 +56,10 @@ bool RecoverDatabaseFile(const fs::path& file_path) Db db(env->dbenv.get(), 0); result = db.verify(newFilename.c_str(), nullptr, &strDump, DB_SALVAGE | DB_AGGRESSIVE); if (result == DB_VERIFY_BAD) { - LogPrintf("Salvage: Database salvage found errors, all data may not be recoverable.\n"); + warnings.push_back(Untranslated("Salvage: Database salvage found errors, all data may not be recoverable.")); } if (result != 0 && result != DB_VERIFY_BAD) { - LogPrintf("Salvage: Database salvage failed with result %d.\n", result); + error = strprintf(Untranslated("Salvage: Database salvage failed with result %d."), result); return false; } @@ -87,7 +83,7 @@ bool RecoverDatabaseFile(const fs::path& file_path) break; getline(strDump, valueHex); if (valueHex == DATA_END) { - LogPrintf("Salvage: WARNING: Number of keys in data does not match number of values.\n"); + warnings.push_back(Untranslated("Salvage: WARNING: Number of keys in data does not match number of values.")); break; } salvagedData.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); @@ -96,7 +92,7 @@ bool RecoverDatabaseFile(const fs::path& file_path) bool fSuccess; if (keyHex != DATA_END) { - LogPrintf("Salvage: WARNING: Unexpected end of file while reading salvage output.\n"); + warnings.push_back(Untranslated("Salvage: WARNING: Unexpected end of file while reading salvage output.")); fSuccess = false; } else { fSuccess = (result == 0); @@ -104,10 +100,9 @@ bool RecoverDatabaseFile(const fs::path& file_path) if (salvagedData.empty()) { - LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); + error = strprintf(Untranslated("Salvage(aggressive) found no records in %s."), newFilename); return false; } - LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); std::unique_ptr pdbCopy = MakeUnique(env->dbenv.get(), 0); int ret = pdbCopy->open(nullptr, // Txn pointer @@ -117,7 +112,7 @@ bool RecoverDatabaseFile(const fs::path& file_path) DB_CREATE, // Flags 0); if (ret > 0) { - LogPrintf("Cannot create database file %s\n", filename); + error = strprintf(Untranslated("Cannot create database file %s"), filename); pdbCopy->close(0); return false; } @@ -141,7 +136,7 @@ bool RecoverDatabaseFile(const fs::path& file_path) } if (!fReadOK) { - LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr); + warnings.push_back(strprintf(Untranslated("WARNING: WalletBatch::Recover skipping %s: %s"), strType, strErr)); continue; } Dbt datKey(&row.first[0], row.first.size()); diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h index e361930f5ed..5a8538f9422 100644 --- a/src/wallet/salvage.h +++ b/src/wallet/salvage.h @@ -9,6 +9,8 @@ #include #include -bool RecoverDatabaseFile(const fs::path& file_path); +struct bilingual_str; + +bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector& warnings); #endif // BITCOIN_WALLET_SALVAGE_H diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 1e699658e47..5cabefcbfc2 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -126,7 +126,18 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) WalletShowInfo(wallet_instance.get()); wallet_instance->Flush(true); } else if (command == "salvage") { - return RecoverDatabaseFile(path); + bilingual_str error; + std::vector warnings; + bool ret = RecoverDatabaseFile(path, error, warnings); + if (!ret) { + for (const auto warning : warnings) { + tfm::format(std::cerr, "%s\n", warning.original); + } + if (!error.empty()) { + tfm::format(std::cerr, "%s\n", error.original); + } + } + return ret; } } else { tfm::format(std::cerr, "Invalid command: %s\n", command); From 0e279fe4899beae8630264ef1fe420dd71f29d5d Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 6 Jul 2020 14:38:35 -0400 Subject: [PATCH 3/3] walletdb: Remove unused static functions from walletdb.h VerifyEnvironment and VerifyDatabaseFile were removed, but their declarations weren't. Remove those. --- src/wallet/walletdb.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 6b55361c07d..292f831ac39 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -264,10 +264,6 @@ public: DBErrors ZapSelectTx(std::vector& vHashIn, std::vector& vHashOut); /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */ static bool IsKeyType(const std::string& strType); - /* verifies the database environment */ - static bool VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr); - /* verifies the database file */ - static bool VerifyDatabaseFile(const fs::path& wallet_path, bilingual_str& errorStr); //! write the hdchain model (external chain child index counter) bool WriteHDChain(const CHDChain& chain);