Bitcoin Core  29.1.0
P2P Digital Currency
walletdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep
7 
8 #include <wallet/walletdb.h>
9 
10 #include <common/system.h>
11 #include <key_io.h>
12 #include <protocol.h>
13 #include <script/script.h>
14 #include <serialize.h>
15 #include <sync.h>
16 #include <util/bip32.h>
17 #include <util/check.h>
18 #include <util/fs.h>
19 #include <util/time.h>
20 #include <util/translation.h>
21 #ifdef USE_BDB
22 #include <wallet/bdb.h>
23 #endif
24 #include <wallet/migrate.h>
25 #ifdef USE_SQLITE
26 #include <wallet/sqlite.h>
27 #endif
28 #include <wallet/wallet.h>
29 
30 #include <atomic>
31 #include <optional>
32 #include <string>
33 
34 namespace wallet {
35 namespace DBKeys {
36 const std::string ACENTRY{"acentry"};
37 const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
38 const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
39 const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
40 const std::string BESTBLOCK{"bestblock"};
41 const std::string CRYPTED_KEY{"ckey"};
42 const std::string CSCRIPT{"cscript"};
43 const std::string DEFAULTKEY{"defaultkey"};
44 const std::string DESTDATA{"destdata"};
45 const std::string FLAGS{"flags"};
46 const std::string HDCHAIN{"hdchain"};
47 const std::string KEYMETA{"keymeta"};
48 const std::string KEY{"key"};
49 const std::string LOCKED_UTXO{"lockedutxo"};
50 const std::string MASTER_KEY{"mkey"};
51 const std::string MINVERSION{"minversion"};
52 const std::string NAME{"name"};
53 const std::string OLD_KEY{"wkey"};
54 const std::string ORDERPOSNEXT{"orderposnext"};
55 const std::string POOL{"pool"};
56 const std::string PURPOSE{"purpose"};
57 const std::string SETTINGS{"settings"};
58 const std::string TX{"tx"};
59 const std::string VERSION{"version"};
60 const std::string WALLETDESCRIPTOR{"walletdescriptor"};
61 const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"};
62 const std::string WALLETDESCRIPTORLHCACHE{"walletdescriptorlhcache"};
63 const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
64 const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
65 const std::string WATCHMETA{"watchmeta"};
66 const std::string WATCHS{"watchs"};
67 const std::unordered_set<std::string> LEGACY_TYPES{CRYPTED_KEY, CSCRIPT, DEFAULTKEY, HDCHAIN, KEYMETA, KEY, OLD_KEY, POOL, WATCHMETA, WATCHS};
68 } // namespace DBKeys
69 
70 //
71 // WalletBatch
72 //
73 
74 bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
75 {
76  return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
77 }
78 
79 bool WalletBatch::EraseName(const std::string& strAddress)
80 {
81  // This should only be used for sending addresses, never for receiving addresses,
82  // receiving addresses must always have an address book entry if they're not change return.
83  return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
84 }
85 
86 bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
87 {
88  return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
89 }
90 
91 bool WalletBatch::ErasePurpose(const std::string& strAddress)
92 {
93  return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
94 }
95 
97 {
98  return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
99 }
100 
102 {
103  return EraseIC(std::make_pair(DBKeys::TX, hash));
104 }
105 
106 bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
107 {
108  return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite);
109 }
110 
111 bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
112 {
113  if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
114  return false;
115  }
116 
117  // hash pubkey/privkey to accelerate wallet load
118  std::vector<unsigned char> vchKey;
119  vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
120  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
121  vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
122 
123  return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
124 }
125 
126 bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
127  const std::vector<unsigned char>& vchCryptedSecret,
128  const CKeyMetadata &keyMeta)
129 {
130  if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
131  return false;
132  }
133 
134  // Compute a checksum of the encrypted key
135  uint256 checksum = Hash(vchCryptedSecret);
136 
137  const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
138  if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
139  // It may already exist, so try writing just the checksum
140  std::vector<unsigned char> val;
141  if (!m_batch->Read(key, val)) {
142  return false;
143  }
144  if (!WriteIC(key, std::make_pair(val, checksum), true)) {
145  return false;
146  }
147  }
148  EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
149  return true;
150 }
151 
152 bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
153 {
154  return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
155 }
156 
157 bool WalletBatch::EraseMasterKey(unsigned int id)
158 {
159  return EraseIC(std::make_pair(DBKeys::MASTER_KEY, id));
160 }
161 
162 bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
163 {
164  return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
165 }
166 
167 bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
168 {
169  if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
170  return false;
171  }
172  return WriteIC(std::make_pair(DBKeys::WATCHS, dest), uint8_t{'1'});
173 }
174 
176 {
177  if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
178  return false;
179  }
180  return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
181 }
182 
184 {
185  WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
186  return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
187 }
188 
190 {
191  if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
192  return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
193 }
194 
196 {
199  if (auto cursor = m_batch->GetNewPrefixCursor(prefix)) {
200  DataStream k, v;
201  if (cursor->Next(k, v) == DatabaseCursor::Status::MORE) return true;
202  }
203  return false;
204 }
205 
206 bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
207 {
208  return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
209 }
210 
211 bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
212 {
213  return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
214 }
215 
216 bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
217 {
218  return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
219 }
220 
221 bool WalletBatch::ErasePool(int64_t nPool)
222 {
223  return EraseIC(std::make_pair(DBKeys::POOL, nPool));
224 }
225 
227 {
228  return WriteIC(DBKeys::MINVERSION, nVersion);
229 }
230 
231 bool WalletBatch::WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal)
232 {
233  std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
234  return WriteIC(make_pair(key, type), id);
235 }
236 
237 bool WalletBatch::EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
238 {
239  const std::string key{internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK};
240  return EraseIC(make_pair(key, type));
241 }
242 
243 bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey)
244 {
245  // hash pubkey/privkey to accelerate wallet load
246  std::vector<unsigned char> key;
247  key.reserve(pubkey.size() + privkey.size());
248  key.insert(key.end(), pubkey.begin(), pubkey.end());
249  key.insert(key.end(), privkey.begin(), privkey.end());
250 
251  return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false);
252 }
253 
254 bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret)
255 {
256  if (!WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORCKEY, std::make_pair(desc_id, pubkey)), secret, false)) {
257  return false;
258  }
259  EraseIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)));
260  return true;
261 }
262 
263 bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor)
264 {
265  return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
266 }
267 
268 bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
269 {
270  std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
271  xpub.Encode(ser_xpub.data());
272  return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
273 }
274 
275 bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
276 {
277  std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
278  xpub.Encode(ser_xpub.data());
279  return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
280 }
281 
282 bool WalletBatch::WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
283 {
284  std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
285  xpub.Encode(ser_xpub.data());
286  return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORLHCACHE, desc_id), key_exp_index), ser_xpub);
287 }
288 
290 {
291  for (const auto& parent_xpub_pair : cache.GetCachedParentExtPubKeys()) {
292  if (!WriteDescriptorParentCache(parent_xpub_pair.second, desc_id, parent_xpub_pair.first)) {
293  return false;
294  }
295  }
296  for (const auto& derived_xpub_map_pair : cache.GetCachedDerivedExtPubKeys()) {
297  for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
298  if (!WriteDescriptorDerivedCache(derived_xpub_pair.second, desc_id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {
299  return false;
300  }
301  }
302  }
303  for (const auto& lh_xpub_pair : cache.GetCachedLastHardenedExtPubKeys()) {
304  if (!WriteDescriptorLastHardenedCache(lh_xpub_pair.second, desc_id, lh_xpub_pair.first)) {
305  return false;
306  }
307  }
308  return true;
309 }
310 
312 {
313  return WriteIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)), uint8_t{'1'});
314 }
315 
317 {
318  return EraseIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)));
319 }
320 
321 bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)
322 {
323  LOCK(pwallet->cs_wallet);
324  try {
325  CPubKey vchPubKey;
326  ssKey >> vchPubKey;
327  if (!vchPubKey.IsValid())
328  {
329  strErr = "Error reading wallet database: CPubKey corrupt";
330  return false;
331  }
332  CKey key;
333  CPrivKey pkey;
334  uint256 hash;
335 
336  ssValue >> pkey;
337 
338  // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
339  // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
340  // using EC operations as a checksum.
341  // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
342  // remaining backwards-compatible.
343  try
344  {
345  ssValue >> hash;
346  }
347  catch (const std::ios_base::failure&) {}
348 
349  bool fSkipCheck = false;
350 
351  if (!hash.IsNull())
352  {
353  // hash pubkey/privkey to accelerate wallet load
354  std::vector<unsigned char> vchKey;
355  vchKey.reserve(vchPubKey.size() + pkey.size());
356  vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
357  vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
358 
359  if (Hash(vchKey) != hash)
360  {
361  strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
362  return false;
363  }
364 
365  fSkipCheck = true;
366  }
367 
368  if (!key.Load(pkey, vchPubKey, fSkipCheck))
369  {
370  strErr = "Error reading wallet database: CPrivKey corrupt";
371  return false;
372  }
373  if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadKey(key, vchPubKey))
374  {
375  strErr = "Error reading wallet database: LegacyDataSPKM::LoadKey failed";
376  return false;
377  }
378  } catch (const std::exception& e) {
379  if (strErr.empty()) {
380  strErr = e.what();
381  }
382  return false;
383  }
384  return true;
385 }
386 
387 bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)
388 {
389  LOCK(pwallet->cs_wallet);
390  try {
391  CPubKey vchPubKey;
392  ssKey >> vchPubKey;
393  if (!vchPubKey.IsValid())
394  {
395  strErr = "Error reading wallet database: CPubKey corrupt";
396  return false;
397  }
398  std::vector<unsigned char> vchPrivKey;
399  ssValue >> vchPrivKey;
400 
401  // Get the checksum and check it
402  bool checksum_valid = false;
403  if (!ssValue.eof()) {
404  uint256 checksum;
405  ssValue >> checksum;
406  if (!(checksum_valid = Hash(vchPrivKey) == checksum)) {
407  strErr = "Error reading wallet database: Encrypted key corrupt";
408  return false;
409  }
410  }
411 
412  if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
413  {
414  strErr = "Error reading wallet database: LegacyDataSPKM::LoadCryptedKey failed";
415  return false;
416  }
417  } catch (const std::exception& e) {
418  if (strErr.empty()) {
419  strErr = e.what();
420  }
421  return false;
422  }
423  return true;
424 }
425 
426 bool LoadEncryptionKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)
427 {
428  LOCK(pwallet->cs_wallet);
429  try {
430  // Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
431  unsigned int nID;
432  ssKey >> nID;
433  CMasterKey kMasterKey;
434  ssValue >> kMasterKey;
435  if(pwallet->mapMasterKeys.count(nID) != 0)
436  {
437  strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
438  return false;
439  }
440  pwallet->mapMasterKeys[nID] = kMasterKey;
441  if (pwallet->nMasterKeyMaxID < nID)
442  pwallet->nMasterKeyMaxID = nID;
443 
444  } catch (const std::exception& e) {
445  if (strErr.empty()) {
446  strErr = e.what();
447  }
448  return false;
449  }
450  return true;
451 }
452 
453 bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr)
454 {
455  LOCK(pwallet->cs_wallet);
456  try {
457  CHDChain chain;
458  ssValue >> chain;
459  pwallet->GetOrCreateLegacyDataSPKM()->LoadHDChain(chain);
460  } catch (const std::exception& e) {
461  if (strErr.empty()) {
462  strErr = e.what();
463  }
464  return false;
465  }
466  return true;
467 }
468 
469 static DBErrors LoadMinVersion(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
470 {
471  AssertLockHeld(pwallet->cs_wallet);
472  int nMinVersion = 0;
473  if (batch.Read(DBKeys::MINVERSION, nMinVersion)) {
474  pwallet->WalletLogPrintf("Wallet file version = %d\n", nMinVersion);
475  if (nMinVersion > FEATURE_LATEST)
476  return DBErrors::TOO_NEW;
477  pwallet->LoadMinVersion(nMinVersion);
478  }
479  return DBErrors::LOAD_OK;
480 }
481 
482 static DBErrors LoadWalletFlags(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
483 {
484  AssertLockHeld(pwallet->cs_wallet);
485  uint64_t flags;
486  if (batch.Read(DBKeys::FLAGS, flags)) {
487  if (!pwallet->LoadWalletFlags(flags)) {
488  pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
489  return DBErrors::TOO_NEW;
490  }
491  }
492  return DBErrors::LOAD_OK;
493 }
494 
496 {
498  int m_records{0};
499 };
500 
501 using LoadFunc = std::function<DBErrors(CWallet* pwallet, DataStream& key, DataStream& value, std::string& err)>;
502 static LoadResult LoadRecords(CWallet* pwallet, DatabaseBatch& batch, const std::string& key, DataStream& prefix, LoadFunc load_func)
503 {
505  DataStream ssKey;
506  DataStream ssValue{};
507 
508  Assume(!prefix.empty());
509  std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);
510  if (!cursor) {
511  pwallet->WalletLogPrintf("Error getting database cursor for '%s' records\n", key);
512  result.m_result = DBErrors::CORRUPT;
513  return result;
514  }
515 
516  while (true) {
517  DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
518  if (status == DatabaseCursor::Status::DONE) {
519  break;
520  } else if (status == DatabaseCursor::Status::FAIL) {
521  pwallet->WalletLogPrintf("Error reading next '%s' record for wallet database\n", key);
522  result.m_result = DBErrors::CORRUPT;
523  return result;
524  }
525  std::string type;
526  ssKey >> type;
527  assert(type == key);
528  std::string error;
529  DBErrors record_res = load_func(pwallet, ssKey, ssValue, error);
530  if (record_res != DBErrors::LOAD_OK) {
531  pwallet->WalletLogPrintf("%s\n", error);
532  }
533  result.m_result = std::max(result.m_result, record_res);
534  ++result.m_records;
535  }
536  return result;
537 }
538 
539 static LoadResult LoadRecords(CWallet* pwallet, DatabaseBatch& batch, const std::string& key, LoadFunc load_func)
540 {
542  prefix << key;
543  return LoadRecords(pwallet, batch, key, prefix, load_func);
544 }
545 
546 static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, int last_client) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
547 {
548  AssertLockHeld(pwallet->cs_wallet);
550 
551  // Make sure descriptor wallets don't have any legacy records
552  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
553  for (const auto& type : DBKeys::LEGACY_TYPES) {
554  DataStream key;
555  DataStream value{};
556 
558  prefix << type;
559  std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);
560  if (!cursor) {
561  pwallet->WalletLogPrintf("Error getting database cursor for '%s' records\n", type);
562  return DBErrors::CORRUPT;
563  }
564 
565  DatabaseCursor::Status status = cursor->Next(key, value);
566  if (status != DatabaseCursor::Status::DONE) {
567  pwallet->WalletLogPrintf("Error: Unexpected legacy entry found in descriptor wallet %s. The wallet might have been tampered with or created with malicious intent.\n", pwallet->GetName());
569  }
570  }
571 
572  return DBErrors::LOAD_OK;
573  }
574 
575  // Load HD Chain
576  // Note: There should only be one HDCHAIN record with no data following the type
577  LoadResult hd_chain_res = LoadRecords(pwallet, batch, DBKeys::HDCHAIN,
578  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
579  return LoadHDChain(pwallet, value, err) ? DBErrors:: LOAD_OK : DBErrors::CORRUPT;
580  });
581  result = std::max(result, hd_chain_res.m_result);
582 
583  // Load unencrypted keys
584  LoadResult key_res = LoadRecords(pwallet, batch, DBKeys::KEY,
585  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
586  return LoadKey(pwallet, key, value, err) ? DBErrors::LOAD_OK : DBErrors::CORRUPT;
587  });
588  result = std::max(result, key_res.m_result);
589 
590  // Load encrypted keys
591  LoadResult ckey_res = LoadRecords(pwallet, batch, DBKeys::CRYPTED_KEY,
592  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
593  return LoadCryptedKey(pwallet, key, value, err) ? DBErrors::LOAD_OK : DBErrors::CORRUPT;
594  });
595  result = std::max(result, ckey_res.m_result);
596 
597  // Load scripts
598  LoadResult script_res = LoadRecords(pwallet, batch, DBKeys::CSCRIPT,
599  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
600  uint160 hash;
601  key >> hash;
602  CScript script;
603  value >> script;
604  if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadCScript(script))
605  {
606  strErr = "Error reading wallet database: LegacyDataSPKM::LoadCScript failed";
608  }
609  return DBErrors::LOAD_OK;
610  });
611  result = std::max(result, script_res.m_result);
612 
613  // Check whether rewrite is needed
614  if (ckey_res.m_records > 0) {
615  // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
616  if (last_client == 40000 || last_client == 50000) result = std::max(result, DBErrors::NEED_REWRITE);
617  }
618 
619  // Load keymeta
620  std::map<uint160, CHDChain> hd_chains;
621  LoadResult keymeta_res = LoadRecords(pwallet, batch, DBKeys::KEYMETA,
622  [&hd_chains] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
623  CPubKey vchPubKey;
624  key >> vchPubKey;
625  CKeyMetadata keyMeta;
626  value >> keyMeta;
627  pwallet->GetOrCreateLegacyDataSPKM()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
628 
629  // Extract some CHDChain info from this metadata if it has any
630  if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && !keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) {
631  // Get the path from the key origin or from the path string
632  // Not applicable when path is "s" or "m" as those indicate a seed
633  // See https://github.com/bitcoin/bitcoin/pull/12924
634  bool internal = false;
635  uint32_t index = 0;
636  if (keyMeta.hdKeypath != "s" && keyMeta.hdKeypath != "m") {
637  std::vector<uint32_t> path;
638  if (keyMeta.has_key_origin) {
639  // We have a key origin, so pull it from its path vector
640  path = keyMeta.key_origin.path;
641  } else {
642  // No key origin, have to parse the string
643  if (!ParseHDKeypath(keyMeta.hdKeypath, path)) {
644  strErr = "Error reading wallet database: keymeta with invalid HD keypath";
646  }
647  }
648 
649  // Extract the index and internal from the path
650  // Path string is m/0'/k'/i'
651  // Path vector is [0', k', i'] (but as ints OR'd with the hardened bit
652  // k == 0 for external, 1 for internal. i is the index
653  if (path.size() != 3) {
654  strErr = "Error reading wallet database: keymeta found with unexpected path";
656  }
657  if (path[0] != 0x80000000) {
658  strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000) for the element at index 0", path[0]);
660  }
661  if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) {
662  strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000 or 0x80000001) for the element at index 1", path[1]);
664  }
665  if ((path[2] & 0x80000000) == 0) {
666  strErr = strprintf("Unexpected path index of 0x%08x (expected to be greater than or equal to 0x80000000)", path[2]);
668  }
669  internal = path[1] == (1 | 0x80000000);
670  index = path[2] & ~0x80000000;
671  }
672 
673  // Insert a new CHDChain, or get the one that already exists
674  auto [ins, inserted] = hd_chains.emplace(keyMeta.hd_seed_id, CHDChain());
675  CHDChain& chain = ins->second;
676  if (inserted) {
677  // For new chains, we want to default to VERSION_HD_BASE until we see an internal
679  chain.seed_id = keyMeta.hd_seed_id;
680  }
681  if (internal) {
683  chain.nInternalChainCounter = std::max(chain.nInternalChainCounter, index + 1);
684  } else {
685  chain.nExternalChainCounter = std::max(chain.nExternalChainCounter, index + 1);
686  }
687  }
688  return DBErrors::LOAD_OK;
689  });
690  result = std::max(result, keymeta_res.m_result);
691 
692  // Set inactive chains
693  if (!hd_chains.empty()) {
694  LegacyDataSPKM* legacy_spkm = pwallet->GetLegacyDataSPKM();
695  if (legacy_spkm) {
696  for (const auto& [hd_seed_id, chain] : hd_chains) {
697  if (hd_seed_id != legacy_spkm->GetHDChain().seed_id) {
698  legacy_spkm->AddInactiveHDChain(chain);
699  }
700  }
701  } else {
702  pwallet->WalletLogPrintf("Inactive HD Chains found but no Legacy ScriptPubKeyMan\n");
704  }
705  }
706 
707  // Load watchonly scripts
708  LoadResult watch_script_res = LoadRecords(pwallet, batch, DBKeys::WATCHS,
709  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
710  CScript script;
711  key >> script;
712  uint8_t fYes;
713  value >> fYes;
714  if (fYes == '1') {
716  }
717  return DBErrors::LOAD_OK;
718  });
719  result = std::max(result, watch_script_res.m_result);
720 
721  // Load watchonly meta
722  LoadResult watch_meta_res = LoadRecords(pwallet, batch, DBKeys::WATCHMETA,
723  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
724  CScript script;
725  key >> script;
726  CKeyMetadata keyMeta;
727  value >> keyMeta;
729  return DBErrors::LOAD_OK;
730  });
731  result = std::max(result, watch_meta_res.m_result);
732 
733  // Load keypool
734  LoadResult pool_res = LoadRecords(pwallet, batch, DBKeys::POOL,
735  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
736  int64_t nIndex;
737  key >> nIndex;
738  CKeyPool keypool;
739  value >> keypool;
740  pwallet->GetOrCreateLegacyDataSPKM()->LoadKeyPool(nIndex, keypool);
741  return DBErrors::LOAD_OK;
742  });
743  result = std::max(result, pool_res.m_result);
744 
745  // Deal with old "wkey" and "defaultkey" records.
746  // These are not actually loaded, but we need to check for them
747 
748  // We don't want or need the default key, but if there is one set,
749  // we want to make sure that it is valid so that we can detect corruption
750  // Note: There should only be one DEFAULTKEY with nothing trailing the type
751  LoadResult default_key_res = LoadRecords(pwallet, batch, DBKeys::DEFAULTKEY,
752  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
753  CPubKey default_pubkey;
754  try {
755  value >> default_pubkey;
756  } catch (const std::exception& e) {
757  err = e.what();
758  return DBErrors::CORRUPT;
759  }
760  if (!default_pubkey.IsValid()) {
761  err = "Error reading wallet database: Default Key corrupt";
762  return DBErrors::CORRUPT;
763  }
764  return DBErrors::LOAD_OK;
765  });
766  result = std::max(result, default_key_res.m_result);
767 
768  // "wkey" records are unsupported, if we see any, throw an error
769  LoadResult wkey_res = LoadRecords(pwallet, batch, DBKeys::OLD_KEY,
770  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
771  err = "Found unsupported 'wkey' record, try loading with version 0.18";
772  return DBErrors::LOAD_FAIL;
773  });
774  result = std::max(result, wkey_res.m_result);
775 
777  // Only do logging and time first key update if there were no critical errors
778  pwallet->WalletLogPrintf("Legacy Wallet Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total.\n",
779  key_res.m_records, ckey_res.m_records, keymeta_res.m_records, key_res.m_records + ckey_res.m_records);
780 
781  // nTimeFirstKey is only reliable if all keys have metadata
782  if (pwallet->IsLegacy() && (key_res.m_records + ckey_res.m_records + watch_script_res.m_records) != (keymeta_res.m_records + watch_meta_res.m_records)) {
783  auto spk_man = pwallet->GetLegacyScriptPubKeyMan();
784  if (spk_man) {
785  LOCK(spk_man->cs_KeyStore);
786  spk_man->UpdateTimeFirstKey(1);
787  }
788  }
789  }
790 
791  return result;
792 }
793 
794 template<typename... Args>
795 static DataStream PrefixStream(const Args&... args)
796 {
799  return prefix;
800 }
801 
802 static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& batch, int last_client) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
803 {
804  AssertLockHeld(pwallet->cs_wallet);
805 
806  // Load descriptor record
807  int num_keys = 0;
808  int num_ckeys= 0;
809  LoadResult desc_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTOR,
810  [&batch, &num_keys, &num_ckeys, &last_client] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
812 
813  uint256 id;
814  key >> id;
815  WalletDescriptor desc;
816  try {
817  value >> desc;
818  } catch (const std::ios_base::failure& e) {
819  strErr = strprintf("Error: Unrecognized descriptor found in wallet %s. ", pwallet->GetName());
820  strErr += (last_client > CLIENT_VERSION) ? "The wallet might had been created on a newer version. " :
821  "The database might be corrupted or the software version is not compatible with one of your wallet descriptors. ";
822  strErr += "Please try running the latest software version";
823  // Also include error details
824  strErr = strprintf("%s\nDetails: %s", strErr, e.what());
826  }
827  DescriptorScriptPubKeyMan& spkm = pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
828 
829  // Prior to doing anything with this spkm, verify ID compatibility
830  if (id != spkm.GetID()) {
831  strErr = "The descriptor ID calculated by the wallet differs from the one in DB";
832  return DBErrors::CORRUPT;
833  }
834 
835  DescriptorCache cache;
836 
837  // Get key cache for this descriptor
839  LoadResult key_cache_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCACHE, prefix,
840  [&id, &cache] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
841  bool parent = true;
842  uint256 desc_id;
843  uint32_t key_exp_index;
844  uint32_t der_index;
845  key >> desc_id;
846  assert(desc_id == id);
847  key >> key_exp_index;
848 
849  // if the der_index exists, it's a derived xpub
850  try
851  {
852  key >> der_index;
853  parent = false;
854  }
855  catch (...) {}
856 
857  std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
858  value >> ser_xpub;
859  CExtPubKey xpub;
860  xpub.Decode(ser_xpub.data());
861  if (parent) {
862  cache.CacheParentExtPubKey(key_exp_index, xpub);
863  } else {
864  cache.CacheDerivedExtPubKey(key_exp_index, der_index, xpub);
865  }
866  return DBErrors::LOAD_OK;
867  });
868  result = std::max(result, key_cache_res.m_result);
869 
870  // Get last hardened cache for this descriptor
872  LoadResult lh_cache_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORLHCACHE, prefix,
873  [&id, &cache] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
874  uint256 desc_id;
875  uint32_t key_exp_index;
876  key >> desc_id;
877  assert(desc_id == id);
878  key >> key_exp_index;
879 
880  std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
881  value >> ser_xpub;
882  CExtPubKey xpub;
883  xpub.Decode(ser_xpub.data());
884  cache.CacheLastHardenedExtPubKey(key_exp_index, xpub);
885  return DBErrors::LOAD_OK;
886  });
887  result = std::max(result, lh_cache_res.m_result);
888 
889  // Set the cache for this descriptor
890  auto spk_man = (DescriptorScriptPubKeyMan*)pwallet->GetScriptPubKeyMan(id);
891  assert(spk_man);
892  spk_man->SetCache(cache);
893 
894  // Get unencrypted keys
896  LoadResult key_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORKEY, prefix,
897  [&id, &spk_man] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
898  uint256 desc_id;
899  CPubKey pubkey;
900  key >> desc_id;
901  assert(desc_id == id);
902  key >> pubkey;
903  if (!pubkey.IsValid())
904  {
905  strErr = "Error reading wallet database: descriptor unencrypted key CPubKey corrupt";
906  return DBErrors::CORRUPT;
907  }
908  CKey privkey;
909  CPrivKey pkey;
910  uint256 hash;
911 
912  value >> pkey;
913  value >> hash;
914 
915  // hash pubkey/privkey to accelerate wallet load
916  std::vector<unsigned char> to_hash;
917  to_hash.reserve(pubkey.size() + pkey.size());
918  to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
919  to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
920 
921  if (Hash(to_hash) != hash)
922  {
923  strErr = "Error reading wallet database: descriptor unencrypted key CPubKey/CPrivKey corrupt";
924  return DBErrors::CORRUPT;
925  }
926 
927  if (!privkey.Load(pkey, pubkey, true))
928  {
929  strErr = "Error reading wallet database: descriptor unencrypted key CPrivKey corrupt";
930  return DBErrors::CORRUPT;
931  }
932  spk_man->AddKey(pubkey.GetID(), privkey);
933  return DBErrors::LOAD_OK;
934  });
935  result = std::max(result, key_res.m_result);
936  num_keys = key_res.m_records;
937 
938  // Get encrypted keys
940  LoadResult ckey_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCKEY, prefix,
941  [&id, &spk_man] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
942  uint256 desc_id;
943  CPubKey pubkey;
944  key >> desc_id;
945  assert(desc_id == id);
946  key >> pubkey;
947  if (!pubkey.IsValid())
948  {
949  err = "Error reading wallet database: descriptor encrypted key CPubKey corrupt";
950  return DBErrors::CORRUPT;
951  }
952  std::vector<unsigned char> privkey;
953  value >> privkey;
954 
955  spk_man->AddCryptedKey(pubkey.GetID(), pubkey, privkey);
956  return DBErrors::LOAD_OK;
957  });
958  result = std::max(result, ckey_res.m_result);
959  num_ckeys = ckey_res.m_records;
960 
961  return result;
962  });
963 
964  if (desc_res.m_result <= DBErrors::NONCRITICAL_ERROR) {
965  // Only log if there are no critical errors
966  pwallet->WalletLogPrintf("Descriptors: %u, Descriptor Keys: %u plaintext, %u encrypted, %u total.\n",
967  desc_res.m_records, num_keys, num_ckeys, num_keys + num_ckeys);
968  }
969 
970  return desc_res.m_result;
971 }
972 
974 {
975  AssertLockHeld(pwallet->cs_wallet);
977 
978  // Load name record
979  LoadResult name_res = LoadRecords(pwallet, batch, DBKeys::NAME,
980  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
981  std::string strAddress;
982  key >> strAddress;
983  std::string label;
984  value >> label;
985  pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
986  return DBErrors::LOAD_OK;
987  });
988  result = std::max(result, name_res.m_result);
989 
990  // Load purpose record
991  LoadResult purpose_res = LoadRecords(pwallet, batch, DBKeys::PURPOSE,
992  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
993  std::string strAddress;
994  key >> strAddress;
995  std::string purpose_str;
996  value >> purpose_str;
997  std::optional<AddressPurpose> purpose{PurposeFromString(purpose_str)};
998  if (!purpose) {
999  pwallet->WalletLogPrintf("Warning: nonstandard purpose string '%s' for address '%s'\n", purpose_str, strAddress);
1000  }
1001  pwallet->m_address_book[DecodeDestination(strAddress)].purpose = purpose;
1002  return DBErrors::LOAD_OK;
1003  });
1004  result = std::max(result, purpose_res.m_result);
1005 
1006  // Load destination data record
1007  LoadResult dest_res = LoadRecords(pwallet, batch, DBKeys::DESTDATA,
1008  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1009  std::string strAddress, strKey, strValue;
1010  key >> strAddress;
1011  key >> strKey;
1012  value >> strValue;
1013  const CTxDestination& dest{DecodeDestination(strAddress)};
1014  if (strKey.compare("used") == 0) {
1015  // Load "used" key indicating if an IsMine address has
1016  // previously been spent from with avoid_reuse option enabled.
1017  // The strValue is not used for anything currently, but could
1018  // hold more information in the future. Current values are just
1019  // "1" or "p" for present (which was written prior to
1020  // f5ba424cd44619d9b9be88b8593d69a7ba96db26).
1021  pwallet->LoadAddressPreviouslySpent(dest);
1022  } else if (strKey.starts_with("rr")) {
1023  // Load "rr##" keys where ## is a decimal number, and strValue
1024  // is a serialized RecentRequestEntry object.
1025  pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);
1026  }
1027  return DBErrors::LOAD_OK;
1028  });
1029  result = std::max(result, dest_res.m_result);
1030 
1031  return result;
1032 }
1033 
1034 static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vector<uint256>& upgraded_txs, bool& any_unordered) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1035 {
1036  AssertLockHeld(pwallet->cs_wallet);
1037  DBErrors result = DBErrors::LOAD_OK;
1038 
1039  // Load tx record
1040  any_unordered = false;
1041  LoadResult tx_res = LoadRecords(pwallet, batch, DBKeys::TX,
1042  [&any_unordered, &upgraded_txs] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1043  DBErrors result = DBErrors::LOAD_OK;
1044  uint256 hash;
1045  key >> hash;
1046  // LoadToWallet call below creates a new CWalletTx that fill_wtx
1047  // callback fills with transaction metadata.
1048  auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
1049  if(!new_tx) {
1050  // There's some corruption here since the tx we just tried to load was already in the wallet.
1051  err = "Error: Corrupt transaction found. This can be fixed by removing transactions from wallet and rescanning.";
1052  result = DBErrors::CORRUPT;
1053  return false;
1054  }
1055  value >> wtx;
1056  if (wtx.GetHash() != hash)
1057  return false;
1058 
1059  // Undo serialize changes in 31600
1060  if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
1061  {
1062  if (!value.empty())
1063  {
1064  uint8_t fTmp;
1065  uint8_t fUnused;
1066  std::string unused_string;
1067  value >> fTmp >> fUnused >> unused_string;
1068  pwallet->WalletLogPrintf("LoadWallet() upgrading tx ver=%d %d %s\n",
1069  wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
1070  wtx.fTimeReceivedIsTxTime = fTmp;
1071  }
1072  else
1073  {
1074  pwallet->WalletLogPrintf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString());
1075  wtx.fTimeReceivedIsTxTime = 0;
1076  }
1077  upgraded_txs.push_back(hash);
1078  }
1079 
1080  if (wtx.nOrderPos == -1)
1081  any_unordered = true;
1082 
1083  return true;
1084  };
1085  if (!pwallet->LoadToWallet(hash, fill_wtx)) {
1086  // Use std::max as fill_wtx may have already set result to CORRUPT
1087  result = std::max(result, DBErrors::NEED_RESCAN);
1088  }
1089  return result;
1090  });
1091  result = std::max(result, tx_res.m_result);
1092 
1093  // Load locked utxo record
1094  LoadResult locked_utxo_res = LoadRecords(pwallet, batch, DBKeys::LOCKED_UTXO,
1095  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1096  Txid hash;
1097  uint32_t n;
1098  key >> hash;
1099  key >> n;
1100  pwallet->LockCoin(COutPoint(hash, n));
1101  return DBErrors::LOAD_OK;
1102  });
1103  result = std::max(result, locked_utxo_res.m_result);
1104 
1105  // Load orderposnext record
1106  // Note: There should only be one ORDERPOSNEXT record with nothing trailing the type
1107  LoadResult order_pos_res = LoadRecords(pwallet, batch, DBKeys::ORDERPOSNEXT,
1108  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1109  try {
1110  value >> pwallet->nOrderPosNext;
1111  } catch (const std::exception& e) {
1112  err = e.what();
1113  return DBErrors::NONCRITICAL_ERROR;
1114  }
1115  return DBErrors::LOAD_OK;
1116  });
1117  result = std::max(result, order_pos_res.m_result);
1118 
1119  // After loading all tx records, abandon any coinbase that is no longer in the active chain.
1120  // This could happen during an external wallet load, or if the user replaced the chain data.
1121  for (auto& [id, wtx] : pwallet->mapWallet) {
1122  if (wtx.IsCoinBase() && wtx.isInactive()) {
1123  pwallet->AbandonTransaction(wtx);
1124  }
1125  }
1126 
1127  return result;
1128 }
1129 
1130 static DBErrors LoadActiveSPKMs(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1131 {
1132  AssertLockHeld(pwallet->cs_wallet);
1133  DBErrors result = DBErrors::LOAD_OK;
1134 
1135  // Load spk records
1136  std::set<std::pair<OutputType, bool>> seen_spks;
1137  for (const auto& spk_key : {DBKeys::ACTIVEEXTERNALSPK, DBKeys::ACTIVEINTERNALSPK}) {
1138  LoadResult spkm_res = LoadRecords(pwallet, batch, spk_key,
1139  [&seen_spks, &spk_key] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {
1140  uint8_t output_type;
1141  key >> output_type;
1142  uint256 id;
1143  value >> id;
1144 
1145  bool internal = spk_key == DBKeys::ACTIVEINTERNALSPK;
1146  auto [it, insert] = seen_spks.emplace(static_cast<OutputType>(output_type), internal);
1147  if (!insert) {
1148  strErr = "Multiple ScriptpubKeyMans specified for a single type";
1149  return DBErrors::CORRUPT;
1150  }
1151  pwallet->LoadActiveScriptPubKeyMan(id, static_cast<OutputType>(output_type), /*internal=*/internal);
1152  return DBErrors::LOAD_OK;
1153  });
1154  result = std::max(result, spkm_res.m_result);
1155  }
1156  return result;
1157 }
1158 
1159 static DBErrors LoadDecryptionKeys(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1160 {
1161  AssertLockHeld(pwallet->cs_wallet);
1162 
1163  // Load decryption key (mkey) records
1164  LoadResult mkey_res = LoadRecords(pwallet, batch, DBKeys::MASTER_KEY,
1165  [] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {
1166  if (!LoadEncryptionKey(pwallet, key, value, err)) {
1167  return DBErrors::CORRUPT;
1168  }
1169  return DBErrors::LOAD_OK;
1170  });
1171  return mkey_res.m_result;
1172 }
1173 
1175 {
1176  DBErrors result = DBErrors::LOAD_OK;
1177  bool any_unordered = false;
1178  std::vector<uint256> upgraded_txs;
1179 
1180  LOCK(pwallet->cs_wallet);
1181 
1182  // Last client version to open this wallet
1183  int last_client = CLIENT_VERSION;
1184  bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client);
1185  if (has_last_client) pwallet->WalletLogPrintf("Last client version = %d\n", last_client);
1186 
1187  try {
1188  if ((result = LoadMinVersion(pwallet, *m_batch)) != DBErrors::LOAD_OK) return result;
1189 
1190  // Load wallet flags, so they are known when processing other records.
1191  // The FLAGS key is absent during wallet creation.
1192  if ((result = LoadWalletFlags(pwallet, *m_batch)) != DBErrors::LOAD_OK) return result;
1193 
1194 #ifndef ENABLE_EXTERNAL_SIGNER
1196  pwallet->WalletLogPrintf("Error: External signer wallet being loaded without external signer support compiled\n");
1197  return DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED;
1198  }
1199 #endif
1200 
1201  // Load legacy wallet keys
1202  result = std::max(LoadLegacyWalletRecords(pwallet, *m_batch, last_client), result);
1203 
1204  // Load descriptors
1205  result = std::max(LoadDescriptorWalletRecords(pwallet, *m_batch, last_client), result);
1206  // Early return if there are unknown descriptors. Later loading of ACTIVEINTERNALSPK and ACTIVEEXTERNALEXPK
1207  // may reference the unknown descriptor's ID which can result in a misleading corruption error
1208  // when in reality the wallet is simply too new.
1209  if (result == DBErrors::UNKNOWN_DESCRIPTOR) return result;
1210 
1211  // Load address book
1212  result = std::max(LoadAddressBookRecords(pwallet, *m_batch), result);
1213 
1214  // Load tx records
1215  result = std::max(LoadTxRecords(pwallet, *m_batch, upgraded_txs, any_unordered), result);
1216 
1217  // Load SPKMs
1218  result = std::max(LoadActiveSPKMs(pwallet, *m_batch), result);
1219 
1220  // Load decryption keys
1221  result = std::max(LoadDecryptionKeys(pwallet, *m_batch), result);
1222  } catch (...) {
1223  // Exceptions that can be ignored or treated as non-critical are handled by the individual loading functions.
1224  // Any uncaught exceptions will be caught here and treated as critical.
1225  result = DBErrors::CORRUPT;
1226  }
1227 
1228  // Any wallet corruption at all: skip any rewriting or
1229  // upgrading, we don't want to make it worse.
1230  if (result != DBErrors::LOAD_OK)
1231  return result;
1232 
1233  for (const uint256& hash : upgraded_txs)
1234  WriteTx(pwallet->mapWallet.at(hash));
1235 
1236  if (!has_last_client || last_client != CLIENT_VERSION) // Update
1237  m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
1238 
1239  if (any_unordered)
1240  result = pwallet->ReorderTransactions();
1241 
1242  // Upgrade all of the wallet keymetadata to have the hd master key id
1243  // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
1244  try {
1245  pwallet->UpgradeKeyMetadata();
1246  } catch (...) {
1247  result = DBErrors::CORRUPT;
1248  }
1249 
1250  // Upgrade all of the descriptor caches to cache the last hardened xpub
1251  // This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
1252  try {
1253  pwallet->UpgradeDescriptorCache();
1254  } catch (...) {
1255  result = DBErrors::CORRUPT;
1256  }
1257 
1258  // Since it was accidentally possible to "encrypt" a wallet with private keys disabled, we should check if this is
1259  // such a wallet and remove the encryption key records to avoid any future issues.
1260  // Although wallets without private keys should not have *ckey records, we should double check that.
1261  // Removing the mkey records is only safe if there are no *ckey records.
1262  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && pwallet->HasEncryptionKeys() && !pwallet->HaveCryptedKeys()) {
1263  pwallet->WalletLogPrintf("Detected extraneous encryption keys in this wallet without private keys. Removing extraneous encryption keys.\n");
1264  for (const auto& [id, _] : pwallet->mapMasterKeys) {
1265  if (!EraseMasterKey(id)) {
1266  pwallet->WalletLogPrintf("Error: Unable to remove extraneous encryption key '%u'. Wallet corrupt.\n", id);
1267  return DBErrors::CORRUPT;
1268  }
1269  }
1270  pwallet->mapMasterKeys.clear();
1271  }
1272 
1273  return result;
1274 }
1275 
1276 static bool RunWithinTxn(WalletBatch& batch, std::string_view process_desc, const std::function<bool(WalletBatch&)>& func)
1277 {
1278  if (!batch.TxnBegin()) {
1279  LogDebug(BCLog::WALLETDB, "Error: cannot create db txn for %s\n", process_desc);
1280  return false;
1281  }
1282 
1283  // Run procedure
1284  if (!func(batch)) {
1285  LogDebug(BCLog::WALLETDB, "Error: %s failed\n", process_desc);
1286  batch.TxnAbort();
1287  return false;
1288  }
1289 
1290  if (!batch.TxnCommit()) {
1291  LogDebug(BCLog::WALLETDB, "Error: cannot commit db txn for %s\n", process_desc);
1292  return false;
1293  }
1294 
1295  // All good
1296  return true;
1297 }
1298 
1299 bool RunWithinTxn(WalletDatabase& database, std::string_view process_desc, const std::function<bool(WalletBatch&)>& func)
1300 {
1301  WalletBatch batch(database);
1302  return RunWithinTxn(batch, process_desc, func);
1303 }
1304 
1306 {
1307  static std::atomic<bool> fOneThread(false);
1308  if (fOneThread.exchange(true)) {
1309  return;
1310  }
1311 
1312  for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
1313  WalletDatabase& dbh = pwallet->GetDatabase();
1314 
1315  unsigned int nUpdateCounter = dbh.nUpdateCounter;
1316 
1317  if (dbh.nLastSeen != nUpdateCounter) {
1318  dbh.nLastSeen = nUpdateCounter;
1319  dbh.nLastWalletUpdate = GetTime();
1320  }
1321 
1322  if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
1323  if (dbh.PeriodicFlush()) {
1324  dbh.nLastFlushed = nUpdateCounter;
1325  }
1326  }
1327  }
1328 
1329  fOneThread = false;
1330 }
1331 
1332 bool WalletBatch::WriteAddressPreviouslySpent(const CTxDestination& dest, bool previously_spent)
1333 {
1334  auto key{std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), std::string("used")))};
1335  return previously_spent ? WriteIC(key, std::string("1")) : EraseIC(key);
1336 }
1337 
1338 bool WalletBatch::WriteAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& receive_request)
1339 {
1340  return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)), receive_request);
1341 }
1342 
1343 bool WalletBatch::EraseAddressReceiveRequest(const CTxDestination& dest, const std::string& id)
1344 {
1345  return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)));
1346 }
1347 
1348 bool WalletBatch::EraseAddressData(const CTxDestination& dest)
1349 {
1352  return m_batch->ErasePrefix(prefix);
1353 }
1354 
1355 bool WalletBatch::WriteHDChain(const CHDChain& chain)
1356 {
1357  return WriteIC(DBKeys::HDCHAIN, chain);
1358 }
1359 
1360 bool WalletBatch::WriteWalletFlags(const uint64_t flags)
1361 {
1362  return WriteIC(DBKeys::FLAGS, flags);
1363 }
1364 
1365 bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
1366 {
1367  return std::all_of(types.begin(), types.end(), [&](const std::string& type) {
1368  return m_batch->ErasePrefix(DataStream() << type);
1369  });
1370 }
1371 
1372 bool WalletBatch::TxnBegin()
1373 {
1374  return m_batch->TxnBegin();
1375 }
1376 
1377 bool WalletBatch::TxnCommit()
1378 {
1379  bool res = m_batch->TxnCommit();
1380  if (res) {
1381  for (const auto& listener : m_txn_listeners) {
1382  listener.on_commit();
1383  }
1384  // txn finished, clear listeners
1385  m_txn_listeners.clear();
1386  }
1387  return res;
1388 }
1389 
1390 bool WalletBatch::TxnAbort()
1391 {
1392  bool res = m_batch->TxnAbort();
1393  if (res) {
1394  for (const auto& listener : m_txn_listeners) {
1395  listener.on_abort();
1396  }
1397  // txn finished, clear listeners
1398  m_txn_listeners.clear();
1399  }
1400  return res;
1401 }
1402 
1403 void WalletBatch::RegisterTxnListener(const DbTxnListener& l)
1404 {
1405  assert(m_batch->HasActiveTxn());
1406  m_txn_listeners.emplace_back(l);
1407 }
1408 
1409 std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
1410 {
1411  bool exists;
1412  try {
1413  exists = fs::symlink_status(path).type() != fs::file_type::not_found;
1414  } catch (const fs::filesystem_error& e) {
1415  error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e)));
1416  status = DatabaseStatus::FAILED_BAD_PATH;
1417  return nullptr;
1418  }
1419 
1420  std::optional<DatabaseFormat> format;
1421  if (exists) {
1422  if (IsBDBFile(BDBDataFile(path))) {
1423  format = DatabaseFormat::BERKELEY;
1424  }
1425  if (IsSQLiteFile(SQLiteDataFile(path))) {
1426  if (format) {
1427  error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", fs::PathToString(path)));
1428  status = DatabaseStatus::FAILED_BAD_FORMAT;
1429  return nullptr;
1430  }
1431  format = DatabaseFormat::SQLITE;
1432  }
1433  } else if (options.require_existing) {
1434  error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", fs::PathToString(path)));
1435  status = DatabaseStatus::FAILED_NOT_FOUND;
1436  return nullptr;
1437  }
1438 
1439  if (!format && options.require_existing) {
1440  error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", fs::PathToString(path)));
1441  status = DatabaseStatus::FAILED_BAD_FORMAT;
1442  return nullptr;
1443  }
1444 
1445  if (format && options.require_create) {
1446  error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(path)));
1447  status = DatabaseStatus::FAILED_ALREADY_EXISTS;
1448  return nullptr;
1449  }
1450 
1451  // If BERKELEY was the format, then change the format from BERKELEY to BERKELEY_RO
1452  if (format && options.require_format && format == DatabaseFormat::BERKELEY && options.require_format == DatabaseFormat::BERKELEY_RO) {
1453  format = DatabaseFormat::BERKELEY_RO;
1454  }
1455 
1456  // A db already exists so format is set, but options also specifies the format, so make sure they agree
1457  if (format && options.require_format && format != options.require_format) {
1458  error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", fs::PathToString(path)));
1459  status = DatabaseStatus::FAILED_BAD_FORMAT;
1460  return nullptr;
1461  }
1462 
1463  // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
1464  if (!format && options.require_format) format = options.require_format;
1465 
1466  // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
1467  if (!format) {
1468 #ifdef USE_SQLITE
1469  format = DatabaseFormat::SQLITE;
1470 #endif
1471 #ifdef USE_BDB
1472  format = DatabaseFormat::BERKELEY;
1473 #endif
1474  }
1475 
1476  if (format == DatabaseFormat::SQLITE) {
1477 #ifdef USE_SQLITE
1478  if constexpr (true) {
1479  return MakeSQLiteDatabase(path, options, status, error);
1480  } else
1481 #endif
1482  {
1483  error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", fs::PathToString(path)));
1484  status = DatabaseStatus::FAILED_BAD_FORMAT;
1485  return nullptr;
1486  }
1487  }
1488 
1489  if (format == DatabaseFormat::BERKELEY_RO) {
1490  return MakeBerkeleyRODatabase(path, options, status, error);
1491  }
1492 
1493 #ifdef USE_BDB
1494  if constexpr (true) {
1495  return MakeBerkeleyDatabase(path, options, status, error);
1496  } else
1497 #endif
1498  {
1499  error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1500  status = DatabaseStatus::FAILED_BAD_FORMAT;
1501  return nullptr;
1502  }
1503 }
1504 } // namespace wallet
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Definition: walletdb.cpp:1409
std::unordered_map< uint32_t, ExtPubKeyMap > GetCachedDerivedExtPubKeys() const
Retrieve all cached derived xpubs.
const std::string MASTER_KEY
Definition: walletdb.cpp:50
bool eof() const
Definition: streams.h:215
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key...
Definition: crypter.h:34
std::optional< DatabaseFormat > require_format
Definition: db.h:194
const std::string BESTBLOCK_NOMERKLE
Definition: walletdb.cpp:39
const std::string SETTINGS
Definition: walletdb.cpp:57
const std::string CRYPTED_KEY
Definition: walletdb.cpp:41
static DBErrors LoadDescriptorWalletRecords(CWallet *pwallet, DatabaseBatch &batch, int last_client) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:802
AssertLockHeld(pool.cs)
ExtPubKeyMap GetCachedParentExtPubKeys() const
Retrieve all cached parent xpubs.
const std::string NAME
Definition: walletdb.cpp:52
const std::string HDCHAIN
Definition: walletdb.cpp:46
bool HasEncryptionKeys() const override
Definition: wallet.cpp:3724
std::unique_ptr< BerkeleyRODatabase > MakeBerkeleyRODatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley Read Only database at specified path.
Definition: migrate.cpp:771
assert(!tx.IsCoinBase())
const std::string ACENTRY
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:123
const std::string VERSION
Definition: walletdb.cpp:59
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.
Definition: wallet.cpp:566
bool LoadToWallet(const uint256 &hash, const UpdateWalletTxFn &fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1200
const std::string DESTDATA
Definition: walletdb.cpp:44
Bilingual messages:
Definition: translation.h:24
static DBErrors LoadAddressBookRecords(CWallet *pwallet, DatabaseBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:973
std::unique_ptr< SQLiteDatabase > MakeSQLiteDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Definition: sqlite.cpp:694
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:47
const std::string WALLETDESCRIPTORCKEY
Definition: walletdb.cpp:63
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bool WriteDescriptorCacheItems(const uint256 &desc_id, const DescriptorCache &cache)
Definition: walletdb.cpp:289
bool RunWithinTxn(WalletDatabase &database, std::string_view process_desc, const std::function< bool(WalletBatch &)> &func)
Executes the provided function &#39;func&#39; within a database transaction context.
Definition: walletdb.cpp:1299
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
const std::string BESTBLOCK
Definition: walletdb.cpp:40
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
Definition: wallet.h:455
const char * prefix
Definition: rest.cpp:1009
bool WriteCryptedDescriptorKey(const uint256 &desc_id, const CPubKey &pubkey, const std::vector< unsigned char > &secret)
Definition: walletdb.cpp:254
uint32_t nExternalChainCounter
Definition: walletdb.h:100
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:370
bool LoadKey(const CKey &key, const CPubKey &pubkey)
Adds a key to the store, without saving it to disk (used by LoadWallet)
static DataStream PrefixStream(const Args &... args)
Definition: walletdb.cpp:795
std::function< DBErrors(CWallet *pwallet, DataStream &key, DataStream &value, std::string &err)> LoadFunc
Definition: walletdb.cpp:501
bool IsLegacy() const
Determine if we are a legacy wallet.
Definition: wallet.cpp:3905
const std::string WALLETDESCRIPTOR
Definition: walletdb.cpp:60
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
Definition: walletdb.cpp:152
virtual std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(Span< const std::byte > prefix)=0
MasterKeyMap mapMasterKeys
Definition: wallet.h:458
bool TxnAbort()
Abort current transaction.
Definition: walletdb.cpp:1390
static DBErrors LoadLegacyWalletRecords(CWallet *pwallet, DatabaseBatch &batch, int last_client) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:546
bool LoadHDChain(CWallet *pwallet, DataStream &ssValue, std::string &strErr)
Definition: walletdb.cpp:453
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:445
const std::string KEY
Definition: walletdb.cpp:48
void AddInactiveHDChain(const CHDChain &chain)
bool EraseWatchOnly(const CScript &script)
Definition: walletdb.cpp:175
void insert(Tdst &dst, const Tsrc &src)
Simplification of std insertion.
Definition: insert.h:14
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:126
bool WriteLockedUTXO(const COutPoint &output)
Definition: walletdb.cpp:311
bool WriteMinVersion(int nVersion)
Definition: walletdb.cpp:226
void LoadHDChain(const CHDChain &chain)
Load a HD chain model (used by LoadWallet)
Access to the wallet database.
Definition: walletdb.h:195
bool WritePool(int64_t nPool, const CKeyPool &keypool)
Definition: walletdb.cpp:216
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
Definition: wallet.cpp:3584
A key from a CWallet&#39;s keypool.
const std::string CSCRIPT
Definition: walletdb.cpp:42
static DBErrors LoadActiveSPKMs(CWallet *pwallet, DatabaseBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:1130
bool WriteOrderPosNext(int64_t nOrderPosNext)
Definition: walletdb.cpp:206
bool ReadBestBlock(CBlockLocator &locator)
Definition: walletdb.cpp:189
const std::string PURPOSE
Definition: walletdb.cpp:56
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
Load a keypool entry.
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:175
const std::string MINVERSION
Definition: walletdb.cpp:51
LegacyScriptPubKeyMan * GetLegacyScriptPubKeyMan() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
Definition: wallet.cpp:3656
std::unique_ptr< DatabaseBatch > m_batch
Definition: walletdb.h:307
bool WriteDescriptor(const uint256 &desc_id, const WalletDescriptor &descriptor)
Definition: walletdb.cpp:263
bool WriteDescriptorKey(const uint256 &desc_id, const CPubKey &pubkey, const CPrivKey &privkey)
Definition: walletdb.cpp:243
const std::string WALLETDESCRIPTORKEY
Definition: walletdb.cpp:64
RAII class that provides access to a WalletDatabase.
Definition: db.h:50
const unsigned char * begin() const
Definition: pubkey.h:114
const std::unordered_set< std::string > LEGACY_TYPES
Definition: walletdb.cpp:67
bool WriteKeyMetadata(const CKeyMetadata &meta, const CPubKey &pubkey, const bool overwrite)
Definition: walletdb.cpp:106
fs::path SQLiteDataFile(const fs::path &path)
Definition: db.cpp:90
void MaybeCompactWalletDB(WalletContext &context)
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:1305
static DBErrors LoadTxRecords(CWallet *pwallet, DatabaseBatch &batch, std::vector< uint256 > &upgraded_txs, bool &any_unordered) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:1034
bool LoadWatchOnly(const CScript &dest)
Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) ...
bool WriteBestBlock(const CBlockLocator &locator)
Definition: walletdb.cpp:183
std::unique_ptr< BerkeleyDatabase > MakeBerkeleyDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley database at specified path.
Definition: bdb.cpp:948
int64_t nLastWalletUpdate
Definition: db.h:178
static DBErrors LoadWalletFlags(CWallet *pwallet, DatabaseBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:482
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
CPrivKey is a serialized private key, with all parameters included (SIZE bytes)
Definition: key.h:23
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:176
const std::string WATCHMETA
Definition: walletdb.cpp:65
bool EraseName(const std::string &strAddress)
Definition: walletdb.cpp:79
Indicates that the wallet needs an external signer.
Definition: walletutil.h:77
bool LoadEncryptionKey(CWallet *pwallet, DataStream &ssKey, DataStream &ssValue, std::string &strErr)
Definition: walletdb.cpp:426
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const
Definition: pubkey.cpp:376
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta)
Definition: walletdb.cpp:167
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE])
Definition: pubkey.cpp:385
bool TxnCommit()
Commit current transaction.
Definition: walletdb.cpp:1377
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
ArgsManager & args
Definition: bitcoind.cpp:277
bool IsBDBFile(const fs::path &path)
Definition: db.cpp:95
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
Definition: walletdb.cpp:231
const unsigned char * end() const
Definition: pubkey.h:115
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Definition: walletdb.cpp:211
static const int VERSION_WITH_HDDATA
Definition: walletdb.h:139
bool WriteDescriptorDerivedCache(const CExtPubKey &xpub, const uint256 &desc_id, uint32_t key_exp_index, uint32_t der_index)
Definition: walletdb.cpp:268
bool LoadCryptedKey(CWallet *pwallet, DataStream &ssKey, DataStream &ssValue, std::string &strErr)
Definition: walletdb.cpp:387
#define LOCK(cs)
Definition: sync.h:257
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
bool WriteTx(const CWalletTx &wtx)
Definition: walletdb.cpp:96
unsigned int nLastFlushed
Definition: db.h:177
bool IsValid() const
Definition: pubkey.h:189
Txid hash
Definition: transaction.h:31
void WalletLogPrintf(util::ConstevalFormatString< sizeof...(Params)> wallet_fmt, const Params &... params) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
Definition: wallet.h:935
An encapsulated public key.
Definition: pubkey.h:33
const std::string POOL
Definition: walletdb.cpp:55
LegacyDataSPKM * GetOrCreateLegacyDataSPKM()
Definition: wallet.cpp:3694
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, bool checksum_valid)
Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) ...
uint32_t n
Definition: transaction.h:32
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
uint32_t nInternalChainCounter
Definition: walletdb.h:101
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:299
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
Definition: walletdb.cpp:162
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:112
std::vector< uint256 > vHave
Definition: block.h:134
virtual void LoadKeyMetadata(const CKeyID &keyID, const CKeyMetadata &metadata)
Load metadata (used by LoadWallet)
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
Definition: wallet.cpp:1748
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
static DBErrors LoadMinVersion(CWallet *pwallet, DatabaseBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:469
constexpr bool IsNull() const
Definition: uint256.h:48
virtual bool PeriodicFlush()=0
const std::string FLAGS
Definition: walletdb.cpp:45
#define Assume(val)
Assume is the identity function.
Definition: check.h:97
bool ErasePurpose(const std::string &strAddress)
Definition: walletdb.cpp:91
bool ErasePool(int64_t nPool)
Definition: walletdb.cpp:221
Descriptor with some wallet metadata.
Definition: walletutil.h:84
const std::string ACTIVEINTERNALSPK
Definition: walletdb.cpp:38
const std::string KEYMETA
Definition: walletdb.cpp:47
bool WriteDescriptorParentCache(const CExtPubKey &xpub, const uint256 &desc_id, uint32_t key_exp_index)
Definition: walletdb.cpp:275
void CacheLastHardenedExtPubKey(uint32_t key_exp_pos, const CExtPubKey &xpub)
Cache a last hardened xpub.
if(!SetupNetworking())
int flags
Definition: bitcoin-tx.cpp:536
virtual void LoadScriptMetadata(const CScriptID &script_id, const CKeyMetadata &metadata)
DatabaseStatus
Definition: db.h:205
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:118
256-bit opaque blob.
Definition: uint256.h:201
bool LoadKey(CWallet *pwallet, DataStream &ssKey, DataStream &ssValue, std::string &strErr)
Definition: walletdb.cpp:321
catch(const std::exception &e)
const std::string WALLETDESCRIPTORCACHE
Definition: walletdb.cpp:61
bool EraseIC(const K &key)
Definition: walletdb.h:212
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:351
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:191
auto result
Definition: common-types.h:74
#define LogDebug(category,...)
Definition: logging.h:381
const std::string ACTIVEEXTERNALSPK
Definition: walletdb.cpp:37
bool ParseHDKeypath(const std::string &keypath_str, std::vector< uint32_t > &keypath)
Parse an HD keypaths like "m/7/0&#39;/2000".
Definition: bip32.cpp:13
Cache for single descriptor&#39;s derived extended pubkeys.
Definition: descriptor.h:19
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Loads an active ScriptPubKeyMan for the specified type and internal.
Definition: wallet.cpp:3868
void CacheParentExtPubKey(uint32_t key_exp_pos, const CExtPubKey &xpub)
Cache a parent xpub.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:140
const unsigned int BIP32_EXTKEY_SIZE
Definition: pubkey.h:19
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:76
static LoadResult LoadRecords(CWallet *pwallet, DatabaseBatch &batch, const std::string &key, DataStream &prefix, LoadFunc load_func)
Definition: walletdb.cpp:502
bool TxnBegin()
Begin a new transaction.
Definition: walletdb.cpp:1372
bool HaveCryptedKeys() const
Definition: wallet.cpp:3729
bool EraseTx(uint256 hash)
Definition: walletdb.cpp:101
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
Definition: walletdb.cpp:111
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
Definition: context.h:36
DBErrors ReorderTransactions()
Definition: wallet.cpp:913
const std::string LOCKED_UTXO
Definition: walletdb.cpp:49
160-bit opaque blob.
Definition: uint256.h:189
bool IsSQLiteFile(const fs::path &path)
Definition: db.cpp:120
bool require_existing
Definition: db.h:192
static const int VERSION_HD_BASE
Definition: walletdb.h:106
A reference to a CScript: the Hash160 of its serialization.
Definition: script.h:601
const std::string WALLETDESCRIPTORLHCACHE
Definition: walletdb.cpp:62
bool WriteName(const std::string &strAddress, const std::string &strName)
Definition: walletdb.cpp:74
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
void SerializeMany(Stream &s, const Args &... args)
Support for (un)serializing many things at once.
Definition: serialize.h:994
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
Definition: wallet.cpp:551
bool WriteIC(const K &key, const T &value, bool fOverwrite=true)
Definition: walletdb.h:199
const std::string DEFAULTKEY
Definition: walletdb.cpp:43
An encapsulated private key.
Definition: key.h:34
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
Definition: hash.h:75
bool EraseLockedUTXO(const COutPoint &output)
Definition: walletdb.cpp:316
static bool exists(const path &p)
Definition: fs.h:89
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:299
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
Definition: walletdb.cpp:237
const std::string ORDERPOSNEXT
Definition: walletdb.cpp:54
bool LoadCScript(const CScript &redeemScript)
Adds a CScript to the store.
unsigned int nMasterKeyMaxID
Definition: wallet.h:459
int64_t GetTime()
DEPRECATED, see GetTime.
Definition: time.cpp:76
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:32
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:31
const CHDChain & GetHDChain() const
const std::string WATCHS
Definition: walletdb.cpp:66
bool EraseMasterKey(unsigned int id)
Definition: walletdb.cpp:157
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
Definition: walletdb.cpp:86
CKeyID seed_id
seed hash160
Definition: walletdb.h:102
LegacyDataSPKM * GetLegacyDataSPKM() const
Definition: wallet.cpp:3668
DescriptorScriptPubKeyMan & LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
Definition: wallet.cpp:3746
void CacheDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_index, const CExtPubKey &xpub)
Cache an xpub derived at an index.
unsigned int nLastSeen
Definition: db.h:176
An instance of this class represents one database.
Definition: db.h:130
const std::string OLD_KEY
Definition: walletdb.cpp:53
const std::string TX
Definition: walletdb.cpp:58
ExtPubKeyMap GetCachedLastHardenedExtPubKeys() const
Retrieve all cached last hardened xpubs.
static LoadResult LoadRecords(CWallet *pwallet, DatabaseBatch &batch, const std::string &key, LoadFunc load_func)
Definition: walletdb.cpp:539
static DBErrors LoadDecryptionKeys(CWallet *pwallet, DatabaseBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: walletdb.cpp:1159
bool WriteDescriptorLastHardenedCache(const CExtPubKey &xpub, const uint256 &desc_id, uint32_t key_exp_index)
Definition: walletdb.cpp:282
bool Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck)
Load private key and check that public key matches.
Definition: key.cpp:278
static const int VERSION_HD_CHAIN_SPLIT
Definition: walletdb.h:107