From 3f3a289c060f9ad19cb468a3d97dececc6e0345e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 8 Jan 2021 19:11:19 -0300 Subject: [PATCH 1/9] wallet: Introduce database handle wrapper Abstract database handle from explicit strFilename into CWalletDBWrapper. Backport and adaptation from btc@71afe3c0995592ff17968816a833a8ed3ce05bf2 --- src/qt/optionsmodel.cpp | 6 +- .../pivx/settings/settingsmultisendwidget.cpp | 8 +- src/sapling/sapling_operation.cpp | 2 +- src/sapling/saplingscriptpubkeyman.cpp | 16 ++-- src/test/librust/wallet_zkeys_tests.cpp | 3 +- src/wallet/db.cpp | 66 +++++++++++++++-- src/wallet/db.h | 36 ++++++++- src/wallet/rpcwallet.cpp | 4 +- src/wallet/scriptpubkeyman.cpp | 18 ++--- src/wallet/test/wallet_test_fixture.cpp | 6 +- src/wallet/wallet.cpp | 73 ++++++++++--------- src/wallet/wallet.h | 24 +++++- src/wallet/walletdb.cpp | 20 ++--- src/wallet/walletdb.h | 8 +- 14 files changed, 197 insertions(+), 93 deletions(-) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 3a19491f11886..25aa2e8556bcd 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -482,7 +482,7 @@ void OptionsModel::setDisplayUnit(const QVariant& value) void OptionsModel::setStakeSplitThreshold(const CAmount nStakeSplitThreshold) { if (pwalletMain && pwalletMain->nStakeSplitThreshold != nStakeSplitThreshold) { - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); LOCK(pwalletMain->cs_wallet); { pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; @@ -513,7 +513,7 @@ bool OptionsModel::isSSTValid() void OptionsModel::setUseCustomFee(bool fUse) { if (pwalletMain && pwalletMain->fUseCustomFee != fUse) { - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); { LOCK(pwalletMain->cs_wallet); pwalletMain->fUseCustomFee = fUse; @@ -526,7 +526,7 @@ void OptionsModel::setUseCustomFee(bool fUse) void OptionsModel::setCustomFeeValue(const CAmount& value) { if (pwalletMain && pwalletMain->nCustomFee != value) { - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); { LOCK(pwalletMain->cs_wallet); pwalletMain->nCustomFee = value; diff --git a/src/qt/pivx/settings/settingsmultisendwidget.cpp b/src/qt/pivx/settings/settingsmultisendwidget.cpp index 75c56d3d81f76..70be1059c64a7 100644 --- a/src/qt/pivx/settings/settingsmultisendwidget.cpp +++ b/src/qt/pivx/settings/settingsmultisendwidget.cpp @@ -244,7 +244,7 @@ void SettingsMultisendWidget::clearAll() std::vector > vMultiSendTemp = pwalletMain->vMultiSend; bool fRemoved = true; pwalletMain->vMultiSend.clear(); - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); if (!walletdb.EraseMultiSend(vMultiSendTemp)) fRemoved = false; if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) @@ -317,7 +317,7 @@ void SettingsMultisendWidget::addMultiSend(QString address, int percentage, QStr AddressBook::AddressBookPurpose::SEND); } - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) { inform(tr("Error saving MultiSend, failed saving properties to the database.")); return; @@ -341,7 +341,7 @@ void SettingsMultisendWidget::activate() pwalletMain->fMultiSendStake = ui->checkBoxStake->isChecked(); pwalletMain->fMultiSendMasternodeReward = ui->checkBoxRewards->isChecked(); - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) strRet = tr("MultiSend activated but writing settings to DB failed"); else @@ -357,7 +357,7 @@ void SettingsMultisendWidget::deactivate() if (pwalletMain->isMultiSendEnabled()) { QString strRet; pwalletMain->setMultiSendDisabled(); - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); inform(!walletdb.WriteMSettings(false, false, pwalletMain->nLastMultiSendHeight) ? tr("MultiSend deactivated but writing settings to DB failed") : tr("MultiSend deactivated") diff --git a/src/sapling/sapling_operation.cpp b/src/sapling/sapling_operation.cpp index 8754bc4e9940d..df302cca2ab2f 100644 --- a/src/sapling/sapling_operation.cpp +++ b/src/sapling/sapling_operation.cpp @@ -379,7 +379,7 @@ static CacheCheckResult CheckCachedNote(const SaplingNoteEntry& t, const libzcas if (sspkm->IsSaplingSpent(*(nd.nullifier))) { LogPrintf("Removed note %s as it appears to be already spent.\n", noteStr); prevTx.MarkDirty(); - CWalletDB(pwalletMain->strWalletFile, "r+").WriteTx(prevTx); + CWalletDB(pwalletMain->GetDBHandle(), "r+").WriteTx(prevTx); pwalletMain->NotifyTransactionChanged(pwalletMain, t.op.hash, CT_UPDATED); return CacheCheckResult::SPENT; } diff --git a/src/sapling/saplingscriptpubkeyman.cpp b/src/sapling/saplingscriptpubkeyman.cpp index 8053cecff0ec5..445146822862a 100644 --- a/src/sapling/saplingscriptpubkeyman.cpp +++ b/src/sapling/saplingscriptpubkeyman.cpp @@ -890,7 +890,7 @@ libzcash::SaplingPaymentAddress SaplingScriptPubKeyMan::GenerateNewSaplingZKey() } while (wallet->HaveSaplingSpendingKey(xsk.ToXFVK())); // Update the chain model in the database - if (wallet->fFileBacked && !CWalletDB(wallet->strWalletFile).WriteHDChain(hdChain)) + if (wallet->fFileBacked && !CWalletDB(wallet->GetDBHandle()).WriteHDChain(hdChain)) throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); // Create new metadata @@ -1000,7 +1000,7 @@ bool SaplingScriptPubKeyMan::AddSaplingZKey( if (!wallet->IsCrypted()) { auto ivk = sk.expsk.full_viewing_key().in_viewing_key(); - return CWalletDB(wallet->strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]); + return CWalletDB(wallet->GetDBHandle()).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]); } return true; @@ -1051,7 +1051,7 @@ bool SaplingScriptPubKeyMan::AddSaplingIncomingViewingKey( } if (!wallet->IsCrypted()) { - return CWalletDB(wallet->strWalletFile).WriteSaplingPaymentAddress(addr, ivk); + return CWalletDB(wallet->GetDBHandle()).WriteSaplingPaymentAddress(addr, ivk); } return true; @@ -1093,7 +1093,7 @@ bool SaplingScriptPubKeyMan::AddCryptedSaplingSpendingKeyDB(const libzcash::Sapl vchCryptedSecret, mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]); } else { - return CWalletDB(wallet->strWalletFile).WriteCryptedSaplingZKey(extfvk, + return CWalletDB(wallet->GetDBHandle()).WriteCryptedSaplingZKey(extfvk, vchCryptedSecret, mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]); } @@ -1180,7 +1180,7 @@ void SaplingScriptPubKeyMan::SetHDSeed(const CKeyID& keyID, bool force, bool mem // Update the commonOVK to recover t->shield notes commonOVK = getCommonOVKFromSeed(); - if (!memonly && !CWalletDB(wallet->strWalletFile).WriteSaplingCommonOVK(*commonOVK)) { + if (!memonly && !CWalletDB(wallet->GetDBHandle()).WriteSaplingCommonOVK(*commonOVK)) { throw std::runtime_error(std::string(__func__) + ": writing sapling commonOVK failed"); } } @@ -1191,7 +1191,7 @@ void SaplingScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly) if (chain.chainType != HDChain::ChainCounterType::Sapling) throw std::runtime_error(std::string(__func__) + ": trying to store an invalid chain type"); - if (!memonly && !CWalletDB(wallet->strWalletFile).WriteHDChain(chain)) + if (!memonly && !CWalletDB(wallet->GetDBHandle()).WriteHDChain(chain)) throw std::runtime_error(std::string(__func__) + ": writing sapling chain failed"); hdChain = chain; @@ -1208,7 +1208,7 @@ uint256 SaplingScriptPubKeyMan::getCommonOVK() // Else, look for it in the database uint256 ovk; - if (CWalletDB(wallet->strWalletFile).ReadSaplingCommonOVK(ovk)) { + if (CWalletDB(wallet->GetDBHandle()).ReadSaplingCommonOVK(ovk)) { commonOVK = std::move(ovk); return *commonOVK; } @@ -1217,7 +1217,7 @@ uint256 SaplingScriptPubKeyMan::getCommonOVK() // So we should always call this after unlocking the wallet during a spend // from a transparent address, or when changing/setting the HD seed. commonOVK = getCommonOVKFromSeed(); - if (!CWalletDB(wallet->strWalletFile).WriteSaplingCommonOVK(*commonOVK)) { + if (!CWalletDB(wallet->GetDBHandle()).WriteSaplingCommonOVK(*commonOVK)) { throw std::runtime_error("Unable to write sapling Common OVK to database"); } return *commonOVK; diff --git a/src/test/librust/wallet_zkeys_tests.cpp b/src/test/librust/wallet_zkeys_tests.cpp index 267d35c6bd6b9..2c584c32722ed 100644 --- a/src/test/librust/wallet_zkeys_tests.cpp +++ b/src/test/librust/wallet_zkeys_tests.cpp @@ -159,7 +159,8 @@ BOOST_AUTO_TEST_CASE(WriteCryptedSaplingZkeyDirectToDb) { // Create a new wallet from the existing wallet path bool fFirstRun; - CWallet wallet2(pwalletMain->strWalletFile); + std::unique_ptr dbw(new CWalletDBWrapper(&bitdb, pwalletMain->GetDBHandle().GetName())); + CWallet wallet2(std::move(dbw)); BOOST_CHECK_EQUAL(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun)); // Confirm it's not the same as the other wallet diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 83c96f6f4a219..a26ccbfb1a49d 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -349,13 +349,12 @@ void CDBEnv::CheckpointLSN(const std::string& strFile) } -CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL) +CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL) { int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; - if (strFilename.empty()) - return; + const std::string& strFilename = dbw.strFile; bool fCreate = strchr(pszMode, 'c') != NULL; unsigned int nFlags = DB_THREAD; @@ -463,8 +462,12 @@ bool CDBEnv::RemoveDb(const std::string& strFile) return (rc == 0); } -bool CDB::Rewrite(const std::string& strFile, const char* pszSkip) +bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) { + if (!dbw.env) { + return true; + } + const std::string& strFile = dbw.strFile; while (true) { { LOCK(bitdb.cs_db); @@ -478,7 +481,7 @@ bool CDB::Rewrite(const std::string& strFile, const char* pszSkip) LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} - CDB db(strFile.c_str(), "r"); + CDB db(dbw, "r"); Db* pdbCopy = new Db(bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer @@ -587,11 +590,13 @@ void CDBEnv::Flush(bool fShutdown) } } -bool CDB::PeriodicFlush(const std::string& strFile) +bool CDB::PeriodicFlush(CWalletDBWrapper& dbw) { bool ret = false; - TRY_LOCK(bitdb.cs_db, lockDb); - if (lockDb) { + const std::string& strFile = dbw.strFile; + TRY_LOCK(bitdb.cs_db,lockDb); + if (lockDb) + { // Don't do this if any databases are in use int nRefCount = 0; std::map::iterator mi = bitdb.mapFileUseCount.begin(); @@ -621,3 +626,48 @@ bool CDB::PeriodicFlush(const std::string& strFile) return ret; } +bool CWalletDBWrapper::Rewrite(const char* pszSkip) +{ + return CDB::Rewrite(*this, pszSkip); +} + +bool CWalletDBWrapper::Backup(const std::string& strDest) +{ + if (!env) { + return false; + } + while (true) + { + { + LOCK(bitdb.cs_db); + if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) + { + // Flush log data to the dat file + bitdb.CloseDb(strFile); + bitdb.CheckpointLSN(strFile); + bitdb.mapFileUseCount.erase(strFile); + + // Copy wallet file + fs::path pathSrc = GetDataDir() / strFile; + fs::path pathDest(strDest); + if (fs::is_directory(pathDest)) + pathDest /= strFile; + + try { +#if BOOST_VERSION >= 107400 + fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_options::overwrite_existing); +#elif BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ + fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_option::overwrite_if_exists); +#endif + LogPrintf("copied %s to %s\n", strFile, pathDest.string()); + return true; + } catch (const fs::filesystem_error& e) { + LogPrintf("error copying %s to %s - %s\n", strFile, pathDest.string(), e.what()); + return false; + } + } + } + MilliSleep(100); + } + return false; +} diff --git a/src/wallet/db.h b/src/wallet/db.h index 94d02be996e73..748937a9086de 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -87,6 +87,36 @@ class CDBEnv extern CDBEnv bitdb; +/** An instance of this class represents one database. + * For BerkeleyDB this is just a (env, strFile) tuple. + **/ +class CWalletDBWrapper +{ + friend class CDB; +public: + CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in): + env(env_in), strFile(strFile_in) + { + } + + /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero + */ + bool Rewrite(const char* pszSkip=nullptr); + + /** Back up the entire database to a file. + */ + bool Backup(const std::string& strDest); + + /** Get a name for this database, for debugging etc. + */ + std::string GetName() const { return strFile; } + +private: + /** BerkeleyDB specific */ + CDBEnv *env; + std::string strFile; +}; + /** RAII class that provides access to a Berkeley database */ class CDB @@ -98,7 +128,7 @@ class CDB bool fReadOnly; bool fFlushOnClose; - explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true); + explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true); ~CDB() { Close(); } public: @@ -108,7 +138,7 @@ class CDB /* flush the wallet passively (TRY_LOCK) ideal to be called periodically */ - static bool PeriodicFlush(const std::string& strFile); + static bool PeriodicFlush(CWalletDBWrapper& dbw); /* verifies the database environment */ static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr); /* verifies the database file */ @@ -312,7 +342,7 @@ class CDB return Write(std::string("version"), nVersion); } - bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); + bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = NULL); }; #endif // BITCOIN_DB_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 118e066b3e048..1c1739084f4da 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3744,7 +3744,7 @@ UniValue setstakesplitthreshold(const JSONRPCRequest& request) EnsureWalletIsUnlocked(); - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); LOCK(pwalletMain->cs_wallet); { bool fFileBacked = pwalletMain->fFileBacked; @@ -3797,7 +3797,7 @@ UniValue autocombinerewards(const JSONRPCRequest& request) "\nExamples:\n" + HelpExampleCli("autocombinerewards", "true 500") + HelpExampleRpc("autocombinerewards", "true 500")); - CWalletDB walletdb(pwalletMain->strWalletFile); + CWalletDB walletdb(pwalletMain->GetDBHandle()); CAmount nThreshold = 0; if (fEnable) diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index ce9ad51df7b1d..2a5a3a5486567 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -100,7 +100,7 @@ int64_t ScriptPubKeyMan::GetOldestKeyPoolTime() { LOCK(wallet->cs_KeyStore); - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); // load oldest key from keypool, get time and return int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch); if (IsHDEnabled()) { @@ -148,7 +148,7 @@ bool ScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const uint8_t& changeType) LogPrintf("%s: Wallet locked, cannot get address\n", __func__); return false; } - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); result = GenerateNewKey(batch, changeType); return true; } @@ -188,7 +188,7 @@ bool ScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, return false; } - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); auto it = setKeyPool.begin(); nIndex = *it; @@ -225,7 +225,7 @@ bool ScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, void ScriptPubKeyMan::KeepDestination(int64_t nIndex) { // Remove from key pool - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); batch.ErasePool(nIndex); CPubKey pubkey; bool have_pk = wallet->GetPubKey(m_index_to_reserved_key.at(nIndex), pubkey); @@ -267,7 +267,7 @@ void ScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id) (staking ? &setStakingKeyPool : &setExternalKeyPool) : &set_pre_split_keypool); auto it = setKeyPool->begin(); - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); while (it != std::end(*setKeyPool)) { const int64_t& index = *(it); if (index > keypool_id) break; // set*KeyPool is ordered @@ -301,7 +301,7 @@ void ScriptPubKeyMan::MarkUnusedAddresses(const CScript& script) void ScriptPubKeyMan::MarkPreSplitKeys() { - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); for (auto it = setExternalKeyPool.begin(); it != setExternalKeyPool.end();) { int64_t index = *it; CKeyPool keypool; @@ -326,7 +326,7 @@ bool ScriptPubKeyMan::NewKeyPool() { LOCK(wallet->cs_wallet); - CWalletDB walletdb(wallet->strWalletFile); + CWalletDB walletdb(wallet->GetDBHandle()); // Internal for (const int64_t nIndex : setInternalKeyPool) { walletdb.ErasePool(nIndex); @@ -387,7 +387,7 @@ bool ScriptPubKeyMan::TopUp(unsigned int kpSize) missingStaking = 0; } - CWalletDB batch(wallet->strWalletFile); + CWalletDB batch(wallet->GetDBHandle()); GeneratePool(batch, missingExternal, HDChain::ChangeType::EXTERNAL); GeneratePool(batch, missingInternal, HDChain::ChangeType::INTERNAL); GeneratePool(batch, missingStaking, HDChain::ChangeType::STAKING); @@ -676,7 +676,7 @@ void ScriptPubKeyMan::SetHDSeed(const CPubKey& seed, bool force, bool memOnly) void ScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly) { LOCK(wallet->cs_wallet); - if (!memonly && !CWalletDB(wallet->strWalletFile).WriteHDChain(chain)) + if (!memonly && !CWalletDB(wallet->GetDBHandle()).WriteHDChain(chain)) throw std::runtime_error(std::string(__func__) + ": writing chain failed"); hdChain = chain; diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 836b9decf759e..6e8a95734a466 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -6,13 +6,10 @@ #include "wallet/test/wallet_test_fixture.h" #include "rpc/server.h" -#include "sapling/sapling_util.h" #include "wallet/db.h" #include "wallet/wallet.h" #include "wallet/rpcwallet.h" -#include - void clean() { delete pwalletMain; @@ -29,7 +26,8 @@ WalletTestingSetup::WalletTestingSetup(): SaplingTestingSetup() RegisterWalletRPCCommands(tableRPC); bool fFirstRun; - pwalletMain = new CWallet("test_wallet.dat"); + std::unique_ptr dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat")); + pwalletMain = new CWallet(std::move(dbw)); pwalletMain->LoadWallet(fFirstRun); RegisterValidationInterface(pwalletMain); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index dd64015159606..599478efb4ecc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -212,7 +212,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey& pubkey) if (!fFileBacked) return true; if (!IsCrypted()) { - return CWalletDB(strWalletFile).WriteKey( + return CWalletDB(*dbw).WriteKey( pubkey, secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); @@ -234,7 +234,7 @@ bool CWallet::AddCryptedKey(const CPubKey& vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); else - return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); + return CWalletDB(*dbw).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); } return false; } @@ -260,7 +260,7 @@ bool CWallet::AddCScript(const CScript& redeemScript) return false; if (!fFileBacked) return true; - return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript); + return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript); } bool CWallet::LoadCScript(const CScript& redeemScript) @@ -286,7 +286,7 @@ bool CWallet::AddWatchOnly(const CScript& dest) NotifyWatchonlyChanged(true); if (!fFileBacked) return true; - return CWalletDB(strWalletFile).WriteWatchOnly(dest); + return CWalletDB(*dbw).WriteWatchOnly(dest); } bool CWallet::RemoveWatchOnly(const CScript& dest) @@ -297,7 +297,7 @@ bool CWallet::RemoveWatchOnly(const CScript& dest) if (!HaveWatchOnly()) NotifyWatchonlyChanged(false); if (fFileBacked) - if (!CWalletDB(strWalletFile).EraseWatchOnly(dest)) + if (!CWalletDB(*dbw).EraseWatchOnly(dest)) return false; return true; @@ -433,7 +433,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey)) return false; - CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second); + CWalletDB(*dbw).WriteMasterKey(pMasterKey.first, pMasterKey.second); if (fWasLocked) Lock(); @@ -467,7 +467,7 @@ void CWallet::ChainTip(const CBlockIndex *pindex, void CWallet::SetBestChain(const CBlockLocator& loc) { - CWalletDB walletdb(strWalletFile); + CWalletDB walletdb(*dbw); SetBestChainInternal(walletdb, loc); } @@ -550,7 +550,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, nWalletMaxVersion = nVersion; if (fFileBacked) { - CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile); + CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(*dbw); if (nWalletVersion > 40000) pwalletdb->WriteMinVersion(nWalletVersion); if (!pwalletdbIn) @@ -838,7 +838,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; if (fFileBacked) { assert(!pwalletdbEncryption); - pwalletdbEncryption = new CWalletDB(strWalletFile); + pwalletdbEncryption = new CWalletDB(*dbw); if (!pwalletdbEncryption->TxnBegin()) { delete pwalletdbEncryption; pwalletdbEncryption = NULL; @@ -883,7 +883,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) // Need to completely rewrite the wallet file; if we don't, bdb might keep // bits of the unencrypted private key in slack space in the database file. - CDB::Rewrite(strWalletFile); + dbw->Rewrite(); } NotifyStatusChanged(this); @@ -897,7 +897,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB* pwalletdb) if (pwalletdb) { pwalletdb->WriteOrderPosNext(nOrderPosNext); } else { - CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); + CWalletDB(*dbw).WriteOrderPosNext(nOrderPosNext); } return nRet; } @@ -929,7 +929,7 @@ void CWallet::MarkDirty() bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) { LOCK(cs_wallet); - CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); + CWalletDB walletdb(*dbw, "r+", fFlushOnClose); uint256 hash = wtxIn.GetHash(); // Inserts only if not already there, returns tx inserted or tx found @@ -1131,7 +1131,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) { LOCK2(cs_main, cs_wallet); - CWalletDB walletdb(strWalletFile, "r+"); + CWalletDB walletdb(*dbw, "r+"); std::set todo; std::set done; @@ -1204,7 +1204,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) return; // Do not flush the wallet here for performance reasons - CWalletDB walletdb(strWalletFile, "r+", false); + CWalletDB walletdb(*dbw, "r+", false); std::set todo; std::set done; @@ -1282,7 +1282,7 @@ void CWallet::EraseFromWallet(const uint256& hash) { LOCK(cs_wallet); if (mapWallet.erase(hash)) - CWalletDB(strWalletFile).EraseTx(hash); + CWalletDB(*dbw).EraseTx(hash); LogPrintf("%s: Erased wtx %s from wallet\n", __func__, hash.GetHex()); } return; @@ -1744,7 +1744,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate, b // Sapling // After rescanning, persist Sapling note data that might have changed, e.g. nullifiers. // Do not flush the wallet here for performance reasons. - CWalletDB walletdb(strWalletFile, "r+", false); + CWalletDB walletdb(*dbw, "r+", false); for (const auto& hash : myTxHashes) { CWalletTx wtx = mapWallet[hash]; if (!wtx.mapSaplingNoteData.empty()) { @@ -3159,9 +3159,9 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) if (!fFileBacked) return DB_LOAD_OK; - DBErrors nLoadWalletRet = CWalletDB(strWalletFile, "cr+").LoadWallet(this); + DBErrors nLoadWalletRet = CWalletDB(*dbw, "cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { - if (CDB::Rewrite(strWalletFile, "\x04pool")) { + if (dbw->Rewrite( "\x04pool")) { // TODO: Implement spk_man->RewriteDB(). m_spk_man->set_pre_split_keypool.clear(); // Note: can't top-up keypool here, because wallet is locked. @@ -3186,9 +3186,9 @@ DBErrors CWallet::ZapWalletTx(std::vector& vWtx) { if (!fFileBacked) return DB_LOAD_OK; - DBErrors nZapWalletTxRet = CWalletDB(strWalletFile, "cr+").ZapWalletTx(this, vWtx); + DBErrors nZapWalletTxRet = CWalletDB(*dbw, "cr+").ZapWalletTx(this, vWtx); if (nZapWalletTxRet == DB_NEED_REWRITE) { - if (CDB::Rewrite(strWalletFile, "\x04pool")) { + if (dbw->Rewrite("\x04pool")) { LOCK(cs_wallet); m_spk_man->set_pre_split_keypool.clear(); // Note: can't top-up keypool here, because wallet is locked. @@ -3224,9 +3224,9 @@ bool CWallet::SetAddressBook(const CWDestination& address, const std::string& st if (!fFileBacked) return false; std::string addressStr = ParseIntoAddress(address, mapAddressBook.at(address).purpose); - if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(addressStr, strPurpose)) + if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(addressStr, strPurpose)) return false; - return CWalletDB(strWalletFile).WriteName(addressStr, strName); + return CWalletDB(*dbw).WriteName(addressStr, strName); } bool CWallet::DelAddressBook(const CWDestination& address, const CChainParams::Base58Type addrType) @@ -3239,7 +3239,7 @@ bool CWallet::DelAddressBook(const CWDestination& address, const CChainParams::B if (fFileBacked) { // Delete destdata tuples associated with address for (const std::pair & item : mapAddressBook[address].destdata) { - CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); + CWalletDB(*dbw).EraseDestData(strAddress, item.first); } } mapAddressBook.erase(address); @@ -3249,8 +3249,8 @@ bool CWallet::DelAddressBook(const CWDestination& address, const CChainParams::B if (!fFileBacked) return false; - CWalletDB(strWalletFile).ErasePurpose(strAddress); - return CWalletDB(strWalletFile).EraseName(strAddress); + CWalletDB(*dbw).ErasePurpose(strAddress); + return CWalletDB(*dbw).EraseName(strAddress); } std::string CWallet::GetPurposeForAddressBookEntry(const CWDestination& address) const @@ -3679,7 +3679,7 @@ bool CWallet::AddDestData(const CTxDestination& dest, const std::string& key, co mapAddressBook[dest].destdata.emplace(key, value); if (!fFileBacked) return true; - return CWalletDB(strWalletFile).WriteDestData(EncodeDestination(dest), key, value); + return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value); } bool CWallet::EraseDestData(const CTxDestination& dest, const std::string& key) @@ -3688,7 +3688,7 @@ bool CWallet::EraseDestData(const CTxDestination& dest, const std::string& key) return false; if (!fFileBacked) return true; - return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key); + return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key); } bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value) @@ -3900,7 +3900,7 @@ bool CWallet::MultiSend() fMultiSendNotify = true; //write nLastMultiSendHeight to DB - CWalletDB walletdb(strWalletFile); + CWalletDB walletdb(*dbw); nLastMultiSendHeight = chainActive.Tip()->nHeight; if (!walletdb.WriteMSettings(fMultiSendStake, fMultiSendMasternodeReward, nLastMultiSendHeight)) LogPrintf("Failed to write MultiSend setting to DB\n"); @@ -3969,7 +3969,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) if (gArgs.GetBoolArg("-zapwallettxes", false)) { uiInterface.InitMessage(_("Zapping all transactions from wallet...")); - CWallet *tempWallet = new CWallet(walletFile); + std::unique_ptr dbw(new CWalletDBWrapper(&bitdb, walletFile)); + CWallet *tempWallet = new CWallet(std::move(dbw)); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); if (nZapWalletRet != DB_LOAD_OK) { UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); @@ -3985,7 +3986,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) int64_t nStart = GetTimeMillis(); bool fFirstRun = true; - CWallet *walletInstance = new CWallet(walletFile); + std::unique_ptr dbw(new CWalletDBWrapper(&bitdb, walletFile)); + CWallet *walletInstance = new CWallet(std::move(dbw)); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); if (nLoadWalletRet != DB_LOAD_OK) { if (nLoadWalletRet == DB_CORRUPT) { @@ -4086,7 +4088,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) if (gArgs.GetBoolArg("-rescan", false)) pindexRescan = chainActive.Genesis(); else { - CWalletDB walletdb(walletFile); + CWalletDB walletdb(*walletInstance->dbw); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = FindForkInGlobalIndex(chainActive, locator); @@ -4107,7 +4109,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) // Restore wallet transaction metadata after -zapwallettxes=1 if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2") { - CWalletDB walletdb(walletFile); + CWalletDB walletdb(*walletInstance->dbw); for (const CWalletTx& wtxOld : vWtx) { uint256 hash = wtxOld.GetHash(); std::map::iterator mi = walletInstance->mapWallet.find(hash); @@ -4261,7 +4263,7 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee, bool std::string CWallet::GetUniqueWalletBackupName() const { - return strprintf("%s%s", strWalletFile, DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); + return strprintf("%s%s", (dbw ? dbw->GetName() : "null"), DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); } CWallet::CWallet() @@ -4269,11 +4271,10 @@ CWallet::CWallet() SetNull(); } -CWallet::CWallet(std::string strWalletFileIn) +CWallet::CWallet(std::unique_ptr dbw_in) + : dbw(std::move(dbw_in)) { SetNull(); - - strWalletFile = strWalletFileIn; fFileBacked = true; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0cc5ba6a39e23..d0fbfb65c80a3 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -280,6 +280,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded int nWalletMaxVersion; + std::unique_ptr dbw; + int64_t nNextResend; int64_t nLastResend; @@ -354,7 +356,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool fFileBacked; bool fWalletUnlockStaking; - std::string strWalletFile; CWalletDB* pwalletdbEncryption; @@ -388,8 +389,27 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool fCombineDust; CAmount nAutoCombineThreshold; + /** Get database handle used by this wallet. Ideally this function would + * not be necessary. + */ + CWalletDBWrapper& GetDBHandle() const + { + return *dbw; + } + + /** Get a name for this wallet for logging/debugging purposes. + */ + std::string GetName() const + { + if (dbw) { + return dbw->GetName(); + } else { + return "dummy"; + } + } + CWallet(); - CWallet(std::string strWalletFileIn); + CWallet(std::unique_ptr dbw_in); ~CWallet(); void SetNull(); bool isMultiSendEnabled(); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 79b6a4e752cc4..5deb98b6506d6 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -917,9 +917,9 @@ void ThreadFlushWalletDB() } if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2) { - const std::string& strFile = pwalletMain->strWalletFile; - if (CDB::PeriodicFlush(strFile)) + if (CDB::PeriodicFlush(pwalletMain->GetDBHandle())) { nLastFlushed = CWalletDB::GetUpdateCounter(); + } } } } @@ -957,18 +957,18 @@ bool BackupWallet(const CWallet& wallet, const fs::path& strDest, bool fEnableCu while (true) { { LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0) { + if (!bitdb.mapFileUseCount.count(wallet.GetDBHandle().GetName()) || bitdb.mapFileUseCount[wallet.GetDBHandle().GetName()] == 0) { // Flush log data to the dat file - bitdb.CloseDb(wallet.strWalletFile); - bitdb.CheckpointLSN(wallet.strWalletFile); - bitdb.mapFileUseCount.erase(wallet.strWalletFile); + bitdb.CloseDb(wallet.GetDBHandle().GetName()); + bitdb.CheckpointLSN(wallet.GetDBHandle().GetName()); + bitdb.mapFileUseCount.erase(wallet.GetDBHandle().GetName()); // Copy wallet file fs::path pathDest(strDest); - fs::path pathSrc = GetDataDir() / wallet.strWalletFile; + fs::path pathSrc = GetDataDir() / wallet.GetDBHandle().GetName(); if (is_directory(pathDest)) { if(!exists(pathDest)) create_directory(pathDest); - pathDest /= wallet.strWalletFile; + pathDest /= wallet.GetDBHandle().GetName(); } bool defaultPath = AttemptBackupWallet(wallet, pathSrc.string(), pathDest.string()); @@ -989,7 +989,7 @@ bool BackupWallet(const CWallet& wallet, const fs::path& strDest, bool fEnableCu if (fs::is_regular_file(dir_iter->status())) { currentFile = dir_iter->path().filename(); // Only add the backups for the current wallet, e.g. wallet.dat.* - if (dir_iter->path().stem().string() == wallet.strWalletFile) { + if (dir_iter->path().stem().string() == wallet.GetDBHandle().GetName()) { folderSet.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter)); } } @@ -1055,7 +1055,7 @@ bool AttemptBackupWallet(const CWallet& wallet, const fs::path& pathSrc, const f src.close(); dst.close(); #endif - strMessage = strprintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string()); + strMessage = strprintf("copied %s to %s\n", wallet.GetDBHandle().GetName(), pathDest.string()); LogPrintf("%s : %s\n", __func__, strMessage); retStatus = true; } catch (const fs::filesystem_error& e) { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 3a7ba8f09dc1e..b86fe59c7c806 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -98,11 +98,15 @@ class CKeyMetadata } }; -/** Access to the wallet database */ +/** Access to the wallet database. + * This should really be named CWalletDBBatch, as it represents a single transaction at the + * database. It will be committed when the object goes out of scope. + * Optionally (on by default) it will flush to disk as well. + */ class CWalletDB : public CDB { public: - CWalletDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) + CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(dbw, pszMode, fFlushOnClose) { } From e420d3dec99986ed54ff89a129c7449097a21d6d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 8 Mar 2017 12:08:26 +0000 Subject: [PATCH 2/9] wallet: Get rid of fFileBacked Instead, CWalletDB() with a dummy handle will just give you a no-op database in which writes always succeeds and reads always fail. CDB already had functionality for this, so just use that. --- src/qt/optionsmodel.cpp | 9 +-- src/sapling/saplingscriptpubkeyman.cpp | 12 +--- src/wallet/db.cpp | 12 +++- src/wallet/db.h | 14 ++++- src/wallet/rpcwallet.cpp | 5 +- src/wallet/wallet.cpp | 82 ++++++++------------------ src/wallet/wallet.h | 8 +-- src/wallet/walletdb.cpp | 4 +- 8 files changed, 56 insertions(+), 90 deletions(-) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 25aa2e8556bcd..9bd54b81e7144 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -486,8 +486,7 @@ void OptionsModel::setStakeSplitThreshold(const CAmount nStakeSplitThreshold) LOCK(pwalletMain->cs_wallet); { pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; - if (pwalletMain->fFileBacked) - walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold); + walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold); } } } @@ -517,8 +516,7 @@ void OptionsModel::setUseCustomFee(bool fUse) { LOCK(pwalletMain->cs_wallet); pwalletMain->fUseCustomFee = fUse; - if (pwalletMain->fFileBacked) - walletdb.WriteUseCustomFee(fUse); + walletdb.WriteUseCustomFee(fUse); } } } @@ -530,8 +528,7 @@ void OptionsModel::setCustomFeeValue(const CAmount& value) { LOCK(pwalletMain->cs_wallet); pwalletMain->nCustomFee = value; - if (pwalletMain->fFileBacked) - walletdb.WriteCustomFeeValue(value); + walletdb.WriteCustomFeeValue(value); } } } diff --git a/src/sapling/saplingscriptpubkeyman.cpp b/src/sapling/saplingscriptpubkeyman.cpp index 445146822862a..196d212429318 100644 --- a/src/sapling/saplingscriptpubkeyman.cpp +++ b/src/sapling/saplingscriptpubkeyman.cpp @@ -890,7 +890,7 @@ libzcash::SaplingPaymentAddress SaplingScriptPubKeyMan::GenerateNewSaplingZKey() } while (wallet->HaveSaplingSpendingKey(xsk.ToXFVK())); // Update the chain model in the database - if (wallet->fFileBacked && !CWalletDB(wallet->GetDBHandle()).WriteHDChain(hdChain)) + if (!CWalletDB(wallet->GetDBHandle()).WriteHDChain(hdChain)) throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); // Create new metadata @@ -994,10 +994,6 @@ bool SaplingScriptPubKeyMan::AddSaplingZKey( return false; } - if (!wallet->fFileBacked) { - return true; - } - if (!wallet->IsCrypted()) { auto ivk = sk.expsk.full_viewing_key().in_viewing_key(); return CWalletDB(wallet->GetDBHandle()).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]); @@ -1046,10 +1042,6 @@ bool SaplingScriptPubKeyMan::AddSaplingIncomingViewingKey( return false; } - if (!wallet->fFileBacked) { - return true; - } - if (!wallet->IsCrypted()) { return CWalletDB(wallet->GetDBHandle()).WriteSaplingPaymentAddress(addr, ivk); } @@ -1084,8 +1076,6 @@ bool SaplingScriptPubKeyMan::AddCryptedSaplingSpendingKeyDB(const libzcash::Sapl { if (!wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret)) return false; - if (!wallet->fFileBacked) - return true; { LOCK(wallet->cs_wallet); if (wallet->pwalletdbEncryption) { diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index a26ccbfb1a49d..57b03922c17b7 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -354,7 +354,10 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; - const std::string& strFilename = dbw.strFile; + if (dbw.IsDummy()) { + return; + } + const std::string &strFilename = dbw.strFile; bool fCreate = strchr(pszMode, 'c') != NULL; unsigned int nFlags = DB_THREAD; @@ -464,7 +467,7 @@ bool CDBEnv::RemoveDb(const std::string& strFile) bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) { - if (!dbw.env) { + if (dbw.IsDummy()) { return true; } const std::string& strFile = dbw.strFile; @@ -592,6 +595,9 @@ void CDBEnv::Flush(bool fShutdown) bool CDB::PeriodicFlush(CWalletDBWrapper& dbw) { + if (dbw.IsDummy()) { + return true; + } bool ret = false; const std::string& strFile = dbw.strFile; TRY_LOCK(bitdb.cs_db,lockDb); @@ -633,7 +639,7 @@ bool CWalletDBWrapper::Rewrite(const char* pszSkip) bool CWalletDBWrapper::Backup(const std::string& strDest) { - if (!env) { + if (IsDummy()) { return false; } while (true) diff --git a/src/wallet/db.h b/src/wallet/db.h index 748937a9086de..eee0e9f24c670 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -94,6 +94,12 @@ class CWalletDBWrapper { friend class CDB; public: + /** Create dummy DB handle */ + CWalletDBWrapper(): env(nullptr) + { + } + + /** Create DB handle to real database */ CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in): env(env_in), strFile(strFile_in) { @@ -111,6 +117,12 @@ class CWalletDBWrapper */ std::string GetName() const { return strFile; } + /** Return whether this database handle is a dummy for testing. + * Only to be used at a low level, application should ideally not care + * about this. + */ + bool IsDummy() { return env == nullptr; } + private: /** BerkeleyDB specific */ CDBEnv *env; @@ -188,7 +200,7 @@ class CDB bool Write(const K& key, const T& value, bool fOverwrite = true) { if (!pdb) - return false; + return true; if (fReadOnly) assert(!"Write called on database in read-only mode"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1c1739084f4da..615d4efe6b880 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3747,13 +3747,10 @@ UniValue setstakesplitthreshold(const JSONRPCRequest& request) CWalletDB walletdb(pwalletMain->GetDBHandle()); LOCK(pwalletMain->cs_wallet); { - bool fFileBacked = pwalletMain->fFileBacked; - UniValue result(UniValue::VOBJ); pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; result.pushKV("threshold", ValueFromAmount(pwalletMain->nStakeSplitThreshold)); - if (fFileBacked) { - walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold); + if (walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold)) { result.pushKV("saved", "true"); } else result.pushKV("saved", "false"); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 599478efb4ecc..9fd1691ea90b6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -209,8 +209,6 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey& pubkey) RemoveWatchOnly(script); } - if (!fFileBacked) - return true; if (!IsCrypted()) { return CWalletDB(*dbw).WriteKey( pubkey, @@ -225,8 +223,6 @@ bool CWallet::AddCryptedKey(const CPubKey& vchPubKey, { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; - if (!fFileBacked) - return true; { LOCK(cs_wallet); if (pwalletdbEncryption) @@ -258,8 +254,6 @@ bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) return false; - if (!fFileBacked) - return true; return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript); } @@ -284,8 +278,6 @@ bool CWallet::AddWatchOnly(const CScript& dest) return false; nTimeFirstKey = 1; // No birthday information for watch-only keys. NotifyWatchonlyChanged(true); - if (!fFileBacked) - return true; return CWalletDB(*dbw).WriteWatchOnly(dest); } @@ -296,9 +288,8 @@ bool CWallet::RemoveWatchOnly(const CScript& dest) return false; if (!HaveWatchOnly()) NotifyWatchonlyChanged(false); - if (fFileBacked) - if (!CWalletDB(*dbw).EraseWatchOnly(dest)) - return false; + if (!CWalletDB(*dbw).EraseWatchOnly(dest)) + return false; return true; } @@ -549,7 +540,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, if (nVersion > nWalletMaxVersion) nWalletMaxVersion = nVersion; - if (fFileBacked) { + { CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(*dbw); if (nWalletVersion > 40000) pwalletdb->WriteMinVersion(nWalletVersion); @@ -836,22 +827,19 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { LOCK(cs_wallet); mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; - if (fFileBacked) { - assert(!pwalletdbEncryption); - pwalletdbEncryption = new CWalletDB(*dbw); - if (!pwalletdbEncryption->TxnBegin()) { - delete pwalletdbEncryption; - pwalletdbEncryption = NULL; - return false; - } - pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey); + assert(!pwalletdbEncryption); + pwalletdbEncryption = new CWalletDB(*dbw); + if (!pwalletdbEncryption->TxnBegin()) { + delete pwalletdbEncryption; + pwalletdbEncryption = NULL; + return false; } + pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey); + if (!EncryptKeys(vMasterKey) || (m_sspk_man->IsEnabled() && !m_sspk_man->EncryptSaplingKeys(vMasterKey))) { - if (fFileBacked) { - pwalletdbEncryption->TxnAbort(); - delete pwalletdbEncryption; - } + pwalletdbEncryption->TxnAbort(); + delete pwalletdbEncryption; // We now probably have half of our keys encrypted in memory, and half not... // die and let the user reload their unencrypted wallet. assert(false); @@ -860,17 +848,16 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) // Encryption was introduced in version 0.4.0 SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true); - if (fFileBacked) { - if (!pwalletdbEncryption->TxnCommit()) { - delete pwalletdbEncryption; - // We now have keys encrypted in memory, but not on disk... - // die to avoid confusion and let the user reload their unencrypted wallet. - assert(false); - } - + if (!pwalletdbEncryption->TxnCommit()) { delete pwalletdbEncryption; - pwalletdbEncryption = NULL; + // We now have keys encrypted in memory, but not on disk... + // die to avoid confusion and let the user reload their unencrypted wallet. + assert(false); } + + delete pwalletdbEncryption; + pwalletdbEncryption = NULL; + Lock(); Unlock(strWalletPassphrase); // if we are using HD, replace the HD seed with a new one @@ -1277,8 +1264,6 @@ void CWallet::MarkAffectedTransactionsDirty(const CTransaction& tx) void CWallet::EraseFromWallet(const uint256& hash) { - if (!fFileBacked) - return; { LOCK(cs_wallet); if (mapWallet.erase(hash)) @@ -3156,9 +3141,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { LOCK2(cs_main, cs_wallet); - if (!fFileBacked) - return DB_LOAD_OK; - DBErrors nLoadWalletRet = CWalletDB(*dbw, "cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (dbw->Rewrite( "\x04pool")) { @@ -3184,8 +3166,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) DBErrors CWallet::ZapWalletTx(std::vector& vWtx) { - if (!fFileBacked) - return DB_LOAD_OK; DBErrors nZapWalletTxRet = CWalletDB(*dbw, "cr+").ZapWalletTx(this, vWtx); if (nZapWalletTxRet == DB_NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { @@ -3221,8 +3201,6 @@ bool CWallet::SetAddressBook(const CWDestination& address, const std::string& st } NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO, mapAddressBook.at(address).purpose, (fUpdated ? CT_UPDATED : CT_NEW)); - if (!fFileBacked) - return false; std::string addressStr = ParseIntoAddress(address, mapAddressBook.at(address).purpose); if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(addressStr, strPurpose)) return false; @@ -3236,19 +3214,15 @@ bool CWallet::DelAddressBook(const CWDestination& address, const CChainParams::B { LOCK(cs_wallet); // mapAddressBook - if (fFileBacked) { - // Delete destdata tuples associated with address - for (const std::pair & item : mapAddressBook[address].destdata) { - CWalletDB(*dbw).EraseDestData(strAddress, item.first); - } + // Delete destdata tuples associated with address + for (const std::pair & item : mapAddressBook[address].destdata) { + CWalletDB(*dbw).EraseDestData(strAddress, item.first); } mapAddressBook.erase(address); } NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, purpose, CT_DELETED); - if (!fFileBacked) - return false; CWalletDB(*dbw).ErasePurpose(strAddress); return CWalletDB(*dbw).EraseName(strAddress); } @@ -3677,8 +3651,6 @@ bool CWallet::AddDestData(const CTxDestination& dest, const std::string& key, co return false; mapAddressBook[dest].destdata.emplace(key, value); - if (!fFileBacked) - return true; return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value); } @@ -3686,8 +3658,6 @@ bool CWallet::EraseDestData(const CTxDestination& dest, const std::string& key) { if (!mapAddressBook[dest].destdata.erase(key)) return false; - if (!fFileBacked) - return true; return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key); } @@ -4266,7 +4236,7 @@ std::string CWallet::GetUniqueWalletBackupName() const return strprintf("%s%s", (dbw ? dbw->GetName() : "null"), DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); } -CWallet::CWallet() +CWallet::CWallet() : dbw(new CWalletDBWrapper()) { SetNull(); } @@ -4275,7 +4245,6 @@ CWallet::CWallet(std::unique_ptr dbw_in) : dbw(std::move(dbw_in)) { SetNull(); - fFileBacked = true; } CWallet::~CWallet() @@ -4288,7 +4257,6 @@ void CWallet::SetNull() { nWalletVersion = FEATURE_BASE; nWalletMaxVersion = FEATURE_BASE; - fFileBacked = false; nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; nOrderPosNext = 0; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index d0fbfb65c80a3..92c56abda32f8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -347,14 +347,10 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /* * Main wallet lock. - * This lock protects all the fields added by CWallet - * except for: - * fFileBacked (immutable after instantiation) - * strWalletFile (immutable after instantiation) + * This lock protects all the fields added by CWallet. */ mutable RecursiveMutex cs_wallet; - bool fFileBacked; bool fWalletUnlockStaking; CWalletDB* pwalletdbEncryption; @@ -408,7 +404,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface } } + // Create wallet with dummy database handle CWallet(); + // Create wallet with passed-in database handle CWallet(std::unique_ptr dbw_in); ~CWallet(); void SetNull(); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5deb98b6506d6..f91ccb24cecd0 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -934,9 +934,7 @@ bool BackupWallet(const CWallet& wallet, const fs::path& strDest, bool fEnableCu { fs::path pathCustom; fs::path pathWithFile; - if (!wallet.fFileBacked) { - return false; - } else if(fEnableCustom) { + if(fEnableCustom) { pathWithFile = gArgs.GetArg("-backuppath", ""); if(!pathWithFile.empty()) { if(!pathWithFile.has_extension()) { From f40006aacea72c522892ff6c1d0a8e4dc196f031 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 8 Mar 2017 13:34:47 +0000 Subject: [PATCH 3/9] wallet: Reduce references to global bitdb environment --- src/wallet/db.cpp | 76 +++++++++++++++++++++++++++-------------------- src/wallet/db.h | 5 ++++ 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 57b03922c17b7..84200807c06fe 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -354,6 +354,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; + env = dbw.env; if (dbw.IsDummy()) { return; } @@ -365,17 +366,17 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb nFlags |= DB_CREATE; { - LOCK(bitdb.cs_db); - if (!bitdb.Open(GetDataDir())) - throw std::runtime_error("CDB : Failed to open database environment."); + LOCK(env->cs_db); + if (!env->Open(GetDataDir())) + throw std::runtime_error("CDB: Failed to open database environment."); strFile = strFilename; - ++bitdb.mapFileUseCount[strFile]; - pdb = bitdb.mapDb[strFile]; + ++env->mapFileUseCount[strFile]; + pdb = env->mapDb[strFile]; if (pdb == NULL) { - pdb = new Db(bitdb.dbenv, 0); + pdb = new Db(env->dbenv, 0); - bool fMockDb = bitdb.IsMock(); + bool fMockDb = env->IsMock(); if (fMockDb) { DbMpoolFile* mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); @@ -393,7 +394,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb if (ret != 0) { delete pdb; pdb = NULL; - --bitdb.mapFileUseCount[strFile]; + --env->mapFileUseCount[strFile]; std::string tempCopy(strFile); strFile = ""; throw std::runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, tempCopy)); @@ -406,7 +407,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb fReadOnly = fTmp; } - bitdb.mapDb[strFile] = pdb; + env->mapDb[strFile] = pdb; } } } @@ -421,7 +422,7 @@ void CDB::Flush() if (fReadOnly) nMinutes = 1; - bitdb.dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); + env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); } void CDB::Close() @@ -437,8 +438,8 @@ void CDB::Close() Flush(); { - LOCK(bitdb.cs_db); - --bitdb.mapFileUseCount[strFile]; + LOCK(env->cs_db); + --env->mapFileUseCount[strFile]; } } @@ -470,22 +471,23 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) if (dbw.IsDummy()) { return true; } + CDBEnv *env = dbw.env; const std::string& strFile = dbw.strFile; while (true) { { - LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { + LOCK(env->cs_db); + if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) { // Flush log data to the dat file - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(strFile); + env->CloseDb(strFile); + env->CheckpointLSN(strFile); + env->mapFileUseCount.erase(strFile); bool fSuccess = true; LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(dbw, "r"); - Db* pdbCopy = new Db(bitdb.dbenv, 0); + Db* pdbCopy = new Db(env->dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename @@ -528,17 +530,17 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) } if (fSuccess) { db.Close(); - bitdb.CloseDb(strFile); + env->CloseDb(strFile); if (pdbCopy->close(0)) fSuccess = false; delete pdbCopy; } } if (fSuccess) { - Db dbA(bitdb.dbenv, 0); + Db dbA(env->dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; - Db dbB(bitdb.dbenv, 0); + Db dbB(env->dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } @@ -599,30 +601,31 @@ bool CDB::PeriodicFlush(CWalletDBWrapper& dbw) return true; } bool ret = false; + CDBEnv *env = dbw.env; const std::string& strFile = dbw.strFile; TRY_LOCK(bitdb.cs_db,lockDb); if (lockDb) { // Don't do this if any databases are in use int nRefCount = 0; - std::map::iterator mi = bitdb.mapFileUseCount.begin(); - while (mi != bitdb.mapFileUseCount.end()) { + std::map::iterator mi = env->mapFileUseCount.begin(); + while (mi != env->mapFileUseCount.end()) { nRefCount += (*mi).second; mi++; } if (nRefCount == 0) { boost::this_thread::interruption_point(); - std::map::iterator _mi = bitdb.mapFileUseCount.find(strFile); - if (_mi != bitdb.mapFileUseCount.end()) { + std::map::iterator _mi = env->mapFileUseCount.find(strFile); + if (_mi != env->mapFileUseCount.end()) { LogPrint(BCLog::DB, "Flushing %s\n", strFile); int64_t nStart = GetTimeMillis(); // Flush wallet file so it's self contained - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); + env->CloseDb(strFile); + env->CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(_mi++); + env->mapFileUseCount.erase(_mi++); LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); ret = true; } @@ -645,13 +648,13 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) while (true) { { - LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) + LOCK(env->cs_db); + if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) { // Flush log data to the dat file - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(strFile); + env->CloseDb(strFile); + env->CheckpointLSN(strFile); + env->mapFileUseCount.erase(strFile); // Copy wallet file fs::path pathSrc = GetDataDir() / strFile; @@ -677,3 +680,10 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) } return false; } + +void CWalletDBWrapper::Flush(bool shutdown) +{ + if (!IsDummy()) { + env->Flush(shutdown); + } +} diff --git a/src/wallet/db.h b/src/wallet/db.h index eee0e9f24c670..a0280dfc95519 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -117,6 +117,10 @@ class CWalletDBWrapper */ std::string GetName() const { return strFile; } + /** Make sure all changes are flushed to disk. + */ + void Flush(bool shutdown); + /** Return whether this database handle is a dummy for testing. * Only to be used at a low level, application should ideally not care * about this. @@ -139,6 +143,7 @@ class CDB DbTxn* activeTxn; bool fReadOnly; bool fFlushOnClose; + CDBEnv *env; explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true); ~CDB() { Close(); } From 2132f42b39b697a3750a5b6fba44b4d6c317d485 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 8 Mar 2017 16:20:08 +0000 Subject: [PATCH 4/9] wallet: CWalletDB CDB composition not inheritance CWalletDB now contains a CDB instead of inheriting from it. This makes it easier to replace the internal transaction with a different database, without leaking through internals. --- src/wallet/db.h | 4 +- src/wallet/walletdb.cpp | 205 ++++++++++++++++++++++------------------ src/wallet/walletdb.h | 18 +++- 3 files changed, 133 insertions(+), 94 deletions(-) diff --git a/src/wallet/db.h b/src/wallet/db.h index a0280dfc95519..ee6917301070d 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -145,10 +145,10 @@ class CDB bool fFlushOnClose; CDBEnv *env; +public: explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true); ~CDB() { Close(); } -public: void Flush(); void Close(); static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue)); @@ -165,7 +165,7 @@ class CDB CDB(const CDB&); void operator=(const CDB&); -protected: +public: template bool Read(const K& key, T& value) { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f91ccb24cecd0..2fdfbff113870 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -35,7 +35,7 @@ static std::atomic nWalletDBUpdateCounter; bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("name"), strAddress), strName); + return batch.Write(std::make_pair(std::string("name"), strAddress), strName); } bool CWalletDB::EraseName(const std::string& strAddress) @@ -43,39 +43,39 @@ bool CWalletDB::EraseName(const std::string& strAddress) // This should only be used for sending addresses, never for receiving addresses, // receiving addresses must always have an address book entry if they're not change return. nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("name"), strAddress)); + return batch.Erase(std::make_pair(std::string("name"), strAddress)); } bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("purpose"), strAddress), strPurpose); + return batch.Write(std::make_pair(std::string("purpose"), strAddress), strPurpose); } bool CWalletDB::ErasePurpose(const std::string& strPurpose) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("purpose"), strPurpose)); + return batch.Erase(std::make_pair(std::string("purpose"), strPurpose)); } bool CWalletDB::WriteTx(const CWalletTx& wtx) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); + return batch.Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); } bool CWalletDB::EraseTx(uint256 hash) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("tx"), hash)); + return batch.Erase(std::make_pair(std::string("tx"), hash)); } bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) { nWalletDBUpdateCounter++; - if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), - keyMeta, false)) + if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey), + keyMeta, false)) return false; // hash pubkey/privkey to accelerate wallet load @@ -84,7 +84,7 @@ bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, c vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); - return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); + return batch.Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); } bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, @@ -94,15 +94,15 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, const bool fEraseUnencryptedKey = true; nWalletDBUpdateCounter++; - if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), + if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) return false; - if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) + if (!batch.Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) return false; if (fEraseUnencryptedKey) { - Erase(std::make_pair(std::string("key"), vchPubKey)); - Erase(std::make_pair(std::string("wkey"), vchPubKey)); + batch.Erase(std::make_pair(std::string("key"), vchPubKey)); + batch.Erase(std::make_pair(std::string("wkey"), vchPubKey)); } return true; } @@ -113,10 +113,10 @@ bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk, { nWalletDBUpdateCounter++; - if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta)) + if (!batch.Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta)) return false; - return Write(std::make_pair(std::string("sapzkey"), ivk), key, false); + return batch.Write(std::make_pair(std::string("sapzkey"), ivk), key, false); } bool CWalletDB::WriteSaplingPaymentAddress( @@ -125,7 +125,7 @@ bool CWalletDB::WriteSaplingPaymentAddress( { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("sapzaddr"), addr), ivk, false); + return batch.Write(std::make_pair(std::string("sapzaddr"), addr), ivk, false); } bool CWalletDB::WriteCryptedSaplingZKey( @@ -137,14 +137,14 @@ bool CWalletDB::WriteCryptedSaplingZKey( nWalletDBUpdateCounter++; auto ivk = extfvk.fvk.in_viewing_key(); - if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta)) + if (!batch.Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta)) return false; - if (!Write(std::make_pair(std::string("csapzkey"), ivk), std::make_pair(extfvk, vchCryptedSecret), false)) + if (!batch.Write(std::make_pair(std::string("csapzkey"), ivk), std::make_pair(extfvk, vchCryptedSecret), false)) return false; if (fEraseUnencryptedKey) { - Erase(std::make_pair(std::string("sapzkey"), ivk)); + batch.Erase(std::make_pair(std::string("sapzkey"), ivk)); } return true; } @@ -152,91 +152,91 @@ bool CWalletDB::WriteCryptedSaplingZKey( bool CWalletDB::WriteSaplingCommonOVK(const uint256& ovk) { nWalletDBUpdateCounter++; - return Write(std::string("commonovk"), ovk); + return batch.Write(std::string("commonovk"), ovk); } bool CWalletDB::ReadSaplingCommonOVK(uint256& ovkRet) { - return Read(std::string("commonovk"), ovkRet); + return batch.Read(std::string("commonovk"), ovkRet); } bool CWalletDB::WriteWitnessCacheSize(int64_t nWitnessCacheSize) { nWalletDBUpdateCounter++; - return Write(std::string("witnesscachesize"), nWitnessCacheSize); + return batch.Write(std::string("witnesscachesize"), nWitnessCacheSize); } bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); + return batch.Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); } bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false); + return batch.Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false); } bool CWalletDB::WriteWatchOnly(const CScript& dest) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); + return batch.Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); } bool CWalletDB::EraseWatchOnly(const CScript& dest) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); + return batch.Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); } bool CWalletDB::WriteMultiSig(const CScript& dest) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("multisig"), *(const CScriptBase*)(&dest)), '1'); + return batch.Write(std::make_pair(std::string("multisig"), *(const CScriptBase*)(&dest)), '1'); } bool CWalletDB::EraseMultiSig(const CScript& dest) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("multisig"), *(const CScriptBase*)(&dest))); + return batch.Erase(std::make_pair(std::string("multisig"), *(const CScriptBase*)(&dest))); } bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) { nWalletDBUpdateCounter++; - Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan - return Write(std::string("bestblock_nomerkle"), locator); + batch.Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan + return batch.Write(std::string("bestblock_nomerkle"), locator); } bool CWalletDB::ReadBestBlock(CBlockLocator& locator) { - if (Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true; - return Read(std::string("bestblock_nomerkle"), locator); + if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true; + return batch.Read(std::string("bestblock_nomerkle"), locator); } bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext) { nWalletDBUpdateCounter++; - return Write(std::string("orderposnext"), nOrderPosNext); + return batch.Write(std::string("orderposnext"), nOrderPosNext); } bool CWalletDB::WriteStakeSplitThreshold(const CAmount& nStakeSplitThreshold) { nWalletDBUpdateCounter++; - return Write(std::string("stakeSplitThreshold"), nStakeSplitThreshold); + return batch.Write(std::string("stakeSplitThreshold"), nStakeSplitThreshold); } bool CWalletDB::WriteUseCustomFee(bool fUse) { nWalletDBUpdateCounter++; - return Write(std::string("fUseCustomFee"), fUse); + return batch.Write(std::string("fUseCustomFee"), fUse); } bool CWalletDB::WriteCustomFeeValue(const CAmount& nFee) { nWalletDBUpdateCounter++; - return Write(std::string("nCustomFee"), nFee); + return batch.Write(std::string("nCustomFee"), nFee); } bool CWalletDB::WriteMultiSend(std::vector > vMultiSend) @@ -304,7 +304,7 @@ bool CWalletDB::EraseMSDisabledAddresses(std::vector vDisabledAddre nWalletDBUpdateCounter++; bool ret = true; for (unsigned int i = 0; i < vDisabledAddresses.size(); i++) { - if (!Erase(std::make_pair(std::string("mdisabled"), i))) + if (!batch.Erase(std::make_pair(std::string("mdisabled"), i))) ret = false; } return ret; @@ -317,29 +317,29 @@ bool CWalletDB::WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold std::pair pSettings; pSettings.first = fEnable; pSettings.second = nCombineThreshold; - return Write(std::string("autocombinesettings"), pSettings, true); + return batch.Write(std::string("autocombinesettings"), pSettings, true); } bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool) { - return Read(std::make_pair(std::string("pool"), nPool), keypool); + return batch.Read(std::make_pair(std::string("pool"), nPool), keypool); } bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("pool"), nPool), keypool); + return batch.Write(std::make_pair(std::string("pool"), nPool), keypool); } bool CWalletDB::ErasePool(int64_t nPool) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("pool"), nPool)); + return batch.Erase(std::make_pair(std::string("pool"), nPool)); } bool CWalletDB::WriteMinVersion(int nVersion) { - return Write(std::string("minversion"), nVersion); + return batch.Write(std::string("minversion"), nVersion); } bool CWalletDB::WriteHDChain(const CHDChain& chain) @@ -348,7 +348,7 @@ bool CWalletDB::WriteHDChain(const CHDChain& chain) std::string key = std::string("hdchain"); if (chain.chainType == HDChain::ChainCounterType::Sapling) key += std::string("_sap"); - return Write(key, chain); + return batch.Write(key, chain); } DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) @@ -731,14 +731,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) LOCK(pwallet->cs_wallet); try { int nMinVersion = 0; - if (Read((std::string) "minversion", nMinVersion)) { + if (batch.Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; pwallet->LoadMinVersion(nMinVersion); } // Get cursor - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); return DB_CORRUPT; @@ -748,7 +748,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue); if (ret == DB_NOTFOUND) break; else if (ret != 0) { @@ -825,14 +825,14 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, std::vector& vTxHash try { LOCK(pwallet->cs_wallet); int nMinVersion = 0; - if (Read((std::string) "minversion", nMinVersion)) { + if (batch.Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; pwallet->LoadMinVersion(nMinVersion); } // Get cursor - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); return DB_CORRUPT; @@ -842,7 +842,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, std::vector& vTxHash // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue); if (ret == DB_NOTFOUND) break; else if (ret != 0) { @@ -1116,44 +1116,44 @@ bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path bool CWalletDB::WriteDestData(const std::string& address, const std::string& key, const std::string& value) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); + return batch.Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); } bool CWalletDB::EraseDestData(const std::string& address, const std::string& key) { nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); + return batch.Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); } bool CWalletDB::WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend) { - return Write(std::make_pair(std::string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); + return batch.Write(std::make_pair(std::string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); } bool CWalletDB::EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry) { - return Erase(std::make_pair(std::string("zcserial"), serialEntry)); + return batch.Erase(std::make_pair(std::string("zcserial"), serialEntry)); } bool CWalletDB::ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial) { CZerocoinSpend spend; - return Read(std::make_pair(std::string("zcserial"), bnSerial), spend); + return batch.Read(std::make_pair(std::string("zcserial"), bnSerial), spend); } bool CWalletDB::WriteDeterministicMint(const CDeterministicMint& dMint) { uint256 hash = dMint.GetPubcoinHash(); - return Write(std::make_pair(std::string("dzpiv"), hash), dMint, true); + return batch.Write(std::make_pair(std::string("dzpiv"), hash), dMint, true); } bool CWalletDB::ReadDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) { - return Read(std::make_pair(std::string("dzpiv"), hashPubcoin), dMint); + return batch.Read(std::make_pair(std::string("dzpiv"), hashPubcoin), dMint); } bool CWalletDB::EraseDeterministicMint(const uint256& hashPubcoin) { - return Erase(std::make_pair(std::string("dzpiv"), hashPubcoin)); + return batch.Erase(std::make_pair(std::string("dzpiv"), hashPubcoin)); } bool CWalletDB::WriteZerocoinMint(const CZerocoinMint& zerocoinMint) @@ -1162,8 +1162,8 @@ bool CWalletDB::WriteZerocoinMint(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end()); - Erase(std::make_pair(std::string("zerocoin"), hash)); - return Write(std::make_pair(std::string("zerocoin"), hash), zerocoinMint, true); + batch.Erase(std::make_pair(std::string("zerocoin"), hash)); + return batch.Write(std::make_pair(std::string("zerocoin"), hash), zerocoinMint, true); } bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& zerocoinMint) @@ -1177,7 +1177,7 @@ bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& z bool CWalletDB::ReadZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) { - return Read(std::make_pair(std::string("zerocoin"), hashPubcoin), mint); + return batch.Read(std::make_pair(std::string("zerocoin"), hashPubcoin), mint); } bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) @@ -1186,7 +1186,7 @@ bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end()); - return Erase(std::make_pair(std::string("zerocoin"), hash)); + return batch.Erase(std::make_pair(std::string("zerocoin"), hash)); } bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) @@ -1195,12 +1195,12 @@ bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) ss << zerocoinMint.GetValue(); uint256 hash = Hash(ss.begin(), ss.end());; - if (!Write(std::make_pair(std::string("zco"), hash), zerocoinMint)) { + if (!batch.Write(std::make_pair(std::string("zco"), hash), zerocoinMint)) { LogPrintf("%s : failed to database orphaned zerocoin mint\n", __func__); return false; } - if (!Erase(std::make_pair(std::string("zerocoin"), hash))) { + if (!batch.Erase(std::make_pair(std::string("zerocoin"), hash))) { LogPrintf("%s : failed to erase orphaned zerocoin mint\n", __func__); return false; } @@ -1210,10 +1210,10 @@ bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) bool CWalletDB::ArchiveDeterministicOrphan(const CDeterministicMint& dMint) { - if (!Write(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()), dMint)) + if (!batch.Write(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()), dMint)) return error("%s: write failed", __func__); - if (!Erase(std::make_pair(std::string("dzpiv"), dMint.GetPubcoinHash()))) + if (!batch.Erase(std::make_pair(std::string("dzpiv"), dMint.GetPubcoinHash()))) return error("%s: failed to erase", __func__); return true; @@ -1221,13 +1221,13 @@ bool CWalletDB::ArchiveDeterministicOrphan(const CDeterministicMint& dMint) bool CWalletDB::UnarchiveDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) { - if (!Read(std::make_pair(std::string("dzco"), hashPubcoin), dMint)) + if (!batch.Read(std::make_pair(std::string("dzco"), hashPubcoin), dMint)) return error("%s: failed to retrieve deterministic mint from archive", __func__); if (!WriteDeterministicMint(dMint)) return error("%s: failed to write deterministic mint", __func__); - if (!Erase(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()))) + if (!batch.Erase(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()))) return error("%s : failed to erase archived deterministic mint", __func__); return true; @@ -1235,14 +1235,14 @@ bool CWalletDB::UnarchiveDeterministicMint(const uint256& hashPubcoin, CDetermin bool CWalletDB::UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) { - if (!Read(std::make_pair(std::string("zco"), hashPubcoin), mint)) + if (!batch.Read(std::make_pair(std::string("zco"), hashPubcoin), mint)) return error("%s: failed to retrieve zerocoinmint from archive", __func__); if (!WriteZerocoinMint(mint)) return error("%s: failed to write zerocoinmint", __func__); uint256 hash = GetPubCoinHash(mint.GetValue()); - if (!Erase(std::make_pair(std::string("zco"), hash))) + if (!batch.Erase(std::make_pair(std::string("zco"), hash))) return error("%s : failed to erase archived zerocoin mint", __func__); return true; @@ -1250,12 +1250,12 @@ bool CWalletDB::UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& bool CWalletDB::WriteCurrentSeedHash(const uint256& hashSeed) { - return Write(std::string("seedhash"), hashSeed); + return batch.Write(std::string("seedhash"), hashSeed); } bool CWalletDB::ReadCurrentSeedHash(uint256& hashSeed) { - return Read(std::string("seedhash"), hashSeed); + return batch.Read(std::string("seedhash"), hashSeed); } bool CWalletDB::WriteZPIVSeed(const uint256& hashSeed, const std::vector& seed) @@ -1263,7 +1263,7 @@ bool CWalletDB::WriteZPIVSeed(const uint256& hashSeed, const std::vector& seed) { - return Read(std::make_pair(std::string("dzs"), hashSeed), seed); + return batch.Read(std::make_pair(std::string("dzs"), hashSeed), seed); } bool CWalletDB::ReadZPIVSeed_deprecated(uint256& seed) { - return Read(std::string("dzs"), seed); + return batch.Read(std::string("dzs"), seed); } bool CWalletDB::WriteZPIVCount(const uint32_t& nCount) { - return Write(std::string("dzc"), nCount); + return batch.Write(std::string("dzc"), nCount); } bool CWalletDB::ReadZPIVCount(uint32_t& nCount) { - return Read(std::string("dzc"), nCount); + return batch.Read(std::string("dzc"), nCount); } bool CWalletDB::WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& hashPubcoin, const uint32_t& nCount) { - return Write(std::make_pair(std::string("mintpool"), hashPubcoin), std::make_pair(hashMasterSeed, nCount)); + return batch.Write(std::make_pair(std::string("mintpool"), hashPubcoin), std::make_pair(hashMasterSeed, nCount)); } @@ -1317,7 +1317,7 @@ bool CWalletDB::WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& std::map > > CWalletDB::MapMintPool() { std::map > > mapPool; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1328,7 +1328,7 @@ std::map > > CWalletDB::MapMin if (setRange) ssKey << std::make_pair(std::string("mintpool"), UINT256_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1373,7 +1373,7 @@ std::map > > CWalletDB::MapMin std::list CWalletDB::ListDeterministicMints() { std::list listMints; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1384,7 +1384,7 @@ std::list CWalletDB::ListDeterministicMints() if (setRange) ssKey << make_pair(std::string("dzpiv"), UINT256_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1416,7 +1416,7 @@ std::list CWalletDB::ListDeterministicMints() std::list CWalletDB::ListMintedCoins() { std::list listPubCoin; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1429,7 +1429,7 @@ std::list CWalletDB::ListMintedCoins() if (setRange) ssKey << make_pair(std::string("zerocoin"), UINT256_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1461,7 +1461,7 @@ std::list CWalletDB::ListMintedCoins() std::list CWalletDB::ListSpentCoins() { std::list listCoinSpend; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1472,7 +1472,7 @@ std::list CWalletDB::ListSpentCoins() if (setRange) ssKey << make_pair(std::string("zcserial"), BN_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1516,7 +1516,7 @@ std::list CWalletDB::ListSpentCoinsSerial() std::list CWalletDB::ListArchivedZerocoins() { std::list listMints; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1527,7 +1527,7 @@ std::list CWalletDB::ListArchivedZerocoins() if (setRange) ssKey << make_pair(std::string("zco"), BN_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1559,7 +1559,7 @@ std::list CWalletDB::ListArchivedZerocoins() std::list CWalletDB::ListArchivedDeterministicMints() { std::list listMints; - Dbc* pcursor = GetCursor(); + Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); bool setRange = true; @@ -1570,7 +1570,7 @@ std::list CWalletDB::ListArchivedDeterministicMints() if (setRange) ssKey << make_pair(std::string("dzco"), BN_ZERO); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; @@ -1608,3 +1608,28 @@ unsigned int CWalletDB::GetUpdateCounter() { return nWalletDBUpdateCounter; } + +bool CWalletDB::TxnBegin() +{ + return batch.TxnBegin(); +} + +bool CWalletDB::TxnCommit() +{ + return batch.TxnCommit(); +} + +bool CWalletDB::TxnAbort() +{ + return batch.TxnAbort(); +} + +bool CWalletDB::ReadVersion(int& nVersion) +{ + return batch.ReadVersion(nVersion); +} + +bool CWalletDB::WriteVersion(int nVersion) +{ + return batch.WriteVersion(nVersion); +} diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index b86fe59c7c806..a044e2c038330 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -103,10 +103,11 @@ class CKeyMetadata * database. It will be committed when the object goes out of scope. * Optionally (on by default) it will flush to disk as well. */ -class CWalletDB : public CDB +class CWalletDB { public: - CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(dbw, pszMode, fFlushOnClose) + CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) : + batch(dbw, pszMode, _fFlushOnClose) { } @@ -230,7 +231,20 @@ class CWalletDB : public CDB static void IncrementUpdateCounter(); static unsigned int GetUpdateCounter(); + + //! Begin a new transaction + bool TxnBegin(); + //! Commit current transaction + bool TxnCommit(); + //! Abort current transaction + bool TxnAbort(); + //! Read wallet version + bool ReadVersion(int& nVersion); + //! Write wallet version + bool WriteVersion(int nVersion); private: + CDB batch; + CWalletDB(const CWalletDB&); void operator=(const CWalletDB&); }; From 08d2310005d8acd0a5ba035b605d4720fb906530 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 20 Apr 2017 17:52:47 +0200 Subject: [PATCH 5/9] wallet: Make IsDummy private in CWalletDBWrapper This is only for use in the low-level functions, and CDB is already a friend class. --- src/wallet/db.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/wallet/db.h b/src/wallet/db.h index ee6917301070d..a280a64007bf4 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -121,16 +121,16 @@ class CWalletDBWrapper */ void Flush(bool shutdown); +private: + /** BerkeleyDB specific */ + CDBEnv *env; + std::string strFile; + /** Return whether this database handle is a dummy for testing. * Only to be used at a low level, application should ideally not care * about this. */ bool IsDummy() { return env == nullptr; } - -private: - /** BerkeleyDB specific */ - CDBEnv *env; - std::string strFile; }; From 53ad1f6d3dfc167e35efece87ba47a92609c92e7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 21 Apr 2017 16:04:26 +0200 Subject: [PATCH 6/9] wallet: Add comment describing the various classes in walletdb.h --- src/wallet/walletdb.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index a044e2c038330..4f7545d9fddf8 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -23,6 +23,21 @@ #include #include +/** + * Overview of wallet database classes: + * + * - CDBEnv is an environment in which the database exists (has no analog in dbwrapper.h) + * - CWalletDBWrapper represents a wallet database (similar to CDBWrapper in dbwrapper.h) + * - CDB is a low-level database transaction (similar to CDBBatch in dbwrapper.h) + * - CWalletDB is a modifier object for the wallet, and encapsulates a database + * transaction as well as methods to act on the database (no analog in + * dbwrapper.h) + * + * The latter two are named confusingly, in contrast to what the names CDB + * and CWalletDB suggest they are transient transaction objects and don't + * represent the database itself. + */ + static const bool DEFAULT_FLUSHWALLET = true; struct CBlockLocator; From 78c86791ac1c2a41648d003ca93e7b02b1d26278 Mon Sep 17 00:00:00 2001 From: furszy Date: Fri, 8 Jan 2021 21:03:30 -0300 Subject: [PATCH 7/9] [Cleanup] walletdb: removing all of the zerocoin related not used methods. --- src/wallet/walletdb.cpp | 478 +--------------------------------------- src/wallet/walletdb.h | 38 ---- 2 files changed, 1 insertion(+), 515 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 2fdfbff113870..7bcf583a59a19 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -14,14 +14,12 @@ #include "sapling/key_io_sapling.h" #include "serialize.h" #include "sync.h" -#include "txdb.h" #include "util.h" #include "utiltime.h" #include "wallet/wallet.h" #include #include -#include #include #include @@ -801,7 +799,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' - for (uint256 hash : wss.vWalletUpgrade) + for (const uint256& hash : wss.vWalletUpgrade) WriteTx(pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: @@ -1125,480 +1123,6 @@ bool CWalletDB::EraseDestData(const std::string& address, const std::string& key return batch.Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); } -bool CWalletDB::WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend) -{ - return batch.Write(std::make_pair(std::string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); -} -bool CWalletDB::EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry) -{ - return batch.Erase(std::make_pair(std::string("zcserial"), serialEntry)); -} - -bool CWalletDB::ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial) -{ - CZerocoinSpend spend; - return batch.Read(std::make_pair(std::string("zcserial"), bnSerial), spend); -} - -bool CWalletDB::WriteDeterministicMint(const CDeterministicMint& dMint) -{ - uint256 hash = dMint.GetPubcoinHash(); - return batch.Write(std::make_pair(std::string("dzpiv"), hash), dMint, true); -} - -bool CWalletDB::ReadDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) -{ - return batch.Read(std::make_pair(std::string("dzpiv"), hashPubcoin), dMint); -} - -bool CWalletDB::EraseDeterministicMint(const uint256& hashPubcoin) -{ - return batch.Erase(std::make_pair(std::string("dzpiv"), hashPubcoin)); -} - -bool CWalletDB::WriteZerocoinMint(const CZerocoinMint& zerocoinMint) -{ - CDataStream ss(SER_GETHASH, 0); - ss << zerocoinMint.GetValue(); - uint256 hash = Hash(ss.begin(), ss.end()); - - batch.Erase(std::make_pair(std::string("zerocoin"), hash)); - return batch.Write(std::make_pair(std::string("zerocoin"), hash), zerocoinMint, true); -} - -bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& zerocoinMint) -{ - CDataStream ss(SER_GETHASH, 0); - ss << bnPubCoinValue; - uint256 hash = Hash(ss.begin(), ss.end()); - - return ReadZerocoinMint(hash, zerocoinMint); -} - -bool CWalletDB::ReadZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) -{ - return batch.Read(std::make_pair(std::string("zerocoin"), hashPubcoin), mint); -} - -bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) -{ - CDataStream ss(SER_GETHASH, 0); - ss << zerocoinMint.GetValue(); - uint256 hash = Hash(ss.begin(), ss.end()); - - return batch.Erase(std::make_pair(std::string("zerocoin"), hash)); -} - -bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) -{ - CDataStream ss(SER_GETHASH, 0); - ss << zerocoinMint.GetValue(); - uint256 hash = Hash(ss.begin(), ss.end());; - - if (!batch.Write(std::make_pair(std::string("zco"), hash), zerocoinMint)) { - LogPrintf("%s : failed to database orphaned zerocoin mint\n", __func__); - return false; - } - - if (!batch.Erase(std::make_pair(std::string("zerocoin"), hash))) { - LogPrintf("%s : failed to erase orphaned zerocoin mint\n", __func__); - return false; - } - - return true; -} - -bool CWalletDB::ArchiveDeterministicOrphan(const CDeterministicMint& dMint) -{ - if (!batch.Write(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()), dMint)) - return error("%s: write failed", __func__); - - if (!batch.Erase(std::make_pair(std::string("dzpiv"), dMint.GetPubcoinHash()))) - return error("%s: failed to erase", __func__); - - return true; -} - -bool CWalletDB::UnarchiveDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint) -{ - if (!batch.Read(std::make_pair(std::string("dzco"), hashPubcoin), dMint)) - return error("%s: failed to retrieve deterministic mint from archive", __func__); - - if (!WriteDeterministicMint(dMint)) - return error("%s: failed to write deterministic mint", __func__); - - if (!batch.Erase(std::make_pair(std::string("dzco"), dMint.GetPubcoinHash()))) - return error("%s : failed to erase archived deterministic mint", __func__); - - return true; -} - -bool CWalletDB::UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint) -{ - if (!batch.Read(std::make_pair(std::string("zco"), hashPubcoin), mint)) - return error("%s: failed to retrieve zerocoinmint from archive", __func__); - - if (!WriteZerocoinMint(mint)) - return error("%s: failed to write zerocoinmint", __func__); - - uint256 hash = GetPubCoinHash(mint.GetValue()); - if (!batch.Erase(std::make_pair(std::string("zco"), hash))) - return error("%s : failed to erase archived zerocoin mint", __func__); - - return true; -} - -bool CWalletDB::WriteCurrentSeedHash(const uint256& hashSeed) -{ - return batch.Write(std::string("seedhash"), hashSeed); -} - -bool CWalletDB::ReadCurrentSeedHash(uint256& hashSeed) -{ - return batch.Read(std::string("seedhash"), hashSeed); -} - -bool CWalletDB::WriteZPIVSeed(const uint256& hashSeed, const std::vector& seed) -{ - if (!WriteCurrentSeedHash(hashSeed)) - return error("%s: failed to write current seed hash", __func__); - - return batch.Write(std::make_pair(std::string("dzs"), hashSeed), seed); -} - -bool CWalletDB::EraseZPIVSeed() -{ - uint256 hash; - if(!ReadCurrentSeedHash(hash)){ - return error("Failed to read a current seed hash"); - } - if(!WriteZPIVSeed(hash, ToByteVector(base_uint<256>(0) << 256))) { - return error("Failed to write empty seed to wallet"); - } - if(!WriteCurrentSeedHash(UINT256_ZERO)) { - return error("Failed to write empty seedHash"); - } - - return true; -} - -bool CWalletDB::EraseZPIVSeed_deprecated() -{ - return batch.Erase(std::string("dzs")); -} - -bool CWalletDB::ReadZPIVSeed(const uint256& hashSeed, std::vector& seed) -{ - return batch.Read(std::make_pair(std::string("dzs"), hashSeed), seed); -} - -bool CWalletDB::ReadZPIVSeed_deprecated(uint256& seed) -{ - return batch.Read(std::string("dzs"), seed); -} - -bool CWalletDB::WriteZPIVCount(const uint32_t& nCount) -{ - return batch.Write(std::string("dzc"), nCount); -} - -bool CWalletDB::ReadZPIVCount(uint32_t& nCount) -{ - return batch.Read(std::string("dzc"), nCount); -} - -bool CWalletDB::WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& hashPubcoin, const uint32_t& nCount) -{ - return batch.Write(std::make_pair(std::string("mintpool"), hashPubcoin), std::make_pair(hashMasterSeed, nCount)); -} - - -//! map with hashMasterSeed as the key, paired with vector of hashPubcoins and their count -std::map > > CWalletDB::MapMintPool() -{ - std::map > > mapPool; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << std::make_pair(std::string("mintpool"), UINT256_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "mintpool") - break; - - uint256 hashPubcoin; - ssKey >> hashPubcoin; - - uint256 hashMasterSeed; - ssValue >> hashMasterSeed; - - uint32_t nCount; - ssValue >> nCount; - - std::pair pMint; - pMint.first = hashPubcoin; - pMint.second = nCount; - if (mapPool.count(hashMasterSeed)) { - mapPool.at(hashMasterSeed).emplace_back(pMint); - } else { - std::vector > vPairs; - vPairs.emplace_back(pMint); - mapPool.emplace(hashMasterSeed, vPairs); - } - } - - pcursor->close(); - - return mapPool; -} - -std::list CWalletDB::ListDeterministicMints() -{ - std::list listMints; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << make_pair(std::string("dzpiv"), UINT256_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "dzpiv") - break; - - uint256 hashPubcoin; - ssKey >> hashPubcoin; - - CDeterministicMint mint; - ssValue >> mint; - - listMints.emplace_back(mint); - } - - pcursor->close(); - return listMints; -} - -std::list CWalletDB::ListMintedCoins() -{ - std::list listPubCoin; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - std::vector vOverWrite; - std::vector vArchive; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << make_pair(std::string("zerocoin"), UINT256_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "zerocoin") - break; - - uint256 hashPubcoin; - ssKey >> hashPubcoin; - - CZerocoinMint mint; - ssValue >> mint; - - listPubCoin.emplace_back(mint); - } - - pcursor->close(); - return listPubCoin; -} - -std::list CWalletDB::ListSpentCoins() -{ - std::list listCoinSpend; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << make_pair(std::string("zcserial"), BN_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "zcserial") - break; - - CBigNum value; - ssKey >> value; - - CZerocoinSpend zerocoinSpendItem; - ssValue >> zerocoinSpendItem; - - listCoinSpend.push_back(zerocoinSpendItem); - } - - pcursor->close(); - return listCoinSpend; -} - -// Just get the Serial Numbers -std::list CWalletDB::ListSpentCoinsSerial() -{ - std::list listPubCoin; - std::list listCoins = ListSpentCoins(); - - for ( auto& coin : listCoins) { - listPubCoin.push_back(coin.GetSerial()); - } - return listPubCoin; -} - -std::list CWalletDB::ListArchivedZerocoins() -{ - std::list listMints; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << make_pair(std::string("zco"), BN_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "zco") - break; - - uint256 value; - ssKey >> value; - - CZerocoinMint mint; - ssValue >> mint; - - listMints.push_back(mint); - } - - pcursor->close(); - return listMints; -} - -std::list CWalletDB::ListArchivedDeterministicMints() -{ - std::list listMints; - Dbc* pcursor = batch.GetCursor(); - if (!pcursor) - throw std::runtime_error(std::string(__func__)+" : cannot create DB cursor"); - bool setRange = true; - for (;;) - { - // Read next record - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (setRange) - ssKey << make_pair(std::string("dzco"), BN_ZERO); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); - setRange = false; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw std::runtime_error(std::string(__func__)+" : error scanning DB"); - } - - // Unserialize - std::string strType; - ssKey >> strType; - if (strType != "dzco") - break; - - uint256 value; - ssKey >> value; - - CDeterministicMint dMint; - ssValue >> dMint; - - listMints.emplace_back(dMint); - } - - pcursor->close(); - return listMints; -} - void CWalletDB::IncrementUpdateCounter() { nWalletDBUpdateCounter++; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 4f7545d9fddf8..20f45a74db0f1 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -13,9 +13,6 @@ #include "key.h" #include "keystore.h" #include "script/keyorigin.h" -#include "zpiv/zerocoin.h" -#include "libzerocoin/Accumulator.h" -#include "libzerocoin/Denominations.h" #include #include @@ -47,8 +44,6 @@ class CScript; class CWallet; class CWalletTx; class CDeterministicMint; -class CZerocoinMint; -class CZerocoinSpend; class uint160; class uint256; @@ -211,39 +206,6 @@ class CWalletDB /* verifies the database file */ static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr); - bool WriteDeterministicMint(const CDeterministicMint& dMint); - bool ReadDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint); - bool EraseDeterministicMint(const uint256& hashPubcoin); - bool WriteZerocoinMint(const CZerocoinMint& zerocoinMint); - bool EraseZerocoinMint(const CZerocoinMint& zerocoinMint); - bool ReadZerocoinMint(const CBigNum &bnPubcoinValue, CZerocoinMint& zerocoinMint); - bool ReadZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint); - bool ArchiveMintOrphan(const CZerocoinMint& zerocoinMint); - bool ArchiveDeterministicOrphan(const CDeterministicMint& dMint); - bool UnarchiveZerocoinMint(const uint256& hashPubcoin, CZerocoinMint& mint); - bool UnarchiveDeterministicMint(const uint256& hashPubcoin, CDeterministicMint& dMint); - std::list ListMintedCoins(); - std::list ListDeterministicMints(); - std::list ListSpentCoins(); - std::list ListSpentCoinsSerial(); - std::list ListArchivedZerocoins(); - std::list ListArchivedDeterministicMints(); - bool WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend); - bool EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry); - bool ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial); - bool WriteCurrentSeedHash(const uint256& hashSeed); - bool ReadCurrentSeedHash(uint256& hashSeed); - bool WriteZPIVSeed(const uint256& hashSeed, const std::vector& seed); - bool ReadZPIVSeed(const uint256& hashSeed, std::vector& seed); - bool ReadZPIVSeed_deprecated(uint256& seed); - bool EraseZPIVSeed(); - bool EraseZPIVSeed_deprecated(); - - bool WriteZPIVCount(const uint32_t& nCount); - bool ReadZPIVCount(uint32_t& nCount); - std::map > > MapMintPool(); - bool WriteMintPoolPair(const uint256& hashMasterSeed, const uint256& hashPubcoin, const uint32_t& nCount); - static void IncrementUpdateCounter(); static unsigned int GetUpdateCounter(); From 1ec4b84fb7ecf6591f041d07aec4bcad2a4adb3c Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 21 Jan 2021 08:55:05 -0300 Subject: [PATCH 8/9] [WalletDb] Decouple custom backup path parsing from BackupWallet function. --- src/wallet/walletdb.cpp | 40 +++++++++++++++++++++++----------------- src/wallet/walletdb.h | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7bcf583a59a19..dc9634e68855c 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -928,27 +928,33 @@ void NotifyBacked(const CWallet& wallet, bool fSuccess, std::string strMessage) wallet.NotifyWalletBacked(fSuccess, strMessage); } -bool BackupWallet(const CWallet& wallet, const fs::path& strDest, bool fEnableCustom) +// Returns first the pathCustom, second the pathWithFile. +std::pair GetBackupPath(const CWallet& wallet) { fs::path pathCustom; - fs::path pathWithFile; - if(fEnableCustom) { - pathWithFile = gArgs.GetArg("-backuppath", ""); - if(!pathWithFile.empty()) { - if(!pathWithFile.has_extension()) { - pathCustom = pathWithFile; - pathWithFile /= wallet.GetUniqueWalletBackupName(); - } else { - pathCustom = pathWithFile.parent_path(); - } - try { - fs::create_directories(pathCustom); - } catch (const fs::filesystem_error& e) { - NotifyBacked(wallet, false, strprintf("%s\n", e.what())); - pathCustom = ""; - } + fs::path pathWithFile = gArgs.GetArg("-backuppath", ""); + if(!pathWithFile.empty()) { + if(!pathWithFile.has_extension()) { + pathCustom = pathWithFile; + pathWithFile /= wallet.GetUniqueWalletBackupName(); + } else { + pathCustom = pathWithFile.parent_path(); + } + try { + fs::create_directories(pathCustom); + } catch (const fs::filesystem_error& e) { + NotifyBacked(wallet, false, strprintf("%s\n", e.what())); + pathCustom = ""; } } + return {pathCustom, pathWithFile}; +} + +bool BackupWallet(const CWallet& wallet, const fs::path& strDest) +{ + const auto& pathsPair = GetBackupPath(wallet); + fs::path pathCustom = pathsPair.first; + fs::path pathWithFile = pathsPair.second; while (true) { { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 20f45a74db0f1..73ad1b4842f53 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -227,7 +227,7 @@ class CWalletDB }; void NotifyBacked(const CWallet& wallet, bool fSuccess, std::string strMessage); -bool BackupWallet(const CWallet& wallet, const fs::path& strDest, bool fEnableCustom = true); +bool BackupWallet(const CWallet& wallet, const fs::path& strDest); bool AttemptBackupWallet(const CWallet& wallet, const fs::path& pathSrc, const fs::path& pathDest); void ThreadFlushWalletDB(); From e5fd21578df210e96730bbf22f99fb96e8752223 Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 21 Jan 2021 09:04:01 -0300 Subject: [PATCH 9/9] [WalletDb] Decouple backups history from the main BackupWallet function. --- src/wallet/walletdb.cpp | 120 +++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index dc9634e68855c..c871c3868b900 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -950,82 +950,88 @@ std::pair GetBackupPath(const CWallet& wallet) return {pathCustom, pathWithFile}; } +void MultiBackup(const CWallet& wallet, fs::path pathCustom, fs::path pathWithFile, const fs::path& pathSrc) +{ + int nThreshold = gArgs.GetArg("-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD); + if (nThreshold > 0) { + + typedef std::multimap folder_set_t; + folder_set_t folderSet; + fs::directory_iterator end_iter; + + pathCustom.make_preferred(); + // Build map of backup files for current(!) wallet sorted by last write time + + fs::path currentFile; + for (fs::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) { + // Only check regular files + if (fs::is_regular_file(dir_iter->status())) { + currentFile = dir_iter->path().filename(); + // Only add the backups for the current wallet, e.g. wallet.dat.* + if (dir_iter->path().stem().string() == wallet.GetDBHandle().GetName()) { + folderSet.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter)); + } + } + } + + int counter = 0; //TODO: add seconds to avoid naming conflicts + for (auto entry : folderSet) { + counter++; + if(entry.second == pathWithFile) { + pathWithFile += "(1)"; + } + } + + if (counter >= nThreshold) { + std::time_t oldestBackup = 0; + for(auto entry : folderSet) { + if(oldestBackup == 0 || entry.first < oldestBackup) { + oldestBackup = entry.first; + } + } + + try { + auto entry = folderSet.find(oldestBackup); + if (entry != folderSet.end()) { + fs::remove(entry->second); + LogPrintf("Old backup deleted: %s\n", (*entry).second); + } + } catch (const fs::filesystem_error& error) { + std::string strMessage = strprintf("Failed to delete backup %s\n", error.what()); + NotifyBacked(wallet, false, strMessage); + } + } + } + AttemptBackupWallet(wallet, pathSrc.string(), pathWithFile.string()); +} + bool BackupWallet(const CWallet& wallet, const fs::path& strDest) { const auto& pathsPair = GetBackupPath(wallet); fs::path pathCustom = pathsPair.first; fs::path pathWithFile = pathsPair.second; + std::string strFile = wallet.GetDBHandle().GetName(); while (true) { { LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(wallet.GetDBHandle().GetName()) || bitdb.mapFileUseCount[wallet.GetDBHandle().GetName()] == 0) { + if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { // Flush log data to the dat file - bitdb.CloseDb(wallet.GetDBHandle().GetName()); - bitdb.CheckpointLSN(wallet.GetDBHandle().GetName()); - bitdb.mapFileUseCount.erase(wallet.GetDBHandle().GetName()); + bitdb.CloseDb(strFile); + bitdb.CheckpointLSN(strFile); + bitdb.mapFileUseCount.erase(strFile); // Copy wallet file fs::path pathDest(strDest); - fs::path pathSrc = GetDataDir() / wallet.GetDBHandle().GetName(); + fs::path pathSrc = GetDataDir() / strFile; if (is_directory(pathDest)) { if(!exists(pathDest)) create_directory(pathDest); - pathDest /= wallet.GetDBHandle().GetName(); + pathDest /= strFile; } bool defaultPath = AttemptBackupWallet(wallet, pathSrc.string(), pathDest.string()); if(defaultPath && !pathCustom.empty()) { - int nThreshold = gArgs.GetArg("-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD); - if (nThreshold > 0) { - - typedef std::multimap folder_set_t; - folder_set_t folderSet; - fs::directory_iterator end_iter; - - pathCustom.make_preferred(); - // Build map of backup files for current(!) wallet sorted by last write time - - fs::path currentFile; - for (fs::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) { - // Only check regular files - if (fs::is_regular_file(dir_iter->status())) { - currentFile = dir_iter->path().filename(); - // Only add the backups for the current wallet, e.g. wallet.dat.* - if (dir_iter->path().stem().string() == wallet.GetDBHandle().GetName()) { - folderSet.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter)); - } - } - } - - int counter = 0; //TODO: add seconds to avoid naming conflicts - for (auto entry : folderSet) { - counter++; - if(entry.second == pathWithFile) { - pathWithFile += "(1)"; - } - } - - if (counter >= nThreshold) { - std::time_t oldestBackup = 0; - for(auto entry : folderSet) { - if(oldestBackup == 0 || entry.first < oldestBackup) { - oldestBackup = entry.first; - } - } - - try { - auto entry = folderSet.find(oldestBackup); - if (entry != folderSet.end()) { - fs::remove(entry->second); - LogPrintf("Old backup deleted: %s\n", (*entry).second); - } - } catch (const fs::filesystem_error& error) { - std::string strMessage = strprintf("Failed to delete backup %s\n", error.what()); - NotifyBacked(wallet, false, strMessage); - } - } - } - AttemptBackupWallet(wallet, pathSrc.string(), pathWithFile.string()); + MultiBackup(wallet, pathCustom, pathWithFile, pathSrc); } return defaultPath;