15 #include <boost/filesystem.hpp>
16 #include <boost/foreach.hpp>
19 using namespace boost;
22 static uint64_t nAccountingEntryNumber = 0;
31 return Write(make_pair(
string(
"name"), strAddress), strName);
39 return Erase(make_pair(
string(
"name"), strAddress));
45 return Write(make_pair(
string(
"purpose"), strAddress), strPurpose);
51 return Erase(make_pair(
string(
"purpose"), strPurpose));
57 return Write(std::make_pair(std::string(
"tx"), hash), wtx);
63 return Erase(std::make_pair(std::string(
"tx"), hash));
70 if (!Write(std::make_pair(std::string(
"keymeta"), vchPubKey),
75 std::vector<unsigned char> vchKey;
76 vchKey.reserve(vchPubKey.
size() + vchPrivKey.size());
77 vchKey.insert(vchKey.end(), vchPubKey.
begin(), vchPubKey.
end());
78 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
80 return Write(std::make_pair(std::string(
"key"), vchPubKey), std::make_pair(vchPrivKey,
Hash(vchKey.begin(), vchKey.end())),
false);
84 const std::vector<unsigned char>& vchCryptedSecret,
87 const bool fEraseUnencryptedKey =
true;
90 if (!Write(std::make_pair(std::string(
"keymeta"), vchPubKey),
94 if (!Write(std::make_pair(std::string(
"ckey"), vchPubKey), vchCryptedSecret,
false))
96 if (fEraseUnencryptedKey)
98 Erase(std::make_pair(std::string(
"key"), vchPubKey));
99 Erase(std::make_pair(std::string(
"wkey"), vchPubKey));
107 return Write(std::make_pair(std::string(
"mkey"), nID), kMasterKey,
true);
113 return Write(std::make_pair(std::string(
"cscript"), hash), redeemScript,
false);
119 return Write(std::make_pair(std::string(
"watchs"), dest),
'1');
125 return Erase(std::make_pair(std::string(
"watchs"), dest));
131 return Write(std::string(
"bestblock"), locator);
136 return Read(std::string(
"bestblock"), locator);
142 return Write(std::string(
"orderposnext"), nOrderPosNext);
148 return Write(std::string(
"defaultkey"), vchPubKey);
153 return Read(std::make_pair(std::string(
"pool"), nPool), keypool);
159 return Write(std::make_pair(std::string(
"pool"), nPool), keypool);
165 return Erase(std::make_pair(std::string(
"pool"), nPool));
170 return Write(std::string(
"minversion"), nVersion);
176 return Read(make_pair(
string(
"acc"), strAccount), account);
181 return Write(make_pair(
string(
"acc"), strAccount), account);
186 return Write(boost::make_tuple(
string(
"acentry"), acentry.
strAccount, nAccEntryNum), acentry);
191 return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
196 list<CAccountingEntry> entries;
197 ListAccountCreditDebit(strAccount, entries);
199 int64_t nCreditDebit = 0;
208 bool fAllAccounts = (strAccount ==
"*");
210 Dbc* pcursor = GetCursor();
212 throw runtime_error(
"CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
213 unsigned int fFlags = DB_SET_RANGE;
218 if (fFlags == DB_SET_RANGE)
219 ssKey << boost::make_tuple(
string(
"acentry"), (fAllAccounts?
string(
"") : strAccount), uint64_t(0));
221 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
223 if (ret == DB_NOTFOUND)
228 throw runtime_error(
"CWalletDB::ListAccountCreditDebit() : error scanning DB");
234 if (strType !=
"acentry")
238 if (!fAllAccounts && acentry.
strAccount != strAccount)
242 ssKey >> acentry.nEntryNo;
243 entries.push_back(acentry);
258 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
259 typedef multimap<int64_t, TxPair > TxItems;
262 for (map<uint256, CWalletTx>::iterator it = pwallet->
mapWallet.begin(); it != pwallet->
mapWallet.end(); ++it)
267 list<CAccountingEntry> acentries;
268 ListAccountCreditDebit(
"", acentries);
271 txByTime.insert(make_pair(entry.
nTime, TxPair((
CWalletTx*)0, &entry)));
276 std::vector<int64_t> nOrderPosOffsets;
277 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
279 CWalletTx *
const pwtx = (*it).second.first;
285 nOrderPos = nOrderPosNext++;
286 nOrderPosOffsets.push_back(nOrderPos);
290 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
295 int64_t nOrderPosOff = 0;
296 BOOST_FOREACH(
const int64_t& nOffsetStart, nOrderPosOffsets)
298 if (nOrderPos >= nOffsetStart)
301 nOrderPos += nOrderPosOff;
302 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
310 if (!WriteTx(pwtx->
GetHash(), *pwtx))
314 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
333 nKeys = nCKeys = nKeyMeta = 0;
334 fIsEncrypted =
false;
335 fAnyUnordered =
false;
349 if (strType ==
"name")
355 else if (strType ==
"purpose")
361 else if (strType ==
"tx")
372 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
374 if (!ssValue.
empty())
378 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
379 strErr =
strprintf(
"LoadWallet() upgrading tx ver=%d %d '%s' %s",
380 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
381 wtx.fTimeReceivedIsTxTime = fTmp;
385 strErr =
strprintf(
"LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
386 wtx.fTimeReceivedIsTxTime = 0;
391 if (wtx.nOrderPos == -1)
403 else if (strType ==
"acentry")
409 if (nNumber > nAccountingEntryNumber)
410 nAccountingEntryNumber = nNumber;
416 if (acentry.nOrderPos == -1)
420 else if (strType ==
"watchs")
433 else if (strType ==
"key" || strType ==
"wkey")
437 if (!vchPubKey.IsValid())
439 strErr =
"Error reading wallet database: CPubKey corrupt";
446 if (strType ==
"key")
467 bool fSkipCheck =
false;
472 std::vector<unsigned char> vchKey;
473 vchKey.reserve(vchPubKey.size() + pkey.size());
474 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
475 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
477 if (
Hash(vchKey.begin(), vchKey.end()) != hash)
479 strErr =
"Error reading wallet database: CPubKey/CPrivKey corrupt";
486 if (!key.
Load(pkey, vchPubKey, fSkipCheck))
488 strErr =
"Error reading wallet database: CPrivKey corrupt";
491 if (!pwallet->
LoadKey(key, vchPubKey))
493 strErr =
"Error reading wallet database: LoadKey failed";
497 else if (strType ==
"mkey")
502 ssValue >> kMasterKey;
505 strErr =
strprintf(
"Error reading wallet database: duplicate CMasterKey id %u", nID);
512 else if (strType ==
"ckey")
514 vector<unsigned char> vchPubKey;
516 vector<unsigned char> vchPrivKey;
517 ssValue >> vchPrivKey;
522 strErr =
"Error reading wallet database: LoadCryptedKey failed";
527 else if (strType ==
"keymeta")
542 else if (strType ==
"defaultkey")
546 else if (strType ==
"pool")
557 CKeyID keyid = keypool.vchPubKey.GetID();
561 else if (strType ==
"version")
567 else if (strType ==
"cscript")
575 strErr =
"Error reading wallet database: LoadCScript failed";
579 else if (strType ==
"orderposnext")
583 else if (strType ==
"destdata")
585 std::string strAddress, strKey, strValue;
591 strErr =
"Error reading wallet database: LoadDestData failed";
602 static bool IsKeyType(
string strType)
604 return (strType==
"key" || strType ==
"wkey" ||
605 strType ==
"mkey" || strType ==
"ckey");
612 bool fNoncriticalErrors =
false;
618 if (Read((
string)
"minversion", nMinVersion))
620 if (nMinVersion > CLIENT_VERSION)
626 Dbc* pcursor = GetCursor();
629 LogPrintf(
"Error getting wallet database cursor\n");
638 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
639 if (ret == DB_NOTFOUND)
643 LogPrintf(
"Error reading next record from wallet database\n");
648 string strType, strErr;
649 if (!
ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
653 if (IsKeyType(strType))
658 fNoncriticalErrors =
true;
669 catch (boost::thread_interrupted) {
676 if (fNoncriticalErrors && result ==
DB_LOAD_OK)
686 LogPrintf(
"Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
701 WriteVersion(CLIENT_VERSION);
704 result = ReorderTransactions(pwallet);
713 bool fNoncriticalErrors =
false;
719 if (Read((
string)
"minversion", nMinVersion))
721 if (nMinVersion > CLIENT_VERSION)
727 Dbc* pcursor = GetCursor();
730 LogPrintf(
"Error getting wallet database cursor\n");
739 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
740 if (ret == DB_NOTFOUND)
744 LogPrintf(
"Error reading next record from wallet database\n");
750 if (strType ==
"tx") {
754 vTxHash.push_back(hash);
759 catch (boost::thread_interrupted) {
766 if (fNoncriticalErrors && result ==
DB_LOAD_OK)
775 vector<uint256> vTxHash;
776 DBErrors err = FindWalletTx(pwallet, vTxHash);
781 BOOST_FOREACH (
uint256& hash, vTxHash) {
794 static bool fOneThread;
803 int64_t nLastWalletUpdate =
GetTime();
824 nRefCount += (*mi).second;
830 boost::this_thread::interruption_point();
834 LogPrint(
"db",
"Flushing wallet.dat\n");
843 LogPrint(
"db",
"Flushed wallet.dat %dms\n",
GetTimeMillis() - nStart);
868 filesystem::path pathDest(strDest);
869 if (filesystem::is_directory(pathDest))
873 #if BOOST_VERSION >= 104000
874 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
876 filesystem::copy_file(pathSrc, pathDest);
878 LogPrintf(
"copied wallet.dat to %s\n", pathDest.string());
880 }
catch(
const filesystem::filesystem_error &e) {
881 LogPrintf(
"error copying wallet.dat to %s - %s\n", pathDest.string(), e.what());
904 std::string newFilename =
strprintf(
"wallet.%d.bak", now);
906 int result = dbenv.
dbenv.dbrename(NULL, filename.c_str(), NULL,
907 newFilename.c_str(), DB_AUTO_COMMIT);
909 LogPrintf(
"Renamed %s to %s\n", filename, newFilename);
912 LogPrintf(
"Failed to rename %s to %s\n", filename, newFilename);
916 std::vector<CDBEnv::KeyValPair> salvagedData;
917 bool allOK = dbenv.
Salvage(newFilename,
true, salvagedData);
918 if (salvagedData.empty())
920 LogPrintf(
"Salvage(aggressive) found no records in %s.\n", newFilename);
923 LogPrintf(
"Salvage(aggressive) found %u records\n", salvagedData.size());
925 bool fSuccess = allOK;
926 Db* pdbCopy =
new Db(&dbenv.
dbenv, 0);
927 int ret = pdbCopy->open(NULL,
935 LogPrintf(
"Cannot create database file %s\n", filename);
948 string strType, strErr;
949 bool fReadOK =
ReadKeyValue(&dummyWallet, ssKey, ssValue,
950 wss, strType, strErr);
951 if (!IsKeyType(strType))
955 LogPrintf(
"WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
959 Dbt datKey(&row.first[0], row.first.size());
960 Dbt datValue(&row.second[0], row.second.size());
961 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
980 return Write(boost::make_tuple(std::string(
"destdata"), address, key), value);
986 return Erase(boost::make_tuple(
string(
"destdata"), address, key));
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
unsigned int nWalletDBUpdated
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
bool WriteMinVersion(int nVersion)
std::set< int64_t > setKeyPool
std::map< std::string, int > mapFileUseCount
bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
Adds a destination data tuple to the store, without saving it to disk.
DBErrors FindWalletTx(CWallet *pwallet, std::vector< uint256 > &vTxHash)
void CheckpointLSN(std::string strFile)
bool WriteAccount(const std::string &strAccount, const CAccount &account)
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
#define TRY_LOCK(cs, name)
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata)
std::map< CTxDestination, CAddressBookData > mapAddressBook
CCriticalSection cs_wallet
Main wallet lock.
void MilliSleep(int64_t n)
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
Master key for wallet encryption.
unsigned int size() const
CTxDestination Get() const
void ListAccountCreditDebit(const std::string &strAccount, std::list< CAccountingEntry > &acentries)
Double ended buffer combining vector and stream-like interfaces.
bool WriteWatchOnly(const CScript &script)
bool ErasePurpose(const std::string &strAddress)
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry &acentry)
bool BackupWallet(const CWallet &wallet, const string &strDest)
DBErrors
Error statuses for the wallet database.
void RenameThread(const char *name)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool EraseTx(uint256 hash)
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
DBErrors ZapWalletTx(CWallet *pwallet)
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
unsigned int nMasterKeyMaxID
bool EraseDestData(const std::string &address, const std::string &key)
Erase destination data tuple from wallet database.
bool WritePool(int64_t nPool, const CKeyPool &keypool)
int64_t GetAccountCreditDebit(const std::string &strAccount)
bool WriteName(const std::string &strAddress, const std::string &strName)
DBErrors LoadWallet(CWallet *pwallet)
An encapsulated public key.
base58-encoded Anoncoin addresses.
bool LoadKey(const CKey &key, const CPubKey &pubkey)
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value)
Write destination data key,value tuple to database.
uint256 Hash(const T1 pbegin, const T1 pend)
bool LoadCScript(const CScript &redeemScript)
bool ErasePool(int64_t nPool)
bool EraseWatchOnly(const CScript &script)
vector< uint256 > vWalletUpgrade
bool WriteTx(uint256 hash, const CWalletTx &wtx)
bool LoadMinVersion(int nVersion)
const unsigned char * begin() const
bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck)
A transaction with a bunch of additional info that only the owner cares about.
DBErrors ReorderTransactions(CWallet *)
std::string strWalletFile
bool ReadBestBlock(CBlockLocator &locator)
bool WriteDefaultKey(const CPubKey &vchPubKey)
Capture information about block/transaction validation.
bool WriteBestBlock(const CBlockLocator &locator)
void ThreadFlushWalletDB(const string &strFile)
bool LoadWatchOnly(const CScript &dest)
bool Salvage(std::string strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
MasterKeyMap mapMasterKeys
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Serialized script, used inside transaction inputs and outputs.
void CloseDb(const std::string &strFile)
static bool Recover(CDBEnv &dbenv, std::string filename, bool fOnlyKeys)
Private key that includes an expiration date in case it never gets used.
A reference to a CKey: the Hash160 of its serialized public key.
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, string &strType, string &strErr)
std::map< uint256, CWalletTx > mapWallet
bool AddToWallet(const CWalletTx &wtxIn, bool fFromLoadWallet=false)
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 WriteCScript(const uint160 &hash, const CScript &redeemScript)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool ReadAccount(const std::string &strAccount, CAccount &account)
bool CheckTransaction(const CTransaction &tx, CValidationState &state)
const unsigned char * end() const
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)