Skip to content

Commit

Permalink
wallet: Introduce database handle wrapper
Browse files Browse the repository at this point in the history
Abstract database handle from explicit strFilename into
CWalletDBWrapper.

Backport and adaptation from btc@71afe3c0995592ff17968816a833a8ed3ce05bf2
  • Loading branch information
laanwj authored and furszy committed Jan 18, 2021
1 parent ba73898 commit 3f3a289
Show file tree
Hide file tree
Showing 14 changed files with 197 additions and 93 deletions.
6 changes: 3 additions & 3 deletions src/qt/optionsmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions src/qt/pivx/settings/settingsmultisendwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ void SettingsMultisendWidget::clearAll()
std::vector<std::pair<std::string, int> > 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))
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion src/sapling/sapling_operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
16 changes: 8 additions & 8 deletions src/sapling/saplingscriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()]);
}
Expand Down Expand Up @@ -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");
}
}
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/test/librust/wallet_zkeys_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CWalletDBWrapper> 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
Expand Down
66 changes: 58 additions & 8 deletions src/wallet/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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<std::string, int>::iterator mi = bitdb.mapFileUseCount.begin();
Expand Down Expand Up @@ -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;
}
36 changes: 33 additions & 3 deletions src/wallet/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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 */
Expand Down Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 3f3a289

Please sign in to comment.