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