8 #include <boost/version.hpp>
9 #include <boost/filesystem.hpp>
12 using namespace boost;
15 static uint64 nAccountingEntryNumber = 0;
24 return Write(make_pair(
string(
"name"), strAddress), strName);
32 return Erase(make_pair(
string(
"name"), strAddress));
38 return Read(make_pair(
string(
"acc"), strAccount), account);
43 return Write(make_pair(
string(
"acc"), strAccount), account);
48 return Write(boost::make_tuple(
string(
"acentry"), acentry.
strAccount, nAccEntryNum), acentry);
53 return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
58 list<CAccountingEntry> entries;
59 ListAccountCreditDebit(strAccount, entries);
61 int64 nCreditDebit = 0;
70 bool fAllAccounts = (strAccount ==
"*");
72 Dbc* pcursor = GetCursor();
74 throw runtime_error(
"CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
75 unsigned int fFlags = DB_SET_RANGE;
80 if (fFlags == DB_SET_RANGE)
81 ssKey << boost::make_tuple(
string(
"acentry"), (fAllAccounts?
string(
"") : strAccount),
uint64(0));
83 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
85 if (ret == DB_NOTFOUND)
90 throw runtime_error(
"CWalletDB::ListAccountCreditDebit() : error scanning DB");
96 if (strType !=
"acentry")
100 if (!fAllAccounts && acentry.
strAccount != strAccount)
104 ssKey >> acentry.nEntryNo;
105 entries.push_back(acentry);
120 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
121 typedef multimap<int64, TxPair > TxItems;
124 for (map<uint256, CWalletTx>::iterator it = pwallet->
mapWallet.begin(); it != pwallet->
mapWallet.end(); ++it)
129 list<CAccountingEntry> acentries;
130 ListAccountCreditDebit(
"", acentries);
133 txByTime.insert(make_pair(entry.
nTime, TxPair((
CWalletTx*)0, &entry)));
138 std::vector<int64> nOrderPosOffsets;
139 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
141 CWalletTx *
const pwtx = (*it).second.first;
147 nOrderPos = nOrderPosNext++;
148 nOrderPosOffsets.push_back(nOrderPos);
152 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
157 int64 nOrderPosOff = 0;
158 BOOST_FOREACH(
const int64& nOffsetStart, nOrderPosOffsets)
160 if (nOrderPos >= nOffsetStart)
163 nOrderPos += nOrderPosOff;
164 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
172 if (!WriteTx(pwtx->
GetHash(), *pwtx))
176 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
187 int& nFileVersion, vector<uint256>& vWalletUpgrade,
188 bool& fIsEncrypted,
bool& fAnyUnordered,
string& strType,
string& strErr)
195 if (strType ==
"name")
201 else if (strType ==
"tx")
208 if (wtx.CheckTransaction(state) && (wtx.GetHash() ==
hash) && state.
IsValid())
209 wtx.BindWallet(pwallet);
217 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
219 if (!ssValue.
empty())
223 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
224 strErr =
strprintf(
"LoadWallet() upgrading tx ver=%d %d '%s' %s",
225 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
226 wtx.fTimeReceivedIsTxTime = fTmp;
230 strErr =
strprintf(
"LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
231 wtx.fTimeReceivedIsTxTime = 0;
233 vWalletUpgrade.push_back(hash);
236 if (wtx.nOrderPos == -1)
237 fAnyUnordered =
true;
247 else if (strType ==
"acentry")
253 if (nNumber > nAccountingEntryNumber)
254 nAccountingEntryNumber = nNumber;
260 if (acentry.nOrderPos == -1)
261 fAnyUnordered =
true;
264 else if (strType ==
"key" || strType ==
"wkey")
268 if (!vchPubKey.IsValid())
270 strErr =
"Error reading wallet database: CPubKey corrupt";
275 if (strType ==
"key")
282 if (!key.
SetPrivKey(pkey, vchPubKey.IsCompressed()))
284 strErr =
"Error reading wallet database: CPrivKey corrupt";
289 strErr =
"Error reading wallet database: CPrivKey pubkey inconsistency";
292 if (!pwallet->
LoadKey(key, vchPubKey))
294 strErr =
"Error reading wallet database: LoadKey failed";
298 else if (strType ==
"mkey")
303 ssValue >> kMasterKey;
306 strErr =
strprintf(
"Error reading wallet database: duplicate CMasterKey id %u", nID);
313 else if (strType ==
"ckey")
315 vector<unsigned char> vchPubKey;
317 vector<unsigned char> vchPrivKey;
318 ssValue >> vchPrivKey;
321 strErr =
"Error reading wallet database: LoadCryptedKey failed";
326 else if (strType ==
"defaultkey")
330 else if (strType ==
"pool")
336 else if (strType ==
"version")
338 ssValue >> nFileVersion;
339 if (nFileVersion == 10300)
342 else if (strType ==
"cscript")
350 strErr =
"Error reading wallet database: LoadCScript failed";
354 else if (strType ==
"orderposnext")
365 static bool IsKeyType(
string strType)
367 return (strType==
"key" || strType ==
"wkey" ||
368 strType ==
"mkey" || strType ==
"ckey");
374 int nFileVersion = 0;
375 vector<uint256> vWalletUpgrade;
376 bool fIsEncrypted =
false;
377 bool fAnyUnordered =
false;
378 bool fNoncriticalErrors =
false;
384 if (Read((
string)
"minversion", nMinVersion))
386 if (nMinVersion > CLIENT_VERSION)
392 Dbc* pcursor = GetCursor();
395 printf(
"Error getting wallet database cursor\n");
404 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
405 if (ret == DB_NOTFOUND)
409 printf(
"Error reading next record from wallet database\n");
414 string strType, strErr;
415 if (!
ReadKeyValue(pwallet, ssKey, ssValue, nFileVersion,
416 vWalletUpgrade, fIsEncrypted, fAnyUnordered, strType, strErr))
420 if (IsKeyType(strType))
425 fNoncriticalErrors =
true;
432 printf(
"%s\n", strErr.c_str());
436 catch (boost::thread_interrupted) {
443 if (fNoncriticalErrors && result ==
DB_LOAD_OK)
451 printf(
"nFileVersion = %d\n", nFileVersion);
457 if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
460 if (nFileVersion < CLIENT_VERSION)
461 WriteVersion(CLIENT_VERSION);
464 result = ReorderTransactions(pwallet);
474 static bool fOneThread;
504 nRefCount += (*mi).second;
510 boost::this_thread::interruption_point();
514 printf(
"Flushing wallet.dat\n");
548 filesystem::path pathDest(strDest);
549 if (filesystem::is_directory(pathDest))
553 #if BOOST_VERSION >= 104000
554 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
556 filesystem::copy_file(pathSrc, pathDest);
558 printf(
"copied wallet.dat to %s\n", pathDest.string().c_str());
560 }
catch(
const filesystem::filesystem_error &e) {
561 printf(
"error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
586 int result = dbenv.
dbenv.dbrename(NULL, filename.c_str(), NULL,
587 newFilename.c_str(), DB_AUTO_COMMIT);
589 printf(
"Renamed %s to %s\n", filename.c_str(), newFilename.c_str());
592 printf(
"Failed to rename %s to %s\n", filename.c_str(), newFilename.c_str());
596 std::vector<CDBEnv::KeyValPair> salvagedData;
597 bool allOK = dbenv.
Salvage(newFilename,
true, salvagedData);
598 if (salvagedData.empty())
600 printf(
"Salvage(aggressive) found no records in %s.\n", newFilename.c_str());
603 printf(
"Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size());
605 bool fSuccess = allOK;
606 Db* pdbCopy =
new Db(&dbenv.
dbenv, 0);
607 int ret = pdbCopy->open(NULL,
615 printf(
"Cannot create database file %s\n", filename.c_str());
619 int nFileVersion = 0;
620 vector<uint256> vWalletUpgrade;
621 bool fIsEncrypted =
false;
622 bool fAnyUnordered =
false;
631 string strType, strErr;
632 bool fReadOK =
ReadKeyValue(&dummyWallet, ssKey, ssValue,
633 nFileVersion, vWalletUpgrade,
634 fIsEncrypted, fAnyUnordered,
636 if (!IsKeyType(strType))
640 printf(
"WARNING: CWalletDB::Recover skipping %s: %s\n", strType.c_str(), strErr.c_str());
644 Dbt datKey(&row.first[0], row.first.size());
645 Dbt datValue(&row.second[0], row.second.size());
646 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
unsigned int nWalletDBUpdated
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
#define strprintf(format,...)
std::map< std::string, int > mapFileUseCount
int64 GetAccountCreditDebit(const std::string &strAccount)
void CheckpointLSN(std::string strFile)
bool WriteAccount(const std::string &strAccount, const CAccount &account)
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
#define TRY_LOCK(cs, name)
CCriticalSection cs_wallet
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Master key for wallet encryption.
void ListAccountCreditDebit(const std::string &strAccount, std::list< CAccountingEntry > &acentries)
Double ended buffer combining vector and stream-like interfaces.
unsigned long long uint64
bool BackupWallet(const CWallet &wallet, const string &strDest)
DBErrors
Error statuses for the wallet database.
CTxDestination Get() const
void RenameThread(const char *name)
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
unsigned int nMasterKeyMaxID
bool WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry &acentry)
CPubKey GetPubKey() const
bool WriteName(const std::string &strAddress, const std::string &strName)
DBErrors LoadWallet(CWallet *pwallet)
An encapsulated public key.
bool LoadKey(const CKey &key, const CPubKey &pubkey)
bool LoadCScript(const CScript &redeemScript)
bool LoadMinVersion(int nVersion)
A transaction with a bunch of additional info that only the owner cares about.
DBErrors ReorderTransactions(CWallet *)
std::string strWalletFile
Capture information about block/transaction validation.
void ThreadFlushWalletDB(const string &strFile)
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed)
std::set< int64 > setKeyPool
bool Salvage(std::string strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
MasterKeyMap mapMasterKeys
Serialized script, used inside transaction inputs and outputs.
void CloseDb(const std::string &strFile)
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, int &nFileVersion, vector< uint256 > &vWalletUpgrade, bool &fIsEncrypted, bool &fAnyUnordered, string &strType, string &strErr)
static bool Recover(CDBEnv &dbenv, std::string filename, bool fOnlyKeys)
Private key that includes an expiration date in case it never gets used.
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
std::map< CTxDestination, std::string > mapAddressBook
std::map< uint256, CWalletTx > mapWallet
unsigned int nTimeReceived
An encapsulated private key.
bool EraseName(const std::string &strAddress)
std::pair< std::vector< unsigned char >, std::vector< unsigned char > > KeyValPair
bool ReadAccount(const std::string &strAccount, CAccount &account)