Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

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