Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/walletdb.cpp
Show All 15 Lines | |||||
#include <sync.h> | #include <sync.h> | ||||
#include <util.h> | #include <util.h> | ||||
#include <utiltime.h> | #include <utiltime.h> | ||||
#include <wallet/wallet.h> | #include <wallet/wallet.h> | ||||
#include <atomic> | #include <atomic> | ||||
// | // | ||||
// CWalletDB | // WalletBatch | ||||
// | // | ||||
bool CWalletDB::WriteName(const CTxDestination &address, | bool WalletBatch::WriteName(const CTxDestination &address, | ||||
const std::string &strName) { | const std::string &strName) { | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return WriteIC(std::make_pair(std::string("name"), | return WriteIC(std::make_pair(std::string("name"), | ||||
EncodeLegacyAddr(address, Params())), | EncodeLegacyAddr(address, Params())), | ||||
strName); | strName); | ||||
} | } | ||||
bool CWalletDB::EraseName(const CTxDestination &address) { | bool WalletBatch::EraseName(const CTxDestination &address) { | ||||
// This should only be used for sending addresses, never for receiving | // This should only be used for sending addresses, never for receiving | ||||
// addresses, receiving addresses must always have an address book entry if | // addresses, receiving addresses must always have an address book entry if | ||||
// they're not change return. | // they're not change return. | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return EraseIC(std::make_pair(std::string("name"), | return EraseIC(std::make_pair(std::string("name"), | ||||
EncodeLegacyAddr(address, Params()))); | EncodeLegacyAddr(address, Params()))); | ||||
} | } | ||||
bool CWalletDB::WritePurpose(const CTxDestination &address, | bool WalletBatch::WritePurpose(const CTxDestination &address, | ||||
const std::string &strPurpose) { | const std::string &strPurpose) { | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return WriteIC(std::make_pair(std::string("purpose"), | return WriteIC(std::make_pair(std::string("purpose"), | ||||
EncodeLegacyAddr(address, Params())), | EncodeLegacyAddr(address, Params())), | ||||
strPurpose); | strPurpose); | ||||
} | } | ||||
bool CWalletDB::ErasePurpose(const CTxDestination &address) { | bool WalletBatch::ErasePurpose(const CTxDestination &address) { | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return EraseIC(std::make_pair(std::string("purpose"), | return EraseIC(std::make_pair(std::string("purpose"), | ||||
EncodeLegacyAddr(address, Params()))); | EncodeLegacyAddr(address, Params()))); | ||||
} | } | ||||
bool CWalletDB::WriteTx(const CWalletTx &wtx) { | bool WalletBatch::WriteTx(const CWalletTx &wtx) { | ||||
return WriteIC(std::make_pair(std::string("tx"), wtx.GetId()), wtx); | return WriteIC(std::make_pair(std::string("tx"), wtx.GetId()), wtx); | ||||
} | } | ||||
bool CWalletDB::EraseTx(uint256 hash) { | bool WalletBatch::EraseTx(uint256 hash) { | ||||
return EraseIC(std::make_pair(std::string("tx"), hash)); | return EraseIC(std::make_pair(std::string("tx"), hash)); | ||||
} | } | ||||
bool CWalletDB::WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, | bool WalletBatch::WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, | ||||
const CKeyMetadata &keyMeta) { | const CKeyMetadata &keyMeta) { | ||||
if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, | if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, | ||||
false)) { | false)) { | ||||
return false; | return false; | ||||
} | } | ||||
// hash pubkey/privkey to accelerate wallet load | // hash pubkey/privkey to accelerate wallet load | ||||
std::vector<uint8_t> vchKey; | std::vector<uint8_t> vchKey; | ||||
vchKey.reserve(vchPubKey.size() + vchPrivKey.size()); | vchKey.reserve(vchPubKey.size() + vchPrivKey.size()); | ||||
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 WriteIC( | return WriteIC( | ||||
std::make_pair(std::string("key"), vchPubKey), | std::make_pair(std::string("key"), vchPubKey), | ||||
std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); | std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); | ||||
} | } | ||||
bool CWalletDB::WriteCryptedKey(const CPubKey &vchPubKey, | bool WalletBatch::WriteCryptedKey(const CPubKey &vchPubKey, | ||||
const std::vector<uint8_t> &vchCryptedSecret, | const std::vector<uint8_t> &vchCryptedSecret, | ||||
const CKeyMetadata &keyMeta) { | const CKeyMetadata &keyMeta) { | ||||
if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) { | if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), | if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), | ||||
vchCryptedSecret, false)) { | vchCryptedSecret, false)) { | ||||
return false; | return false; | ||||
} | } | ||||
EraseIC(std::make_pair(std::string("key"), vchPubKey)); | EraseIC(std::make_pair(std::string("key"), vchPubKey)); | ||||
EraseIC(std::make_pair(std::string("wkey"), vchPubKey)); | EraseIC(std::make_pair(std::string("wkey"), vchPubKey)); | ||||
return true; | return true; | ||||
} | } | ||||
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey) { | bool WalletBatch::WriteMasterKey(unsigned int nID, | ||||
const CMasterKey &kMasterKey) { | |||||
return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true); | return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true); | ||||
} | } | ||||
bool CWalletDB::WriteCScript(const uint160 &hash, const CScript &redeemScript) { | bool WalletBatch::WriteCScript(const uint160 &hash, | ||||
const CScript &redeemScript) { | |||||
return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, | return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, | ||||
false); | false); | ||||
} | } | ||||
bool CWalletDB::WriteWatchOnly(const CScript &dest, | bool WalletBatch::WriteWatchOnly(const CScript &dest, | ||||
const CKeyMetadata &keyMeta) { | const CKeyMetadata &keyMeta) { | ||||
if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) { | if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) { | ||||
return false; | return false; | ||||
} | } | ||||
return WriteIC(std::make_pair(std::string("watchs"), dest), '1'); | return WriteIC(std::make_pair(std::string("watchs"), dest), '1'); | ||||
} | } | ||||
bool CWalletDB::EraseWatchOnly(const CScript &dest) { | bool WalletBatch::EraseWatchOnly(const CScript &dest) { | ||||
if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) { | if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) { | ||||
return false; | return false; | ||||
} | } | ||||
return EraseIC(std::make_pair(std::string("watchs"), dest)); | return EraseIC(std::make_pair(std::string("watchs"), dest)); | ||||
} | } | ||||
bool CWalletDB::WriteBestBlock(const CBlockLocator &locator) { | bool WalletBatch::WriteBestBlock(const CBlockLocator &locator) { | ||||
// Write empty block locator so versions that require a merkle branch | // Write empty block locator so versions that require a merkle branch | ||||
// automatically rescan | // automatically rescan | ||||
WriteIC(std::string("bestblock"), CBlockLocator()); | WriteIC(std::string("bestblock"), CBlockLocator()); | ||||
return WriteIC(std::string("bestblock_nomerkle"), locator); | return WriteIC(std::string("bestblock_nomerkle"), locator); | ||||
} | } | ||||
bool CWalletDB::ReadBestBlock(CBlockLocator &locator) { | bool WalletBatch::ReadBestBlock(CBlockLocator &locator) { | ||||
if (batch.Read(std::string("bestblock"), locator) && | if (m_batch.Read(std::string("bestblock"), locator) && | ||||
!locator.vHave.empty()) { | !locator.vHave.empty()) { | ||||
return true; | return true; | ||||
} | } | ||||
return batch.Read(std::string("bestblock_nomerkle"), locator); | return m_batch.Read(std::string("bestblock_nomerkle"), locator); | ||||
} | } | ||||
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext) { | bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext) { | ||||
return WriteIC(std::string("orderposnext"), nOrderPosNext); | return WriteIC(std::string("orderposnext"), nOrderPosNext); | ||||
} | } | ||||
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool &keypool) { | bool WalletBatch::ReadPool(int64_t nPool, CKeyPool &keypool) { | ||||
return batch.Read(std::make_pair(std::string("pool"), nPool), keypool); | return m_batch.Read(std::make_pair(std::string("pool"), nPool), keypool); | ||||
} | } | ||||
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool &keypool) { | bool WalletBatch::WritePool(int64_t nPool, const CKeyPool &keypool) { | ||||
return WriteIC(std::make_pair(std::string("pool"), nPool), keypool); | return WriteIC(std::make_pair(std::string("pool"), nPool), keypool); | ||||
} | } | ||||
bool CWalletDB::ErasePool(int64_t nPool) { | bool WalletBatch::ErasePool(int64_t nPool) { | ||||
return EraseIC(std::make_pair(std::string("pool"), nPool)); | return EraseIC(std::make_pair(std::string("pool"), nPool)); | ||||
} | } | ||||
bool CWalletDB::WriteMinVersion(int nVersion) { | bool WalletBatch::WriteMinVersion(int nVersion) { | ||||
return WriteIC(std::string("minversion"), nVersion); | return WriteIC(std::string("minversion"), nVersion); | ||||
} | } | ||||
bool CWalletDB::ReadAccount(const std::string &strAccount, CAccount &account) { | bool WalletBatch::ReadAccount(const std::string &strAccount, | ||||
CAccount &account) { | |||||
account.SetNull(); | account.SetNull(); | ||||
return batch.Read(std::make_pair(std::string("acc"), strAccount), account); | return m_batch.Read(std::make_pair(std::string("acc"), strAccount), | ||||
account); | |||||
} | } | ||||
bool CWalletDB::WriteAccount(const std::string &strAccount, | bool WalletBatch::WriteAccount(const std::string &strAccount, | ||||
const CAccount &account) { | const CAccount &account) { | ||||
return WriteIC(std::make_pair(std::string("acc"), strAccount), account); | return WriteIC(std::make_pair(std::string("acc"), strAccount), account); | ||||
} | } | ||||
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, | bool WalletBatch::WriteAccountingEntry(const uint64_t nAccEntryNum, | ||||
const CAccountingEntry &acentry) { | const CAccountingEntry &acentry) { | ||||
return WriteIC( | return WriteIC( | ||||
std::make_pair(std::string("acentry"), | std::make_pair(std::string("acentry"), | ||||
std::make_pair(acentry.strAccount, nAccEntryNum)), | std::make_pair(acentry.strAccount, nAccEntryNum)), | ||||
acentry); | acentry); | ||||
} | } | ||||
Amount CWalletDB::GetAccountCreditDebit(const std::string &strAccount) { | Amount WalletBatch::GetAccountCreditDebit(const std::string &strAccount) { | ||||
std::list<CAccountingEntry> entries; | std::list<CAccountingEntry> entries; | ||||
ListAccountCreditDebit(strAccount, entries); | ListAccountCreditDebit(strAccount, entries); | ||||
Amount nCreditDebit = Amount::zero(); | Amount nCreditDebit = Amount::zero(); | ||||
for (const CAccountingEntry &entry : entries) { | for (const CAccountingEntry &entry : entries) { | ||||
nCreditDebit += entry.nCreditDebit; | nCreditDebit += entry.nCreditDebit; | ||||
} | } | ||||
return nCreditDebit; | return nCreditDebit; | ||||
} | } | ||||
void CWalletDB::ListAccountCreditDebit(const std::string &strAccount, | void WalletBatch::ListAccountCreditDebit(const std::string &strAccount, | ||||
std::list<CAccountingEntry> &entries) { | std::list<CAccountingEntry> &entries) { | ||||
bool fAllAccounts = (strAccount == "*"); | bool fAllAccounts = (strAccount == "*"); | ||||
Dbc *pcursor = batch.GetCursor(); | Dbc *pcursor = m_batch.GetCursor(); | ||||
if (!pcursor) { | if (!pcursor) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": cannot create DB cursor"); | ": cannot create DB cursor"); | ||||
} | } | ||||
bool setRange = true; | bool setRange = true; | ||||
while (true) { | while (true) { | ||||
// Read next record | // Read next record | ||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION); | CDataStream ssKey(SER_DISK, CLIENT_VERSION); | ||||
if (setRange) { | if (setRange) { | ||||
ssKey << std::make_pair( | ssKey << std::make_pair( | ||||
std::string("acentry"), | std::string("acentry"), | ||||
std::make_pair((fAllAccounts ? std::string("") : strAccount), | std::make_pair((fAllAccounts ? std::string("") : strAccount), | ||||
uint64_t(0))); | uint64_t(0))); | ||||
} | } | ||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION); | CDataStream ssValue(SER_DISK, CLIENT_VERSION); | ||||
int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); | int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); | ||||
setRange = false; | setRange = false; | ||||
if (ret == DB_NOTFOUND) { | if (ret == DB_NOTFOUND) { | ||||
break; | break; | ||||
} | } | ||||
if (ret != 0) { | if (ret != 0) { | ||||
pcursor->close(); | pcursor->close(); | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
▲ Show 20 Lines • Show All 281 Lines • ▼ Show 20 Lines | try { | ||||
} | } | ||||
} | } | ||||
} catch (...) { | } catch (...) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWalletDB::IsKeyType(const std::string &strType) { | bool WalletBatch::IsKeyType(const std::string &strType) { | ||||
return (strType == "key" || strType == "wkey" || strType == "mkey" || | return (strType == "key" || strType == "wkey" || strType == "mkey" || | ||||
strType == "ckey"); | strType == "ckey"); | ||||
} | } | ||||
DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { | DBErrors WalletBatch::LoadWallet(CWallet *pwallet) { | ||||
CWalletScanState wss; | CWalletScanState wss; | ||||
bool fNoncriticalErrors = false; | bool fNoncriticalErrors = false; | ||||
DBErrors result = DBErrors::LOAD_OK; | DBErrors result = DBErrors::LOAD_OK; | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
try { | try { | ||||
int nMinVersion = 0; | int nMinVersion = 0; | ||||
if (batch.Read((std::string) "minversion", nMinVersion)) { | if (m_batch.Read((std::string) "minversion", nMinVersion)) { | ||||
if (nMinVersion > CLIENT_VERSION) { | if (nMinVersion > CLIENT_VERSION) { | ||||
return DBErrors::TOO_NEW; | return DBErrors::TOO_NEW; | ||||
} | } | ||||
pwallet->LoadMinVersion(nMinVersion); | pwallet->LoadMinVersion(nMinVersion); | ||||
} | } | ||||
// Get cursor | // Get cursor | ||||
Dbc *pcursor = batch.GetCursor(); | Dbc *pcursor = m_batch.GetCursor(); | ||||
if (!pcursor) { | if (!pcursor) { | ||||
LogPrintf("Error getting wallet database cursor\n"); | LogPrintf("Error getting wallet database cursor\n"); | ||||
return DBErrors::CORRUPT; | return DBErrors::CORRUPT; | ||||
} | } | ||||
while (true) { | while (true) { | ||||
// 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 = batch.ReadAtCursor(pcursor, ssKey, ssValue); | int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); | ||||
if (ret == DB_NOTFOUND) { | if (ret == DB_NOTFOUND) { | ||||
break; | break; | ||||
} | } | ||||
if (ret != 0) { | if (ret != 0) { | ||||
LogPrintf("Error reading next record from wallet database\n"); | LogPrintf("Error reading next record from wallet database\n"); | ||||
return DBErrors::CORRUPT; | return DBErrors::CORRUPT; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | DBErrors WalletBatch::LoadWallet(CWallet *pwallet) { | ||||
for (CAccountingEntry &entry : pwallet->laccentries) { | for (CAccountingEntry &entry : pwallet->laccentries) { | ||||
pwallet->wtxOrdered.insert( | pwallet->wtxOrdered.insert( | ||||
std::make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry))); | std::make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry))); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
DBErrors CWalletDB::FindWalletTx(std::vector<TxId> &txIds, | DBErrors WalletBatch::FindWalletTx(std::vector<TxId> &txIds, | ||||
std::vector<CWalletTx> &vWtx) { | std::vector<CWalletTx> &vWtx) { | ||||
DBErrors result = DBErrors::LOAD_OK; | DBErrors result = DBErrors::LOAD_OK; | ||||
try { | try { | ||||
int nMinVersion = 0; | int nMinVersion = 0; | ||||
if (batch.Read((std::string) "minversion", nMinVersion)) { | if (m_batch.Read((std::string) "minversion", nMinVersion)) { | ||||
if (nMinVersion > CLIENT_VERSION) { | if (nMinVersion > CLIENT_VERSION) { | ||||
return DBErrors::TOO_NEW; | return DBErrors::TOO_NEW; | ||||
} | } | ||||
} | } | ||||
// Get cursor | // Get cursor | ||||
Dbc *pcursor = batch.GetCursor(); | Dbc *pcursor = m_batch.GetCursor(); | ||||
if (!pcursor) { | if (!pcursor) { | ||||
LogPrintf("Error getting wallet database cursor\n"); | LogPrintf("Error getting wallet database cursor\n"); | ||||
return DBErrors::CORRUPT; | return DBErrors::CORRUPT; | ||||
} | } | ||||
while (true) { | while (true) { | ||||
// 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 = batch.ReadAtCursor(pcursor, ssKey, ssValue); | int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); | ||||
if (ret == DB_NOTFOUND) { | if (ret == DB_NOTFOUND) { | ||||
break; | break; | ||||
} | } | ||||
if (ret != 0) { | if (ret != 0) { | ||||
LogPrintf("Error reading next record from wallet database\n"); | LogPrintf("Error reading next record from wallet database\n"); | ||||
return DBErrors::CORRUPT; | return DBErrors::CORRUPT; | ||||
} | } | ||||
Show All 16 Lines | try { | ||||
throw; | throw; | ||||
} catch (...) { | } catch (...) { | ||||
result = DBErrors::CORRUPT; | result = DBErrors::CORRUPT; | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
DBErrors CWalletDB::ZapSelectTx(std::vector<TxId> &txIdsIn, | DBErrors WalletBatch::ZapSelectTx(std::vector<TxId> &txIdsIn, | ||||
std::vector<TxId> &txIdsOut) { | std::vector<TxId> &txIdsOut) { | ||||
// Build list of wallet TXs and hashes. | // Build list of wallet TXs and hashes. | ||||
std::vector<TxId> txIds; | std::vector<TxId> txIds; | ||||
std::vector<CWalletTx> vWtx; | std::vector<CWalletTx> vWtx; | ||||
DBErrors err = FindWalletTx(txIds, vWtx); | DBErrors err = FindWalletTx(txIds, vWtx); | ||||
if (err != DBErrors::LOAD_OK) { | if (err != DBErrors::LOAD_OK) { | ||||
return err; | return err; | ||||
} | } | ||||
Show All 24 Lines | DBErrors WalletBatch::ZapSelectTx(std::vector<TxId> &txIdsIn, | ||||
} | } | ||||
if (delerror) { | if (delerror) { | ||||
return DBErrors::CORRUPT; | return DBErrors::CORRUPT; | ||||
} | } | ||||
return DBErrors::LOAD_OK; | return DBErrors::LOAD_OK; | ||||
} | } | ||||
DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx> &vWtx) { | DBErrors WalletBatch::ZapWalletTx(std::vector<CWalletTx> &vWtx) { | ||||
// Build list of wallet TXs. | // Build list of wallet TXs. | ||||
std::vector<TxId> txIds; | std::vector<TxId> txIds; | ||||
DBErrors err = FindWalletTx(txIds, vWtx); | DBErrors err = FindWalletTx(txIds, vWtx); | ||||
if (err != DBErrors::LOAD_OK) { | if (err != DBErrors::LOAD_OK) { | ||||
return err; | return err; | ||||
} | } | ||||
// Erase each wallet TX. | // Erase each wallet TX. | ||||
Show All 11 Lines | void MaybeCompactWalletDB() { | ||||
if (fOneThread.exchange(true)) { | if (fOneThread.exchange(true)) { | ||||
return; | return; | ||||
} | } | ||||
if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) { | if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) { | ||||
return; | return; | ||||
} | } | ||||
for (CWallet *pwallet : GetWallets()) { | for (CWallet *pwallet : GetWallets()) { | ||||
CWalletDBWrapper &dbh = pwallet->GetDBHandle(); | WalletDatabase &dbh = pwallet->GetDBHandle(); | ||||
unsigned int nUpdateCounter = dbh.nUpdateCounter; | unsigned int nUpdateCounter = dbh.nUpdateCounter; | ||||
if (dbh.nLastSeen != nUpdateCounter) { | if (dbh.nLastSeen != nUpdateCounter) { | ||||
dbh.nLastSeen = nUpdateCounter; | dbh.nLastSeen = nUpdateCounter; | ||||
dbh.nLastWalletUpdate = GetTime(); | dbh.nLastWalletUpdate = GetTime(); | ||||
} | } | ||||
if (dbh.nLastFlushed != nUpdateCounter && | if (dbh.nLastFlushed != nUpdateCounter && | ||||
GetTime() - dbh.nLastWalletUpdate >= 2) { | GetTime() - dbh.nLastWalletUpdate >= 2) { | ||||
if (CDB::PeriodicFlush(dbh)) { | if (BerkeleyBatch::PeriodicFlush(dbh)) { | ||||
dbh.nLastFlushed = nUpdateCounter; | dbh.nLastFlushed = nUpdateCounter; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
fOneThread = false; | fOneThread = false; | ||||
} | } | ||||
// | // | ||||
// Try to (very carefully!) recover wallet file if there is a problem. | // Try to (very carefully!) recover wallet file if there is a problem. | ||||
// | // | ||||
bool CWalletDB::Recover(const fs::path &wallet_path, void *callbackDataIn, | bool WalletBatch::Recover(const fs::path &wallet_path, void *callbackDataIn, | ||||
bool (*recoverKVcallback)(void *callbackData, | bool (*recoverKVcallback)(void *callbackData, | ||||
CDataStream ssKey, | CDataStream ssKey, | ||||
CDataStream ssValue), | CDataStream ssValue), | ||||
std::string &out_backup_filename) { | std::string &out_backup_filename) { | ||||
return CDB::Recover(wallet_path, callbackDataIn, recoverKVcallback, | return BerkeleyBatch::Recover(wallet_path, callbackDataIn, | ||||
out_backup_filename); | recoverKVcallback, out_backup_filename); | ||||
} | } | ||||
bool CWalletDB::Recover(const fs::path &wallet_path, | bool WalletBatch::Recover(const fs::path &wallet_path, | ||||
std::string &out_backup_filename) { | std::string &out_backup_filename) { | ||||
// recover without a key filter callback | // recover without a key filter callback | ||||
// results in recovering all record types | // results in recovering all record types | ||||
return CWalletDB::Recover(wallet_path, nullptr, nullptr, | return WalletBatch::Recover(wallet_path, nullptr, nullptr, | ||||
out_backup_filename); | out_backup_filename); | ||||
} | } | ||||
bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, | bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, | ||||
CDataStream ssValue) { | CDataStream ssValue) { | ||||
CWallet *dummyWallet = reinterpret_cast<CWallet *>(callbackData); | CWallet *dummyWallet = reinterpret_cast<CWallet *>(callbackData); | ||||
CWalletScanState dummyWss; | CWalletScanState dummyWss; | ||||
std::string strType, strErr; | std::string strType, strErr; | ||||
bool fReadOK; | bool fReadOK; | ||||
{ | { | ||||
// Required in LoadKeyMetadata(): | // Required in LoadKeyMetadata(): | ||||
LOCK(dummyWallet->cs_wallet); | LOCK(dummyWallet->cs_wallet); | ||||
fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, dummyWss, strType, | fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, dummyWss, strType, | ||||
strErr); | strErr); | ||||
} | } | ||||
if (!IsKeyType(strType) && strType != "hdchain") { | if (!IsKeyType(strType) && strType != "hdchain") { | ||||
return false; | return false; | ||||
} | } | ||||
if (!fReadOK) { | if (!fReadOK) { | ||||
LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, | LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, | ||||
strErr); | strErr); | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWalletDB::VerifyEnvironment(const fs::path &wallet_path, | bool WalletBatch::VerifyEnvironment(const fs::path &wallet_path, | ||||
std::string &errorStr) { | std::string &errorStr) { | ||||
return CDB::VerifyEnvironment(wallet_path, errorStr); | return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr); | ||||
} | } | ||||
bool CWalletDB::VerifyDatabaseFile(const fs::path &wallet_path, | bool WalletBatch::VerifyDatabaseFile(const fs::path &wallet_path, | ||||
std::string &warningStr, | std::string &warningStr, | ||||
std::string &errorStr) { | std::string &errorStr) { | ||||
return CDB::VerifyDatabaseFile(wallet_path, warningStr, errorStr, | return BerkeleyBatch::VerifyDatabaseFile(wallet_path, warningStr, errorStr, | ||||
CWalletDB::Recover); | WalletBatch::Recover); | ||||
} | } | ||||
bool CWalletDB::WriteDestData(const CTxDestination &address, | bool WalletBatch::WriteDestData(const CTxDestination &address, | ||||
const std::string &key, | const std::string &key, | ||||
const std::string &value) { | const std::string &value) { | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return WriteIC( | return WriteIC( | ||||
std::make_pair( | std::make_pair( | ||||
std::string("destdata"), | std::string("destdata"), | ||||
std::make_pair(EncodeLegacyAddr(address, Params()), key)), | std::make_pair(EncodeLegacyAddr(address, Params()), key)), | ||||
value); | value); | ||||
} | } | ||||
bool CWalletDB::EraseDestData(const CTxDestination &address, | bool WalletBatch::EraseDestData(const CTxDestination &address, | ||||
const std::string &key) { | const std::string &key) { | ||||
if (!IsValidDestination(address)) { | if (!IsValidDestination(address)) { | ||||
return false; | return false; | ||||
} | } | ||||
return EraseIC(std::make_pair( | return EraseIC(std::make_pair( | ||||
std::string("destdata"), | std::string("destdata"), | ||||
std::make_pair(EncodeLegacyAddr(address, Params()), key))); | std::make_pair(EncodeLegacyAddr(address, Params()), key))); | ||||
} | } | ||||
bool CWalletDB::WriteHDChain(const CHDChain &chain) { | bool WalletBatch::WriteHDChain(const CHDChain &chain) { | ||||
return WriteIC(std::string("hdchain"), chain); | return WriteIC(std::string("hdchain"), chain); | ||||
} | } | ||||
bool CWalletDB::TxnBegin() { | bool WalletBatch::TxnBegin() { | ||||
return batch.TxnBegin(); | return m_batch.TxnBegin(); | ||||
} | } | ||||
bool CWalletDB::TxnCommit() { | bool WalletBatch::TxnCommit() { | ||||
return batch.TxnCommit(); | return m_batch.TxnCommit(); | ||||
} | } | ||||
bool CWalletDB::TxnAbort() { | bool WalletBatch::TxnAbort() { | ||||
return batch.TxnAbort(); | return m_batch.TxnAbort(); | ||||
} | } | ||||
bool CWalletDB::ReadVersion(int &nVersion) { | bool WalletBatch::ReadVersion(int &nVersion) { | ||||
return batch.ReadVersion(nVersion); | return m_batch.ReadVersion(nVersion); | ||||
} | } | ||||
bool CWalletDB::WriteVersion(int nVersion) { | bool WalletBatch::WriteVersion(int nVersion) { | ||||
return batch.WriteVersion(nVersion); | return m_batch.WriteVersion(nVersion); | ||||
} | } |