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