diff options
Diffstat (limited to 'src/walletdb.cpp')
| -rw-r--r-- | src/walletdb.cpp | 531 |
1 files changed, 409 insertions, 122 deletions
diff --git a/src/walletdb.cpp b/src/walletdb.cpp index fe9bce21e..b5b523740 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -1,17 +1,24 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "walletdb.h" + +#include "base58.h" +#include "protocol.h" +#include "serialize.h" +#include "sync.h" #include "wallet.h" + #include <boost/filesystem.hpp> +#include <boost/foreach.hpp> using namespace std; using namespace boost; -static uint64 nAccountingEntryNumber = 0; +static uint64_t nAccountingEntryNumber = 0; // // CWalletDB @@ -31,6 +38,125 @@ bool CWalletDB::EraseName(const string& strAddress) return Erase(make_pair(string("name"), strAddress)); } +bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose) +{ + nWalletDBUpdated++; + return Write(make_pair(string("purpose"), strAddress), strPurpose); +} + +bool CWalletDB::ErasePurpose(const string& strPurpose) +{ + nWalletDBUpdated++; + return Erase(make_pair(string("purpose"), strPurpose)); +} + +bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx) +{ + nWalletDBUpdated++; + return Write(std::make_pair(std::string("tx"), hash), wtx); +} + +bool CWalletDB::EraseTx(uint256 hash) +{ + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("tx"), hash)); +} + +bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) +{ + nWalletDBUpdated++; + + if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), + keyMeta, false)) + return false; + + // hash pubkey/privkey to accelerate wallet load + std::vector<unsigned char> vchKey; + vchKey.reserve(vchPubKey.size() + vchPrivKey.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.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); +} + +bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, + const std::vector<unsigned char>& vchCryptedSecret, + const CKeyMetadata &keyMeta) +{ + const bool fEraseUnencryptedKey = true; + nWalletDBUpdated++; + + if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), + keyMeta)) + return false; + + if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) + return false; + if (fEraseUnencryptedKey) + { + Erase(std::make_pair(std::string("key"), vchPubKey)); + Erase(std::make_pair(std::string("wkey"), vchPubKey)); + } + return true; +} + +bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) +{ + nWalletDBUpdated++; + return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); +} + +bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) +{ + nWalletDBUpdated++; + return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false); +} + +bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) +{ + nWalletDBUpdated++; + return Write(std::string("bestblock"), locator); +} + +bool CWalletDB::ReadBestBlock(CBlockLocator& locator) +{ + return Read(std::string("bestblock"), locator); +} + +bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext) +{ + nWalletDBUpdated++; + return Write(std::string("orderposnext"), nOrderPosNext); +} + +bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey) +{ + nWalletDBUpdated++; + return Write(std::string("defaultkey"), vchPubKey); +} + +bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool) +{ + return Read(std::make_pair(std::string("pool"), nPool), keypool); +} + +bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool) +{ + nWalletDBUpdated++; + return Write(std::make_pair(std::string("pool"), nPool), keypool); +} + +bool CWalletDB::ErasePool(int64_t nPool) +{ + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("pool"), nPool)); +} + +bool CWalletDB::WriteMinVersion(int nVersion) +{ + return Write(std::string("minversion"), nVersion); +} + bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) { account.SetNull(); @@ -42,7 +168,7 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) return Write(make_pair(string("acc"), strAccount), account); } -bool CWalletDB::WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry) +bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry) { return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry); } @@ -52,12 +178,12 @@ bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } -int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) +int64_t CWalletDB::GetAccountCreditDebit(const string& strAccount) { list<CAccountingEntry> entries; ListAccountCreditDebit(strAccount, entries); - int64 nCreditDebit = 0; + int64_t nCreditDebit = 0; BOOST_FOREACH (const CAccountingEntry& entry, entries) nCreditDebit += entry.nCreditDebit; @@ -72,12 +198,12 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin if (!pcursor) throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; - loop + while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0)); + ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64_t(0)); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -117,7 +243,7 @@ CWalletDB::ReorderTransactions(CWallet* pwallet) // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. typedef pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef multimap<int64, TxPair > TxItems; + typedef multimap<int64_t, TxPair > TxItems; TxItems txByTime; for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) @@ -132,14 +258,14 @@ CWalletDB::ReorderTransactions(CWallet* pwallet) txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } - int64& nOrderPosNext = pwallet->nOrderPosNext; + int64_t& nOrderPosNext = pwallet->nOrderPosNext; nOrderPosNext = 0; - std::vector<int64> nOrderPosOffsets; + std::vector<int64_t> nOrderPosOffsets; for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) { CWalletTx *const pwtx = (*it).second.first; CAccountingEntry *const pacentry = (*it).second.second; - int64& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos; + int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos; if (nOrderPos == -1) { @@ -153,8 +279,8 @@ CWalletDB::ReorderTransactions(CWallet* pwallet) } else { - int64 nOrderPosOff = 0; - BOOST_FOREACH(const int64& nOffsetStart, nOrderPosOffsets) + int64_t nOrderPosOff = 0; + BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets) { if (nOrderPos >= nOffsetStart) ++nOrderPosOff; @@ -180,11 +306,27 @@ CWalletDB::ReorderTransactions(CWallet* pwallet) return DB_LOAD_OK; } +class CWalletScanState { +public: + unsigned int nKeys; + unsigned int nCKeys; + unsigned int nKeyMeta; + bool fIsEncrypted; + bool fAnyUnordered; + int nFileVersion; + vector<uint256> vWalletUpgrade; + + CWalletScanState() { + nKeys = nCKeys = nKeyMeta = 0; + fIsEncrypted = false; + fAnyUnordered = false; + nFileVersion = 0; + } +}; bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, - int& nFileVersion, vector<uint256>& vWalletUpgrade, - bool& fIsEncrypted, bool& fAnyUnordered, string& strType, string& strErr) + CWalletScanState &wss, string& strType, string& strErr) { try { // Unserialize @@ -195,22 +337,25 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()]; + ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; + } + else if (strType == "purpose") + { + string strAddress; + ssKey >> strAddress; + ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose; } else if (strType == "tx") { uint256 hash; ssKey >> hash; - CWalletTx& wtx = pwallet->mapWallet[hash]; + CWalletTx wtx; ssValue >> wtx; CValidationState state; - if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid()) + if (CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()) wtx.BindWallet(pwallet); else - { - pwallet->mapWallet.erase(hash); return false; - } // Undo serialize changes in 31600 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) @@ -221,93 +366,105 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, char fUnused; ssValue >> fTmp >> fUnused >> wtx.strFromAccount; strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s", - wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); + wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString()); wtx.fTimeReceivedIsTxTime = fTmp; } else { - strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); + strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString()); wtx.fTimeReceivedIsTxTime = 0; } - vWalletUpgrade.push_back(hash); + wss.vWalletUpgrade.push_back(hash); } if (wtx.nOrderPos == -1) - fAnyUnordered = true; + wss.fAnyUnordered = true; + pwallet->AddToWallet(wtx, true); //// debug print - //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); - //printf(" %12"PRI64d" %s %s %s\n", + //LogPrintf("LoadWallet %s\n", wtx.GetHash().ToString()); + //LogPrintf(" %12"PRId64" %s %s %s\n", // wtx.vout[0].nValue, - // DateTimeStrFormat("%Y-%m-%d %H:%M:%S", wtx.GetBlockTime()).c_str(), - // wtx.hashBlock.ToString().substr(0,20).c_str(), - // wtx.mapValue["message"].c_str()); + // DateTimeStrFormat("%Y-%m-%d %H:%M:%S", wtx.GetBlockTime()), + // wtx.hashBlock.ToString(), + // wtx.mapValue["message"]); } else if (strType == "acentry") { string strAccount; ssKey >> strAccount; - uint64 nNumber; + uint64_t nNumber; ssKey >> nNumber; if (nNumber > nAccountingEntryNumber) nAccountingEntryNumber = nNumber; - if (!fAnyUnordered) + if (!wss.fAnyUnordered) { CAccountingEntry acentry; ssValue >> acentry; if (acentry.nOrderPos == -1) - fAnyUnordered = true; + wss.fAnyUnordered = true; } } else if (strType == "key" || strType == "wkey") { - vector<unsigned char> vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; + if (!vchPubKey.IsValid()) + { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } CKey key; + CPrivKey pkey; + uint256 hash = 0; + if (strType == "key") { - CPrivKey pkey; + wss.nKeys++; ssValue >> pkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(pkey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) - { - strErr = "Error reading wallet database: invalid CPrivKey"; - return false; - } - } - else - { + } else { CWalletKey wkey; ssValue >> wkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(wkey.vchPrivKey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CWalletKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) + pkey = wkey.vchPrivKey; + } + + // Old wallets store keys as "key" [pubkey] => [privkey] + // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key + // using EC operations as a checksum. + // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while + // remaining backwards-compatible. + try + { + ssValue >> hash; + } + catch(...){} + + bool fSkipCheck = false; + + if (hash != 0) + { + // hash pubkey/privkey to accelerate wallet load + std::vector<unsigned char> vchKey; + vchKey.reserve(vchPubKey.size() + pkey.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); + vchKey.insert(vchKey.end(), pkey.begin(), pkey.end()); + + if (Hash(vchKey.begin(), vchKey.end()) != hash) { - strErr = "Error reading wallet database: invalid CWalletKey"; + strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt"; return false; } + + fSkipCheck = true; } - if (!pwallet->LoadKey(key)) + + if (!key.Load(pkey, vchPubKey, fSkipCheck)) + { + strErr = "Error reading wallet database: CPrivKey corrupt"; + return false; + } + if (!pwallet->LoadKey(key, vchPubKey)) { strErr = "Error reading wallet database: LoadKey failed"; return false; @@ -334,12 +491,29 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> vchPubKey; vector<unsigned char> vchPrivKey; ssValue >> vchPrivKey; + wss.nCKeys++; + if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) { strErr = "Error reading wallet database: LoadCryptedKey failed"; return false; } - fIsEncrypted = true; + wss.fIsEncrypted = true; + } + else if (strType == "keymeta") + { + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKeyMetadata keyMeta; + ssValue >> keyMeta; + wss.nKeyMeta++; + + pwallet->LoadKeyMetadata(vchPubKey, keyMeta); + + // find earliest key creation time, as wallet birthday + if (!pwallet->nTimeFirstKey || + (keyMeta.nCreateTime < pwallet->nTimeFirstKey)) + pwallet->nTimeFirstKey = keyMeta.nCreateTime; } else if (strType == "defaultkey") { @@ -347,15 +521,24 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "pool") { - int64 nIndex; + int64_t nIndex; ssKey >> nIndex; + CKeyPool keypool; + ssValue >> keypool; pwallet->setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (pwallet->mapKeyMetadata.count(keyid) == 0) + pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); } else if (strType == "version") { - ssValue >> nFileVersion; - if (nFileVersion == 10300) - nFileVersion = 300; + ssValue >> wss.nFileVersion; + if (wss.nFileVersion == 10300) + wss.nFileVersion = 300; } else if (strType == "cscript") { @@ -373,6 +556,18 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { ssValue >> pwallet->nOrderPosNext; } + else if (strType == "destdata") + { + std::string strAddress, strKey, strValue; + ssKey >> strAddress; + ssKey >> strKey; + ssValue >> strValue; + if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue)) + { + strErr = "Error reading wallet database: LoadDestData failed"; + return false; + } + } } catch (...) { return false; @@ -389,10 +584,7 @@ static bool IsKeyType(string strType) DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { pwallet->vchDefaultKey = CPubKey(); - int nFileVersion = 0; - vector<uint256> vWalletUpgrade; - bool fIsEncrypted = false; - bool fAnyUnordered = false; + CWalletScanState wss; bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; @@ -410,11 +602,11 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) Dbc* pcursor = GetCursor(); if (!pcursor) { - printf("Error getting wallet database cursor\n"); + LogPrintf("Error getting wallet database cursor\n"); return DB_CORRUPT; } - loop + while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); @@ -424,14 +616,13 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) break; else if (ret != 0) { - printf("Error reading next record from wallet database\n"); + LogPrintf("Error reading next record from wallet database\n"); return DB_CORRUPT; } // Try to be tolerant of single corrupt records: string strType, strErr; - if (!ReadKeyValue(pwallet, ssKey, ssValue, nFileVersion, - vWalletUpgrade, fIsEncrypted, fAnyUnordered, strType, strErr)) + if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: @@ -447,12 +638,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) } } if (!strErr.empty()) - printf("%s\n", strErr.c_str()); + LogPrintf("%s\n", strErr); } pcursor->close(); } - catch (...) - { + catch (boost::thread_interrupted) { + throw; + } + catch (...) { result = DB_CORRUPT; } @@ -464,30 +657,116 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (result != DB_LOAD_OK) return result; - printf("nFileVersion = %d\n", nFileVersion); + LogPrintf("nFileVersion = %d\n", wss.nFileVersion); + + LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n", + wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys); + + // nTimeFirstKey is only reliable if all keys have metadata + if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) + pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' - BOOST_FOREACH(uint256 hash, vWalletUpgrade) + BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade) WriteTx(hash, pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: - if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) + if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) return DB_NEED_REWRITE; - if (nFileVersion < CLIENT_VERSION) // Update + if (wss.nFileVersion < CLIENT_VERSION) // Update WriteVersion(CLIENT_VERSION); - if (fAnyUnordered) + if (wss.fAnyUnordered) result = ReorderTransactions(pwallet); return result; } -void ThreadFlushWalletDB(void* parg) +DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash) +{ + pwallet->vchDefaultKey = CPubKey(); + CWalletScanState wss; + bool fNoncriticalErrors = false; + DBErrors result = DB_LOAD_OK; + + try { + LOCK(pwallet->cs_wallet); + int nMinVersion = 0; + if (Read((string)"minversion", nMinVersion)) + { + if (nMinVersion > CLIENT_VERSION) + return DB_TOO_NEW; + pwallet->LoadMinVersion(nMinVersion); + } + + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + { + LogPrintf("Error getting wallet database cursor\n"); + return DB_CORRUPT; + } + + while (true) + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + LogPrintf("Error reading next record from wallet database\n"); + return DB_CORRUPT; + } + + string strType; + ssKey >> strType; + if (strType == "tx") { + uint256 hash; + ssKey >> hash; + + vTxHash.push_back(hash); + } + } + pcursor->close(); + } + catch (boost::thread_interrupted) { + throw; + } + catch (...) { + result = DB_CORRUPT; + } + + if (fNoncriticalErrors && result == DB_LOAD_OK) + result = DB_NONCRITICAL_ERROR; + + return result; +} + +DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet) +{ + // build list of wallet TXs + vector<uint256> vTxHash; + DBErrors err = FindWalletTx(pwallet, vTxHash); + if (err != DB_LOAD_OK) + return err; + + // erase each wallet TX + BOOST_FOREACH (uint256& hash, vTxHash) { + if (!EraseTx(hash)) + return DB_CORRUPT; + } + + return DB_LOAD_OK; +} + +void ThreadFlushWalletDB(const string& strFile) { // Make this thread recognisable as the wallet flushing thread RenameThread("bitcoin-wallet"); - const string& strFile = ((const string*)parg)[0]; static bool fOneThread; if (fOneThread) return; @@ -497,10 +776,10 @@ void ThreadFlushWalletDB(void* parg) unsigned int nLastSeen = nWalletDBUpdated; unsigned int nLastFlushed = nWalletDBUpdated; - int64 nLastWalletUpdate = GetTime(); - while (!fShutdown) + int64_t nLastWalletUpdate = GetTime(); + while (true) { - Sleep(500); + MilliSleep(500); if (nLastSeen != nWalletDBUpdated) { @@ -522,21 +801,22 @@ void ThreadFlushWalletDB(void* parg) mi++; } - if (nRefCount == 0 && !fShutdown) + if (nRefCount == 0) { + boost::this_thread::interruption_point(); map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { - printf("Flushing wallet.dat\n"); + LogPrint("db", "Flushing wallet.dat\n"); nLastFlushed = nWalletDBUpdated; - int64 nStart = GetTimeMillis(); + int64_t nStart = GetTimeMillis(); // Flush wallet.dat so it's self contained bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(mi++); - printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); + LogPrint("db", "Flushed wallet.dat %"PRId64"ms\n", GetTimeMillis() - nStart); } } } @@ -548,7 +828,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) { if (!wallet.fFileBacked) return false; - while (!fShutdown) + while (true) { { LOCK(bitdb.cs_db); @@ -571,15 +851,15 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) #else filesystem::copy_file(pathSrc, pathDest); #endif - printf("copied wallet.dat to %s\n", pathDest.string().c_str()); + LogPrintf("copied wallet.dat to %s\n", pathDest.string()); return true; } catch(const filesystem::filesystem_error &e) { - printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what()); + LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what()); return false; } } } - Sleep(100); + MilliSleep(100); } return false; } @@ -596,16 +876,16 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) // Rewrite salvaged data to wallet.dat // Set -rescan so any missing transactions will be // found. - int64 now = GetTime(); - std::string newFilename = strprintf("wallet.%"PRI64d".bak", now); + int64_t now = GetTime(); + std::string newFilename = strprintf("wallet.%"PRId64".bak", now); int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL, newFilename.c_str(), DB_AUTO_COMMIT); if (result == 0) - printf("Renamed %s to %s\n", filename.c_str(), newFilename.c_str()); + LogPrintf("Renamed %s to %s\n", filename, newFilename); else { - printf("Failed to rename %s to %s\n", filename.c_str(), newFilename.c_str()); + LogPrintf("Failed to rename %s to %s\n", filename, newFilename); return false; } @@ -613,29 +893,26 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) bool allOK = dbenv.Salvage(newFilename, true, salvagedData); if (salvagedData.empty()) { - printf("Salvage(aggressive) found no records in %s.\n", newFilename.c_str()); + LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); return false; } - printf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size()); + LogPrintf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size()); bool fSuccess = allOK; Db* pdbCopy = new Db(&dbenv.dbenv, 0); - int ret = pdbCopy->open(NULL, // Txn pointer + int ret = pdbCopy->open(NULL, // Txn pointer filename.c_str(), // Filename - "main", // Logical db name - DB_BTREE, // Database type - DB_CREATE, // Flags + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags 0); if (ret > 0) { - printf("Cannot create database file %s\n", filename.c_str()); + LogPrintf("Cannot create database file %s\n", filename); return false; } CWallet dummyWallet; - int nFileVersion = 0; - vector<uint256> vWalletUpgrade; - bool fIsEncrypted = false; - bool fAnyUnordered = false; + CWalletScanState wss; DbTxn* ptxn = dbenv.TxnBegin(); BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData) @@ -646,14 +923,12 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); string strType, strErr; bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, - nFileVersion, vWalletUpgrade, - fIsEncrypted, fAnyUnordered, - strType, strErr); + wss, strType, strErr); if (!IsKeyType(strType)) continue; if (!fReadOK) { - printf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType.c_str(), strErr.c_str()); + LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr); continue; } } @@ -674,3 +949,15 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename) { return CWalletDB::Recover(dbenv, filename, false); } + +bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value) +{ + nWalletDBUpdated++; + return Write(boost::make_tuple(std::string("destdata"), address, key), value); +} + +bool CWalletDB::EraseDestData(const std::string &address, const std::string &key) +{ + nWalletDBUpdated++; + return Erase(boost::make_tuple(string("destdata"), address, key)); +} |