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