Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/walletdb.cpp
Show All 15 Lines | |||||
#include "wallet/wallet.h" | #include "wallet/wallet.h" | ||||
#include <atomic> | #include <atomic> | ||||
#include <boost/filesystem.hpp> | #include <boost/filesystem.hpp> | ||||
#include <boost/thread.hpp> | #include <boost/thread.hpp> | ||||
#include <boost/version.hpp> | #include <boost/version.hpp> | ||||
using namespace std; | |||||
static uint64_t nAccountingEntryNumber = 0; | static uint64_t nAccountingEntryNumber = 0; | ||||
static std::atomic<unsigned int> nWalletDBUpdateCounter; | static std::atomic<unsigned int> nWalletDBUpdateCounter; | ||||
// | // | ||||
// CWalletDB | // CWalletDB | ||||
// | // | ||||
bool CWalletDB::WriteName(const string &strAddress, const string &strName) { | bool CWalletDB::WriteName(const std::string &strAddress, const std::string &strName) { | ||||
nWalletDBUpdateCounter++; | nWalletDBUpdateCounter++; | ||||
return Write(make_pair(string("name"), strAddress), strName); | return Write(make_pair(std::string("name"), strAddress), strName); | ||||
} | } | ||||
bool CWalletDB::EraseName(const string &strAddress) { | bool CWalletDB::EraseName(const std::string &strAddress) { | ||||
// 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. | ||||
nWalletDBUpdateCounter++; | nWalletDBUpdateCounter++; | ||||
return Erase(make_pair(string("name"), strAddress)); | return Erase(make_pair(std::string("name"), strAddress)); | ||||
} | } | ||||
bool CWalletDB::WritePurpose(const string &strAddress, | bool CWalletDB::WritePurpose(const std::string &strAddress, | ||||
const string &strPurpose) { | const std::string &strPurpose) { | ||||
nWalletDBUpdateCounter++; | nWalletDBUpdateCounter++; | ||||
return Write(make_pair(string("purpose"), strAddress), strPurpose); | return Write(make_pair(std::string("purpose"), strAddress), strPurpose); | ||||
} | } | ||||
bool CWalletDB::ErasePurpose(const string &strPurpose) { | bool CWalletDB::ErasePurpose(const std::string &strPurpose) { | ||||
nWalletDBUpdateCounter++; | nWalletDBUpdateCounter++; | ||||
return Erase(make_pair(string("purpose"), strPurpose)); | return Erase(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.GetId()), wtx); | return Write(std::make_pair(std::string("tx"), wtx.GetId()), wtx); | ||||
} | } | ||||
bool CWalletDB::EraseTx(uint256 hash) { | bool CWalletDB::EraseTx(uint256 hash) { | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | bool CWalletDB::ErasePool(int64_t nPool) { | ||||
nWalletDBUpdateCounter++; | nWalletDBUpdateCounter++; | ||||
return Erase(std::make_pair(std::string("pool"), nPool)); | return 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 Write(std::string("minversion"), nVersion); | ||||
} | } | ||||
bool CWalletDB::ReadAccount(const string &strAccount, CAccount &account) { | bool CWalletDB::ReadAccount(const std::string &strAccount, CAccount &account) { | ||||
account.SetNull(); | account.SetNull(); | ||||
return Read(make_pair(string("acc"), strAccount), account); | return Read(make_pair(std::string("acc"), strAccount), account); | ||||
} | } | ||||
bool CWalletDB::WriteAccount(const string &strAccount, | bool CWalletDB::WriteAccount(const std::string &strAccount, | ||||
const CAccount &account) { | const CAccount &account) { | ||||
return Write(make_pair(string("acc"), strAccount), account); | return Write(make_pair(std::string("acc"), strAccount), account); | ||||
} | } | ||||
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, | bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, | ||||
const CAccountingEntry &acentry) { | const CAccountingEntry &acentry) { | ||||
return Write( | return Write( | ||||
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); | ||||
} | } | ||||
bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry &acentry) { | bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry &acentry) { | ||||
return WriteAccountingEntry(++nAccountingEntryNumber, acentry); | return WriteAccountingEntry(++nAccountingEntryNumber, acentry); | ||||
} | } | ||||
CAmount CWalletDB::GetAccountCreditDebit(const string &strAccount) { | CAmount CWalletDB::GetAccountCreditDebit(const std::string &strAccount) { | ||||
list<CAccountingEntry> entries; | std::list<CAccountingEntry> entries; | ||||
ListAccountCreditDebit(strAccount, entries); | ListAccountCreditDebit(strAccount, entries); | ||||
CAmount nCreditDebit = 0; | CAmount nCreditDebit = 0; | ||||
for (const CAccountingEntry &entry : entries) { | for (const CAccountingEntry &entry : entries) { | ||||
nCreditDebit += entry.nCreditDebit; | nCreditDebit += entry.nCreditDebit; | ||||
} | } | ||||
return nCreditDebit; | return nCreditDebit; | ||||
} | } | ||||
void CWalletDB::ListAccountCreditDebit(const string &strAccount, | void CWalletDB::ListAccountCreditDebit(const std::string &strAccount, | ||||
list<CAccountingEntry> &entries) { | std::list<CAccountingEntry> &entries) { | ||||
bool fAllAccounts = (strAccount == "*"); | bool fAllAccounts = (strAccount == "*"); | ||||
Dbc *pcursor = GetCursor(); | Dbc *pcursor = GetCursor(); | ||||
if (!pcursor) | if (!pcursor) | ||||
throw 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 ? 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 = ReadAtCursor(pcursor, ssKey, ssValue, setRange); | int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); | ||||
setRange = false; | setRange = false; | ||||
if (ret == DB_NOTFOUND) | if (ret == DB_NOTFOUND) | ||||
break; | break; | ||||
else if (ret != 0) { | else if (ret != 0) { | ||||
pcursor->close(); | pcursor->close(); | ||||
throw runtime_error(std::string(__func__) + ": error scanning DB"); | throw std::runtime_error(std::string(__func__) + ": error scanning DB"); | ||||
} | } | ||||
// Unserialize | // Unserialize | ||||
string strType; | std::string strType; | ||||
ssKey >> strType; | ssKey >> strType; | ||||
if (strType != "acentry") break; | if (strType != "acentry") break; | ||||
CAccountingEntry acentry; | CAccountingEntry acentry; | ||||
ssKey >> acentry.strAccount; | ssKey >> acentry.strAccount; | ||||
if (!fAllAccounts && acentry.strAccount != strAccount) break; | if (!fAllAccounts && acentry.strAccount != strAccount) break; | ||||
ssValue >> acentry; | ssValue >> acentry; | ||||
ssKey >> acentry.nEntryNo; | ssKey >> acentry.nEntryNo; | ||||
entries.push_back(acentry); | entries.push_back(acentry); | ||||
} | } | ||||
pcursor->close(); | pcursor->close(); | ||||
} | } | ||||
class CWalletScanState { | class CWalletScanState { | ||||
public: | public: | ||||
unsigned int nKeys; | unsigned int nKeys; | ||||
unsigned int nCKeys; | unsigned int nCKeys; | ||||
unsigned int nWatchKeys; | unsigned int nWatchKeys; | ||||
unsigned int nKeyMeta; | unsigned int nKeyMeta; | ||||
bool fIsEncrypted; | bool fIsEncrypted; | ||||
bool fAnyUnordered; | bool fAnyUnordered; | ||||
int nFileVersion; | int nFileVersion; | ||||
vector<uint256> vWalletUpgrade; | std::vector<uint256> vWalletUpgrade; | ||||
CWalletScanState() { | CWalletScanState() { | ||||
nKeys = nCKeys = nWatchKeys = nKeyMeta = 0; | nKeys = nCKeys = nWatchKeys = nKeyMeta = 0; | ||||
fIsEncrypted = false; | fIsEncrypted = false; | ||||
fAnyUnordered = false; | fAnyUnordered = false; | ||||
nFileVersion = 0; | nFileVersion = 0; | ||||
} | } | ||||
}; | }; | ||||
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, | bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, | ||||
CWalletScanState &wss, string &strType, string &strErr) { | CWalletScanState &wss, std::string &strType, std::string &strErr) { | ||||
try { | try { | ||||
// Unserialize | // Unserialize | ||||
// Taking advantage of the fact that pair serialization is just the two | // Taking advantage of the fact that pair serialization is just the two | ||||
// items serialized one after the other. | // items serialized one after the other. | ||||
ssKey >> strType; | ssKey >> strType; | ||||
if (strType == "name") { | if (strType == "name") { | ||||
string strAddress; | std::string strAddress; | ||||
ssKey >> strAddress; | ssKey >> strAddress; | ||||
ssValue >> | ssValue >> | ||||
pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; | pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; | ||||
} else if (strType == "purpose") { | } else if (strType == "purpose") { | ||||
string strAddress; | std::string strAddress; | ||||
ssKey >> strAddress; | ssKey >> strAddress; | ||||
ssValue >> | ssValue >> | ||||
pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()] | pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()] | ||||
.purpose; | .purpose; | ||||
} else if (strType == "tx") { | } else if (strType == "tx") { | ||||
uint256 hash; | uint256 hash; | ||||
ssKey >> hash; | ssKey >> hash; | ||||
CWalletTx wtx; | CWalletTx wtx; | ||||
Show All 24 Lines | try { | ||||
} | } | ||||
wss.vWalletUpgrade.push_back(hash); | wss.vWalletUpgrade.push_back(hash); | ||||
} | } | ||||
if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; | if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; | ||||
pwallet->LoadToWallet(wtx); | pwallet->LoadToWallet(wtx); | ||||
} else if (strType == "acentry") { | } else if (strType == "acentry") { | ||||
string strAccount; | std::string strAccount; | ||||
ssKey >> strAccount; | ssKey >> strAccount; | ||||
uint64_t nNumber; | uint64_t nNumber; | ||||
ssKey >> nNumber; | ssKey >> nNumber; | ||||
if (nNumber > nAccountingEntryNumber) | if (nNumber > nAccountingEntryNumber) | ||||
nAccountingEntryNumber = nNumber; | nAccountingEntryNumber = nNumber; | ||||
if (!wss.fAnyUnordered) { | if (!wss.fAnyUnordered) { | ||||
CAccountingEntry acentry; | CAccountingEntry acentry; | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | try { | ||||
if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; | if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; | ||||
} else if (strType == "ckey") { | } else if (strType == "ckey") { | ||||
CPubKey vchPubKey; | CPubKey vchPubKey; | ||||
ssKey >> vchPubKey; | ssKey >> vchPubKey; | ||||
if (!vchPubKey.IsValid()) { | if (!vchPubKey.IsValid()) { | ||||
strErr = "Error reading wallet database: CPubKey corrupt"; | strErr = "Error reading wallet database: CPubKey corrupt"; | ||||
return false; | return false; | ||||
} | } | ||||
vector<unsigned char> vchPrivKey; | std::vector<unsigned char> vchPrivKey; | ||||
ssValue >> vchPrivKey; | ssValue >> vchPrivKey; | ||||
wss.nCKeys++; | wss.nCKeys++; | ||||
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) { | if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) { | ||||
strErr = "Error reading wallet database: LoadCryptedKey failed"; | strErr = "Error reading wallet database: LoadCryptedKey failed"; | ||||
return false; | return false; | ||||
} | } | ||||
wss.fIsEncrypted = true; | wss.fIsEncrypted = true; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | try { | ||||
} | } | ||||
} | } | ||||
} catch (...) { | } catch (...) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static bool IsKeyType(string strType) { | static bool IsKeyType(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 CWalletDB::LoadWallet(CWallet *pwallet) { | ||||
pwallet->vchDefaultKey = CPubKey(); | pwallet->vchDefaultKey = CPubKey(); | ||||
CWalletScanState wss; | CWalletScanState wss; | ||||
bool fNoncriticalErrors = false; | bool fNoncriticalErrors = false; | ||||
DBErrors result = DB_LOAD_OK; | DBErrors result = DB_LOAD_OK; | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
try { | try { | ||||
int nMinVersion = 0; | int nMinVersion = 0; | ||||
if (Read((string) "minversion", nMinVersion)) { | if (Read((std::string) "minversion", nMinVersion)) { | ||||
if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; | if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; | ||||
pwallet->LoadMinVersion(nMinVersion); | pwallet->LoadMinVersion(nMinVersion); | ||||
} | } | ||||
// Get cursor | // Get cursor | ||||
Dbc *pcursor = GetCursor(); | Dbc *pcursor = GetCursor(); | ||||
if (!pcursor) { | if (!pcursor) { | ||||
LogPrintf("Error getting wallet database cursor\n"); | LogPrintf("Error getting wallet database cursor\n"); | ||||
return DB_CORRUPT; | return DB_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 = ReadAtCursor(pcursor, ssKey, ssValue); | int ret = ReadAtCursor(pcursor, ssKey, ssValue); | ||||
if (ret == DB_NOTFOUND) | if (ret == DB_NOTFOUND) | ||||
break; | break; | ||||
else if (ret != 0) { | else if (ret != 0) { | ||||
LogPrintf("Error reading next record from wallet database\n"); | LogPrintf("Error reading next record from wallet database\n"); | ||||
return DB_CORRUPT; | return DB_CORRUPT; | ||||
} | } | ||||
// Try to be tolerant of single corrupt records: | // Try to be tolerant of single corrupt records: | ||||
string strType, strErr; | std::string strType, strErr; | ||||
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { | if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { | ||||
// losing keys is considered a catastrophic error, anything else | // losing keys is considered a catastrophic error, anything else | ||||
// we assume the user can live with: | // we assume the user can live with: | ||||
if (IsKeyType(strType)) | if (IsKeyType(strType)) | ||||
result = DB_CORRUPT; | result = DB_CORRUPT; | ||||
else { | else { | ||||
// Leave other errors alone, if we try to fix them we might | // Leave other errors alone, if we try to fix them we might | ||||
// make things worse. But do warn the user there is | // make things worse. But do warn the user there is | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { | ||||
for (CAccountingEntry &entry : pwallet->laccentries) { | for (CAccountingEntry &entry : pwallet->laccentries) { | ||||
pwallet->wtxOrdered.insert(make_pair( | pwallet->wtxOrdered.insert(make_pair( | ||||
entry.nOrderPos, CWallet::TxPair((CWalletTx *)0, &entry))); | entry.nOrderPos, CWallet::TxPair((CWalletTx *)0, &entry))); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
DBErrors CWalletDB::FindWalletTx(CWallet *pwallet, vector<uint256> &vTxHash, | DBErrors CWalletDB::FindWalletTx(CWallet *pwallet, std::vector<uint256> &vTxHash, | ||||
vector<CWalletTx> &vWtx) { | std::vector<CWalletTx> &vWtx) { | ||||
pwallet->vchDefaultKey = CPubKey(); | pwallet->vchDefaultKey = CPubKey(); | ||||
bool fNoncriticalErrors = false; | bool fNoncriticalErrors = false; | ||||
DBErrors result = DB_LOAD_OK; | DBErrors result = DB_LOAD_OK; | ||||
try { | try { | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
int nMinVersion = 0; | int nMinVersion = 0; | ||||
if (Read((string) "minversion", nMinVersion)) { | if (Read((std::string) "minversion", nMinVersion)) { | ||||
if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; | if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; | ||||
pwallet->LoadMinVersion(nMinVersion); | pwallet->LoadMinVersion(nMinVersion); | ||||
} | } | ||||
// Get cursor | // Get cursor | ||||
Dbc *pcursor = GetCursor(); | Dbc *pcursor = GetCursor(); | ||||
if (!pcursor) { | if (!pcursor) { | ||||
LogPrintf("Error getting wallet database cursor\n"); | LogPrintf("Error getting wallet database cursor\n"); | ||||
return DB_CORRUPT; | return DB_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 = ReadAtCursor(pcursor, ssKey, ssValue); | int ret = ReadAtCursor(pcursor, ssKey, ssValue); | ||||
if (ret == DB_NOTFOUND) | if (ret == DB_NOTFOUND) | ||||
break; | break; | ||||
else if (ret != 0) { | else if (ret != 0) { | ||||
LogPrintf("Error reading next record from wallet database\n"); | LogPrintf("Error reading next record from wallet database\n"); | ||||
return DB_CORRUPT; | return DB_CORRUPT; | ||||
} | } | ||||
string strType; | std::string strType; | ||||
ssKey >> strType; | ssKey >> strType; | ||||
if (strType == "tx") { | if (strType == "tx") { | ||||
uint256 hash; | uint256 hash; | ||||
ssKey >> hash; | ssKey >> hash; | ||||
CWalletTx wtx; | CWalletTx wtx; | ||||
ssValue >> wtx; | ssValue >> wtx; | ||||
Show All 9 Lines | DBErrors CWalletDB::FindWalletTx(CWallet *pwallet, std::vector<uint256> &vTxHash, | ||||
} | } | ||||
if (fNoncriticalErrors && result == DB_LOAD_OK) | if (fNoncriticalErrors && result == DB_LOAD_OK) | ||||
result = DB_NONCRITICAL_ERROR; | result = DB_NONCRITICAL_ERROR; | ||||
return result; | return result; | ||||
} | } | ||||
DBErrors CWalletDB::ZapSelectTx(CWallet *pwallet, vector<uint256> &vTxHashIn, | DBErrors CWalletDB::ZapSelectTx(CWallet *pwallet, std::vector<uint256> &vTxHashIn, | ||||
vector<uint256> &vTxHashOut) { | std::vector<uint256> &vTxHashOut) { | ||||
// Build list of wallet TXs and hashes. | // Build list of wallet TXs and hashes. | ||||
vector<uint256> vTxHash; | std::vector<uint256> vTxHash; | ||||
vector<CWalletTx> vWtx; | std::vector<CWalletTx> vWtx; | ||||
DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); | DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); | ||||
if (err != DB_LOAD_OK) { | if (err != DB_LOAD_OK) { | ||||
return err; | return err; | ||||
} | } | ||||
std::sort(vTxHash.begin(), vTxHash.end()); | std::sort(vTxHash.begin(), vTxHash.end()); | ||||
std::sort(vTxHashIn.begin(), vTxHashIn.end()); | std::sort(vTxHashIn.begin(), vTxHashIn.end()); | ||||
// Erase each matching wallet TX. | // Erase each matching wallet TX. | ||||
bool delerror = false; | bool delerror = false; | ||||
vector<uint256>::iterator it = vTxHashIn.begin(); | std::vector<uint256>::iterator it = vTxHashIn.begin(); | ||||
for (uint256 hash : vTxHash) { | for (uint256 hash : vTxHash) { | ||||
while (it < vTxHashIn.end() && (*it) < hash) { | while (it < vTxHashIn.end() && (*it) < hash) { | ||||
it++; | it++; | ||||
} | } | ||||
if (it == vTxHashIn.end()) { | if (it == vTxHashIn.end()) { | ||||
break; | break; | ||||
} else if ((*it) == hash) { | } else if ((*it) == hash) { | ||||
pwallet->mapWallet.erase(hash); | pwallet->mapWallet.erase(hash); | ||||
if (!EraseTx(hash)) { | if (!EraseTx(hash)) { | ||||
LogPrint("db", "Transaction was found for deletion but " | LogPrint("db", "Transaction was found for deletion but " | ||||
"returned database error: %s\n", | "returned database error: %s\n", | ||||
hash.GetHex()); | hash.GetHex()); | ||||
delerror = true; | delerror = true; | ||||
} | } | ||||
vTxHashOut.push_back(hash); | vTxHashOut.push_back(hash); | ||||
} | } | ||||
} | } | ||||
if (delerror) { | if (delerror) { | ||||
return DB_CORRUPT; | return DB_CORRUPT; | ||||
} | } | ||||
return DB_LOAD_OK; | return DB_LOAD_OK; | ||||
} | } | ||||
DBErrors CWalletDB::ZapWalletTx(CWallet *pwallet, vector<CWalletTx> &vWtx) { | DBErrors CWalletDB::ZapWalletTx(CWallet *pwallet, std::vector<CWalletTx> &vWtx) { | ||||
// Build list of wallet TXs. | // Build list of wallet TXs. | ||||
vector<uint256> vTxHash; | std::vector<uint256> vTxHash; | ||||
DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); | DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); | ||||
if (err != DB_LOAD_OK) return err; | if (err != DB_LOAD_OK) return err; | ||||
// Erase each wallet TX. | // Erase each wallet TX. | ||||
for (uint256 &hash : vTxHash) { | for (uint256 &hash : vTxHash) { | ||||
if (!EraseTx(hash)) return DB_CORRUPT; | if (!EraseTx(hash)) return DB_CORRUPT; | ||||
} | } | ||||
Show All 21 Lines | while (true) { | ||||
} | } | ||||
if (nLastFlushed != CWalletDB::GetUpdateCounter() && | if (nLastFlushed != CWalletDB::GetUpdateCounter() && | ||||
GetTime() - nLastWalletUpdate >= 2) { | GetTime() - nLastWalletUpdate >= 2) { | ||||
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; | ||||
map<string, int>::iterator mi = bitdb.mapFileUseCount.begin(); | std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.begin(); | ||||
while (mi != bitdb.mapFileUseCount.end()) { | while (mi != bitdb.mapFileUseCount.end()) { | ||||
nRefCount += (*mi).second; | nRefCount += (*mi).second; | ||||
mi++; | mi++; | ||||
} | } | ||||
if (nRefCount == 0) { | if (nRefCount == 0) { | ||||
boost::this_thread::interruption_point(); | boost::this_thread::interruption_point(); | ||||
const std::string &strFile = pwalletMain->strWalletFile; | const std::string &strFile = pwalletMain->strWalletFile; | ||||
map<string, int>::iterator _mi = | std::map<std::string, int>::iterator _mi = | ||||
bitdb.mapFileUseCount.find(strFile); | bitdb.mapFileUseCount.find(strFile); | ||||
if (_mi != bitdb.mapFileUseCount.end()) { | if (_mi != bitdb.mapFileUseCount.end()) { | ||||
LogPrint("db", "Flushing %s\n", strFile); | LogPrint("db", "Flushing %s\n", strFile); | ||||
nLastFlushed = CWalletDB::GetUpdateCounter(); | nLastFlushed = CWalletDB::GetUpdateCounter(); | ||||
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); | bitdb.CloseDb(strFile); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | bool CWalletDB::Recover(CDBEnv &dbenv, const std::string &filename, | ||||
CWallet dummyWallet; | CWallet dummyWallet; | ||||
CWalletScanState wss; | CWalletScanState wss; | ||||
DbTxn *ptxn = dbenv.TxnBegin(); | DbTxn *ptxn = dbenv.TxnBegin(); | ||||
for (CDBEnv::KeyValPair &row : salvagedData) { | for (CDBEnv::KeyValPair &row : salvagedData) { | ||||
if (fOnlyKeys) { | if (fOnlyKeys) { | ||||
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); | CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); | ||||
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); | CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); | ||||
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, wss, | fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, wss, | ||||
strType, strErr); | strType, strErr); | ||||
} | } | ||||
if (!IsKeyType(strType) && strType != "hdchain") continue; | if (!IsKeyType(strType) && strType != "hdchain") continue; | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |