Anoncoin  0.9.4
P2P Digital Currency
walletdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Copyright (c) 2013-2014 The Anoncoin Core developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "walletdb.h"
8 
9 #include "base58.h"
10 #include "protocol.h"
11 #include "serialize.h"
12 #include "sync.h"
13 #include "wallet.h"
14 
15 #include <boost/filesystem.hpp>
16 #include <boost/foreach.hpp>
17 
18 using namespace std;
19 using namespace boost;
20 
21 
22 static uint64_t nAccountingEntryNumber = 0;
23 
24 //
25 // CWalletDB
26 //
27 
28 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
29 {
31  return Write(make_pair(string("name"), strAddress), strName);
32 }
33 
34 bool CWalletDB::EraseName(const string& strAddress)
35 {
36  // This should only be used for sending addresses, never for receiving addresses,
37  // receiving addresses must always have an address book entry if they're not change return.
39  return Erase(make_pair(string("name"), strAddress));
40 }
41 
42 bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
43 {
45  return Write(make_pair(string("purpose"), strAddress), strPurpose);
46 }
47 
48 bool CWalletDB::ErasePurpose(const string& strPurpose)
49 {
51  return Erase(make_pair(string("purpose"), strPurpose));
52 }
53 
54 bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
55 {
57  return Write(std::make_pair(std::string("tx"), hash), wtx);
58 }
59 
61 {
63  return Erase(std::make_pair(std::string("tx"), hash));
64 }
65 
66 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
67 {
69 
70  if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
71  keyMeta, false))
72  return false;
73 
74  // hash pubkey/privkey to accelerate wallet load
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());
79 
80  return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
81 }
82 
83 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
84  const std::vector<unsigned char>& vchCryptedSecret,
85  const CKeyMetadata &keyMeta)
86 {
87  const bool fEraseUnencryptedKey = true;
89 
90  if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
91  keyMeta))
92  return false;
93 
94  if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
95  return false;
96  if (fEraseUnencryptedKey)
97  {
98  Erase(std::make_pair(std::string("key"), vchPubKey));
99  Erase(std::make_pair(std::string("wkey"), vchPubKey));
100  }
101  return true;
102 }
103 
104 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
105 {
107  return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
108 }
109 
110 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
111 {
113  return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
114 }
115 
117 {
119  return Write(std::make_pair(std::string("watchs"), dest), '1');
120 }
121 
123 {
125  return Erase(std::make_pair(std::string("watchs"), dest));
126 }
127 
129 {
131  return Write(std::string("bestblock"), locator);
132 }
133 
135 {
136  return Read(std::string("bestblock"), locator);
137 }
138 
139 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
140 {
142  return Write(std::string("orderposnext"), nOrderPosNext);
143 }
144 
145 bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
146 {
148  return Write(std::string("defaultkey"), vchPubKey);
149 }
150 
151 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
152 {
153  return Read(std::make_pair(std::string("pool"), nPool), keypool);
154 }
155 
156 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
157 {
159  return Write(std::make_pair(std::string("pool"), nPool), keypool);
160 }
161 
162 bool CWalletDB::ErasePool(int64_t nPool)
163 {
165  return Erase(std::make_pair(std::string("pool"), nPool));
166 }
167 
168 bool CWalletDB::WriteMinVersion(int nVersion)
169 {
170  return Write(std::string("minversion"), nVersion);
171 }
172 
173 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
174 {
175  account.SetNull();
176  return Read(make_pair(string("acc"), strAccount), account);
177 }
178 
179 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
180 {
181  return Write(make_pair(string("acc"), strAccount), account);
182 }
183 
184 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
185 {
186  return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry);
187 }
188 
190 {
191  return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
192 }
193 
194 int64_t CWalletDB::GetAccountCreditDebit(const string& strAccount)
195 {
196  list<CAccountingEntry> entries;
197  ListAccountCreditDebit(strAccount, entries);
198 
199  int64_t nCreditDebit = 0;
200  BOOST_FOREACH (const CAccountingEntry& entry, entries)
201  nCreditDebit += entry.nCreditDebit;
202 
203  return nCreditDebit;
204 }
205 
206 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
207 {
208  bool fAllAccounts = (strAccount == "*");
209 
210  Dbc* pcursor = GetCursor();
211  if (!pcursor)
212  throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
213  unsigned int fFlags = DB_SET_RANGE;
214  while (true)
215  {
216  // Read next record
217  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
218  if (fFlags == DB_SET_RANGE)
219  ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64_t(0));
220  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
221  int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
222  fFlags = DB_NEXT;
223  if (ret == DB_NOTFOUND)
224  break;
225  else if (ret != 0)
226  {
227  pcursor->close();
228  throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
229  }
230 
231  // Unserialize
232  string strType;
233  ssKey >> strType;
234  if (strType != "acentry")
235  break;
236  CAccountingEntry acentry;
237  ssKey >> acentry.strAccount;
238  if (!fAllAccounts && acentry.strAccount != strAccount)
239  break;
240 
241  ssValue >> acentry;
242  ssKey >> acentry.nEntryNo;
243  entries.push_back(acentry);
244  }
245 
246  pcursor->close();
247 }
248 
249 
250 DBErrors
252 {
253  LOCK(pwallet->cs_wallet);
254  // Old wallets didn't have any defined order for transactions
255  // Probably a bad idea to change the output of this
256 
257  // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
258  typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
259  typedef multimap<int64_t, TxPair > TxItems;
260  TxItems txByTime;
261 
262  for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
263  {
264  CWalletTx* wtx = &((*it).second);
265  txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
266  }
267  list<CAccountingEntry> acentries;
268  ListAccountCreditDebit("", acentries);
269  BOOST_FOREACH(CAccountingEntry& entry, acentries)
270  {
271  txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
272  }
273 
274  int64_t& nOrderPosNext = pwallet->nOrderPosNext;
275  nOrderPosNext = 0;
276  std::vector<int64_t> nOrderPosOffsets;
277  for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
278  {
279  CWalletTx *const pwtx = (*it).second.first;
280  CAccountingEntry *const pacentry = (*it).second.second;
281  int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
282 
283  if (nOrderPos == -1)
284  {
285  nOrderPos = nOrderPosNext++;
286  nOrderPosOffsets.push_back(nOrderPos);
287 
288  if (pacentry)
289  // Have to write accounting regardless, since we don't keep it in memory
290  if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
291  return DB_LOAD_FAIL;
292  }
293  else
294  {
295  int64_t nOrderPosOff = 0;
296  BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
297  {
298  if (nOrderPos >= nOffsetStart)
299  ++nOrderPosOff;
300  }
301  nOrderPos += nOrderPosOff;
302  nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
303 
304  if (!nOrderPosOff)
305  continue;
306 
307  // Since we're changing the order, write it back
308  if (pwtx)
309  {
310  if (!WriteTx(pwtx->GetHash(), *pwtx))
311  return DB_LOAD_FAIL;
312  }
313  else
314  if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
315  return DB_LOAD_FAIL;
316  }
317  }
318 
319  return DB_LOAD_OK;
320 }
321 
323 public:
324  unsigned int nKeys;
325  unsigned int nCKeys;
326  unsigned int nKeyMeta;
330  vector<uint256> vWalletUpgrade;
331 
333  nKeys = nCKeys = nKeyMeta = 0;
334  fIsEncrypted = false;
335  fAnyUnordered = false;
336  nFileVersion = 0;
337  }
338 };
339 
340 bool
341 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
342  CWalletScanState &wss, string& strType, string& strErr)
343 {
344  try {
345  // Unserialize
346  // Taking advantage of the fact that pair serialization
347  // is just the two items serialized one after the other
348  ssKey >> strType;
349  if (strType == "name")
350  {
351  string strAddress;
352  ssKey >> strAddress;
353  ssValue >> pwallet->mapAddressBook[CAnoncoinAddress(strAddress).Get()].name;
354  }
355  else if (strType == "purpose")
356  {
357  string strAddress;
358  ssKey >> strAddress;
359  ssValue >> pwallet->mapAddressBook[CAnoncoinAddress(strAddress).Get()].purpose;
360  }
361  else if (strType == "tx")
362  {
363  uint256 hash;
364  ssKey >> hash;
365  CWalletTx wtx;
366  ssValue >> wtx;
367  CValidationState state;
368  if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
369  return false;
370 
371  // Undo serialize changes in 31600
372  if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
373  {
374  if (!ssValue.empty())
375  {
376  char fTmp;
377  char fUnused;
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;
382  }
383  else
384  {
385  strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
386  wtx.fTimeReceivedIsTxTime = 0;
387  }
388  wss.vWalletUpgrade.push_back(hash);
389  }
390 
391  if (wtx.nOrderPos == -1)
392  wss.fAnyUnordered = true;
393 
394  pwallet->AddToWallet(wtx, true);
396  //LogPrintf("LoadWallet %s\n", wtx.GetHash().ToString());
397  //LogPrintf(" %12d %s %s %s\n",
398  // wtx.vout[0].nValue,
399  // DateTimeStrFormat("%Y-%m-%d %H:%M:%S", wtx.GetBlockTime()),
400  // wtx.hashBlock.ToString(),
401  // wtx.mapValue["message"]);
402  }
403  else if (strType == "acentry")
404  {
405  string strAccount;
406  ssKey >> strAccount;
407  uint64_t nNumber;
408  ssKey >> nNumber;
409  if (nNumber > nAccountingEntryNumber)
410  nAccountingEntryNumber = nNumber;
411 
412  if (!wss.fAnyUnordered)
413  {
414  CAccountingEntry acentry;
415  ssValue >> acentry;
416  if (acentry.nOrderPos == -1)
417  wss.fAnyUnordered = true;
418  }
419  }
420  else if (strType == "watchs")
421  {
422  CScript script;
423  ssKey >> script;
424  char fYes;
425  ssValue >> fYes;
426  if (fYes == '1')
427  pwallet->LoadWatchOnly(script);
428 
429  // Watch-only addresses have no birthday information for now,
430  // so set the wallet birthday to the beginning of time.
431  pwallet->nTimeFirstKey = 1;
432  }
433  else if (strType == "key" || strType == "wkey")
434  {
435  CPubKey vchPubKey;
436  ssKey >> vchPubKey;
437  if (!vchPubKey.IsValid())
438  {
439  strErr = "Error reading wallet database: CPubKey corrupt";
440  return false;
441  }
442  CKey key;
443  CPrivKey pkey;
444  uint256 hash = 0;
445 
446  if (strType == "key")
447  {
448  wss.nKeys++;
449  ssValue >> pkey;
450  } else {
451  CWalletKey wkey;
452  ssValue >> wkey;
453  pkey = wkey.vchPrivKey;
454  }
455 
456  // Old wallets store keys as "key" [pubkey] => [privkey]
457  // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
458  // using EC operations as a checksum.
459  // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
460  // remaining backwards-compatible.
461  try
462  {
463  ssValue >> hash;
464  }
465  catch(...){}
466 
467  bool fSkipCheck = false;
468 
469  if (hash != 0)
470  {
471  // hash pubkey/privkey to accelerate wallet load
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());
476 
477  if (Hash(vchKey.begin(), vchKey.end()) != hash)
478  {
479  strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
480  return false;
481  }
482 
483  fSkipCheck = true;
484  }
485 
486  if (!key.Load(pkey, vchPubKey, fSkipCheck))
487  {
488  strErr = "Error reading wallet database: CPrivKey corrupt";
489  return false;
490  }
491  if (!pwallet->LoadKey(key, vchPubKey))
492  {
493  strErr = "Error reading wallet database: LoadKey failed";
494  return false;
495  }
496  }
497  else if (strType == "mkey")
498  {
499  unsigned int nID;
500  ssKey >> nID;
501  CMasterKey kMasterKey;
502  ssValue >> kMasterKey;
503  if(pwallet->mapMasterKeys.count(nID) != 0)
504  {
505  strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
506  return false;
507  }
508  pwallet->mapMasterKeys[nID] = kMasterKey;
509  if (pwallet->nMasterKeyMaxID < nID)
510  pwallet->nMasterKeyMaxID = nID;
511  }
512  else if (strType == "ckey")
513  {
514  vector<unsigned char> vchPubKey;
515  ssKey >> vchPubKey;
516  vector<unsigned char> vchPrivKey;
517  ssValue >> vchPrivKey;
518  wss.nCKeys++;
519 
520  if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
521  {
522  strErr = "Error reading wallet database: LoadCryptedKey failed";
523  return false;
524  }
525  wss.fIsEncrypted = true;
526  }
527  else if (strType == "keymeta")
528  {
529  CPubKey vchPubKey;
530  ssKey >> vchPubKey;
531  CKeyMetadata keyMeta;
532  ssValue >> keyMeta;
533  wss.nKeyMeta++;
534 
535  pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
536 
537  // find earliest key creation time, as wallet birthday
538  if (!pwallet->nTimeFirstKey ||
539  (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
540  pwallet->nTimeFirstKey = keyMeta.nCreateTime;
541  }
542  else if (strType == "defaultkey")
543  {
544  ssValue >> pwallet->vchDefaultKey;
545  }
546  else if (strType == "pool")
547  {
548  int64_t nIndex;
549  ssKey >> nIndex;
550  CKeyPool keypool;
551  ssValue >> keypool;
552  pwallet->setKeyPool.insert(nIndex);
553 
554  // If no metadata exists yet, create a default with the pool key's
555  // creation time. Note that this may be overwritten by actually
556  // stored metadata for that key later, which is fine.
557  CKeyID keyid = keypool.vchPubKey.GetID();
558  if (pwallet->mapKeyMetadata.count(keyid) == 0)
559  pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
560  }
561  else if (strType == "version")
562  {
563  ssValue >> wss.nFileVersion;
564  if (wss.nFileVersion == 10300)
565  wss.nFileVersion = 300;
566  }
567  else if (strType == "cscript")
568  {
569  uint160 hash;
570  ssKey >> hash;
571  CScript script;
572  ssValue >> script;
573  if (!pwallet->LoadCScript(script))
574  {
575  strErr = "Error reading wallet database: LoadCScript failed";
576  return false;
577  }
578  }
579  else if (strType == "orderposnext")
580  {
581  ssValue >> pwallet->nOrderPosNext;
582  }
583  else if (strType == "destdata")
584  {
585  std::string strAddress, strKey, strValue;
586  ssKey >> strAddress;
587  ssKey >> strKey;
588  ssValue >> strValue;
589  if (!pwallet->LoadDestData(CAnoncoinAddress(strAddress).Get(), strKey, strValue))
590  {
591  strErr = "Error reading wallet database: LoadDestData failed";
592  return false;
593  }
594  }
595  } catch (...)
596  {
597  return false;
598  }
599  return true;
600 }
601 
602 static bool IsKeyType(string strType)
603 {
604  return (strType== "key" || strType == "wkey" ||
605  strType == "mkey" || strType == "ckey");
606 }
607 
609 {
610  pwallet->vchDefaultKey = CPubKey();
611  CWalletScanState wss;
612  bool fNoncriticalErrors = false;
613  DBErrors result = DB_LOAD_OK;
614 
615  try {
616  LOCK(pwallet->cs_wallet);
617  int nMinVersion = 0;
618  if (Read((string)"minversion", nMinVersion))
619  {
620  if (nMinVersion > CLIENT_VERSION)
621  return DB_TOO_NEW;
622  pwallet->LoadMinVersion(nMinVersion);
623  }
624 
625  // Get cursor
626  Dbc* pcursor = GetCursor();
627  if (!pcursor)
628  {
629  LogPrintf("Error getting wallet database cursor\n");
630  return DB_CORRUPT;
631  }
632 
633  while (true)
634  {
635  // Read next record
636  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
637  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
638  int ret = ReadAtCursor(pcursor, ssKey, ssValue);
639  if (ret == DB_NOTFOUND)
640  break;
641  else if (ret != 0)
642  {
643  LogPrintf("Error reading next record from wallet database\n");
644  return DB_CORRUPT;
645  }
646 
647  // Try to be tolerant of single corrupt records:
648  string strType, strErr;
649  if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
650  {
651  // losing keys is considered a catastrophic error, anything else
652  // we assume the user can live with:
653  if (IsKeyType(strType))
654  result = DB_CORRUPT;
655  else
656  {
657  // Leave other errors alone, if we try to fix them we might make things worse.
658  fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
659  if (strType == "tx")
660  // Rescan if there is a bad transaction record:
661  SoftSetBoolArg("-rescan", true);
662  }
663  }
664  if (!strErr.empty())
665  LogPrintf("%s\n", strErr);
666  }
667  pcursor->close();
668  }
669  catch (boost::thread_interrupted) {
670  throw;
671  }
672  catch (...) {
673  result = DB_CORRUPT;
674  }
675 
676  if (fNoncriticalErrors && result == DB_LOAD_OK)
677  result = DB_NONCRITICAL_ERROR;
678 
679  // Any wallet corruption at all: skip any rewriting or
680  // upgrading, we don't want to make it worse.
681  if (result != DB_LOAD_OK)
682  return result;
683 
684  LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
685 
686  LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
687  wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
688 
689  // nTimeFirstKey is only reliable if all keys have metadata
690  if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
691  pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
692 
693  BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
694  WriteTx(hash, pwallet->mapWallet[hash]);
695 
696  // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
697  if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
698  return DB_NEED_REWRITE;
699 
700  if (wss.nFileVersion < CLIENT_VERSION) // Update
701  WriteVersion(CLIENT_VERSION);
702 
703  if (wss.fAnyUnordered)
704  result = ReorderTransactions(pwallet);
705 
706  return result;
707 }
708 
709 DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
710 {
711  pwallet->vchDefaultKey = CPubKey();
712  CWalletScanState wss;
713  bool fNoncriticalErrors = false;
714  DBErrors result = DB_LOAD_OK;
715 
716  try {
717  LOCK(pwallet->cs_wallet);
718  int nMinVersion = 0;
719  if (Read((string)"minversion", nMinVersion))
720  {
721  if (nMinVersion > CLIENT_VERSION)
722  return DB_TOO_NEW;
723  pwallet->LoadMinVersion(nMinVersion);
724  }
725 
726  // Get cursor
727  Dbc* pcursor = GetCursor();
728  if (!pcursor)
729  {
730  LogPrintf("Error getting wallet database cursor\n");
731  return DB_CORRUPT;
732  }
733 
734  while (true)
735  {
736  // Read next record
737  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
738  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
739  int ret = ReadAtCursor(pcursor, ssKey, ssValue);
740  if (ret == DB_NOTFOUND)
741  break;
742  else if (ret != 0)
743  {
744  LogPrintf("Error reading next record from wallet database\n");
745  return DB_CORRUPT;
746  }
747 
748  string strType;
749  ssKey >> strType;
750  if (strType == "tx") {
751  uint256 hash;
752  ssKey >> hash;
753 
754  vTxHash.push_back(hash);
755  }
756  }
757  pcursor->close();
758  }
759  catch (boost::thread_interrupted) {
760  throw;
761  }
762  catch (...) {
763  result = DB_CORRUPT;
764  }
765 
766  if (fNoncriticalErrors && result == DB_LOAD_OK)
767  result = DB_NONCRITICAL_ERROR;
768 
769  return result;
770 }
771 
773 {
774  // build list of wallet TXs
775  vector<uint256> vTxHash;
776  DBErrors err = FindWalletTx(pwallet, vTxHash);
777  if (err != DB_LOAD_OK)
778  return err;
779 
780  // erase each wallet TX
781  BOOST_FOREACH (uint256& hash, vTxHash) {
782  if (!EraseTx(hash))
783  return DB_CORRUPT;
784  }
785 
786  return DB_LOAD_OK;
787 }
788 
789 void ThreadFlushWalletDB(const string& strFile)
790 {
791  // Make this thread recognisable as the wallet flushing thread
792  RenameThread("anoncoin-wallet");
793 
794  static bool fOneThread;
795  if (fOneThread)
796  return;
797  fOneThread = true;
798  if (!GetBoolArg("-flushwallet", true))
799  return;
800 
801  unsigned int nLastSeen = nWalletDBUpdated;
802  unsigned int nLastFlushed = nWalletDBUpdated;
803  int64_t nLastWalletUpdate = GetTime();
804  while (true)
805  {
806  MilliSleep(500);
807 
808  if (nLastSeen != nWalletDBUpdated)
809  {
810  nLastSeen = nWalletDBUpdated;
811  nLastWalletUpdate = GetTime();
812  }
813 
814  if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
815  {
816  TRY_LOCK(bitdb.cs_db,lockDb);
817  if (lockDb)
818  {
819  // Don't do this if any databases are in use
820  int nRefCount = 0;
821  map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
822  while (mi != bitdb.mapFileUseCount.end())
823  {
824  nRefCount += (*mi).second;
825  mi++;
826  }
827 
828  if (nRefCount == 0)
829  {
830  boost::this_thread::interruption_point();
831  map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
832  if (mi != bitdb.mapFileUseCount.end())
833  {
834  LogPrint("db", "Flushing wallet.dat\n");
835  nLastFlushed = nWalletDBUpdated;
836  int64_t nStart = GetTimeMillis();
837 
838  // Flush wallet.dat so it's self contained
839  bitdb.CloseDb(strFile);
840  bitdb.CheckpointLSN(strFile);
841 
842  bitdb.mapFileUseCount.erase(mi++);
843  LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart);
844  }
845  }
846  }
847  }
848  }
849 }
850 
851 bool BackupWallet(const CWallet& wallet, const string& strDest)
852 {
853  if (!wallet.fFileBacked)
854  return false;
855  while (true)
856  {
857  {
858  LOCK(bitdb.cs_db);
859  if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
860  {
861  // Flush log data to the dat file
862  bitdb.CloseDb(wallet.strWalletFile);
864  bitdb.mapFileUseCount.erase(wallet.strWalletFile);
865 
866  // Copy wallet.dat
867  filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
868  filesystem::path pathDest(strDest);
869  if (filesystem::is_directory(pathDest))
870  pathDest /= wallet.strWalletFile;
871 
872  try {
873 #if BOOST_VERSION >= 104000
874  filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
875 #else
876  filesystem::copy_file(pathSrc, pathDest);
877 #endif
878  LogPrintf("copied wallet.dat to %s\n", pathDest.string());
879  return true;
880  } catch(const filesystem::filesystem_error &e) {
881  LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what());
882  return false;
883  }
884  }
885  }
886  MilliSleep(100);
887  }
888  return false;
889 }
890 
891 //
892 // Try to (very carefully!) recover wallet.dat if there is a problem.
893 //
894 bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
895 {
896  // Recovery procedure:
897  // move wallet.dat to wallet.timestamp.bak
898  // Call Salvage with fAggressive=true to
899  // get as much data as possible.
900  // Rewrite salvaged data to wallet.dat
901  // Set -rescan so any missing transactions will be
902  // found.
903  int64_t now = GetTime();
904  std::string newFilename = strprintf("wallet.%d.bak", now);
905 
906  int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL,
907  newFilename.c_str(), DB_AUTO_COMMIT);
908  if (result == 0)
909  LogPrintf("Renamed %s to %s\n", filename, newFilename);
910  else
911  {
912  LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
913  return false;
914  }
915 
916  std::vector<CDBEnv::KeyValPair> salvagedData;
917  bool allOK = dbenv.Salvage(newFilename, true, salvagedData);
918  if (salvagedData.empty())
919  {
920  LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
921  return false;
922  }
923  LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
924 
925  bool fSuccess = allOK;
926  Db* pdbCopy = new Db(&dbenv.dbenv, 0);
927  int ret = pdbCopy->open(NULL, // Txn pointer
928  filename.c_str(), // Filename
929  "main", // Logical db name
930  DB_BTREE, // Database type
931  DB_CREATE, // Flags
932  0);
933  if (ret > 0)
934  {
935  LogPrintf("Cannot create database file %s\n", filename);
936  return false;
937  }
938  CWallet dummyWallet;
939  CWalletScanState wss;
940 
941  DbTxn* ptxn = dbenv.TxnBegin();
942  BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
943  {
944  if (fOnlyKeys)
945  {
946  CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
947  CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
948  string strType, strErr;
949  bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
950  wss, strType, strErr);
951  if (!IsKeyType(strType))
952  continue;
953  if (!fReadOK)
954  {
955  LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
956  continue;
957  }
958  }
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);
962  if (ret2 > 0)
963  fSuccess = false;
964  }
965  ptxn->commit(0);
966  pdbCopy->close(0);
967  delete pdbCopy;
968 
969  return fSuccess;
970 }
971 
972 bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename)
973 {
974  return CWalletDB::Recover(dbenv, filename, false);
975 }
976 
977 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
978 {
980  return Write(boost::make_tuple(std::string("destdata"), address, key), value);
981 }
982 
983 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
984 {
986  return Erase(boost::make_tuple(string("destdata"), address, key));
987 }
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:968
unsigned int nWalletDBUpdated
Definition: db.cpp:28
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Definition: wallet.cpp:125
bool WriteMinVersion(int nVersion)
Definition: walletdb.cpp:168
unsigned int nKeyMeta
Definition: walletdb.cpp:326
unsigned int nKeys
Definition: walletdb.cpp:324
Account information.
Definition: wallet.h:887
std::set< int64_t > setKeyPool
Definition: wallet.h:138
int64_t nOrderPos
Definition: wallet.h:924
std::map< std::string, int > mapFileUseCount
Definition: db.h:43
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.
Definition: wallet.cpp:2169
DBErrors FindWalletTx(CWallet *pwallet, std::vector< uint256 > &vTxHash)
Definition: walletdb.cpp:709
void CheckpointLSN(std::string strFile)
Definition: db.cpp:216
bool WriteAccount(const std::string &strAccount, const CAccount &account)
Definition: walletdb.cpp:179
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Definition: db.h:77
CPrivKey vchPrivKey
Definition: wallet.h:855
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Definition: core.h:457
#define TRY_LOCK(cs, name)
Definition: sync.h:159
Definition: init.h:14
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata)
Definition: wallet.cpp:115
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:174
CCriticalSection cs_wallet
Main wallet lock.
Definition: wallet.h:133
void MilliSleep(int64_t n)
Definition: util.h:80
#define strprintf
Definition: tinyformat.h:1011
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: util.cpp:539
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
Definition: walletdb.cpp:104
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:83
CPubKey vchDefaultKey
Definition: wallet.h:176
Master key for wallet encryption.
Definition: crypter.h:34
unsigned int size() const
Definition: key.h:91
CTxDestination Get() const
Definition: base58.cpp:223
int64_t nOrderPos
Definition: wallet.h:477
uint256 GetHash() const
Definition: core.cpp:76
int64_t nTimeFirstKey
Definition: wallet.h:180
void ListAccountCreditDebit(const std::string &strAccount, std::list< CAccountingEntry > &acentries)
Definition: walletdb.cpp:206
void SetNull()
Definition: wallet.h:897
Double ended buffer combining vector and stream-like interfaces.
Definition: serialize.h:848
bool WriteWatchOnly(const CScript &script)
Definition: walletdb.cpp:116
bool ErasePurpose(const std::string &strAddress)
Definition: walletdb.cpp:48
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry &acentry)
Definition: walletdb.cpp:184
unsigned int nCKeys
Definition: walletdb.cpp:325
bool BackupWallet(const CWallet &wallet, const string &strDest)
Definition: walletdb.cpp:851
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:31
void RenameThread(const char *name)
Definition: util.cpp:1368
bool WriteOrderPosNext(int64_t nOrderPosNext)
Definition: walletdb.cpp:139
CDBEnv bitdb
Definition: db.cpp:36
bool EraseTx(uint256 hash)
Definition: walletdb.cpp:60
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
Definition: key.h:177
DBErrors ZapWalletTx(CWallet *pwallet)
Definition: walletdb.cpp:772
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:520
#define LogPrintf(...)
Definition: util.h:118
unsigned int nMasterKeyMaxID
Definition: wallet.h:143
bool EraseDestData(const std::string &address, const std::string &key)
Erase destination data tuple from wallet database.
Definition: walletdb.cpp:983
bool WritePool(int64_t nPool, const CKeyPool &keypool)
Definition: walletdb.cpp:156
uint64_t nEntryNo
Definition: wallet.h:925
int64_t GetAccountCreditDebit(const std::string &strAccount)
Definition: walletdb.cpp:194
int64_t nCreditDebit
Definition: wallet.h:919
#define LOCK(cs)
Definition: sync.h:157
bool WriteName(const std::string &strAddress, const std::string &strName)
Definition: walletdb.cpp:28
DBErrors LoadWallet(CWallet *pwallet)
Definition: walletdb.cpp:608
An encapsulated public key.
Definition: key.h:43
base58-encoded Anoncoin addresses.
Definition: base58.h:102
bool LoadKey(const CKey &key, const CPubKey &pubkey)
Definition: wallet.h:204
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value)
Write destination data key,value tuple to database.
Definition: walletdb.cpp:977
uint256 Hash(const T1 pbegin, const T1 pend)
Definition: hash.h:20
int64_t GetTimeMillis()
Definition: util.h:304
bool IsValid() const
Definition: main.h:989
CCriticalSection cs_db
Definition: db.h:41
bool LoadCScript(const CScript &redeemScript)
Definition: wallet.cpp:139
bool ErasePool(int64_t nPool)
Definition: walletdb.cpp:162
bool EraseWatchOnly(const CScript &script)
Definition: walletdb.cpp:122
vector< uint256 > vWalletUpgrade
Definition: walletdb.cpp:330
int64_t GetTime()
Definition: util.cpp:1220
bool WriteTx(uint256 hash, const CWalletTx &wtx)
Definition: walletdb.cpp:54
bool LoadMinVersion(int nVersion)
Definition: wallet.h:208
const unsigned char * begin() const
Definition: key.h:92
bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck)
Definition: key.cpp:428
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:464
DBErrors ReorderTransactions(CWallet *)
Definition: walletdb.cpp:251
std::string strWalletFile
Definition: wallet.h:136
bool ReadBestBlock(CBlockLocator &locator)
Definition: walletdb.cpp:134
bool WriteDefaultKey(const CPubKey &vchPubKey)
Definition: walletdb.cpp:145
bool fFileBacked
Definition: wallet.h:135
Capture information about block/transaction validation.
Definition: main.h:950
bool WriteBestBlock(const CBlockLocator &locator)
Definition: walletdb.cpp:128
256-bit unsigned integer
Definition: uint256.h:532
void ThreadFlushWalletDB(const string &strFile)
Definition: walletdb.cpp:789
bool LoadWatchOnly(const CScript &dest)
Definition: wallet.cpp:180
bool Salvage(std::string strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
Definition: db.cpp:161
MasterKeyMap mapMasterKeys
Definition: wallet.h:142
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Definition: walletdb.cpp:151
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
int64_t nOrderPosNext
Definition: wallet.h:171
void CloseDb(const std::string &strFile)
Definition: db.cpp:318
static bool Recover(CDBEnv &dbenv, std::string filename, bool fOnlyKeys)
Definition: walletdb.cpp:894
Private key that includes an expiration date in case it never gets used.
Definition: wallet.h:852
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:27
Internal transfers.
Definition: wallet.h:915
Definition: db.h:31
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:101
160-bit unsigned integer
Definition: uint256.h:420
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
Definition: wallet.h:139
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, string &strType, string &strErr)
Definition: walletdb.cpp:341
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:169
bool AddToWallet(const CWalletTx &wtxIn, bool fFromLoadWallet=false)
Definition: wallet.cpp:521
DbEnv dbenv
Definition: db.h:42
unsigned int nTimeReceived
Definition: wallet.h:473
An encapsulated private key.
Definition: key.h:180
bool EraseName(const std::string &strAddress)
Definition: walletdb.cpp:34
std::pair< std::vector< unsigned char >, std::vector< unsigned char > > KeyValPair
Definition: db.h:66
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
Definition: walletdb.cpp:110
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
Definition: walletdb.cpp:42
bool ReadAccount(const std::string &strAccount, CAccount &account)
Definition: walletdb.cpp:173
bool CheckTransaction(const CTransaction &tx, CValidationState &state)
Definition: main.cpp:783
const unsigned char * end() const
Definition: key.h:93
int64_t nTime
Definition: wallet.h:920
bool empty() const
Definition: serialize.h:938
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:66
A key pool entry.
Definition: wallet.h:56
std::string strAccount
Definition: wallet.h:918