mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 05:23:01 +01:00
Merge #9951: Wallet database handling abstractions/simplifications
911a480
wallet: Add comment describing the various classes in walletdb.h (Wladimir J. van der Laan)69d2e9b
wallet: Make IsDummy private in CWalletDBWrapper (Wladimir J. van der Laan)3323281
wallet: CWalletDB CDB composition not inheritance (Wladimir J. van der Laan)be9e1a9
wallet: Reduce references to global bitdb environment (Wladimir J. van der Laan)071c955
wallet: Get rid of fFileBacked (Wladimir J. van der Laan)71afe3c
wallet: Introduce database handle wrapper (Wladimir J. van der Laan) Tree-SHA512: e4e72953c61a2f6995d609a32f8ed8e18cab9a92bc9e193d46a1d1f06d9daa5c6da6fce2867d4e3ba4fc0439141901a3d35f246486f0fa8f59587786379dfcbd
This commit is contained in:
commit
fa1ac2881f
@ -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);
|
||||||
{
|
{
|
||||||
|
@ -359,13 +359,16 @@ 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())
|
env = dbw.env;
|
||||||
|
if (dbw.IsDummy()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
const std::string &strFilename = dbw.strFile;
|
||||||
|
|
||||||
bool fCreate = strchr(pszMode, 'c') != NULL;
|
bool fCreate = strchr(pszMode, 'c') != NULL;
|
||||||
unsigned int nFlags = DB_THREAD;
|
unsigned int nFlags = DB_THREAD;
|
||||||
@ -373,17 +376,17 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
|
|||||||
nFlags |= DB_CREATE;
|
nFlags |= DB_CREATE;
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(bitdb.cs_db);
|
LOCK(env->cs_db);
|
||||||
if (!bitdb.Open(GetDataDir()))
|
if (!env->Open(GetDataDir()))
|
||||||
throw std::runtime_error("CDB: Failed to open database environment.");
|
throw std::runtime_error("CDB: Failed to open database environment.");
|
||||||
|
|
||||||
strFile = strFilename;
|
strFile = strFilename;
|
||||||
++bitdb.mapFileUseCount[strFile];
|
++env->mapFileUseCount[strFile];
|
||||||
pdb = bitdb.mapDb[strFile];
|
pdb = env->mapDb[strFile];
|
||||||
if (pdb == NULL) {
|
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) {
|
if (fMockDb) {
|
||||||
DbMpoolFile* mpf = pdb->get_mpf();
|
DbMpoolFile* mpf = pdb->get_mpf();
|
||||||
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
|
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
|
||||||
@ -401,7 +404,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
delete pdb;
|
delete pdb;
|
||||||
pdb = NULL;
|
pdb = NULL;
|
||||||
--bitdb.mapFileUseCount[strFile];
|
--env->mapFileUseCount[strFile];
|
||||||
strFile = "";
|
strFile = "";
|
||||||
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
|
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
|
||||||
}
|
}
|
||||||
@ -413,7 +416,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
|
|||||||
fReadOnly = fTmp;
|
fReadOnly = fTmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitdb.mapDb[strFile] = pdb;
|
env->mapDb[strFile] = pdb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,7 +431,7 @@ void CDB::Flush()
|
|||||||
if (fReadOnly)
|
if (fReadOnly)
|
||||||
nMinutes = 1;
|
nMinutes = 1;
|
||||||
|
|
||||||
bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
|
env->dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDB::Close()
|
void CDB::Close()
|
||||||
@ -444,8 +447,8 @@ void CDB::Close()
|
|||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(bitdb.cs_db);
|
LOCK(env->cs_db);
|
||||||
--bitdb.mapFileUseCount[strFile];
|
--env->mapFileUseCount[strFile];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,23 +475,28 @@ 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.IsDummy()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CDBEnv *env = dbw.env;
|
||||||
|
const std::string& strFile = dbw.strFile;
|
||||||
while (true) {
|
while (true) {
|
||||||
{
|
{
|
||||||
LOCK(bitdb.cs_db);
|
LOCK(env->cs_db);
|
||||||
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) {
|
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) {
|
||||||
// Flush log data to the dat file
|
// Flush log data to the dat file
|
||||||
bitdb.CloseDb(strFile);
|
env->CloseDb(strFile);
|
||||||
bitdb.CheckpointLSN(strFile);
|
env->CheckpointLSN(strFile);
|
||||||
bitdb.mapFileUseCount.erase(strFile);
|
env->mapFileUseCount.erase(strFile);
|
||||||
|
|
||||||
bool fSuccess = true;
|
bool fSuccess = true;
|
||||||
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(env->dbenv, 0);
|
||||||
|
|
||||||
int ret = pdbCopy->open(NULL, // Txn pointer
|
int ret = pdbCopy->open(NULL, // Txn pointer
|
||||||
strFileRes.c_str(), // Filename
|
strFileRes.c_str(), // Filename
|
||||||
@ -531,17 +539,17 @@ bool CDB::Rewrite(const std::string& strFile, const char* pszSkip)
|
|||||||
}
|
}
|
||||||
if (fSuccess) {
|
if (fSuccess) {
|
||||||
db.Close();
|
db.Close();
|
||||||
bitdb.CloseDb(strFile);
|
env->CloseDb(strFile);
|
||||||
if (pdbCopy->close(0))
|
if (pdbCopy->close(0))
|
||||||
fSuccess = false;
|
fSuccess = false;
|
||||||
delete pdbCopy;
|
delete pdbCopy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fSuccess) {
|
if (fSuccess) {
|
||||||
Db dbA(bitdb.dbenv, 0);
|
Db dbA(env->dbenv, 0);
|
||||||
if (dbA.remove(strFile.c_str(), NULL, 0))
|
if (dbA.remove(strFile.c_str(), NULL, 0))
|
||||||
fSuccess = false;
|
fSuccess = false;
|
||||||
Db dbB(bitdb.dbenv, 0);
|
Db dbB(env->dbenv, 0);
|
||||||
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
|
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
|
||||||
fSuccess = false;
|
fSuccess = false;
|
||||||
}
|
}
|
||||||
@ -596,16 +604,21 @@ void CDBEnv::Flush(bool fShutdown)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDB::PeriodicFlush(std::string strFile)
|
bool CDB::PeriodicFlush(CWalletDBWrapper& dbw)
|
||||||
{
|
{
|
||||||
|
if (dbw.IsDummy()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
CDBEnv *env = dbw.env;
|
||||||
|
const std::string& strFile = dbw.strFile;
|
||||||
TRY_LOCK(bitdb.cs_db,lockDb);
|
TRY_LOCK(bitdb.cs_db,lockDb);
|
||||||
if (lockDb)
|
if (lockDb)
|
||||||
{
|
{
|
||||||
// Don't do this if any databases are in use
|
// Don't do this if any databases are in use
|
||||||
int nRefCount = 0;
|
int nRefCount = 0;
|
||||||
std::map<std::string, int>::iterator mit = bitdb.mapFileUseCount.begin();
|
std::map<std::string, int>::iterator mit = env->mapFileUseCount.begin();
|
||||||
while (mit != bitdb.mapFileUseCount.end())
|
while (mit != env->mapFileUseCount.end())
|
||||||
{
|
{
|
||||||
nRefCount += (*mit).second;
|
nRefCount += (*mit).second;
|
||||||
mit++;
|
mit++;
|
||||||
@ -614,17 +627,17 @@ bool CDB::PeriodicFlush(std::string strFile)
|
|||||||
if (nRefCount == 0)
|
if (nRefCount == 0)
|
||||||
{
|
{
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
|
std::map<std::string, int>::iterator mi = env->mapFileUseCount.find(strFile);
|
||||||
if (mi != bitdb.mapFileUseCount.end())
|
if (mi != env->mapFileUseCount.end())
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::DB, "Flushing %s\n", strFile);
|
LogPrint(BCLog::DB, "Flushing %s\n", strFile);
|
||||||
int64_t nStart = GetTimeMillis();
|
int64_t nStart = GetTimeMillis();
|
||||||
|
|
||||||
// Flush wallet file so it's self contained
|
// Flush wallet file so it's self contained
|
||||||
bitdb.CloseDb(strFile);
|
env->CloseDb(strFile);
|
||||||
bitdb.CheckpointLSN(strFile);
|
env->CheckpointLSN(strFile);
|
||||||
|
|
||||||
bitdb.mapFileUseCount.erase(mi++);
|
env->mapFileUseCount.erase(mi++);
|
||||||
LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
|
LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
@ -633,3 +646,52 @@ 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 (IsDummy()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LOCK(env->cs_db);
|
||||||
|
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0)
|
||||||
|
{
|
||||||
|
// Flush log data to the dat file
|
||||||
|
env->CloseDb(strFile);
|
||||||
|
env->CheckpointLSN(strFile);
|
||||||
|
env->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWalletDBWrapper::Flush(bool shutdown)
|
||||||
|
{
|
||||||
|
if (!IsDummy()) {
|
||||||
|
env->Flush(shutdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -86,6 +86,52 @@ 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:
|
||||||
|
/** 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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; }
|
||||||
|
|
||||||
|
/** Make sure all changes are flushed to disk.
|
||||||
|
*/
|
||||||
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** RAII class that provides access to a Berkeley database */
|
/** RAII class that provides access to a Berkeley database */
|
||||||
class CDB
|
class CDB
|
||||||
@ -96,18 +142,19 @@ protected:
|
|||||||
DbTxn* activeTxn;
|
DbTxn* activeTxn;
|
||||||
bool fReadOnly;
|
bool fReadOnly;
|
||||||
bool fFlushOnClose;
|
bool fFlushOnClose;
|
||||||
|
CDBEnv *env;
|
||||||
explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
|
|
||||||
~CDB() { Close(); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
|
||||||
|
~CDB() { Close(); }
|
||||||
|
|
||||||
void Flush();
|
void Flush();
|
||||||
void Close();
|
void Close();
|
||||||
static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
|
static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
|
||||||
|
|
||||||
/* 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 */
|
||||||
@ -117,7 +164,7 @@ private:
|
|||||||
CDB(const CDB&);
|
CDB(const CDB&);
|
||||||
void operator=(const CDB&);
|
void operator=(const CDB&);
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
template <typename K, typename T>
|
template <typename K, typename T>
|
||||||
bool Read(const K& key, T& value)
|
bool Read(const K& key, T& value)
|
||||||
{
|
{
|
||||||
@ -156,7 +203,7 @@ protected:
|
|||||||
bool Write(const K& key, const T& value, bool fOverwrite = true)
|
bool Write(const K& key, const T& value, bool fOverwrite = true)
|
||||||
{
|
{
|
||||||
if (!pdb)
|
if (!pdb)
|
||||||
return false;
|
return true;
|
||||||
if (fReadOnly)
|
if (fReadOnly)
|
||||||
assert(!"Write called on database in read-only mode");
|
assert(!"Write called on database in read-only mode");
|
||||||
|
|
||||||
@ -310,7 +357,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
|
||||||
|
@ -2078,7 +2078,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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -162,7 +162,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,10 +181,8 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
|||||||
if (HaveWatchOnly(script))
|
if (HaveWatchOnly(script))
|
||||||
RemoveWatchOnly(script);
|
RemoveWatchOnly(script);
|
||||||
|
|
||||||
if (!fFileBacked)
|
|
||||||
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()]);
|
||||||
}
|
}
|
||||||
@ -196,8 +194,6 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
|||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
|
||||||
return true;
|
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
if (pwalletdbEncryption)
|
if (pwalletdbEncryption)
|
||||||
@ -205,7 +201,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()]);
|
||||||
}
|
}
|
||||||
@ -241,9 +237,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
|
|||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript);
|
||||||
return true;
|
|
||||||
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::LoadCScript(const CScript& redeemScript)
|
bool CWallet::LoadCScript(const CScript& redeemScript)
|
||||||
@ -269,9 +263,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
|
|||||||
const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
|
const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
|
||||||
UpdateTimeFirstKey(meta.nCreateTime);
|
UpdateTimeFirstKey(meta.nCreateTime);
|
||||||
NotifyWatchonlyChanged(true);
|
NotifyWatchonlyChanged(true);
|
||||||
if (!fFileBacked)
|
return CWalletDB(*dbw).WriteWatchOnly(dest, meta);
|
||||||
return true;
|
|
||||||
return CWalletDB(strWalletFile).WriteWatchOnly(dest, meta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
|
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
|
||||||
@ -287,9 +279,8 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
|
|||||||
return false;
|
return false;
|
||||||
if (!HaveWatchOnly())
|
if (!HaveWatchOnly())
|
||||||
NotifyWatchonlyChanged(false);
|
NotifyWatchonlyChanged(false);
|
||||||
if (fFileBacked)
|
if (!CWalletDB(*dbw).EraseWatchOnly(dest))
|
||||||
if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -354,7 +345,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;
|
||||||
@ -367,7 +358,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,9 +377,8 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
|
|||||||
if (nVersion > nWalletMaxVersion)
|
if (nVersion > nWalletMaxVersion)
|
||||||
nWalletMaxVersion = nVersion;
|
nWalletMaxVersion = nVersion;
|
||||||
|
|
||||||
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)
|
||||||
@ -442,7 +432,7 @@ bool CWallet::HasWalletSpend(const uint256& txid) const
|
|||||||
|
|
||||||
void CWallet::Flush(bool shutdown)
|
void CWallet::Flush(bool shutdown)
|
||||||
{
|
{
|
||||||
bitdb.Flush(shutdown);
|
dbw->Flush(shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::Verify()
|
bool CWallet::Verify()
|
||||||
@ -595,24 +585,19 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
|||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
|
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
|
||||||
if (fFileBacked)
|
assert(!pwalletdbEncryption);
|
||||||
{
|
pwalletdbEncryption = new CWalletDB(*dbw);
|
||||||
assert(!pwalletdbEncryption);
|
if (!pwalletdbEncryption->TxnBegin()) {
|
||||||
pwalletdbEncryption = new CWalletDB(strWalletFile);
|
delete pwalletdbEncryption;
|
||||||
if (!pwalletdbEncryption->TxnBegin()) {
|
pwalletdbEncryption = NULL;
|
||||||
delete pwalletdbEncryption;
|
return false;
|
||||||
pwalletdbEncryption = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
|
|
||||||
}
|
}
|
||||||
|
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
|
||||||
|
|
||||||
if (!EncryptKeys(_vMasterKey))
|
if (!EncryptKeys(_vMasterKey))
|
||||||
{
|
{
|
||||||
if (fFileBacked) {
|
pwalletdbEncryption->TxnAbort();
|
||||||
pwalletdbEncryption->TxnAbort();
|
delete pwalletdbEncryption;
|
||||||
delete pwalletdbEncryption;
|
|
||||||
}
|
|
||||||
// We now probably have half of our keys encrypted in memory, and half not...
|
// We now probably have half of our keys encrypted in memory, and half not...
|
||||||
// die and let the user reload the unencrypted wallet.
|
// die and let the user reload the unencrypted wallet.
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -621,19 +606,16 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
|||||||
// Encryption was introduced in version 0.4.0
|
// Encryption was introduced in version 0.4.0
|
||||||
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
|
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
|
||||||
|
|
||||||
if (fFileBacked)
|
if (!pwalletdbEncryption->TxnCommit()) {
|
||||||
{
|
|
||||||
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 the unencrypted wallet.
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete pwalletdbEncryption;
|
delete pwalletdbEncryption;
|
||||||
pwalletdbEncryption = NULL;
|
// We now have keys encrypted in memory, but not on disk...
|
||||||
|
// die to avoid confusion and let the user reload the unencrypted wallet.
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete pwalletdbEncryption;
|
||||||
|
pwalletdbEncryption = NULL;
|
||||||
|
|
||||||
Lock();
|
Lock();
|
||||||
Unlock(strWalletPassphrase);
|
Unlock(strWalletPassphrase);
|
||||||
|
|
||||||
@ -652,7 +634,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);
|
||||||
@ -663,7 +645,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
|
||||||
@ -744,14 +726,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;
|
||||||
|
|
||||||
@ -785,7 +767,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);
|
||||||
@ -846,7 +828,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)) {
|
||||||
@ -863,7 +845,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();
|
||||||
|
|
||||||
@ -1007,7 +989,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;
|
||||||
@ -1079,7 +1061,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;
|
||||||
@ -1362,7 +1344,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;
|
||||||
@ -2759,13 +2741,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);
|
||||||
}
|
}
|
||||||
@ -2817,13 +2799,11 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
|
|||||||
|
|
||||||
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||||
{
|
{
|
||||||
if (!fFileBacked)
|
|
||||||
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();
|
||||||
@ -2844,17 +2824,15 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
|||||||
|
|
||||||
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
|
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
|
||||||
{
|
{
|
||||||
if (!fFileBacked)
|
|
||||||
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.
|
||||||
@ -2874,13 +2852,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
|
|||||||
|
|
||||||
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
|
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
|
||||||
{
|
{
|
||||||
if (!fFileBacked)
|
|
||||||
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();
|
||||||
@ -2910,11 +2886,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
|
|||||||
}
|
}
|
||||||
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
|
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
|
||||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||||
if (!fFileBacked)
|
if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
|
||||||
return false;
|
return false;
|
||||||
if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
|
return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
|
||||||
return false;
|
|
||||||
return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::DelAddressBook(const CTxDestination& address)
|
bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||||
@ -2922,33 +2896,25 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
|||||||
{
|
{
|
||||||
LOCK(cs_wallet); // mapAddressBook
|
LOCK(cs_wallet); // mapAddressBook
|
||||||
|
|
||||||
if(fFileBacked)
|
// Delete destdata tuples associated with address
|
||||||
|
std::string strAddress = CBitcoinAddress(address).ToString();
|
||||||
|
BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata)
|
||||||
{
|
{
|
||||||
// Delete destdata tuples associated with address
|
CWalletDB(*dbw).EraseDestData(strAddress, item.first);
|
||||||
std::string strAddress = CBitcoinAddress(address).ToString();
|
|
||||||
BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata)
|
|
||||||
{
|
|
||||||
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mapAddressBook.erase(address);
|
mapAddressBook.erase(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
|
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
|
||||||
|
|
||||||
if (!fFileBacked)
|
CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString());
|
||||||
return false;
|
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
|
||||||
CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString());
|
|
||||||
return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||||
{
|
{
|
||||||
if (fFileBacked)
|
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
|
||||||
{
|
return false;
|
||||||
if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vchDefaultKey = vchPubKey;
|
vchDefaultKey = vchPubKey;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2961,7 +2927,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();
|
||||||
@ -2982,7 +2948,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;
|
||||||
@ -3025,7 +2991,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;
|
||||||
@ -3056,7 +3022,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)
|
||||||
@ -3082,11 +3048,8 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
|
|||||||
void CWallet::KeepKey(int64_t nIndex)
|
void CWallet::KeepKey(int64_t nIndex)
|
||||||
{
|
{
|
||||||
// Remove from key pool
|
// Remove from key pool
|
||||||
if (fFileBacked)
|
CWalletDB walletdb(*dbw);
|
||||||
{
|
walletdb.ErasePool(nIndex);
|
||||||
CWalletDB walletdb(strWalletFile);
|
|
||||||
walletdb.ErasePool(nIndex);
|
|
||||||
}
|
|
||||||
LogPrintf("keypool keep %d\n", nIndex);
|
LogPrintf("keypool keep %d\n", nIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3128,7 +3091,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))
|
||||||
{
|
{
|
||||||
@ -3296,7 +3259,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3376,7 +3339,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)
|
||||||
@ -3598,18 +3561,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
||||||
if (!fFileBacked)
|
return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
|
||||||
return true;
|
|
||||||
return CWalletDB(strWalletFile).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)
|
||||||
{
|
{
|
||||||
if (!mapAddressBook[dest].destdata.erase(key))
|
if (!mapAddressBook[dest].destdata.erase(key))
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key);
|
||||||
return true;
|
|
||||||
return CWalletDB(strWalletFile).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)
|
||||||
@ -3679,7 +3638,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));
|
||||||
@ -3694,7 +3654,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)
|
||||||
{
|
{
|
||||||
@ -3785,7 +3746,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);
|
||||||
@ -3818,7 +3779,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)
|
||||||
{
|
{
|
||||||
@ -3978,38 +3939,7 @@ bool CWallet::ParameterInteraction()
|
|||||||
|
|
||||||
bool CWallet::BackupWallet(const std::string& strDest)
|
bool CWallet::BackupWallet(const std::string& strDest)
|
||||||
{
|
{
|
||||||
if (!fFileBacked)
|
return dbw->Backup(strDest);
|
||||||
return false;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
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()
|
||||||
|
@ -699,8 +699,6 @@ private:
|
|||||||
/* HD derive new child key (on internal or external chain) */
|
/* HD derive new child key (on internal or external chain) */
|
||||||
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
|
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
|
||||||
|
|
||||||
bool fFileBacked;
|
|
||||||
|
|
||||||
std::set<int64_t> setKeyPool;
|
std::set<int64_t> setKeyPool;
|
||||||
|
|
||||||
int64_t nTimeFirstKey;
|
int64_t nTimeFirstKey;
|
||||||
@ -716,17 +714,33 @@ 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:
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
@ -748,15 +762,16 @@ public:
|
|||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
unsigned int nMasterKeyMaxID;
|
unsigned int nMasterKeyMaxID;
|
||||||
|
|
||||||
CWallet()
|
// Create wallet with dummy database handle
|
||||||
|
CWallet(): dbw(new CWalletDBWrapper())
|
||||||
{
|
{
|
||||||
SetNull();
|
SetNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
CWallet(const std::string& strWalletFileIn) : strWalletFile(strWalletFileIn)
|
// Create wallet with passed-in database handle
|
||||||
|
CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
|
||||||
{
|
{
|
||||||
SetNull();
|
SetNull();
|
||||||
fFileBacked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CWallet()
|
~CWallet()
|
||||||
@ -769,7 +784,6 @@ public:
|
|||||||
{
|
{
|
||||||
nWalletVersion = FEATURE_BASE;
|
nWalletVersion = FEATURE_BASE;
|
||||||
nWalletMaxVersion = FEATURE_BASE;
|
nWalletMaxVersion = FEATURE_BASE;
|
||||||
fFileBacked = false;
|
|
||||||
nMasterKeyMaxID = 0;
|
nMasterKeyMaxID = 0;
|
||||||
pwalletdbEncryption = NULL;
|
pwalletdbEncryption = NULL;
|
||||||
nOrderPosNext = 0;
|
nOrderPosNext = 0;
|
||||||
|
@ -33,7 +33,7 @@ static std::atomic<unsigned int> nWalletDBUpdateCounter;
|
|||||||
bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
|
bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Write(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)
|
bool CWalletDB::EraseName(const std::string& strAddress)
|
||||||
@ -41,38 +41,38 @@ bool CWalletDB::EraseName(const std::string& strAddress)
|
|||||||
// This should only be used for sending addresses, never for receiving addresses,
|
// 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.
|
// receiving addresses must always have an address book entry if they're not change return.
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Erase(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)
|
bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Write(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)
|
bool CWalletDB::ErasePurpose(const std::string& strPurpose)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Erase(make_pair(std::string("purpose"), strPurpose));
|
return batch.Erase(std::make_pair(std::string("purpose"), strPurpose));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteTx(const CWalletTx& wtx)
|
bool CWalletDB::WriteTx(const CWalletTx& wtx)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::EraseTx(uint256 hash)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
|
|
||||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||||
keyMeta, false))
|
keyMeta, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, c
|
|||||||
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
|
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
|
||||||
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.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,
|
bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
|
||||||
@ -92,16 +92,16 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
|
|||||||
const bool fEraseUnencryptedKey = true;
|
const bool fEraseUnencryptedKey = true;
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
|
|
||||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||||
keyMeta))
|
keyMeta))
|
||||||
return false;
|
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;
|
return false;
|
||||||
if (fEraseUnencryptedKey)
|
if (fEraseUnencryptedKey)
|
||||||
{
|
{
|
||||||
Erase(std::make_pair(std::string("key"), vchPubKey));
|
batch.Erase(std::make_pair(std::string("key"), vchPubKey));
|
||||||
Erase(std::make_pair(std::string("wkey"), vchPubKey));
|
batch.Erase(std::make_pair(std::string("wkey"), vchPubKey));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -109,92 +109,92 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
|
|||||||
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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, const CKeyMetadata& keyMeta)
|
bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
if (!Write(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
|
if (!batch.Write(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
|
||||||
return false;
|
return false;
|
||||||
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)
|
bool CWalletDB::EraseWatchOnly(const CScript &dest)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
if (!Erase(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
|
if (!batch.Erase(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
|
||||||
return false;
|
return false;
|
||||||
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::WriteBestBlock(const CBlockLocator& locator)
|
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
|
batch.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);
|
return batch.Write(std::string("bestblock_nomerkle"), locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
|
bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
|
||||||
{
|
{
|
||||||
if (Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
|
if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
|
||||||
return Read(std::string("bestblock_nomerkle"), locator);
|
return batch.Read(std::string("bestblock_nomerkle"), locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
|
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Write(std::string("orderposnext"), nOrderPosNext);
|
return batch.Write(std::string("orderposnext"), nOrderPosNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
|
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Write(std::string("defaultkey"), vchPubKey);
|
return batch.Write(std::string("defaultkey"), vchPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
|
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)
|
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::ErasePool(int64_t nPool)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::WriteMinVersion(int nVersion)
|
||||||
{
|
{
|
||||||
return Write(std::string("minversion"), nVersion);
|
return batch.Write(std::string("minversion"), nVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
|
bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
|
||||||
{
|
{
|
||||||
account.SetNull();
|
account.SetNull();
|
||||||
return Read(make_pair(std::string("acc"), strAccount), account);
|
return batch.Read(std::make_pair(std::string("acc"), strAccount), account);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
|
bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
|
||||||
{
|
{
|
||||||
return Write(make_pair(std::string("acc"), strAccount), account);
|
return batch.Write(std::make_pair(std::string("acc"), strAccount), account);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
|
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
|
||||||
{
|
{
|
||||||
return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
|
return batch.Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
|
bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
|
||||||
@ -218,7 +218,7 @@ void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<
|
|||||||
{
|
{
|
||||||
bool fAllAccounts = (strAccount == "*");
|
bool fAllAccounts = (strAccount == "*");
|
||||||
|
|
||||||
Dbc* pcursor = GetCursor();
|
Dbc* pcursor = batch.GetCursor();
|
||||||
if (!pcursor)
|
if (!pcursor)
|
||||||
throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
|
throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
|
||||||
bool setRange = true;
|
bool setRange = true;
|
||||||
@ -229,7 +229,7 @@ void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<
|
|||||||
if (setRange)
|
if (setRange)
|
||||||
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
|
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
|
||||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||||
int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
|
int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
|
||||||
setRange = false;
|
setRange = false;
|
||||||
if (ret == DB_NOTFOUND)
|
if (ret == DB_NOTFOUND)
|
||||||
break;
|
break;
|
||||||
@ -560,7 +560,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
try {
|
try {
|
||||||
int nMinVersion = 0;
|
int nMinVersion = 0;
|
||||||
if (Read((std::string)"minversion", nMinVersion))
|
if (batch.Read((std::string)"minversion", nMinVersion))
|
||||||
{
|
{
|
||||||
if (nMinVersion > CLIENT_VERSION)
|
if (nMinVersion > CLIENT_VERSION)
|
||||||
return DB_TOO_NEW;
|
return DB_TOO_NEW;
|
||||||
@ -568,7 +568,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get cursor
|
// Get cursor
|
||||||
Dbc* pcursor = GetCursor();
|
Dbc* pcursor = batch.GetCursor();
|
||||||
if (!pcursor)
|
if (!pcursor)
|
||||||
{
|
{
|
||||||
LogPrintf("Error getting wallet database cursor\n");
|
LogPrintf("Error getting wallet database cursor\n");
|
||||||
@ -580,7 +580,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||||||
// Read next record
|
// Read next record
|
||||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||||
CDataStream ssValue(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)
|
if (ret == DB_NOTFOUND)
|
||||||
break;
|
break;
|
||||||
else if (ret != 0)
|
else if (ret != 0)
|
||||||
@ -664,14 +664,14 @@ DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWal
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
int nMinVersion = 0;
|
int nMinVersion = 0;
|
||||||
if (Read((std::string)"minversion", nMinVersion))
|
if (batch.Read((std::string)"minversion", nMinVersion))
|
||||||
{
|
{
|
||||||
if (nMinVersion > CLIENT_VERSION)
|
if (nMinVersion > CLIENT_VERSION)
|
||||||
return DB_TOO_NEW;
|
return DB_TOO_NEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cursor
|
// Get cursor
|
||||||
Dbc* pcursor = GetCursor();
|
Dbc* pcursor = batch.GetCursor();
|
||||||
if (!pcursor)
|
if (!pcursor)
|
||||||
{
|
{
|
||||||
LogPrintf("Error getting wallet database cursor\n");
|
LogPrintf("Error getting wallet database cursor\n");
|
||||||
@ -683,7 +683,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWal
|
|||||||
// Read next record
|
// Read next record
|
||||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||||
CDataStream ssValue(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)
|
if (ret == DB_NOTFOUND)
|
||||||
break;
|
break;
|
||||||
else if (ret != 0)
|
else if (ret != 0)
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -855,20 +855,20 @@ 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)
|
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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)
|
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
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::WriteHDChain(const CHDChain& chain)
|
bool CWalletDB::WriteHDChain(const CHDChain& chain)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
return Write(std::string("hdchain"), chain);
|
return batch.Write(std::string("hdchain"), chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWalletDB::IncrementUpdateCounter()
|
void CWalletDB::IncrementUpdateCounter()
|
||||||
@ -880,3 +880,28 @@ unsigned int CWalletDB::GetUpdateCounter()
|
|||||||
{
|
{
|
||||||
return nWalletDBUpdateCounter;
|
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);
|
||||||
|
}
|
||||||
|
@ -17,6 +17,21 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
static const bool DEFAULT_FLUSHWALLET = true;
|
||||||
|
|
||||||
class CAccount;
|
class CAccount;
|
||||||
@ -118,11 +133,16 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Access to the wallet database */
|
/** Access to the wallet database.
|
||||||
class CWalletDB : public CDB
|
* 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:
|
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) :
|
||||||
|
batch(dbw, pszMode, _fFlushOnClose)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +214,20 @@ public:
|
|||||||
|
|
||||||
static void IncrementUpdateCounter();
|
static void IncrementUpdateCounter();
|
||||||
static unsigned int GetUpdateCounter();
|
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:
|
private:
|
||||||
|
CDB batch;
|
||||||
|
|
||||||
CWalletDB(const CWalletDB&);
|
CWalletDB(const CWalletDB&);
|
||||||
void operator=(const CWalletDB&);
|
void operator=(const CWalletDB&);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user