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