Skip to content

Commit

Permalink
[Wallet] refactor wallet/init interaction
Browse files Browse the repository at this point in the history
>> adapted from bitcoin/bitcoin@25340b7
  • Loading branch information
random-zebra committed Aug 23, 2020
1 parent 49646b2 commit e585dad
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 101 deletions.
66 changes: 7 additions & 59 deletions src/init.cpp
Expand Up @@ -1109,12 +1109,7 @@ bool AppInit2()
return UIError(_("Initialization sanity check failed. PIVX Core is shutting down."));

std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET
// Wallet file must be a plain filename without a directory
fs::path wallet_file_path(strWalletFile);
if (strWalletFile != wallet_file_path.filename().string())
return UIError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
#endif

// Make sure only a single PIVX process is using the data directory.
fs::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fsbridge::fopen(pathLockFile, "a"); // empty lock file; created if it doesn't exist.
Expand Down Expand Up @@ -1283,47 +1278,8 @@ bool AppInit2()
}
}

LogPrintf("Using wallet %s\n", strWalletFile);
uiInterface.InitMessage(_("Verifying wallet..."));

if (!bitdb.Open(GetDataDir())) {
// try moving the database env out of the way
fs::path pathDatabase = GetDataDir() / "database";
fs::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
try {
fs::rename(pathDatabase, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
} catch (const fs::filesystem_error& error) {
// failure is ok (well, not really, but it's not worse than what we started with)
}

// try again
if (!bitdb.Open(GetDataDir())) {
// if it still fails, it probably means we can't even create the database env
std::string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir);
return UIError(msg);
}
}

if (GetBoolArg("-salvagewallet", false)) {
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, strWalletFile, true))
return false;
}

if (fs::exists(GetDataDir() / strWalletFile)) {
CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover);
if (r == CDBEnv::RECOVER_OK) {
std::string msg = strprintf(_("Warning: wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."),
strWalletFile, "wallet.{timestamp}.bak", strDataDir);
UIWarning(msg);
}
if (r == CDBEnv::RECOVER_FAIL)
return UIError(strprintf(_("%s corrupt, salvage failed"), strWalletFile));
}
if (!CWallet::Verify())
return false;

} // (!fDisableWallet)
#endif // ENABLE_WALLET
Expand Down Expand Up @@ -1700,21 +1656,13 @@ bool AppInit2()
if (fDisableWallet) {
LogPrintf("Wallet disabled!\n");
} else {
std::string warningString;
std::string errorString;
pwalletMain = CWallet::InitLoadWallet(fDisableWallet, strWalletFile, warningString, errorString);
if (!warningString.empty())
UIWarning(warningString);
if (!errorString.empty()) {
LogPrintf("%s", errorString);
return UIError(errorString);
}
CWallet::InitLoadWallet();
if (!pwalletMain)
return false;
} // (!fDisableWallet)
#else // ENABLE_WALLET
}
#else
LogPrintf("No wallet compiled in!\n");
#endif // !ENABLE_WALLET
#endif
// ********************************************************* Step 9: import blocks

if (!CheckDiskSpace())
Expand Down
116 changes: 79 additions & 37 deletions src/wallet/wallet.cpp
Expand Up @@ -590,7 +590,6 @@ bool CWallet::ParameterInteraction()
return true;
}


//////// End Init ////////////

const CKeyingMaterial& CWallet::GetEncryptionKey() const
Expand Down Expand Up @@ -1679,6 +1678,61 @@ std::set<uint256> CWalletTx::GetConflicts() const
return result;
}

bool CWallet::Verify()
{
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
std::string strDataDir = GetDataDir().string();

// Wallet file must be a plain filename without a directory
fs::path wallet_file_path(walletFile);
if (walletFile != wallet_file_path.filename().string())
return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, strDataDir));

LogPrintf("Using wallet %s\n", walletFile);
uiInterface.InitMessage(_("Verifying wallet..."));

if (!bitdb.Open(GetDataDir())) {
// try moving the database env out of the way
fs::path pathDatabase = GetDataDir() / "database";
fs::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
try {
fs::rename(pathDatabase, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
} catch (const fs::filesystem_error& error) {
// failure is ok (well, not really, but it's not worse than what we started with)
}

// try again
if (!bitdb.Open(GetDataDir())) {
// if it still fails, it probably means we can't even create the database env
return UIError(strprintf(_("Error initializing wallet database environment %s!"), strDataDir));
}
}

if (GetBoolArg("-salvagewallet", false)) {
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, walletFile, true))
return false;
}

if (fs::exists(GetDataDir() / walletFile)) {
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
if (r == CDBEnv::RECOVER_OK) {
UIWarning(strprintf(_("Warning: wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."),
walletFile, "wallet.{timestamp}.bak", strDataDir));
}
if (r == CDBEnv::RECOVER_FAIL)
return UIError(strprintf(_("%s corrupt, salvage failed"), walletFile));
}

return true;
}



void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
Expand Down Expand Up @@ -3816,20 +3870,20 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
return strUsage;
}

CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString)
bool CWallet::InitLoadWallet()
{
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);

// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;

if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));

CWallet *tempWallet = new CWallet(strWalletFile);
DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
CWallet *tempWallet = new CWallet(walletFile);
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
errorString = strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile);
uiInterface.InitMessage(errorString);
return nullptr;
return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
}

delete tempWallet;
Expand All @@ -3841,30 +3895,26 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall

int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
CWallet *walletInstance = new CWallet(strWalletFile);
CWallet *walletInstance = new CWallet(walletFile);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK) {
if (nLoadWalletRet == DB_CORRUPT)
errorString += strprintf(_("Error loading %s: Wallet corrupted\n"), strWalletFile);
return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) {
warningString += strprintf(_("Warning: error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect.\n"), strWalletFile);
UIWarning(strprintf(_("Warning: error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."), walletFile));
} else if (nLoadWalletRet == DB_TOO_NEW)
errorString += strprintf(_("Error loading %s: Wallet requires newer version of PIVX Core\n"), strWalletFile);
return UIError(strprintf(_("Error loading %s: Wallet requires newer version of PIVX Core"), walletFile));
else if (nLoadWalletRet == DB_NEED_REWRITE) {
errorString += _("Wallet needed to be rewritten: restart PIVX Core to complete\n");
LogPrintf("%s", errorString);
return UIError(_("Wallet needed to be rewritten: restart PIVX Core to complete"));
} else
errorString += strprintf(_("Error loading %s\n"), strWalletFile);
return UIError(strprintf(_("Error loading %s\n"), walletFile));
}

if (!errorString.empty())
return nullptr;

// check minimum stake split threshold
if (walletInstance->nStakeSplitThreshold && walletInstance->nStakeSplitThreshold < CWallet::minStakeSplitThreshold) {
LogPrintf("WARNING: stake split threshold value %s too low. Restoring to minimum value %s.\n",
FormatMoney(pwalletMain->nStakeSplitThreshold), FormatMoney(CWallet::minStakeSplitThreshold));
FormatMoney(walletInstance->nStakeSplitThreshold), FormatMoney(CWallet::minStakeSplitThreshold));
walletInstance->nStakeSplitThreshold = CWallet::minStakeSplitThreshold;
}

Expand All @@ -3875,9 +3925,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
if (GetBoolArg("-upgradewallet", fFirstRun && !fLegacyWallet)) {
if (prev_version <= FEATURE_PRE_PIVX && walletInstance->IsLocked()) {
// Cannot upgrade a locked wallet
errorString += "Cannot upgrade a locked wallet.\n";
LogPrintf("%s", errorString);
return nullptr;
return UIError("Cannot upgrade a locked wallet.");
}

int nMaxVersion = GetArg("-upgradewallet", 0);
Expand All @@ -3889,8 +3937,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
} else
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion()) {
errorString += _("Cannot downgrade wallet\n");
return nullptr;
return UIError("Cannot downgrade wallet\n");
}
walletInstance->SetMaxVersion(nMaxVersion);
}
Expand All @@ -3899,8 +3946,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
if (GetBoolArg("-upgradewallet", false)) {
std::string upgradeError;
if (!walletInstance->Upgrade(upgradeError, prev_version)) {
errorString += (upgradeError + "\n");
return nullptr;
return UIError(upgradeError);
}
}

Expand All @@ -3913,9 +3959,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
walletInstance->SetupSPKM();
} else {
if (!Params().IsRegTestNet()) {
errorString += "Legacy wallets can only be created on RegTest.\n";
LogPrintf("%s", errorString);
return nullptr;
return UIError("Legacy wallets can only be created on RegTest.");
}
// Create legacy wallet
LogPrintf("Creating Pre-HD Wallet\n");
Expand All @@ -3925,8 +3969,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
// Top up the keypool
if (!walletInstance->TopUpKeyPool()) {
// Error generating keys
errorString += _("Unable to generate initial key\n");
return nullptr;
return UIError("Unable to generate initial key!");
}

walletInstance->SetBestChain(chainActive.GetLocator());
Expand All @@ -3943,7 +3986,7 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
if (GetBoolArg("-rescan", false))
pindexRescan = chainActive.Genesis();
else {
CWalletDB walletdb(strWalletFile);
CWalletDB walletdb(walletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
Expand All @@ -3955,16 +3998,15 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
const int64_t nWalletRescanTime = GetTimeMillis();
if (walletInstance->ScanForWalletTransactions(pindexRescan, true, true) == -1) {
errorString += _("Shutdown requested over the txs scan. Exiting.\n");
return walletInstance;
return UIError(_("Shutdown requested over the txs scan. Exiting."));
}
LogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nWalletRescanTime);
walletInstance->SetBestChain(chainActive.GetLocator());
CWalletDB::IncrementUpdateCounter();

// Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") {
CWalletDB walletdb(strWalletFile);
CWalletDB walletdb(walletFile);
for (const CWalletTx& wtxOld : vWtx) {
uint256 hash = wtxOld.GetHash();
std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
Expand Down Expand Up @@ -3995,7 +4037,8 @@ CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWall
zwalletInstance->SyncWithChain();
}

return walletInstance;
pwalletMain = walletInstance;
return true;
}

std::atomic<bool> CWallet::fFlushThreadRunning(false);
Expand All @@ -4011,7 +4054,6 @@ void CWallet::postInitProcess(boost::thread_group& threadGroup)
}
}


CKeyPool::CKeyPool()
{
nTime = GetTime();
Expand Down
13 changes: 8 additions & 5 deletions src/wallet/wallet.h
Expand Up @@ -647,14 +647,20 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
//! Get wallet transactions that conflict with given transaction (spend same outputs)
std::set<uint256> GetConflicts(const uint256& txid) const;

//! Verify the wallet database and perform salvage if required
static bool Verify();

/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);

/* Returns the wallets help message */
static std::string GetWalletHelpString(bool showDebug);

/* initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static CWallet* InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static bool InitLoadWallet();

/* Wallets parameter interaction */
static bool ParameterInteraction();

/**
* Wallet post-init setup
Expand Down Expand Up @@ -734,9 +740,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
bool UpdateMint(const CBigNum& bnValue, const int& nHeight, const uint256& txid, const libzerocoin::CoinDenomination& denom);
// Zerocoin entry changed. (called with lock cs_wallet held)
boost::signals2::signal<void(CWallet* wallet, const std::string& pubCoin, const std::string& isUsed, ChangeType status)> NotifyZerocoinChanged;

/* Wallets parameter interaction */
static bool ParameterInteraction();
};

/** A key allocated from the key pool. */
Expand Down

0 comments on commit e585dad

Please sign in to comment.