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