Browse Source

wallet: Introduce database handle wrapper

Abstract database handle from explicit strFilename into
CWalletDBWrapper.

Also move CWallet::Backup to db.cpp - as it deals with representation
details this is a database specific operation.
0.15
Wladimir J. van der Laan 7 years ago
parent
commit
71afe3c099
  1. 3
      src/qt/test/wallettests.cpp
  2. 58
      src/wallet/db.cpp
  3. 36
      src/wallet/db.h
  4. 2
      src/wallet/rpcwallet.cpp
  5. 3
      src/wallet/test/wallet_test_fixture.cpp
  6. 129
      src/wallet/wallet.cpp
  7. 24
      src/wallet/wallet.h
  8. 5
      src/wallet/walletdb.cpp
  9. 8
      src/wallet/walletdb.h

3
src/qt/test/wallettests.cpp

@ -86,7 +86,8 @@ void WalletTests::walletTests()
TestChain100Setup test; TestChain100Setup test;
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
bitdb.MakeMock(); bitdb.MakeMock();
CWallet wallet("wallet_test.dat"); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
CWallet wallet(std::move(dbw));
bool firstRun; bool firstRun;
wallet.LoadWallet(firstRun); wallet.LoadWallet(firstRun);
{ {

58
src/wallet/db.cpp

@ -359,13 +359,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; int ret;
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
fFlushOnClose = fFlushOnCloseIn; fFlushOnClose = fFlushOnCloseIn;
if (strFilename.empty()) const std::string& strFilename = dbw.strFile;
return;
bool fCreate = strchr(pszMode, 'c') != NULL; bool fCreate = strchr(pszMode, 'c') != NULL;
unsigned int nFlags = DB_THREAD; unsigned int nFlags = DB_THREAD;
@ -472,8 +471,12 @@ bool CDBEnv::RemoveDb(const std::string& strFile)
return (rc == 0); 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) { while (true) {
{ {
LOCK(bitdb.cs_db); LOCK(bitdb.cs_db);
@ -487,7 +490,7 @@ bool CDB::Rewrite(const std::string& strFile, const char* pszSkip)
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile);
std::string strFileRes = strFile + ".rewrite"; std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {} { // surround usage of db with extra {}
CDB db(strFile.c_str(), "r"); CDB db(dbw, "r");
Db* pdbCopy = new Db(bitdb.dbenv, 0); Db* pdbCopy = new Db(bitdb.dbenv, 0);
int ret = pdbCopy->open(NULL, // Txn pointer int ret = pdbCopy->open(NULL, // Txn pointer
@ -596,9 +599,10 @@ void CDBEnv::Flush(bool fShutdown)
} }
} }
bool CDB::PeriodicFlush(std::string strFile) bool CDB::PeriodicFlush(CWalletDBWrapper& dbw)
{ {
bool ret = false; bool ret = false;
const std::string& strFile = dbw.strFile;
TRY_LOCK(bitdb.cs_db,lockDb); TRY_LOCK(bitdb.cs_db,lockDb);
if (lockDb) if (lockDb)
{ {
@ -633,3 +637,45 @@ bool CDB::PeriodicFlush(std::string strFile)
return ret; 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 {
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
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
src/wallet/db.h

@ -86,6 +86,36 @@ public:
extern CDBEnv bitdb; 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 */ /** RAII class that provides access to a Berkeley database */
class CDB class CDB
@ -97,7 +127,7 @@ protected:
bool fReadOnly; bool fReadOnly;
bool fFlushOnClose; 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(); } ~CDB() { Close(); }
public: public:
@ -107,7 +137,7 @@ public:
/* flush the wallet passively (TRY_LOCK) /* flush the wallet passively (TRY_LOCK)
ideal to be called periodically */ ideal to be called periodically */
static bool PeriodicFlush(std::string strFile); static bool PeriodicFlush(CWalletDBWrapper& dbw);
/* verifies the database environment */ /* verifies the database environment */
static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr); static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
/* verifies the database file */ /* verifies the database file */
@ -310,7 +340,7 @@ public:
return Write(std::string("version"), nVersion); 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_WALLET_DB_H #endif // BITCOIN_WALLET_DB_H

2
src/wallet/rpcwallet.cpp

@ -2076,7 +2076,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
int64_t nSleepTime = request.params[1].get_int64(); int64_t nSleepTime = request.params[1].get_int64();
pwallet->nRelockTime = GetTime() + nSleepTime; pwallet->nRelockTime = GetTime() + nSleepTime;
RPCRunLater(strprintf("lockwallet(%s)", pwallet->strWalletFile), boost::bind(LockWallet, pwallet), nSleepTime); RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), boost::bind(LockWallet, pwallet), nSleepTime);
return NullUniValue; return NullUniValue;
} }

3
src/wallet/test/wallet_test_fixture.cpp

@ -14,7 +14,8 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
bitdb.MakeMock(); bitdb.MakeMock();
bool fFirstRun; bool fFirstRun;
pwalletMain = new CWallet("wallet_test.dat"); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
pwalletMain = new CWallet(std::move(dbw));
pwalletMain->LoadWallet(fFirstRun); pwalletMain->LoadWallet(fFirstRun);
RegisterValidationInterface(pwalletMain); RegisterValidationInterface(pwalletMain);

129
src/wallet/wallet.cpp

@ -161,7 +161,7 @@ void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool inter
secret = childKey.key; secret = childKey.key;
metadata.hdMasterKeyID = hdChain.masterKeyID; metadata.hdMasterKeyID = hdChain.masterKeyID;
// update the chain model in the database // update the chain model in the database
if (!CWalletDB(strWalletFile).WriteHDChain(hdChain)) if (!CWalletDB(*dbw).WriteHDChain(hdChain))
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
} }
@ -183,7 +183,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
if (!fFileBacked) if (!fFileBacked)
return true; return true;
if (!IsCrypted()) { if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(pubkey, return CWalletDB(*dbw).WriteKey(pubkey,
secret.GetPrivKey(), secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]); mapKeyMetadata[pubkey.GetID()]);
} }
@ -204,7 +204,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
vchCryptedSecret, vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]); mapKeyMetadata[vchPubKey.GetID()]);
else else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, return CWalletDB(*dbw).WriteCryptedKey(vchPubKey,
vchCryptedSecret, vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]); mapKeyMetadata[vchPubKey.GetID()]);
} }
@ -242,7 +242,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
return false; return false;
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript); return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript);
} }
bool CWallet::LoadCScript(const CScript& redeemScript) bool CWallet::LoadCScript(const CScript& redeemScript)
@ -270,7 +270,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
NotifyWatchonlyChanged(true); NotifyWatchonlyChanged(true);
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest, meta); return CWalletDB(*dbw).WriteWatchOnly(dest, meta);
} }
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
@ -287,7 +287,7 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
if (!HaveWatchOnly()) if (!HaveWatchOnly())
NotifyWatchonlyChanged(false); NotifyWatchonlyChanged(false);
if (fFileBacked) if (fFileBacked)
if (!CWalletDB(strWalletFile).EraseWatchOnly(dest)) if (!CWalletDB(*dbw).EraseWatchOnly(dest))
return false; return false;
return true; return true;
@ -353,7 +353,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false; return false;
if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey)) if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
return false; return false;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second); CWalletDB(*dbw).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked) if (fWasLocked)
Lock(); Lock();
return true; return true;
@ -366,7 +366,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
void CWallet::SetBestChain(const CBlockLocator& loc) void CWallet::SetBestChain(const CBlockLocator& loc)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
walletdb.WriteBestBlock(loc); walletdb.WriteBestBlock(loc);
} }
@ -387,7 +387,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
if (fFileBacked) if (fFileBacked)
{ {
CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile); CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(*dbw);
if (nWalletVersion > 40000) if (nWalletVersion > 40000)
pwalletdb->WriteMinVersion(nWalletVersion); pwalletdb->WriteMinVersion(nWalletVersion);
if (!pwalletdbIn) if (!pwalletdbIn)
@ -597,7 +597,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
if (fFileBacked) if (fFileBacked)
{ {
assert(!pwalletdbEncryption); assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile); pwalletdbEncryption = new CWalletDB(*dbw);
if (!pwalletdbEncryption->TxnBegin()) { if (!pwalletdbEncryption->TxnBegin()) {
delete pwalletdbEncryption; delete pwalletdbEncryption;
pwalletdbEncryption = NULL; pwalletdbEncryption = NULL;
@ -651,7 +651,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Need to completely rewrite the wallet file; if we don't, bdb might keep // 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. // bits of the unencrypted private key in slack space in the database file.
CDB::Rewrite(strWalletFile); dbw->Rewrite();
} }
NotifyStatusChanged(this); NotifyStatusChanged(this);
@ -662,7 +662,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
DBErrors CWallet::ReorderTransactions() DBErrors CWallet::ReorderTransactions()
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
// Old wallets didn't have any defined order for transactions // Old wallets didn't have any defined order for transactions
// Probably a bad idea to change the output of this // Probably a bad idea to change the output of this
@ -743,14 +743,14 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
if (pwalletdb) { if (pwalletdb) {
pwalletdb->WriteOrderPosNext(nOrderPosNext); pwalletdb->WriteOrderPosNext(nOrderPosNext);
} else { } else {
CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); CWalletDB(*dbw).WriteOrderPosNext(nOrderPosNext);
} }
return nRet; return nRet;
} }
bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment) bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
if (!walletdb.TxnBegin()) if (!walletdb.TxnBegin())
return false; return false;
@ -784,7 +784,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew) bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
CAccount account; CAccount account;
walletdb.ReadAccount(strAccount, account); walletdb.ReadAccount(strAccount, account);
@ -845,7 +845,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString(); wtx.mapValue["replaced_by_txid"] = newHash.ToString();
CWalletDB walletdb(strWalletFile, "r+"); CWalletDB walletdb(*dbw, "r+");
bool success = true; bool success = true;
if (!walletdb.WriteTx(wtx)) { if (!walletdb.WriteTx(wtx)) {
@ -862,7 +862,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); CWalletDB walletdb(*dbw, "r+", fFlushOnClose);
uint256 hash = wtxIn.GetHash(); uint256 hash = wtxIn.GetHash();
@ -1006,7 +1006,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
CWalletDB walletdb(strWalletFile, "r+"); CWalletDB walletdb(*dbw, "r+");
std::set<uint256> todo; std::set<uint256> todo;
std::set<uint256> done; std::set<uint256> done;
@ -1078,7 +1078,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
return; return;
// Do not flush the wallet here for performance reasons // Do not flush the wallet here for performance reasons
CWalletDB walletdb(strWalletFile, "r+", false); CWalletDB walletdb(*dbw, "r+", false);
std::set<uint256> todo; std::set<uint256> todo;
std::set<uint256> done; std::set<uint256> done;
@ -1361,7 +1361,7 @@ bool CWallet::SetHDMasterKey(const CPubKey& pubkey, CHDChain *possibleOldChain)
bool CWallet::SetHDChain(const CHDChain& chain, bool memonly) bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain)) if (!memonly && !CWalletDB(*dbw).WriteHDChain(chain))
throw std::runtime_error(std::string(__func__) + ": writing chain failed"); throw std::runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain; hdChain = chain;
@ -2758,13 +2758,13 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
} }
void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
return walletdb.ListAccountCreditDebit(strAccount, entries); return walletdb.ListAccountCreditDebit(strAccount, entries);
} }
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
return AddAccountingEntry(acentry, &walletdb); return AddAccountingEntry(acentry, &walletdb);
} }
@ -2819,10 +2819,10 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
if (!fFileBacked) if (!fFileBacked)
return DB_LOAD_OK; return DB_LOAD_OK;
fFirstRunRet = false; fFirstRunRet = false;
DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE) if (nLoadWalletRet == DB_NEED_REWRITE)
{ {
if (CDB::Rewrite(strWalletFile, "\x04pool")) if (dbw->Rewrite("\x04pool"))
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
setKeyPool.clear(); setKeyPool.clear();
@ -2847,13 +2847,13 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
return DB_LOAD_OK; return DB_LOAD_OK;
AssertLockHeld(cs_wallet); // mapWallet AssertLockHeld(cs_wallet); // mapWallet
vchDefaultKey = CPubKey(); vchDefaultKey = CPubKey();
DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(vHashIn, vHashOut); DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut) for (uint256 hash : vHashOut)
mapWallet.erase(hash); mapWallet.erase(hash);
if (nZapSelectTxRet == DB_NEED_REWRITE) if (nZapSelectTxRet == DB_NEED_REWRITE)
{ {
if (CDB::Rewrite(strWalletFile, "\x04pool")) if (dbw->Rewrite("\x04pool"))
{ {
setKeyPool.clear(); setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked. // Note: can't top-up keypool here, because wallet is locked.
@ -2876,10 +2876,10 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
if (!fFileBacked) if (!fFileBacked)
return DB_LOAD_OK; return DB_LOAD_OK;
vchDefaultKey = CPubKey(); vchDefaultKey = CPubKey();
DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(vWtx); DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE) if (nZapWalletTxRet == DB_NEED_REWRITE)
{ {
if (CDB::Rewrite(strWalletFile, "\x04pool")) if (dbw->Rewrite("\x04pool"))
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
setKeyPool.clear(); setKeyPool.clear();
@ -2911,9 +2911,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
if (!fFileBacked) if (!fFileBacked)
return false; return false;
if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
return false; return false;
return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
} }
bool CWallet::DelAddressBook(const CTxDestination& address) bool CWallet::DelAddressBook(const CTxDestination& address)
@ -2927,7 +2927,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
std::string strAddress = CBitcoinAddress(address).ToString(); std::string strAddress = CBitcoinAddress(address).ToString();
BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata) BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata)
{ {
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); CWalletDB(*dbw).EraseDestData(strAddress, item.first);
} }
} }
mapAddressBook.erase(address); mapAddressBook.erase(address);
@ -2937,15 +2937,15 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
if (!fFileBacked) if (!fFileBacked)
return false; return false;
CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString()); CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString());
return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
} }
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
{ {
if (fFileBacked) if (fFileBacked)
{ {
if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
return false; return false;
} }
vchDefaultKey = vchPubKey; vchDefaultKey = vchPubKey;
@ -2960,7 +2960,7 @@ bool CWallet::NewKeyPool()
{ {
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
BOOST_FOREACH(int64_t nIndex, setKeyPool) BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex); walletdb.ErasePool(nIndex);
setKeyPool.clear(); setKeyPool.clear();
@ -2981,7 +2981,7 @@ size_t CWallet::KeypoolCountExternalKeys()
if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
return setKeyPool.size(); return setKeyPool.size();
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
// count amount of external keys // count amount of external keys
size_t amountE = 0; size_t amountE = 0;
@ -3024,7 +3024,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
missingInternal = 0; missingInternal = 0;
} }
bool internal = false; bool internal = false;
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
for (int64_t i = missingInternal + missingExternal; i--;) for (int64_t i = missingInternal + missingExternal; i--;)
{ {
int64_t nEnd = 1; int64_t nEnd = 1;
@ -3055,7 +3055,7 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
if(setKeyPool.empty()) if(setKeyPool.empty())
return; return;
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
// try to find a key that matches the internal/external filter // try to find a key that matches the internal/external filter
for(const int64_t& id : setKeyPool) for(const int64_t& id : setKeyPool)
@ -3083,7 +3083,7 @@ void CWallet::KeepKey(int64_t nIndex)
// Remove from key pool // Remove from key pool
if (fFileBacked) if (fFileBacked)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
walletdb.ErasePool(nIndex); walletdb.ErasePool(nIndex);
} }
LogPrintf("keypool keep %d\n", nIndex); LogPrintf("keypool keep %d\n", nIndex);
@ -3127,7 +3127,7 @@ int64_t CWallet::GetOldestKeyPoolTime()
return GetTime(); return GetTime();
CKeyPool keypool; CKeyPool keypool;
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT))
{ {
@ -3295,7 +3295,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter) CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
} }
@ -3375,7 +3375,7 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
{ {
setAddress.clear(); setAddress.clear();
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(*dbw);
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64_t& id, setKeyPool) BOOST_FOREACH(const int64_t& id, setKeyPool)
@ -3599,7 +3599,7 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
} }
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
@ -3608,7 +3608,7 @@ bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
return false; return false;
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key); return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key);
} }
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@ -3678,7 +3678,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (GetBoolArg("-zapwallettxes", false)) { if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet...")); uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
CWallet *tempWallet = new CWallet(walletFile); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
CWallet *tempWallet = new CWallet(std::move(dbw));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) { if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
@ -3693,7 +3694,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
bool fFirstRun = true; bool fFirstRun = true;
CWallet *walletInstance = new CWallet(walletFile); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
CWallet *walletInstance = new CWallet(std::move(dbw));
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK) if (nLoadWalletRet != DB_LOAD_OK)
{ {
@ -3784,7 +3786,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
CBlockIndex *pindexRescan = chainActive.Genesis(); CBlockIndex *pindexRescan = chainActive.Genesis();
if (!GetBoolArg("-rescan", false)) if (!GetBoolArg("-rescan", false))
{ {
CWalletDB walletdb(walletFile); CWalletDB walletdb(*walletInstance->dbw);
CBlockLocator locator; CBlockLocator locator;
if (walletdb.ReadBestBlock(locator)) if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator); pindexRescan = FindForkInGlobalIndex(chainActive, locator);
@ -3817,7 +3819,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
// Restore wallet transaction metadata after -zapwallettxes=1 // Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
{ {
CWalletDB walletdb(walletFile); CWalletDB walletdb(*walletInstance->dbw);
BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
{ {
@ -3979,36 +3981,7 @@ bool CWallet::BackupWallet(const std::string& strDest)
{ {
if (!fFileBacked) if (!fFileBacked)
return false; return false;
while (true) return dbw->Backup(strDest);
{
{
LOCK(bitdb.cs_db);
if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
{
// Flush log data to the dat file
bitdb.CloseDb(strWalletFile);
bitdb.CheckpointLSN(strWalletFile);
bitdb.mapFileUseCount.erase(strWalletFile);
// Copy wallet file
fs::path pathSrc = GetDataDir() / strWalletFile;
fs::path pathDest(strDest);
if (fs::is_directory(pathDest))
pathDest /= strWalletFile;
try {
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
return true;
} catch (const fs::filesystem_error& e) {
LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
return false;
}
}
}
MilliSleep(100);
}
return false;
} }
CKeyPool::CKeyPool() CKeyPool::CKeyPool()

24
src/wallet/wallet.h

@ -715,17 +715,35 @@ private:
*/ */
bool AddWatchOnly(const CScript& dest) override; bool AddWatchOnly(const CScript& dest) override;
std::unique_ptr<CWalletDBWrapper> dbw;
public: public:
/* /*
* Main wallet lock. * Main wallet lock.
* This lock protects all the fields added by CWallet * This lock protects all the fields added by CWallet
* except for: * except for:
* fFileBacked (immutable after instantiation) * fFileBacked (immutable after instantiation)
* strWalletFile (immutable after instantiation)
*/ */
mutable CCriticalSection cs_wallet; mutable CCriticalSection cs_wallet;
const std::string strWalletFile; /** Get database handle used by this wallet. Ideally this function would
* not be necessary.
*/
CWalletDBWrapper& GetDBHandle()
{
return *dbw;
}
/** Get a name for this wallet for logging/debugging purposes.
*/
std::string GetName() const
{
if (dbw) {
return dbw->GetName();
} else {
return "dummy";
}
}
void LoadKeyPool(int nIndex, const CKeyPool &keypool) void LoadKeyPool(int nIndex, const CKeyPool &keypool)
{ {
@ -752,7 +770,7 @@ public:
SetNull(); SetNull();
} }
CWallet(const std::string& strWalletFileIn) : strWalletFile(strWalletFileIn) CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
{ {
SetNull(); SetNull();
fFileBacked = true; fFileBacked = true;

5
src/wallet/walletdb.cpp

@ -797,9 +797,9 @@ void MaybeCompactWalletDB()
if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2) if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
{ {
const std::string& strFile = pwalletMain->strWalletFile; if (CDB::PeriodicFlush(pwalletMain->GetDBHandle())) {
if (CDB::PeriodicFlush(strFile))
nLastFlushed = CWalletDB::GetUpdateCounter(); nLastFlushed = CWalletDB::GetUpdateCounter();
}
} }
fOneThread = false; fOneThread = false;
} }
@ -880,3 +880,4 @@ unsigned int CWalletDB::GetUpdateCounter()
{ {
return nWalletDBUpdateCounter; return nWalletDBUpdateCounter;
} }

8
src/wallet/walletdb.h

@ -118,11 +118,15 @@ public:
} }
}; };
/** 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 class CWalletDB : public CDB
{ {
public: 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)
{ {
} }

Loading…
Cancel
Save