Fabcoin Core  0.16.2
P2P Digital Currency
walletdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2017 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <wallet/walletdb.h>
7 
8 #include <base58.h>
9 #include <consensus/tx_verify.h>
10 #include <consensus/validation.h>
11 #include <fs.h>
12 #include <protocol.h>
13 #include <serialize.h>
14 #include <sync.h>
15 #include <util.h>
16 #include <utiltime.h>
17 #include <wallet/wallet.h>
18 
19 #include <atomic>
20 
21 #include <boost/thread.hpp>
22 
23 //
24 // CWalletDB
25 //
26 
27 bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
28 {
29  return WriteIC(std::make_pair(std::string("name"), strAddress), strName);
30 }
31 
32 bool CWalletDB::EraseName(const std::string& strAddress)
33 {
34  // This should only be used for sending addresses, never for receiving addresses,
35  // receiving addresses must always have an address book entry if they're not change return.
36  return EraseIC(std::make_pair(std::string("name"), strAddress));
37 }
38 
39 bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
40 {
41  return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
42 }
43 
44 bool CWalletDB::ErasePurpose(const std::string& strPurpose)
45 {
46  return EraseIC(std::make_pair(std::string("purpose"), strPurpose));
47 }
48 
49 bool CWalletDB::WriteTx(const CWalletTx& wtx)
50 {
51  return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
52 }
53 
55 {
56  return EraseIC(std::make_pair(std::string("tx"), hash));
57 }
58 
59 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
60 {
61  if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, false)) {
62  return false;
63  }
64 
65  // hash pubkey/privkey to accelerate wallet load
66  std::vector<unsigned char> vchKey;
67  vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
68  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
69  vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
70 
71  return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
72 }
73 
74 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
75  const std::vector<unsigned char>& vchCryptedSecret,
76  const CKeyMetadata &keyMeta)
77 {
78  if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) {
79  return false;
80  }
81 
82  if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) {
83  return false;
84  }
85  EraseIC(std::make_pair(std::string("key"), vchPubKey));
86  EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
87  return true;
88 }
89 
90 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
91 {
92  return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
93 }
94 
95 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
96 {
97  return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false);
98 }
99 
100 bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
101 {
102  if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) {
103  return false;
104  }
105  return WriteIC(std::make_pair(std::string("watchs"), dest), '1');
106 }
107 
109 {
110  if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) {
111  return false;
112  }
113  return EraseIC(std::make_pair(std::string("watchs"), dest));
114 }
115 
117 {
118  WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
119  return WriteIC(std::string("bestblock_nomerkle"), locator);
120 }
121 
123 {
124  if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
125  return batch.Read(std::string("bestblock_nomerkle"), locator);
126 }
127 
128 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
129 {
130  return WriteIC(std::string("orderposnext"), nOrderPosNext);
131 }
132 
133 bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
134 {
135  return WriteIC(std::string("defaultkey"), vchPubKey);
136 }
137 
138 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
139 {
140  return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
141 }
142 
143 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
144 {
145  return WriteIC(std::make_pair(std::string("pool"), nPool), keypool);
146 }
147 
148 bool CWalletDB::ErasePool(int64_t nPool)
149 {
150  return EraseIC(std::make_pair(std::string("pool"), nPool));
151 }
152 
153 bool CWalletDB::WriteMinVersion(int nVersion)
154 {
155  return WriteIC(std::string("minversion"), nVersion);
156 }
157 
158 bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
159 {
160  account.SetNull();
161  return batch.Read(std::make_pair(std::string("acc"), strAccount), account);
162 }
163 
164 bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
165 {
166  return WriteIC(std::make_pair(std::string("acc"), strAccount), account);
167 }
168 
169 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
170 {
171  return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
172 }
173 
174 CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
175 {
176  std::list<CAccountingEntry> entries;
177  ListAccountCreditDebit(strAccount, entries);
178 
179  CAmount nCreditDebit = 0;
180  for (const CAccountingEntry& entry : entries)
181  nCreditDebit += entry.nCreditDebit;
182 
183  return nCreditDebit;
184 }
185 
186 void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
187 {
188  bool fAllAccounts = (strAccount == "*");
189 
190  Dbc* pcursor = batch.GetCursor();
191  if (!pcursor)
192  throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
193  bool setRange = true;
194  while (true)
195  {
196  // Read next record
197  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
198  if (setRange)
199  ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
200  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
201  int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
202  setRange = false;
203  if (ret == DB_NOTFOUND)
204  break;
205  else if (ret != 0)
206  {
207  pcursor->close();
208  throw std::runtime_error(std::string(__func__) + ": error scanning DB");
209  }
210 
211  // Unserialize
212  std::string strType;
213  ssKey >> strType;
214  if (strType != "acentry")
215  break;
216  CAccountingEntry acentry;
217  ssKey >> acentry.strAccount;
218  if (!fAllAccounts && acentry.strAccount != strAccount)
219  break;
220 
221  ssValue >> acentry;
222  ssKey >> acentry.nEntryNo;
223  entries.push_back(acentry);
224  }
225 
226  pcursor->close();
227 }
228 
230 public:
231  unsigned int nKeys;
232  unsigned int nCKeys;
233  unsigned int nWatchKeys;
234  unsigned int nKeyMeta;
238  std::vector<uint256> vWalletUpgrade;
239 
241  nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
242  fIsEncrypted = false;
243  fAnyUnordered = false;
244  nFileVersion = 0;
245  }
246 };
247 
248 bool
249 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
250  CWalletScanState &wss, std::string& strType, std::string& strErr)
251 {
252  try {
253  // Unserialize
254  // Taking advantage of the fact that pair serialization
255  // is just the two items serialized one after the other
256  ssKey >> strType;
257  if (strType == "name")
258  {
259  std::string strAddress;
260  ssKey >> strAddress;
261  ssValue >> pwallet->mapAddressBook[CFabcoinAddress(strAddress).Get()].name;
262  }
263  else if (strType == "purpose")
264  {
265  std::string strAddress;
266  ssKey >> strAddress;
267  ssValue >> pwallet->mapAddressBook[CFabcoinAddress(strAddress).Get()].purpose;
268  }
269  else if (strType == "tx")
270  {
271  uint256 hash;
272  ssKey >> hash;
273  CWalletTx wtx;
274  ssValue >> wtx;
275  CValidationState state;
276  if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
277  return false;
278 
279  // Undo serialize changes in 31600
280  if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
281  {
282  if (!ssValue.empty())
283  {
284  char fTmp;
285  char fUnused;
286  ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
287  strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
288  wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
289  wtx.fTimeReceivedIsTxTime = fTmp;
290  }
291  else
292  {
293  strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
294  wtx.fTimeReceivedIsTxTime = 0;
295  }
296  wss.vWalletUpgrade.push_back(hash);
297  }
298 
299  if (wtx.nOrderPos == -1)
300  wss.fAnyUnordered = true;
301 
302  pwallet->LoadToWallet(wtx);
303  }
304  else if (strType == "acentry")
305  {
306  std::string strAccount;
307  ssKey >> strAccount;
308  uint64_t nNumber;
309  ssKey >> nNumber;
310  if (nNumber > pwallet->nAccountingEntryNumber) {
311  pwallet->nAccountingEntryNumber = nNumber;
312  }
313 
314  if (!wss.fAnyUnordered)
315  {
316  CAccountingEntry acentry;
317  ssValue >> acentry;
318  if (acentry.nOrderPos == -1)
319  wss.fAnyUnordered = true;
320  }
321  }
322  else if (strType == "watchs")
323  {
324  wss.nWatchKeys++;
325  CScript script;
326  ssKey >> script;
327  char fYes;
328  ssValue >> fYes;
329  if (fYes == '1')
330  pwallet->LoadWatchOnly(script);
331  }
332  else if (strType == "key" || strType == "wkey")
333  {
334  CPubKey vchPubKey;
335  ssKey >> vchPubKey;
336  if (!vchPubKey.IsValid())
337  {
338  strErr = "Error reading wallet database: CPubKey corrupt";
339  return false;
340  }
341  CKey key;
342  CPrivKey pkey;
343  uint256 hash;
344 
345  if (strType == "key")
346  {
347  wss.nKeys++;
348  ssValue >> pkey;
349  } else {
350  CWalletKey wkey;
351  ssValue >> wkey;
352  pkey = wkey.vchPrivKey;
353  }
354 
355  // Old wallets store keys as "key" [pubkey] => [privkey]
356  // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
357  // using EC operations as a checksum.
358  // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
359  // remaining backwards-compatible.
360  try
361  {
362  ssValue >> hash;
363  }
364  catch (...) {}
365 
366  bool fSkipCheck = false;
367 
368  if (!hash.IsNull())
369  {
370  // hash pubkey/privkey to accelerate wallet load
371  std::vector<unsigned char> vchKey;
372  vchKey.reserve(vchPubKey.size() + pkey.size());
373  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
374  vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
375 
376  if (Hash(vchKey.begin(), vchKey.end()) != hash)
377  {
378  strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
379  return false;
380  }
381 
382  fSkipCheck = true;
383  }
384 
385  if (!key.Load(pkey, vchPubKey, fSkipCheck))
386  {
387  strErr = "Error reading wallet database: CPrivKey corrupt";
388  return false;
389  }
390  if (!pwallet->LoadKey(key, vchPubKey))
391  {
392  strErr = "Error reading wallet database: LoadKey failed";
393  return false;
394  }
395  }
396  else if (strType == "mkey")
397  {
398  unsigned int nID;
399  ssKey >> nID;
400  CMasterKey kMasterKey;
401  ssValue >> kMasterKey;
402  if(pwallet->mapMasterKeys.count(nID) != 0)
403  {
404  strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
405  return false;
406  }
407  pwallet->mapMasterKeys[nID] = kMasterKey;
408  if (pwallet->nMasterKeyMaxID < nID)
409  pwallet->nMasterKeyMaxID = nID;
410  }
411  else if (strType == "ckey")
412  {
413  CPubKey vchPubKey;
414  ssKey >> vchPubKey;
415  if (!vchPubKey.IsValid())
416  {
417  strErr = "Error reading wallet database: CPubKey corrupt";
418  return false;
419  }
420  std::vector<unsigned char> vchPrivKey;
421  ssValue >> vchPrivKey;
422  wss.nCKeys++;
423 
424  if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
425  {
426  strErr = "Error reading wallet database: LoadCryptedKey failed";
427  return false;
428  }
429  wss.fIsEncrypted = true;
430  }
431  else if (strType == "keymeta" || strType == "watchmeta")
432  {
433  CTxDestination keyID;
434  if (strType == "keymeta")
435  {
436  CPubKey vchPubKey;
437  ssKey >> vchPubKey;
438  keyID = vchPubKey.GetID();
439  }
440  else if (strType == "watchmeta")
441  {
442  CScript script;
443  ssKey >> script;
444  keyID = CScriptID(script);
445  }
446 
447  CKeyMetadata keyMeta;
448  ssValue >> keyMeta;
449  wss.nKeyMeta++;
450 
451  pwallet->LoadKeyMetadata(keyID, keyMeta);
452  }
453  else if (strType == "defaultkey")
454  {
455  ssValue >> pwallet->vchDefaultKey;
456  }
457  else if (strType == "pool")
458  {
459  int64_t nIndex;
460  ssKey >> nIndex;
461  CKeyPool keypool;
462  ssValue >> keypool;
463 
464  pwallet->LoadKeyPool(nIndex, keypool);
465  }
466  else if (strType == "version")
467  {
468  ssValue >> wss.nFileVersion;
469  if (wss.nFileVersion == 10300)
470  wss.nFileVersion = 300;
471  }
472  else if (strType == "cscript")
473  {
474  uint160 hash;
475  ssKey >> hash;
476  CScript script;
477  ssValue >> script;
478  if (!pwallet->LoadCScript(script))
479  {
480  strErr = "Error reading wallet database: LoadCScript failed";
481  return false;
482  }
483  }
484  else if (strType == "orderposnext")
485  {
486  ssValue >> pwallet->nOrderPosNext;
487  }
488  else if (strType == "destdata")
489  {
490  std::string strAddress, strKey, strValue;
491  ssKey >> strAddress;
492  ssKey >> strKey;
493  ssValue >> strValue;
494  if (!pwallet->LoadDestData(CFabcoinAddress(strAddress).Get(), strKey, strValue))
495  {
496  strErr = "Error reading wallet database: LoadDestData failed";
497  return false;
498  }
499  }
500  else if (strType == "hdchain")
501  {
502  CHDChain chain;
503  ssValue >> chain;
504  if (!pwallet->SetHDChain(chain, true))
505  {
506  strErr = "Error reading wallet database: SetHDChain failed";
507  return false;
508  }
509  }
510  else if (strType == "token")
511  {
512  uint256 hash;
513  ssKey >> hash;
514  CTokenInfo wtoken;
515  ssValue >> wtoken;
516  if (wtoken.GetHash() != hash)
517  {
518  strErr = "Error reading wallet database: CTokenInfo corrupt";
519  return false;
520  }
521 
522  pwallet->LoadToken(wtoken);
523  }
524  else if (strType == "tokentx")
525  {
526  uint256 hash;
527  ssKey >> hash;
528  CTokenTx wTokenTx;
529  ssValue >> wTokenTx;
530  if (wTokenTx.GetHash() != hash)
531  {
532  strErr = "Error reading wallet database: CTokenTx corrupt";
533  return false;
534  }
535 
536  pwallet->LoadTokenTx(wTokenTx);
537  }
538  else if (strType == "contractdata")
539  {
540  std::string strAddress, strKey, strValue;
541  ssKey >> strAddress;
542  ssKey >> strKey;
543  ssValue >> strValue;
544  if (!pwallet->LoadContractData(strAddress, strKey, strValue))
545  {
546  strErr = "Error reading wallet database: LoadContractData failed";
547  return false;
548  }
549  }
550  } catch (...)
551  {
552  return false;
553  }
554  return true;
555 }
556 
557 bool CWalletDB::IsKeyType(const std::string& strType)
558 {
559  return (strType== "key" || strType == "wkey" ||
560  strType == "mkey" || strType == "ckey");
561 }
562 
564 {
565  pwallet->vchDefaultKey = CPubKey();
566  CWalletScanState wss;
567  bool fNoncriticalErrors = false;
568  DBErrors result = DB_LOAD_OK;
569 
570  LOCK(pwallet->cs_wallet);
571  try {
572  int nMinVersion = 0;
573  if (batch.Read((std::string)"minversion", nMinVersion))
574  {
575  if (nMinVersion > CLIENT_VERSION)
576  return DB_TOO_NEW;
577  pwallet->LoadMinVersion(nMinVersion);
578  }
579 
580  // Get cursor
581  Dbc* pcursor = batch.GetCursor();
582  if (!pcursor)
583  {
584  LogPrintf("Error getting wallet database cursor\n");
585  return DB_CORRUPT;
586  }
587 
588  while (true)
589  {
590  // Read next record
591  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
592  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
593  int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
594  if (ret == DB_NOTFOUND)
595  break;
596  else if (ret != 0)
597  {
598  LogPrintf("Error reading next record from wallet database\n");
599  return DB_CORRUPT;
600  }
601 
602  // Try to be tolerant of single corrupt records:
603  std::string strType, strErr;
604  if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
605  {
606  // losing keys is considered a catastrophic error, anything else
607  // we assume the user can live with:
608  if (IsKeyType(strType))
609  result = DB_CORRUPT;
610  else
611  {
612  // Leave other errors alone, if we try to fix them we might make things worse.
613  fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
614  if (strType == "tx")
615  // Rescan if there is a bad transaction record:
616  gArgs.SoftSetBoolArg("-rescan", true);
617  }
618  }
619  if (!strErr.empty())
620  LogPrintf("%s\n", strErr);
621  }
622  pcursor->close();
623  }
624  catch (const boost::thread_interrupted&) {
625  throw;
626  }
627  catch (...) {
628  result = DB_CORRUPT;
629  }
630 
631  if (fNoncriticalErrors && result == DB_LOAD_OK)
632  result = DB_NONCRITICAL_ERROR;
633 
634  // Any wallet corruption at all: skip any rewriting or
635  // upgrading, we don't want to make it worse.
636  if (result != DB_LOAD_OK)
637  return result;
638 
639  LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
640 
641  LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
642  wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
643 
644  // nTimeFirstKey is only reliable if all keys have metadata
645  if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
646  pwallet->UpdateTimeFirstKey(1);
647 
648  for (uint256 hash : wss.vWalletUpgrade)
649  WriteTx(pwallet->mapWallet[hash]);
650 
651  // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
652  if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
653  return DB_NEED_REWRITE;
654 
655  if (wss.nFileVersion < CLIENT_VERSION) // Update
656  WriteVersion(CLIENT_VERSION);
657 
658  if (wss.fAnyUnordered)
659  result = pwallet->ReorderTransactions();
660 
661  pwallet->laccentries.clear();
662  ListAccountCreditDebit("*", pwallet->laccentries);
663  for (CAccountingEntry& entry : pwallet->laccentries) {
664  pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
665  }
666 
667  return result;
668 }
669 
670 DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
671 {
672  bool fNoncriticalErrors = false;
673  DBErrors result = DB_LOAD_OK;
674 
675  try {
676  int nMinVersion = 0;
677  if (batch.Read((std::string)"minversion", nMinVersion))
678  {
679  if (nMinVersion > CLIENT_VERSION)
680  return DB_TOO_NEW;
681  }
682 
683  // Get cursor
684  Dbc* pcursor = batch.GetCursor();
685  if (!pcursor)
686  {
687  LogPrintf("Error getting wallet database cursor\n");
688  return DB_CORRUPT;
689  }
690 
691  while (true)
692  {
693  // Read next record
694  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
695  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
696  int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
697  if (ret == DB_NOTFOUND)
698  break;
699  else if (ret != 0)
700  {
701  LogPrintf("Error reading next record from wallet database\n");
702  return DB_CORRUPT;
703  }
704 
705  std::string strType;
706  ssKey >> strType;
707  if (strType == "tx") {
708  uint256 hash;
709  ssKey >> hash;
710 
711  CWalletTx wtx;
712  ssValue >> wtx;
713 
714  vTxHash.push_back(hash);
715  vWtx.push_back(wtx);
716  }
717  }
718  pcursor->close();
719  }
720  catch (const boost::thread_interrupted&) {
721  throw;
722  }
723  catch (...) {
724  result = DB_CORRUPT;
725  }
726 
727  if (fNoncriticalErrors && result == DB_LOAD_OK)
728  result = DB_NONCRITICAL_ERROR;
729 
730  return result;
731 }
732 
733 DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
734 {
735  // build list of wallet TXs and hashes
736  std::vector<uint256> vTxHash;
737  std::vector<CWalletTx> vWtx;
738  DBErrors err = FindWalletTx(vTxHash, vWtx);
739  if (err != DB_LOAD_OK) {
740  return err;
741  }
742 
743  std::sort(vTxHash.begin(), vTxHash.end());
744  std::sort(vTxHashIn.begin(), vTxHashIn.end());
745 
746  // erase each matching wallet TX
747  bool delerror = false;
748  std::vector<uint256>::iterator it = vTxHashIn.begin();
749  for (uint256 hash : vTxHash) {
750  while (it < vTxHashIn.end() && (*it) < hash) {
751  it++;
752  }
753  if (it == vTxHashIn.end()) {
754  break;
755  }
756  else if ((*it) == hash) {
757  if(!EraseTx(hash)) {
758  LogPrint(BCLog::DB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
759  delerror = true;
760  }
761  vTxHashOut.push_back(hash);
762  }
763  }
764 
765  if (delerror) {
766  return DB_CORRUPT;
767  }
768  return DB_LOAD_OK;
769 }
770 
771 DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
772 {
773  // build list of wallet TXs
774  std::vector<uint256> vTxHash;
775  DBErrors err = FindWalletTx(vTxHash, vWtx);
776  if (err != DB_LOAD_OK)
777  return err;
778 
779  // erase each wallet TX
780  for (uint256& hash : vTxHash) {
781  if (!EraseTx(hash))
782  return DB_CORRUPT;
783  }
784 
785  return DB_LOAD_OK;
786 }
787 
789 {
790  static std::atomic<bool> fOneThread(false);
791  if (fOneThread.exchange(true)) {
792  return;
793  }
794  if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
795  return;
796  }
797 
798  for (CWalletRef pwallet : vpwallets) {
799  CWalletDBWrapper& dbh = pwallet->GetDBHandle();
800 
801  unsigned int nUpdateCounter = dbh.nUpdateCounter;
802 
803  if (dbh.nLastSeen != nUpdateCounter) {
804  dbh.nLastSeen = nUpdateCounter;
805  dbh.nLastWalletUpdate = GetTime();
806  }
807 
808  if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
809  if (CDB::PeriodicFlush(dbh)) {
810  dbh.nLastFlushed = nUpdateCounter;
811  }
812  }
813  }
814 
815  fOneThread = false;
816 }
817 
818 //
819 // Try to (very carefully!) recover wallet file if there is a problem.
820 //
821 bool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
822 {
823  return CDB::Recover(filename, callbackDataIn, recoverKVcallback, out_backup_filename);
824 }
825 
826 bool CWalletDB::Recover(const std::string& filename, std::string& out_backup_filename)
827 {
828  // recover without a key filter callback
829  // results in recovering all record types
830  return CWalletDB::Recover(filename, nullptr, nullptr, out_backup_filename);
831 }
832 
833 bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
834 {
835  CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
836  CWalletScanState dummyWss;
837  std::string strType, strErr;
838  bool fReadOK;
839  {
840  // Required in LoadKeyMetadata():
841  LOCK(dummyWallet->cs_wallet);
842  fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
843  dummyWss, strType, strErr);
844  }
845  if (!IsKeyType(strType) && strType != "hdchain" && strType != "token" && strType != "tokentx")
846  return false;
847  if (!fReadOK)
848  {
849  LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
850  return false;
851  }
852 
853  return true;
854 }
855 
856 bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
857 {
858  return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
859 }
860 
861 bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
862 {
863  return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
864 }
865 
866 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
867 {
868  return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
869 }
870 
871 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
872 {
873  return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
874 }
875 
876 
878 {
879  return WriteIC(std::string("hdchain"), chain);
880 }
881 
883 {
884  return batch.TxnBegin();
885 }
886 
888 {
889  return batch.TxnCommit();
890 }
891 
893 {
894  return batch.TxnAbort();
895 }
896 
897 bool CWalletDB::ReadVersion(int& nVersion)
898 {
899  return batch.ReadVersion(nVersion);
900 }
901 
902 bool CWalletDB::WriteVersion(int nVersion)
903 {
904  return batch.WriteVersion(nVersion);
905 }
906 
908 {
909  return WriteIC(std::make_pair(std::string("token"), wtoken.GetHash()), wtoken);
910 }
911 
913 {
914  return EraseIC(std::make_pair(std::string("token"), hash));
915 }
916 
917 bool CWalletDB::WriteTokenTx(const CTokenTx &wTokenTx)
918 {
919  return WriteIC(std::make_pair(std::string("tokentx"), wTokenTx.GetHash()), wTokenTx);
920 }
921 
923 {
924  return EraseIC(std::make_pair(std::string("tokentx"), hash));
925 }
926 bool CWalletDB::WriteContractData(const std::string &address, const std::string &key, const std::string &value)
927 {
928  return WriteIC(std::make_pair(std::string("contractdata"), std::make_pair(address, key)), value);
929 }
930 
931 bool CWalletDB::EraseContractData(const std::string &address, const std::string &key)
932 {
933  return EraseIC(std::make_pair(std::string("contractdata"), std::make_pair(address, key)));
934 }
uint256 GetHash() const
Definition: wallet.cpp:4543
bool WriteMinVersion(int nVersion)
Definition: walletdb.cpp:153
unsigned int nKeyMeta
Definition: walletdb.cpp:234
unsigned int nKeys
Definition: walletdb.cpp:231
Account information.
Definition: wallet.h:1244
int64_t nOrderPos
position in ordered transaction list
Definition: wallet.h:598
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:79
std::vector< CWalletRef > vpwallets
Definition: wallet.cpp:41
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:3928
unsigned int nWatchKeys
Definition: walletdb.cpp:233
bool WriteAccount(const std::string &strAccount, const CAccount &account)
Definition: walletdb.cpp:164
unsigned int nLastSeen
Definition: db.h:127
CPrivKey vchPrivKey
Definition: wallet.h:562
Describes a place in the block chain to another node such that if the other node doesn&#39;t have the sam...
Definition: block.h:251
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, std::string &strType, std::string &strErr)
Definition: walletdb.cpp:249
uint64_t nAccountingEntryNumber
Definition: wallet.h:823
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn&#39;t already have a value.
Definition: util.cpp:537
bool WriteTx(const CWalletTx &wtx)
Definition: walletdb.cpp:49
bool TxnBegin()
Begin a new transaction.
Definition: walletdb.cpp:882
bool WriteIC(const K &key, const T &value, bool fOverwrite=true)
Definition: walletdb.h:147
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:826
Definition: util.h:95
CCriticalSection cs_wallet
Definition: wallet.h:748
const uint256 & GetHash() const
Definition: wallet.h:278
#define strprintf
Definition: tinyformat.h:1054
bool WriteToken(const CTokenInfo &wtoken)
Definition: walletdb.cpp:907
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
Definition: walletdb.cpp:90
bool TxnCommit()
Commit current transaction.
Definition: walletdb.cpp:887
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:74
TxItems wtxOrdered
Definition: wallet.h:820
CPubKey vchDefaultKey
Definition: wallet.h:830
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key...
Definition: crypter.h:32
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:97
base58-encoded Fabcoin addresses.
Definition: base58.h:104
std::vector< uint256 > vWalletUpgrade
Definition: walletdb.cpp:238
Dbc * GetCursor()
Definition: db.h:282
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:520
bool EraseIC(const K &key)
Definition: walletdb.h:157
static bool VerifyDatabaseFile(const std::string &walletFile, const fs::path &dataDir, std::string &warningStr, std::string &errorStr, CDBEnv::recoverFunc_type recoverFunc)
Definition: db.cpp:297
void ListAccountCreditDebit(const std::string &strAccount, std::list< CAccountingEntry > &acentries)
Definition: walletdb.cpp:186
void SetNull()
Definition: wallet.h:1254
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
bool ErasePurpose(const std::string &strAddress)
Definition: walletdb.cpp:44
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry &acentry)
This writes directly to the database, and will not update the CWallet&#39;s cached accounting entries! Us...
Definition: walletdb.cpp:169
unsigned int nCKeys
Definition: walletdb.cpp:232
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:51
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
Definition: wallet.cpp:3355
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) ...
Definition: wallet.cpp:297
bool WriteVersion(int nVersion)
Write wallet version.
Definition: walletdb.cpp:902
bool LoadContractData(const std::string &address, const std::string &key, const std::string &value)
Adds a contract data tuple to the store, without saving it to disk.
Definition: wallet.cpp:4678
bool TxnBegin()
Definition: db.h:329
bool WriteOrderPosNext(int64_t nOrderPosNext)
Definition: walletdb.cpp:128
static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
Definition: walletdb.cpp:833
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:126
bool EraseTx(uint256 hash)
Definition: walletdb.cpp:54
std::list< CAccountingEntry > laccentries
Definition: wallet.h:816
int64_t CAmount
Amount in lius (Can be negative)
Definition: amount.h:15
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
secp256k1: const unsigned int PRIVATE_KEY_SIZE = 279; const unsigned int PUBLIC_KEY_SIZE = 65; const ...
Definition: key.h:32
DBErrors ReorderTransactions()
Definition: wallet.cpp:754
An instance of this class represents one database.
Definition: db.h:93
bool WriteTokenTx(const CTokenTx &wTokenTx)
Definition: walletdb.cpp:917
#define LogPrintf(...)
Definition: util.h:153
unsigned int nMasterKeyMaxID
Definition: wallet.h:777
bool EraseToken(uint256 hash)
Definition: walletdb.cpp:912
static bool VerifyEnvironment(const std::string &walletFile, const fs::path &dataDir, std::string &errorStr)
Definition: db.cpp:263
bool EraseDestData(const std::string &address, const std::string &key)
Erase destination data tuple from wallet database.
Definition: walletdb.cpp:871
bool WritePool(int64_t nPool, const CKeyPool &keypool)
Definition: walletdb.cpp:143
static bool VerifyEnvironment(const std::string &walletFile, const fs::path &dataDir, std::string &errorStr)
Definition: walletdb.cpp:856
bool IsNull() const
Definition: uint256.h:38
#define LOCK(cs)
Definition: sync.h:175
bool WriteName(const std::string &strAddress, const std::string &strName)
Definition: walletdb.cpp:27
DBErrors LoadWallet(CWallet *pwallet)
Definition: walletdb.cpp:563
bool ReadVersion(int &nVersion)
Definition: db.h:358
bool EraseContractData(const std::string &address, const std::string &key)
Erase contract data tuple from wallet database.
Definition: walletdb.cpp:931
An encapsulated public key.
Definition: pubkey.h:39
bool TxnCommit()
Definition: db.h:340
static bool VerifyDatabaseFile(const std::string &walletFile, const fs::path &dataDir, std::string &warningStr, std::string &errorStr)
Definition: walletdb.cpp:861
bool LoadKey(const CKey &key, const CPubKey &pubkey)
Adds a key to the store, without saving it to disk (used by LoadWallet)
Definition: wallet.h:890
unsigned int nLastFlushed
Definition: db.h:128
bool EraseTokenTx(uint256 hash)
Definition: walletdb.cpp:922
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:866
bool TxnAbort()
Definition: db.h:349
void UpdateTimeFirstKey(int64_t nCreateTime)
Update wallet first key creation time.
Definition: wallet.cpp:306
CheckTransaction
Definition: Transaction.h:42
void MaybeCompactWalletDB()
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:788
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:70
static bool Recover(const std::string &filename, void *callbackDataIn, bool(*recoverKVcallback)(void *callbackData, CDataStream ssKey, CDataStream ssValue), std::string &out_backup_filename)
Definition: walletdb.cpp:821
bool IsValid() const
Definition: validation.h:66
std::vector< uint256 > vHave
Definition: block.h:253
bool LoadToWallet(const CWalletTx &wtxIn)
Definition: wallet.cpp:1037
bool ErasePool(int64_t nPool)
Definition: walletdb.cpp:148
bool EraseWatchOnly(const CScript &script)
Definition: walletdb.cpp:108
CTxDestination Get() const
Definition: base58.cpp:260
int64_t nLastWalletUpdate
Definition: db.h:129
bool LoadMinVersion(int nVersion)
Definition: wallet.h:894
static bool Recover(const std::string &filename, void *callbackDataIn, bool(*recoverKVcallback)(void *callbackData, CDataStream ssKey, CDataStream ssValue), std::string &out_backup_filename)
Definition: db.cpp:197
bool Read(const K &key, T &value)
Definition: db.h:177
const unsigned char * begin() const
Definition: pubkey.h:98
bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck)
Load private key and check that public key matches.
Definition: key.cpp:204
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:287
DBErrors ZapWalletTx(std::vector< CWalletTx > &vWtx)
Definition: walletdb.cpp:771
DBErrors FindWalletTx(std::vector< uint256 > &vTxHash, std::vector< CWalletTx > &vWtx)
Definition: walletdb.cpp:670
bool ReadBestBlock(CBlockLocator &locator)
Definition: walletdb.cpp:122
bool WriteDefaultKey(const CPubKey &vchPubKey)
Definition: walletdb.cpp:133
#define LogPrint(category,...)
Definition: util.h:164
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external chain child index counter)
Definition: walletdb.cpp:877
Capture information about block/transaction validation.
Definition: validation.h:27
bool WriteBestBlock(const CBlockLocator &locator)
Definition: walletdb.cpp:116
256-bit opaque blob.
Definition: uint256.h:132
ArgsManager gArgs
Definition: util.cpp:94
MasterKeyMap mapMasterKeys
Definition: wallet.h:776
bool LoadKeyMetadata(const CTxDestination &pubKey, const CKeyMetadata &metadata)
Load metadata (used by LoadWallet)
Definition: wallet.cpp:289
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Definition: walletdb.cpp:138
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:417
bool LoadTokenTx(const CTokenTx &tokenTx)
Definition: wallet.cpp:4364
int64_t nOrderPosNext
Definition: wallet.h:822
CAmount GetAccountCreditDebit(const std::string &strAccount)
Definition: walletdb.cpp:174
bool WriteVersion(int nVersion)
Definition: db.h:364
Private key that includes an expiration date in case it never gets used.
Definition: wallet.h:559
bool WriteContractData(const std::string &address, const std::string &key, const std::string &value)
Write contract data key,value tuple to database.
Definition: walletdb.cpp:926
Internal transfers.
Definition: wallet.h:589
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:672
bool SetHDChain(const CHDChain &chain, bool memonly)
Definition: wallet.cpp:1490
160-bit opaque blob.
Definition: uint256.h:120
bool LoadCScript(const CScript &redeemScript)
Definition: wallet.cpp:330
int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue, bool setRange=false)
Definition: db.h:293
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:815
bool LoadToken(const CTokenInfo &token)
Definition: wallet.cpp:4356
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:28
bool TxnAbort()
Abort current transaction.
Definition: walletdb.cpp:892
int64_t GetTime()
GetTimeMicros() and GetTimeMillis() both return the system time, but in different units...
Definition: utiltime.cpp:19
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13
An encapsulated private key.
Definition: key.h:35
bool EraseName(const std::string &strAddress)
Definition: walletdb.cpp:32
uint256 GetHash() const
Definition: wallet.cpp:4549
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
Definition: walletdb.cpp:95
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
Definition: walletdb.cpp:39
std::pair< CWalletTx *, CAccountingEntry * > TxPair
Definition: wallet.h:818
static bool PeriodicFlush(CWalletDBWrapper &dbw)
Definition: db.cpp:638
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:146
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut)
Definition: walletdb.cpp:733
static bool IsKeyType(const std::string &strType)
Definition: walletdb.cpp:557
CDB batch
Definition: walletdb.h:261
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta)
Definition: walletdb.cpp:100
bool ReadAccount(const std::string &strAccount, CAccount &account)
Definition: walletdb.cpp:158
const unsigned char * end() const
Definition: pubkey.h:99
bool LoadWatchOnly(const CScript &dest)
Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) ...
Definition: wallet.cpp:375
bool empty() const
Definition: streams.h:238
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:59
A key pool entry.
Definition: wallet.h:120
std::string strAccount
Definition: wallet.h:592
bool ReadVersion(int &nVersion)
Read wallet version.
Definition: walletdb.cpp:897