walletdb: Don't remove database transaction logs and instead error

Instead of removing the database transaction logs and retrying the
wallet loading, just return an error message to the user. Additionally,
specifically for DB_RUNRECOVERY, notify the user that this could be due
to different BDB versions. This error is pretty much only caused by
compiling with a newer version of BDB and then trying to open the wallet
with a version compiled with an older version of BDB.
This commit is contained in:
Andrew Chow 2020-05-07 14:30:04 -04:00
parent 160800ac10
commit d0ea9bab28
3 changed files with 16 additions and 24 deletions

View file

@ -139,7 +139,7 @@ BerkeleyEnvironment::~BerkeleyEnvironment()
Close();
}
bool BerkeleyEnvironment::Open(bool retry)
bool BerkeleyEnvironment::Open(bilingual_str& err)
{
if (fDbEnvInit) {
return true;
@ -149,6 +149,7 @@ bool BerkeleyEnvironment::Open(bool retry)
TryCreateDirectories(pathIn);
if (!LockDirectory(pathIn, ".walletlock")) {
LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it.\n", strPath);
err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
return false;
}
@ -188,23 +189,11 @@ bool BerkeleyEnvironment::Open(bool retry)
LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
}
Reset();
if (retry) {
// try moving the database env out of the way
fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime());
try {
fs::rename(pathLogDir, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathLogDir.string(), pathDatabaseBak.string());
} catch (const fs::filesystem_error&) {
// failure is ok (well, not really, but it's not worse than what we started with)
}
// try opening it again one more time
if (!Open(false /* retry */)) {
// if it still fails, it probably means we can't even create the database env
return false;
}
} else {
return false;
err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
if (ret == DB_RUNRECOVERY) {
err += Untranslated(" ") + _("This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
}
return false;
}
fDbEnvInit = true;
@ -300,8 +289,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
LogPrintf("Using BerkeleyDB version %s\n", BerkeleyDatabaseVersion());
LogPrintf("Using wallet %s\n", file_path.string());
if (!env->Open(true /* retry */)) {
errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
if (!env->Open(errorStr)) {
return false;
}
@ -342,7 +330,8 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
{
LOCK(cs_db);
if (!env->Open(false /* retry */))
bilingual_str open_err;
if (!env->Open(open_err))
throw std::runtime_error("BerkeleyBatch: Failed to open database environment.");
pdb = database.m_db.get();
@ -482,7 +471,8 @@ void BerkeleyEnvironment::ReloadDbEnv()
// Reset the environment
Flush(true); // This will flush and close the environment
Reset();
Open(true);
bilingual_str open_err;
Open(open_err);
}
bool BerkeleyDatabase::Rewrite(const char* pszSkip)

View file

@ -69,7 +69,7 @@ public:
bool Verify(const std::string& strFile);
bool Open(bool retry);
bool Open(bilingual_str& error);
void Close();
void Flush(bool fShutdown);
void CheckpointLSN(const std::string& strFile);

View file

@ -5,6 +5,7 @@
#include <fs.h>
#include <streams.h>
#include <util/translation.h>
#include <wallet/salvage.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
@ -20,8 +21,9 @@ bool RecoverDatabaseFile(const fs::path& file_path)
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
if (!env->Open(true /* retry */)) {
tfm::format(std::cerr, "Error initializing wallet database environment %s!", env->Directory());
bilingual_str open_err;
if (!env->Open(open_err)) {
tfm::format(std::cerr, "%s\n", open_err.original);
return false;
}