Bitcoin Core  0.18.99
P2P Digital Currency
walletdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 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 <consensus/tx_check.h>
9 #include <consensus/validation.h>
10 #include <fs.h>
11 #include <key_io.h>
12 #include <protocol.h>
13 #include <serialize.h>
14 #include <sync.h>
15 #include <util/system.h>
16 #include <util/time.h>
17 #include <wallet/wallet.h>
18 
19 #include <atomic>
20 #include <string>
21 
22 #include <boost/thread.hpp>
23 
24 namespace DBKeys {
25 const std::string ACENTRY{"acentry"};
26 const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
27 const std::string BESTBLOCK{"bestblock"};
28 const std::string CRYPTED_KEY{"ckey"};
29 const std::string CSCRIPT{"cscript"};
30 const std::string DEFAULTKEY{"defaultkey"};
31 const std::string DESTDATA{"destdata"};
32 const std::string FLAGS{"flags"};
33 const std::string HDCHAIN{"hdchain"};
34 const std::string KEYMETA{"keymeta"};
35 const std::string KEY{"key"};
36 const std::string MASTER_KEY{"mkey"};
37 const std::string MINVERSION{"minversion"};
38 const std::string NAME{"name"};
39 const std::string OLD_KEY{"wkey"};
40 const std::string ORDERPOSNEXT{"orderposnext"};
41 const std::string POOL{"pool"};
42 const std::string PURPOSE{"purpose"};
43 const std::string SETTINGS{"settings"};
44 const std::string TX{"tx"};
45 const std::string VERSION{"version"};
46 const std::string WATCHMETA{"watchmeta"};
47 const std::string WATCHS{"watchs"};
48 } // namespace DBKeys
49 
50 //
51 // WalletBatch
52 //
53 
54 bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
55 {
56  return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
57 }
58 
59 bool WalletBatch::EraseName(const std::string& strAddress)
60 {
61  // This should only be used for sending addresses, never for receiving addresses,
62  // receiving addresses must always have an address book entry if they're not change return.
63  return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
64 }
65 
66 bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
67 {
68  return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
69 }
70 
71 bool WalletBatch::ErasePurpose(const std::string& strAddress)
72 {
73  return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
74 }
75 
77 {
78  return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
79 }
80 
82 {
83  return EraseIC(std::make_pair(DBKeys::TX, hash));
84 }
85 
86 bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
87 {
88  return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite);
89 }
90 
91 bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
92 {
93  if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
94  return false;
95  }
96 
97  // hash pubkey/privkey to accelerate wallet load
98  std::vector<unsigned char> vchKey;
99  vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
100  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
101  vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
102 
103  return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
104 }
105 
106 bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
107  const std::vector<unsigned char>& vchCryptedSecret,
108  const CKeyMetadata &keyMeta)
109 {
110  if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
111  return false;
112  }
113 
114  if (!WriteIC(std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey), vchCryptedSecret, false)) {
115  return false;
116  }
117  EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
118  return true;
119 }
120 
121 bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
122 {
123  return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
124 }
125 
126 bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
127 {
128  return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
129 }
130 
131 bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
132 {
133  if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
134  return false;
135  }
136  return WriteIC(std::make_pair(DBKeys::WATCHS, dest), '1');
137 }
138 
140 {
141  if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
142  return false;
143  }
144  return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
145 }
146 
148 {
149  WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
150  return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
151 }
152 
154 {
155  if (m_batch.Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
156  return m_batch.Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
157 }
158 
159 bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
160 {
161  return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
162 }
163 
164 bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
165 {
166  return m_batch.Read(std::make_pair(DBKeys::POOL, nPool), keypool);
167 }
168 
169 bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
170 {
171  return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
172 }
173 
174 bool WalletBatch::ErasePool(int64_t nPool)
175 {
176  return EraseIC(std::make_pair(DBKeys::POOL, nPool));
177 }
178 
180 {
181  return WriteIC(DBKeys::MINVERSION, nVersion);
182 }
183 
185 public:
186  unsigned int nKeys{0};
187  unsigned int nCKeys{0};
188  unsigned int nWatchKeys{0};
189  unsigned int nKeyMeta{0};
190  unsigned int m_unknown_records{0};
191  bool fIsEncrypted{false};
192  bool fAnyUnordered{false};
193  std::vector<uint256> vWalletUpgrade;
194 
196  }
197 };
198 
199 static bool
200 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
201  CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
202 {
203  try {
204  // Unserialize
205  // Taking advantage of the fact that pair serialization
206  // is just the two items serialized one after the other
207  ssKey >> strType;
208  if (strType == DBKeys::NAME) {
209  std::string strAddress;
210  ssKey >> strAddress;
211  ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
212  } else if (strType == DBKeys::PURPOSE) {
213  std::string strAddress;
214  ssKey >> strAddress;
215  ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
216  } else if (strType == DBKeys::TX) {
217  uint256 hash;
218  ssKey >> hash;
219  CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
220  ssValue >> wtx;
221  CValidationState state;
222  if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
223  return false;
224 
225  // Undo serialize changes in 31600
226  if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
227  {
228  if (!ssValue.empty())
229  {
230  char fTmp;
231  char fUnused;
232  std::string unused_string;
233  ssValue >> fTmp >> fUnused >> unused_string;
234  strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
235  wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
236  wtx.fTimeReceivedIsTxTime = fTmp;
237  }
238  else
239  {
240  strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
241  wtx.fTimeReceivedIsTxTime = 0;
242  }
243  wss.vWalletUpgrade.push_back(hash);
244  }
245 
246  if (wtx.nOrderPos == -1)
247  wss.fAnyUnordered = true;
248 
249  pwallet->LoadToWallet(wtx);
250  } else if (strType == DBKeys::WATCHS) {
251  wss.nWatchKeys++;
252  CScript script;
253  ssKey >> script;
254  char fYes;
255  ssValue >> fYes;
256  if (fYes == '1')
257  pwallet->LoadWatchOnly(script);
258  } else if (strType == DBKeys::KEY) {
259  CPubKey vchPubKey;
260  ssKey >> vchPubKey;
261  if (!vchPubKey.IsValid())
262  {
263  strErr = "Error reading wallet database: CPubKey corrupt";
264  return false;
265  }
266  CKey key;
267  CPrivKey pkey;
268  uint256 hash;
269 
270  wss.nKeys++;
271  ssValue >> pkey;
272 
273  // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
274  // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
275  // using EC operations as a checksum.
276  // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
277  // remaining backwards-compatible.
278  try
279  {
280  ssValue >> hash;
281  }
282  catch (...) {}
283 
284  bool fSkipCheck = false;
285 
286  if (!hash.IsNull())
287  {
288  // hash pubkey/privkey to accelerate wallet load
289  std::vector<unsigned char> vchKey;
290  vchKey.reserve(vchPubKey.size() + pkey.size());
291  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
292  vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
293 
294  if (Hash(vchKey.begin(), vchKey.end()) != hash)
295  {
296  strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
297  return false;
298  }
299 
300  fSkipCheck = true;
301  }
302 
303  if (!key.Load(pkey, vchPubKey, fSkipCheck))
304  {
305  strErr = "Error reading wallet database: CPrivKey corrupt";
306  return false;
307  }
308  if (!pwallet->LoadKey(key, vchPubKey))
309  {
310  strErr = "Error reading wallet database: LoadKey failed";
311  return false;
312  }
313  } else if (strType == DBKeys::MASTER_KEY) {
314  unsigned int nID;
315  ssKey >> nID;
316  CMasterKey kMasterKey;
317  ssValue >> kMasterKey;
318  if(pwallet->mapMasterKeys.count(nID) != 0)
319  {
320  strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
321  return false;
322  }
323  pwallet->mapMasterKeys[nID] = kMasterKey;
324  if (pwallet->nMasterKeyMaxID < nID)
325  pwallet->nMasterKeyMaxID = nID;
326  } else if (strType == DBKeys::CRYPTED_KEY) {
327  CPubKey vchPubKey;
328  ssKey >> vchPubKey;
329  if (!vchPubKey.IsValid())
330  {
331  strErr = "Error reading wallet database: CPubKey corrupt";
332  return false;
333  }
334  std::vector<unsigned char> vchPrivKey;
335  ssValue >> vchPrivKey;
336  wss.nCKeys++;
337 
338  if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
339  {
340  strErr = "Error reading wallet database: LoadCryptedKey failed";
341  return false;
342  }
343  wss.fIsEncrypted = true;
344  } else if (strType == DBKeys::KEYMETA) {
345  CPubKey vchPubKey;
346  ssKey >> vchPubKey;
347  CKeyMetadata keyMeta;
348  ssValue >> keyMeta;
349  wss.nKeyMeta++;
350  pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
351  } else if (strType == DBKeys::WATCHMETA) {
352  CScript script;
353  ssKey >> script;
354  CKeyMetadata keyMeta;
355  ssValue >> keyMeta;
356  wss.nKeyMeta++;
357  pwallet->LoadScriptMetadata(CScriptID(script), keyMeta);
358  } else if (strType == DBKeys::DEFAULTKEY) {
359  // We don't want or need the default key, but if there is one set,
360  // we want to make sure that it is valid so that we can detect corruption
361  CPubKey vchPubKey;
362  ssValue >> vchPubKey;
363  if (!vchPubKey.IsValid()) {
364  strErr = "Error reading wallet database: Default Key corrupt";
365  return false;
366  }
367  } else if (strType == DBKeys::POOL) {
368  int64_t nIndex;
369  ssKey >> nIndex;
370  CKeyPool keypool;
371  ssValue >> keypool;
372 
373  pwallet->LoadKeyPool(nIndex, keypool);
374  } else if (strType == DBKeys::CSCRIPT) {
375  uint160 hash;
376  ssKey >> hash;
377  CScript script;
378  ssValue >> script;
379  if (!pwallet->LoadCScript(script))
380  {
381  strErr = "Error reading wallet database: LoadCScript failed";
382  return false;
383  }
384  } else if (strType == DBKeys::ORDERPOSNEXT) {
385  ssValue >> pwallet->nOrderPosNext;
386  } else if (strType == DBKeys::DESTDATA) {
387  std::string strAddress, strKey, strValue;
388  ssKey >> strAddress;
389  ssKey >> strKey;
390  ssValue >> strValue;
391  pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue);
392  } else if (strType == DBKeys::HDCHAIN) {
393  CHDChain chain;
394  ssValue >> chain;
395  pwallet->SetHDChain(chain, true);
396  } else if (strType == DBKeys::FLAGS) {
397  uint64_t flags;
398  ssValue >> flags;
399  if (!pwallet->SetWalletFlags(flags, true)) {
400  strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found";
401  return false;
402  }
403  } else if (strType == DBKeys::OLD_KEY) {
404  strErr = "Found unsupported 'wkey' record, try loading with version 0.18";
405  return false;
406  } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
407  strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
408  strType != DBKeys::VERSION && strType != DBKeys::SETTINGS) {
409  wss.m_unknown_records++;
410  }
411  } catch (const std::exception& e) {
412  if (strErr.empty()) {
413  strErr = e.what();
414  }
415  return false;
416  } catch (...) {
417  if (strErr.empty()) {
418  strErr = "Caught unknown exception in ReadKeyValue";
419  }
420  return false;
421  }
422  return true;
423 }
424 
425 bool WalletBatch::IsKeyType(const std::string& strType)
426 {
427  return (strType == DBKeys::KEY ||
428  strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY);
429 }
430 
432 {
433  CWalletScanState wss;
434  bool fNoncriticalErrors = false;
435  DBErrors result = DBErrors::LOAD_OK;
436 
437  LOCK(pwallet->cs_wallet);
438  try {
439  int nMinVersion = 0;
440  if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) {
441  if (nMinVersion > FEATURE_LATEST)
442  return DBErrors::TOO_NEW;
443  pwallet->LoadMinVersion(nMinVersion);
444  }
445 
446  // Get cursor
447  Dbc* pcursor = m_batch.GetCursor();
448  if (!pcursor)
449  {
450  pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
451  return DBErrors::CORRUPT;
452  }
453 
454  while (true)
455  {
456  // Read next record
459  int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
460  if (ret == DB_NOTFOUND)
461  break;
462  else if (ret != 0)
463  {
464  pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
465  return DBErrors::CORRUPT;
466  }
467 
468  // Try to be tolerant of single corrupt records:
469  std::string strType, strErr;
470  if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
471  {
472  // losing keys is considered a catastrophic error, anything else
473  // we assume the user can live with:
474  if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
475  result = DBErrors::CORRUPT;
476  } else if (strType == DBKeys::FLAGS) {
477  // reading the wallet flags can only fail if unknown flags are present
478  result = DBErrors::TOO_NEW;
479  } else {
480  // Leave other errors alone, if we try to fix them we might make things worse.
481  fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
482  if (strType == DBKeys::TX)
483  // Rescan if there is a bad transaction record:
484  gArgs.SoftSetBoolArg("-rescan", true);
485  }
486  }
487  if (!strErr.empty())
488  pwallet->WalletLogPrintf("%s\n", strErr);
489  }
490  pcursor->close();
491  }
492  catch (const boost::thread_interrupted&) {
493  throw;
494  }
495  catch (...) {
496  result = DBErrors::CORRUPT;
497  }
498 
499  if (fNoncriticalErrors && result == DBErrors::LOAD_OK)
501 
502  // Any wallet corruption at all: skip any rewriting or
503  // upgrading, we don't want to make it worse.
504  if (result != DBErrors::LOAD_OK)
505  return result;
506 
507  // Last client version to open this wallet, was previously the file version number
508  int last_client = CLIENT_VERSION;
509  m_batch.Read(DBKeys::VERSION, last_client);
510 
511  int wallet_version = pwallet->GetVersion();
512  pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
513 
514  pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
515  wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
516 
517  // nTimeFirstKey is only reliable if all keys have metadata
518  if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
519  pwallet->UpdateTimeFirstKey(1);
520 
521  for (const uint256& hash : wss.vWalletUpgrade)
522  WriteTx(pwallet->mapWallet.at(hash));
523 
524  // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
525  if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
526  return DBErrors::NEED_REWRITE;
527 
528  if (last_client < CLIENT_VERSION) // Update
529  m_batch.Write(DBKeys::VERSION, CLIENT_VERSION);
530 
531  if (wss.fAnyUnordered)
532  result = pwallet->ReorderTransactions();
533 
534  // Upgrade all of the wallet keymetadata to have the hd master key id
535  // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
536  try {
537  pwallet->UpgradeKeyMetadata();
538  } catch (...) {
539  result = DBErrors::CORRUPT;
540  }
541 
542  return result;
543 }
544 
545 DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
546 {
547  DBErrors result = DBErrors::LOAD_OK;
548 
549  try {
550  int nMinVersion = 0;
551  if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) {
552  if (nMinVersion > FEATURE_LATEST)
553  return DBErrors::TOO_NEW;
554  }
555 
556  // Get cursor
557  Dbc* pcursor = m_batch.GetCursor();
558  if (!pcursor)
559  {
560  LogPrintf("Error getting wallet database cursor\n");
561  return DBErrors::CORRUPT;
562  }
563 
564  while (true)
565  {
566  // Read next record
569  int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
570  if (ret == DB_NOTFOUND)
571  break;
572  else if (ret != 0)
573  {
574  LogPrintf("Error reading next record from wallet database\n");
575  return DBErrors::CORRUPT;
576  }
577 
578  std::string strType;
579  ssKey >> strType;
580  if (strType == DBKeys::TX) {
581  uint256 hash;
582  ssKey >> hash;
583 
584  CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
585  ssValue >> wtx;
586 
587  vTxHash.push_back(hash);
588  vWtx.push_back(wtx);
589  }
590  }
591  pcursor->close();
592  }
593  catch (const boost::thread_interrupted&) {
594  throw;
595  }
596  catch (...) {
597  result = DBErrors::CORRUPT;
598  }
599 
600  return result;
601 }
602 
603 DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
604 {
605  // build list of wallet TXs and hashes
606  std::vector<uint256> vTxHash;
607  std::vector<CWalletTx> vWtx;
608  DBErrors err = FindWalletTx(vTxHash, vWtx);
609  if (err != DBErrors::LOAD_OK) {
610  return err;
611  }
612 
613  std::sort(vTxHash.begin(), vTxHash.end());
614  std::sort(vTxHashIn.begin(), vTxHashIn.end());
615 
616  // erase each matching wallet TX
617  bool delerror = false;
618  std::vector<uint256>::iterator it = vTxHashIn.begin();
619  for (const uint256& hash : vTxHash) {
620  while (it < vTxHashIn.end() && (*it) < hash) {
621  it++;
622  }
623  if (it == vTxHashIn.end()) {
624  break;
625  }
626  else if ((*it) == hash) {
627  if(!EraseTx(hash)) {
628  LogPrint(BCLog::DB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
629  delerror = true;
630  }
631  vTxHashOut.push_back(hash);
632  }
633  }
634 
635  if (delerror) {
636  return DBErrors::CORRUPT;
637  }
638  return DBErrors::LOAD_OK;
639 }
640 
641 DBErrors WalletBatch::ZapWalletTx(std::vector<CWalletTx>& vWtx)
642 {
643  // build list of wallet TXs
644  std::vector<uint256> vTxHash;
645  DBErrors err = FindWalletTx(vTxHash, vWtx);
646  if (err != DBErrors::LOAD_OK)
647  return err;
648 
649  // erase each wallet TX
650  for (const uint256& hash : vTxHash) {
651  if (!EraseTx(hash))
652  return DBErrors::CORRUPT;
653  }
654 
655  return DBErrors::LOAD_OK;
656 }
657 
659 {
660  static std::atomic<bool> fOneThread(false);
661  if (fOneThread.exchange(true)) {
662  return;
663  }
664  if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
665  return;
666  }
667 
668  for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
669  WalletDatabase& dbh = pwallet->GetDBHandle();
670 
671  unsigned int nUpdateCounter = dbh.nUpdateCounter;
672 
673  if (dbh.nLastSeen != nUpdateCounter) {
674  dbh.nLastSeen = nUpdateCounter;
675  dbh.nLastWalletUpdate = GetTime();
676  }
677 
678  if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
679  if (BerkeleyBatch::PeriodicFlush(dbh)) {
680  dbh.nLastFlushed = nUpdateCounter;
681  }
682  }
683  }
684 
685  fOneThread = false;
686 }
687 
688 //
689 // Try to (very carefully!) recover wallet file if there is a problem.
690 //
691 bool WalletBatch::Recover(const fs::path& wallet_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
692 {
693  return BerkeleyBatch::Recover(wallet_path, callbackDataIn, recoverKVcallback, out_backup_filename);
694 }
695 
696 bool WalletBatch::Recover(const fs::path& wallet_path, std::string& out_backup_filename)
697 {
698  // recover without a key filter callback
699  // results in recovering all record types
700  return WalletBatch::Recover(wallet_path, nullptr, nullptr, out_backup_filename);
701 }
702 
703 bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
704 {
705  CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
706  CWalletScanState dummyWss;
707  std::string strType, strErr;
708  bool fReadOK;
709  {
710  // Required in LoadKeyMetadata():
711  LOCK(dummyWallet->cs_wallet);
712  fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
713  dummyWss, strType, strErr);
714  }
715  if (!IsKeyType(strType) && strType != DBKeys::HDCHAIN) {
716  return false;
717  }
718  if (!fReadOK)
719  {
720  LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr);
721  return false;
722  }
723 
724  return true;
725 }
726 
727 bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr)
728 {
729  return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr);
730 }
731 
732 bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::string& warningStr, std::string& errorStr)
733 {
734  return BerkeleyBatch::VerifyDatabaseFile(wallet_path, warningStr, errorStr, WalletBatch::Recover);
735 }
736 
737 bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
738 {
739  return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value);
740 }
741 
742 bool WalletBatch::EraseDestData(const std::string &address, const std::string &key)
743 {
744  return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)));
745 }
746 
747 
749 {
750  return WriteIC(DBKeys::HDCHAIN, chain);
751 }
752 
754 {
755  return WriteIC(DBKeys::FLAGS, flags);
756 }
757 
759 {
760  return m_batch.TxnBegin();
761 }
762 
764 {
765  return m_batch.TxnCommit();
766 }
767 
769 {
770  return m_batch.TxnAbort();
771 }
bool TxnCommit()
Commit current transaction.
Definition: walletdb.cpp:763
bool WriteName(const std::string &strAddress, const std::string &strName)
Definition: walletdb.cpp:54
bool EraseDestData(const std::string &address, const std::string &key)
Erase destination data tuple from wallet database.
Definition: walletdb.cpp:742
unsigned int nKeyMeta
Definition: walletdb.cpp:189
const std::string POOL
Definition: walletdb.cpp:41
unsigned int nKeys
Definition: walletdb.cpp:186
const std::string FLAGS
Definition: walletdb.cpp:32
bool ErasePurpose(const std::string &strAddress)
Definition: walletdb.cpp:71
unsigned int nWatchKeys
Definition: walletdb.cpp:188
bool ReadBestBlock(CBlockLocator &locator)
Definition: walletdb.cpp:153
std::vector< std::shared_ptr< CWallet > > GetWallets()
Definition: dummywallet.cpp:69
const std::string NAME
Definition: walletdb.cpp:38
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:126
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
Definition: wallet.cpp:435
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:106
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn&#39;t already have a value.
Definition: system.cpp:528
const std::string SETTINGS
Definition: walletdb.cpp:43
unsigned int nLastSeen
Definition: db.h:173
CCriticalSection cs_wallet
Definition: wallet.h:890
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1067
const std::string CRYPTED_KEY
Definition: walletdb.cpp:28
const std::string DEFAULTKEY
Definition: walletdb.cpp:30
DBErrors FindWalletTx(std::vector< uint256 > &vTxHash, std::vector< CWalletTx > &vWtx)
Definition: walletdb.cpp:545
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut)
Definition: walletdb.cpp:603
bool WriteMinVersion(int nVersion)
Definition: walletdb.cpp:179
static bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, std::string &strType, std::string &strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:200
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external chain child index counter)
Definition: walletdb.cpp:748
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key...
Definition: crypter.h:34
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:409
bool IsValid() const
Definition: validation.h:129
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta)
Definition: walletdb.cpp:131
const std::string KEYMETA
Definition: walletdb.cpp:34
std::vector< uint256 > vWalletUpgrade
Definition: walletdb.cpp:193
static bool VerifyDatabaseFile(const fs::path &wallet_path, std::string &warningStr, std::string &errorStr)
Definition: walletdb.cpp:732
An instance of this class represents one database.
Definition: db.h:113
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:144
unsigned int m_unknown_records
Definition: walletdb.cpp:190
bool TxnBegin()
Begin a new transaction.
Definition: walletdb.cpp:758
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:203
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:512
DBErrors ZapWalletTx(std::vector< CWalletTx > &vWtx)
Definition: walletdb.cpp:641
bool WriteTx(const CWalletTx &wtx)
Definition: walletdb.cpp:76
unsigned int nCKeys
Definition: walletdb.cpp:187
DBErrors LoadWallet(CWallet *pwallet)
Definition: walletdb.cpp:431
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:48
const std::string ORDERPOSNEXT
Definition: walletdb.cpp:40
static bool PeriodicFlush(BerkeleyDatabase &database)
Definition: db.cpp:807
bool WriteWalletFlags(const uint64_t flags)
Definition: walletdb.cpp:753
const std::string VERSION
Definition: walletdb.cpp:45
bool IsNull() const
Definition: uint256.h:31
const unsigned char * begin() const
Definition: pubkey.h:111
const std::string MASTER_KEY
Definition: walletdb.cpp:36
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:691
bool EraseWatchOnly(const CScript &script)
Definition: walletdb.cpp:139
bool WriteBestBlock(const CBlockLocator &locator)
Definition: walletdb.cpp:147
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:768
const std::string OLD_KEY
Definition: walletdb.cpp:39
DBErrors ReorderTransactions()
Definition: wallet.cpp:943
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:737
const std::string HDCHAIN
Definition: walletdb.cpp:33
static bool IsKeyType(const std::string &strType)
Definition: walletdb.cpp:425
const unsigned char * end() const
Definition: pubkey.h:112
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
Definition: walletdb.cpp:126
void WalletLogPrintf(std::string fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
Definition: wallet.h:1405
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Update wallet first key creation time.
Definition: wallet.cpp:481
static bool VerifyEnvironment(const fs::path &wallet_path, std::string &errorStr)
Definition: walletdb.cpp:727
#define LOCK(cs)
Definition: sync.h:182
int GetVersion()
get the current wallet format (the oldest client version guaranteed to understand this wallet) ...
Definition: wallet.h:1264
An encapsulated public key.
Definition: pubkey.h:30
const std::string WATCHMETA
Definition: walletdb.cpp:46
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
Definition: walletdb.cpp:121
static void LogPrint(const BCLog::LogFlags &category, const Args &... args)
Definition: logging.h:159
void MaybeCompactWalletDB()
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:658
const std::string DESTDATA
Definition: walletdb.cpp:31
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:71
bool WriteOrderPosNext(int64_t nOrderPosNext)
Definition: walletdb.cpp:159
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:109
std::vector< uint256 > vHave
Definition: block.h:128
const uint256 & GetHash() const
Definition: wallet.h:663
static bool VerifyEnvironment(const fs::path &file_path, std::string &errorStr)
Definition: db.cpp:398
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:329
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:394
bool WriteKeyMetadata(const CKeyMetadata &meta, const CPubKey &pubkey, const bool overwrite)
Definition: walletdb.cpp:86
int flags
Definition: bitcoin-tx.cpp:509
bool ErasePool(int64_t nPool)
Definition: walletdb.cpp:174
bool WritePool(int64_t nPool, const CKeyPool &keypool)
Definition: walletdb.cpp:169
Capture information about block/transaction validation.
Definition: validation.h:98
256-bit opaque blob.
Definition: uint256.h:121
CTxDestination DecodeDestination(const std::string &str)
Definition: key_io.cpp:216
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
const std::string ACENTRY
Definition: walletdb.cpp:25
int64_t nLastWalletUpdate
Definition: db.h:175
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:390
unsigned int nLastFlushed
Definition: db.h:174
const std::string MINVERSION
Definition: walletdb.cpp:37
static const bool DEFAULT_FLUSHWALLET
Overview of wallet database classes:
Definition: walletdb.h:33
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:729
ArgsManager gArgs
Definition: system.cpp:73
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
Definition: walletdb.cpp:66
160-bit opaque blob.
Definition: uint256.h:110
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:172
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Definition: walletdb.cpp:164
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:22
static bool VerifyDatabaseFile(const fs::path &file_path, std::string &warningStr, std::string &errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
Definition: db.cpp:415
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.h:1041
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:91
const std::string WATCHS
Definition: walletdb.cpp:47
An encapsulated private key.
Definition: key.h:27
const std::string BESTBLOCK
Definition: walletdb.cpp:27
const std::string CSCRIPT
Definition: walletdb.cpp:29
bool EraseTx(uint256 hash)
Definition: walletdb.cpp:81
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:20
auto it
Definition: validation.cpp:366
const std::string BESTBLOCK_NOMERKLE
Definition: walletdb.cpp:26
const std::string TX
Definition: walletdb.cpp:44
const std::string KEY
Definition: walletdb.cpp:35
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
Definition: walletdb.cpp:703
bool Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck)
Load private key and check that public key matches.
Definition: key.cpp:261
bool CheckTransaction(const CTransaction &tx, CValidationState &state, bool fCheckDuplicateInputs)
Definition: tx_check.cpp:10
A key from a CWallet&#39;s keypool.
Definition: wallet.h:217
bool EraseName(const std::string &strAddress)
Definition: walletdb.cpp:59
const std::string PURPOSE
Definition: walletdb.cpp:42