LCOV - code coverage report
Current view: top level - src/wallet - walletdb.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 615 854 72.0 %
Date: 2022-04-21 14:51:19 Functions: 47 50 94.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 245 352 69.6 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <wallet/walletdb.h>
#       7                 :            : 
#       8                 :            : #include <fs.h>
#       9                 :            : #include <key_io.h>
#      10                 :            : #include <protocol.h>
#      11                 :            : #include <serialize.h>
#      12                 :            : #include <sync.h>
#      13                 :            : #include <util/bip32.h>
#      14                 :            : #include <util/system.h>
#      15                 :            : #include <util/time.h>
#      16                 :            : #include <util/translation.h>
#      17                 :            : #ifdef USE_BDB
#      18                 :            : #include <wallet/bdb.h>
#      19                 :            : #endif
#      20                 :            : #ifdef USE_SQLITE
#      21                 :            : #include <wallet/sqlite.h>
#      22                 :            : #endif
#      23                 :            : #include <wallet/wallet.h>
#      24                 :            : 
#      25                 :            : #include <atomic>
#      26                 :            : #include <optional>
#      27                 :            : #include <string>
#      28                 :            : 
#      29                 :            : namespace wallet {
#      30                 :            : namespace DBKeys {
#      31                 :            : const std::string ACENTRY{"acentry"};
#      32                 :            : const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
#      33                 :            : const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
#      34                 :            : const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
#      35                 :            : const std::string BESTBLOCK{"bestblock"};
#      36                 :            : const std::string CRYPTED_KEY{"ckey"};
#      37                 :            : const std::string CSCRIPT{"cscript"};
#      38                 :            : const std::string DEFAULTKEY{"defaultkey"};
#      39                 :            : const std::string DESTDATA{"destdata"};
#      40                 :            : const std::string FLAGS{"flags"};
#      41                 :            : const std::string HDCHAIN{"hdchain"};
#      42                 :            : const std::string KEYMETA{"keymeta"};
#      43                 :            : const std::string KEY{"key"};
#      44                 :            : const std::string LOCKED_UTXO{"lockedutxo"};
#      45                 :            : const std::string MASTER_KEY{"mkey"};
#      46                 :            : const std::string MINVERSION{"minversion"};
#      47                 :            : const std::string NAME{"name"};
#      48                 :            : const std::string OLD_KEY{"wkey"};
#      49                 :            : const std::string ORDERPOSNEXT{"orderposnext"};
#      50                 :            : const std::string POOL{"pool"};
#      51                 :            : const std::string PURPOSE{"purpose"};
#      52                 :            : const std::string SETTINGS{"settings"};
#      53                 :            : const std::string TX{"tx"};
#      54                 :            : const std::string VERSION{"version"};
#      55                 :            : const std::string WALLETDESCRIPTOR{"walletdescriptor"};
#      56                 :            : const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"};
#      57                 :            : const std::string WALLETDESCRIPTORLHCACHE{"walletdescriptorlhcache"};
#      58                 :            : const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
#      59                 :            : const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
#      60                 :            : const std::string WATCHMETA{"watchmeta"};
#      61                 :            : const std::string WATCHS{"watchs"};
#      62                 :            : } // namespace DBKeys
#      63                 :            : 
#      64                 :            : //
#      65                 :            : // WalletBatch
#      66                 :            : //
#      67                 :            : 
#      68                 :            : bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
#      69                 :      14840 : {
#      70                 :      14840 :     return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
#      71                 :      14840 : }
#      72                 :            : 
#      73                 :            : bool WalletBatch::EraseName(const std::string& strAddress)
#      74                 :          0 : {
#      75                 :            :     // This should only be used for sending addresses, never for receiving addresses,
#      76                 :            :     // receiving addresses must always have an address book entry if they're not change return.
#      77                 :          0 :     return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
#      78                 :          0 : }
#      79                 :            : 
#      80                 :            : bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
#      81                 :      14840 : {
#      82                 :      14840 :     return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
#      83                 :      14840 : }
#      84                 :            : 
#      85                 :            : bool WalletBatch::ErasePurpose(const std::string& strAddress)
#      86                 :          0 : {
#      87                 :          0 :     return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
#      88                 :          0 : }
#      89                 :            : 
#      90                 :            : bool WalletBatch::WriteTx(const CWalletTx& wtx)
#      91                 :      32060 : {
#      92                 :      32060 :     return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
#      93                 :      32060 : }
#      94                 :            : 
#      95                 :            : bool WalletBatch::EraseTx(uint256 hash)
#      96                 :          5 : {
#      97                 :          5 :     return EraseIC(std::make_pair(DBKeys::TX, hash));
#      98                 :          5 : }
#      99                 :            : 
#     100                 :            : bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
#     101                 :      21746 : {
#     102                 :      21746 :     return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite);
#     103                 :      21746 : }
#     104                 :            : 
#     105                 :            : bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
#     106                 :      20410 : {
#     107         [ -  + ]:      20410 :     if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
#     108                 :          0 :         return false;
#     109                 :          0 :     }
#     110                 :            : 
#     111                 :            :     // hash pubkey/privkey to accelerate wallet load
#     112                 :      20410 :     std::vector<unsigned char> vchKey;
#     113                 :      20410 :     vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
#     114                 :      20410 :     vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
#     115                 :      20410 :     vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
#     116                 :            : 
#     117                 :      20410 :     return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
#     118                 :      20410 : }
#     119                 :            : 
#     120                 :            : bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
#     121                 :            :                                 const std::vector<unsigned char>& vchCryptedSecret,
#     122                 :            :                                 const CKeyMetadata &keyMeta)
#     123                 :       1173 : {
#     124         [ -  + ]:       1173 :     if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
#     125                 :          0 :         return false;
#     126                 :          0 :     }
#     127                 :            : 
#     128                 :            :     // Compute a checksum of the encrypted key
#     129                 :       1173 :     uint256 checksum = Hash(vchCryptedSecret);
#     130                 :            : 
#     131                 :       1173 :     const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
#     132         [ +  + ]:       1173 :     if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
#     133                 :            :         // It may already exist, so try writing just the checksum
#     134                 :         81 :         std::vector<unsigned char> val;
#     135         [ -  + ]:         81 :         if (!m_batch->Read(key, val)) {
#     136                 :          0 :             return false;
#     137                 :          0 :         }
#     138         [ -  + ]:         81 :         if (!WriteIC(key, std::make_pair(val, checksum), true)) {
#     139                 :          0 :             return false;
#     140                 :          0 :         }
#     141                 :         81 :     }
#     142                 :       1173 :     EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
#     143                 :       1173 :     return true;
#     144                 :       1173 : }
#     145                 :            : 
#     146                 :            : bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
#     147                 :         35 : {
#     148                 :         35 :     return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
#     149                 :         35 : }
#     150                 :            : 
#     151                 :            : bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
#     152                 :      20704 : {
#     153                 :      20704 :     return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
#     154                 :      20704 : }
#     155                 :            : 
#     156                 :            : bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
#     157                 :        675 : {
#     158         [ -  + ]:        675 :     if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
#     159                 :          0 :         return false;
#     160                 :          0 :     }
#     161                 :        675 :     return WriteIC(std::make_pair(DBKeys::WATCHS, dest), uint8_t{'1'});
#     162                 :        675 : }
#     163                 :            : 
#     164                 :            : bool WalletBatch::EraseWatchOnly(const CScript &dest)
#     165                 :         13 : {
#     166         [ -  + ]:         13 :     if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
#     167                 :          0 :         return false;
#     168                 :          0 :     }
#     169                 :         13 :     return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
#     170                 :         13 : }
#     171                 :            : 
#     172                 :            : bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
#     173                 :       1196 : {
#     174                 :       1196 :     WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
#     175                 :       1196 :     return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
#     176                 :       1196 : }
#     177                 :            : 
#     178                 :            : bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
#     179                 :        784 : {
#     180 [ +  + ][ -  + ]:        784 :     if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
#     181                 :        784 :     return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
#     182                 :        784 : }
#     183                 :            : 
#     184                 :            : bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
#     185                 :      25391 : {
#     186                 :      25391 :     return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
#     187                 :      25391 : }
#     188                 :            : 
#     189                 :            : bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
#     190                 :      13200 : {
#     191                 :      13200 :     return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
#     192                 :      13200 : }
#     193                 :            : 
#     194                 :            : bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
#     195                 :      19752 : {
#     196                 :      19752 :     return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
#     197                 :      19752 : }
#     198                 :            : 
#     199                 :            : bool WalletBatch::ErasePool(int64_t nPool)
#     200                 :      12608 : {
#     201                 :      12608 :     return EraseIC(std::make_pair(DBKeys::POOL, nPool));
#     202                 :      12608 : }
#     203                 :            : 
#     204                 :            : bool WalletBatch::WriteMinVersion(int nVersion)
#     205                 :        463 : {
#     206                 :        463 :     return WriteIC(DBKeys::MINVERSION, nVersion);
#     207                 :        463 : }
#     208                 :            : 
#     209                 :            : bool WalletBatch::WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal)
#     210                 :       1525 : {
#     211         [ +  + ]:       1525 :     std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
#     212                 :       1525 :     return WriteIC(make_pair(key, type), id);
#     213                 :       1525 : }
#     214                 :            : 
#     215                 :            : bool WalletBatch::EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
#     216                 :          1 : {
#     217         [ +  - ]:          1 :     const std::string key{internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK};
#     218                 :          1 :     return EraseIC(make_pair(key, type));
#     219                 :          1 : }
#     220                 :            : 
#     221                 :            : bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey)
#     222                 :       1522 : {
#     223                 :            :     // hash pubkey/privkey to accelerate wallet load
#     224                 :       1522 :     std::vector<unsigned char> key;
#     225                 :       1522 :     key.reserve(pubkey.size() + privkey.size());
#     226                 :       1522 :     key.insert(key.end(), pubkey.begin(), pubkey.end());
#     227                 :       1522 :     key.insert(key.end(), privkey.begin(), privkey.end());
#     228                 :            : 
#     229                 :       1522 :     return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false);
#     230                 :       1522 : }
#     231                 :            : 
#     232                 :            : bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret)
#     233                 :        196 : {
#     234         [ -  + ]:        196 :     if (!WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORCKEY, std::make_pair(desc_id, pubkey)), secret, false)) {
#     235                 :          0 :         return false;
#     236                 :          0 :     }
#     237                 :        196 :     EraseIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)));
#     238                 :        196 :     return true;
#     239                 :        196 : }
#     240                 :            : 
#     241                 :            : bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor)
#     242                 :      54693 : {
#     243                 :      54693 :     return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
#     244                 :      54693 : }
#     245                 :            : 
#     246                 :            : bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
#     247                 :       1876 : {
#     248                 :       1876 :     std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
#     249                 :       1876 :     xpub.Encode(ser_xpub.data());
#     250                 :       1876 :     return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
#     251                 :       1876 : }
#     252                 :            : 
#     253                 :            : bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
#     254                 :       1937 : {
#     255                 :       1937 :     std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
#     256                 :       1937 :     xpub.Encode(ser_xpub.data());
#     257                 :       1937 :     return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
#     258                 :       1937 : }
#     259                 :            : 
#     260                 :            : bool WalletBatch::WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
#     261                 :       1365 : {
#     262                 :       1365 :     std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
#     263                 :       1365 :     xpub.Encode(ser_xpub.data());
#     264                 :       1365 :     return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORLHCACHE, desc_id), key_exp_index), ser_xpub);
#     265                 :       1365 : }
#     266                 :            : 
#     267                 :            : bool WalletBatch::WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache)
#     268                 :     171284 : {
#     269         [ +  + ]:     171284 :     for (const auto& parent_xpub_pair : cache.GetCachedParentExtPubKeys()) {
#     270         [ -  + ]:       1937 :         if (!WriteDescriptorParentCache(parent_xpub_pair.second, desc_id, parent_xpub_pair.first)) {
#     271                 :          0 :             return false;
#     272                 :          0 :         }
#     273                 :       1937 :     }
#     274         [ +  + ]:     171284 :     for (const auto& derived_xpub_map_pair : cache.GetCachedDerivedExtPubKeys()) {
#     275         [ +  + ]:       1876 :         for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
#     276         [ -  + ]:       1876 :             if (!WriteDescriptorDerivedCache(derived_xpub_pair.second, desc_id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {
#     277                 :          0 :                 return false;
#     278                 :          0 :             }
#     279                 :       1876 :         }
#     280                 :       1876 :     }
#     281         [ +  + ]:     171284 :     for (const auto& lh_xpub_pair : cache.GetCachedLastHardenedExtPubKeys()) {
#     282         [ -  + ]:       1365 :         if (!WriteDescriptorLastHardenedCache(lh_xpub_pair.second, desc_id, lh_xpub_pair.first)) {
#     283                 :          0 :             return false;
#     284                 :          0 :         }
#     285                 :       1365 :     }
#     286                 :     171284 :     return true;
#     287                 :     171284 : }
#     288                 :            : 
#     289                 :            : bool WalletBatch::WriteLockedUTXO(const COutPoint& output)
#     290                 :          2 : {
#     291                 :          2 :     return WriteIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)), uint8_t{'1'});
#     292                 :          2 : }
#     293                 :            : 
#     294                 :            : bool WalletBatch::EraseLockedUTXO(const COutPoint& output)
#     295                 :        126 : {
#     296                 :        126 :     return EraseIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)));
#     297                 :        126 : }
#     298                 :            : 
#     299                 :            : class CWalletScanState {
#     300                 :            : public:
#     301                 :            :     unsigned int nKeys{0};
#     302                 :            :     unsigned int nCKeys{0};
#     303                 :            :     unsigned int nWatchKeys{0};
#     304                 :            :     unsigned int nKeyMeta{0};
#     305                 :            :     unsigned int m_unknown_records{0};
#     306                 :            :     bool fIsEncrypted{false};
#     307                 :            :     bool fAnyUnordered{false};
#     308                 :            :     std::vector<uint256> vWalletUpgrade;
#     309                 :            :     std::map<OutputType, uint256> m_active_external_spks;
#     310                 :            :     std::map<OutputType, uint256> m_active_internal_spks;
#     311                 :            :     std::map<uint256, DescriptorCache> m_descriptor_caches;
#     312                 :            :     std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys;
#     313                 :            :     std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
#     314                 :            :     std::map<uint160, CHDChain> m_hd_chains;
#     315                 :            :     bool tx_corrupt{false};
#     316                 :            : 
#     317                 :        852 :     CWalletScanState() {
#     318                 :        852 :     }
#     319                 :            : };
#     320                 :            : 
#     321                 :            : static bool
#     322                 :            : ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
#     323                 :            :              CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
#     324                 :      60798 : {
#     325                 :      60798 :     try {
#     326                 :            :         // Unserialize
#     327                 :            :         // Taking advantage of the fact that pair serialization
#     328                 :            :         // is just the two items serialized one after the other
#     329                 :      60798 :         ssKey >> strType;
#     330                 :            :         // If we have a filter, check if this matches the filter
#     331 [ +  + ][ +  + ]:      60798 :         if (filter_fn && !filter_fn(strType)) {
#     332                 :         10 :             return true;
#     333                 :         10 :         }
#     334         [ +  + ]:      60788 :         if (strType == DBKeys::NAME) {
#     335                 :       4761 :             std::string strAddress;
#     336                 :       4761 :             ssKey >> strAddress;
#     337                 :       4761 :             std::string label;
#     338                 :       4761 :             ssValue >> label;
#     339                 :       4761 :             pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
#     340         [ +  + ]:      56027 :         } else if (strType == DBKeys::PURPOSE) {
#     341                 :       4761 :             std::string strAddress;
#     342                 :       4761 :             ssKey >> strAddress;
#     343                 :       4761 :             ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
#     344         [ +  + ]:      51266 :         } else if (strType == DBKeys::TX) {
#     345                 :      10201 :             uint256 hash;
#     346                 :      10201 :             ssKey >> hash;
#     347                 :            :             // LoadToWallet call below creates a new CWalletTx that fill_wtx
#     348                 :            :             // callback fills with transaction metadata.
#     349                 :      10201 :             auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
#     350         [ -  + ]:      10201 :                 if(!new_tx) {
#     351                 :            :                     // There's some corruption here since the tx we just tried to load was already in the wallet.
#     352                 :            :                     // We don't consider this type of corruption critical, and can fix it by removing tx data and
#     353                 :            :                     // rescanning.
#     354                 :          0 :                     wss.tx_corrupt = true;
#     355                 :          0 :                     return false;
#     356                 :          0 :                 }
#     357                 :      10201 :                 ssValue >> wtx;
#     358         [ -  + ]:      10201 :                 if (wtx.GetHash() != hash)
#     359                 :          0 :                     return false;
#     360                 :            : 
#     361                 :            :                 // Undo serialize changes in 31600
#     362 [ -  + ][ #  # ]:      10201 :                 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
#     363                 :          0 :                 {
#     364         [ #  # ]:          0 :                     if (!ssValue.empty())
#     365                 :          0 :                     {
#     366                 :          0 :                         uint8_t fTmp;
#     367                 :          0 :                         uint8_t fUnused;
#     368                 :          0 :                         std::string unused_string;
#     369                 :          0 :                         ssValue >> fTmp >> fUnused >> unused_string;
#     370                 :          0 :                         strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
#     371                 :          0 :                                            wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
#     372                 :          0 :                         wtx.fTimeReceivedIsTxTime = fTmp;
#     373                 :          0 :                     }
#     374                 :          0 :                     else
#     375                 :          0 :                     {
#     376                 :          0 :                         strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
#     377                 :          0 :                         wtx.fTimeReceivedIsTxTime = 0;
#     378                 :          0 :                     }
#     379                 :          0 :                     wss.vWalletUpgrade.push_back(hash);
#     380                 :          0 :                 }
#     381                 :            : 
#     382         [ -  + ]:      10201 :                 if (wtx.nOrderPos == -1)
#     383                 :          0 :                     wss.fAnyUnordered = true;
#     384                 :            : 
#     385                 :      10201 :                 return true;
#     386                 :      10201 :             };
#     387         [ -  + ]:      10201 :             if (!pwallet->LoadToWallet(hash, fill_wtx)) {
#     388                 :          0 :                 return false;
#     389                 :          0 :             }
#     390         [ +  + ]:      41065 :         } else if (strType == DBKeys::WATCHS) {
#     391                 :        258 :             wss.nWatchKeys++;
#     392                 :        258 :             CScript script;
#     393                 :        258 :             ssKey >> script;
#     394                 :        258 :             uint8_t fYes;
#     395                 :        258 :             ssValue >> fYes;
#     396         [ +  - ]:        258 :             if (fYes == '1') {
#     397                 :        258 :                 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
#     398                 :        258 :             }
#     399         [ +  + ]:      40807 :         } else if (strType == DBKeys::KEY) {
#     400                 :      10972 :             CPubKey vchPubKey;
#     401                 :      10972 :             ssKey >> vchPubKey;
#     402         [ -  + ]:      10972 :             if (!vchPubKey.IsValid())
#     403                 :          0 :             {
#     404                 :          0 :                 strErr = "Error reading wallet database: CPubKey corrupt";
#     405                 :          0 :                 return false;
#     406                 :          0 :             }
#     407                 :      10972 :             CKey key;
#     408                 :      10972 :             CPrivKey pkey;
#     409                 :      10972 :             uint256 hash;
#     410                 :            : 
#     411                 :      10972 :             wss.nKeys++;
#     412                 :      10972 :             ssValue >> pkey;
#     413                 :            : 
#     414                 :            :             // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
#     415                 :            :             // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
#     416                 :            :             // using EC operations as a checksum.
#     417                 :            :             // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
#     418                 :            :             // remaining backwards-compatible.
#     419                 :      10972 :             try
#     420                 :      10972 :             {
#     421                 :      10972 :                 ssValue >> hash;
#     422                 :      10972 :             }
#     423                 :      10972 :             catch (const std::ios_base::failure&) {}
#     424                 :            : 
#     425                 :      10972 :             bool fSkipCheck = false;
#     426                 :            : 
#     427         [ +  - ]:      10972 :             if (!hash.IsNull())
#     428                 :      10972 :             {
#     429                 :            :                 // hash pubkey/privkey to accelerate wallet load
#     430                 :      10972 :                 std::vector<unsigned char> vchKey;
#     431                 :      10972 :                 vchKey.reserve(vchPubKey.size() + pkey.size());
#     432                 :      10972 :                 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
#     433                 :      10972 :                 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
#     434                 :            : 
#     435         [ -  + ]:      10972 :                 if (Hash(vchKey) != hash)
#     436                 :          0 :                 {
#     437                 :          0 :                     strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
#     438                 :          0 :                     return false;
#     439                 :          0 :                 }
#     440                 :            : 
#     441                 :      10972 :                 fSkipCheck = true;
#     442                 :      10972 :             }
#     443                 :            : 
#     444         [ -  + ]:      10972 :             if (!key.Load(pkey, vchPubKey, fSkipCheck))
#     445                 :          0 :             {
#     446                 :          0 :                 strErr = "Error reading wallet database: CPrivKey corrupt";
#     447                 :          0 :                 return false;
#     448                 :          0 :             }
#     449         [ -  + ]:      10972 :             if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
#     450                 :          0 :             {
#     451                 :          0 :                 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
#     452                 :          0 :                 return false;
#     453                 :          0 :             }
#     454         [ +  + ]:      29835 :         } else if (strType == DBKeys::MASTER_KEY) {
#     455                 :            :             // Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
#     456                 :         20 :             unsigned int nID;
#     457                 :         20 :             ssKey >> nID;
#     458                 :         20 :             CMasterKey kMasterKey;
#     459                 :         20 :             ssValue >> kMasterKey;
#     460         [ -  + ]:         20 :             if(pwallet->mapMasterKeys.count(nID) != 0)
#     461                 :          0 :             {
#     462                 :          0 :                 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
#     463                 :          0 :                 return false;
#     464                 :          0 :             }
#     465                 :         20 :             pwallet->mapMasterKeys[nID] = kMasterKey;
#     466         [ +  - ]:         20 :             if (pwallet->nMasterKeyMaxID < nID)
#     467                 :         20 :                 pwallet->nMasterKeyMaxID = nID;
#     468         [ +  + ]:      29815 :         } else if (strType == DBKeys::CRYPTED_KEY) {
#     469                 :        150 :             CPubKey vchPubKey;
#     470                 :        150 :             ssKey >> vchPubKey;
#     471         [ -  + ]:        150 :             if (!vchPubKey.IsValid())
#     472                 :          0 :             {
#     473                 :          0 :                 strErr = "Error reading wallet database: CPubKey corrupt";
#     474                 :          0 :                 return false;
#     475                 :          0 :             }
#     476                 :        150 :             std::vector<unsigned char> vchPrivKey;
#     477                 :        150 :             ssValue >> vchPrivKey;
#     478                 :            : 
#     479                 :            :             // Get the checksum and check it
#     480                 :        150 :             bool checksum_valid = false;
#     481         [ +  - ]:        150 :             if (!ssValue.eof()) {
#     482                 :        150 :                 uint256 checksum;
#     483                 :        150 :                 ssValue >> checksum;
#     484         [ -  + ]:        150 :                 if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
#     485                 :          0 :                     strErr = "Error reading wallet database: Encrypted key corrupt";
#     486                 :          0 :                     return false;
#     487                 :          0 :                 }
#     488                 :        150 :             }
#     489                 :            : 
#     490                 :        150 :             wss.nCKeys++;
#     491                 :            : 
#     492         [ -  + ]:        150 :             if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
#     493                 :          0 :             {
#     494                 :          0 :                 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
#     495                 :          0 :                 return false;
#     496                 :          0 :             }
#     497                 :        150 :             wss.fIsEncrypted = true;
#     498         [ +  + ]:      29665 :         } else if (strType == DBKeys::KEYMETA) {
#     499                 :      11224 :             CPubKey vchPubKey;
#     500                 :      11224 :             ssKey >> vchPubKey;
#     501                 :      11224 :             CKeyMetadata keyMeta;
#     502                 :      11224 :             ssValue >> keyMeta;
#     503                 :      11224 :             wss.nKeyMeta++;
#     504                 :      11224 :             pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
#     505                 :            : 
#     506                 :            :             // Extract some CHDChain info from this metadata if it has any
#     507 [ +  - ][ +  + ]:      11224 :             if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && !keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) {
#                 [ +  - ]
#     508                 :            :                 // Get the path from the key origin or from the path string
#     509                 :            :                 // Not applicable when path is "s" or "m" as those indicate a seed
#     510                 :            :                 // See https://github.com/bitcoin/bitcoin/pull/12924
#     511                 :      10999 :                 bool internal = false;
#     512                 :      10999 :                 uint32_t index = 0;
#     513 [ +  + ][ +  - ]:      10999 :                 if (keyMeta.hdKeypath != "s" && keyMeta.hdKeypath != "m") {
#     514                 :      10777 :                     std::vector<uint32_t> path;
#     515         [ +  - ]:      10777 :                     if (keyMeta.has_key_origin) {
#     516                 :            :                         // We have a key origin, so pull it from its path vector
#     517                 :      10777 :                         path = keyMeta.key_origin.path;
#     518                 :      10777 :                     } else {
#     519                 :            :                         // No key origin, have to parse the string
#     520         [ #  # ]:          0 :                         if (!ParseHDKeypath(keyMeta.hdKeypath, path)) {
#     521                 :          0 :                             strErr = "Error reading wallet database: keymeta with invalid HD keypath";
#     522                 :          0 :                             return false;
#     523                 :          0 :                         }
#     524                 :          0 :                     }
#     525                 :            : 
#     526                 :            :                     // Extract the index and internal from the path
#     527                 :            :                     // Path string is m/0'/k'/i'
#     528                 :            :                     // Path vector is [0', k', i'] (but as ints OR'd with the hardened bit
#     529                 :            :                     // k == 0 for external, 1 for internal. i is the index
#     530         [ -  + ]:      10777 :                     if (path.size() != 3) {
#     531                 :          0 :                         strErr = "Error reading wallet database: keymeta found with unexpected path";
#     532                 :          0 :                         return false;
#     533                 :          0 :                     }
#     534         [ -  + ]:      10777 :                     if (path[0] != 0x80000000) {
#     535                 :          0 :                         strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000) for the element at index 0", path[0]);
#     536                 :          0 :                         return false;
#     537                 :          0 :                     }
#     538 [ +  + ][ -  + ]:      10777 :                     if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) {
#     539                 :          0 :                         strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000 or 0x80000001) for the element at index 1", path[1]);
#     540                 :          0 :                         return false;
#     541                 :          0 :                     }
#     542         [ -  + ]:      10777 :                     if ((path[2] & 0x80000000) == 0) {
#     543                 :          0 :                         strErr = strprintf("Unexpected path index of 0x%08x (expected to be greater than or equal to 0x80000000)", path[2]);
#     544                 :          0 :                         return false;
#     545                 :          0 :                     }
#     546                 :      10777 :                     internal = path[1] == (1 | 0x80000000);
#     547                 :      10777 :                     index = path[2] & ~0x80000000;
#     548                 :      10777 :                 }
#     549                 :            : 
#     550                 :            :                 // Insert a new CHDChain, or get the one that already exists
#     551                 :      10999 :                 auto ins = wss.m_hd_chains.emplace(keyMeta.hd_seed_id, CHDChain());
#     552                 :      10999 :                 CHDChain& chain = ins.first->second;
#     553         [ +  + ]:      10999 :                 if (ins.second) {
#     554                 :            :                     // For new chains, we want to default to VERSION_HD_BASE until we see an internal
#     555                 :        222 :                     chain.nVersion = CHDChain::VERSION_HD_BASE;
#     556                 :        222 :                     chain.seed_id = keyMeta.hd_seed_id;
#     557                 :        222 :                 }
#     558         [ +  + ]:      10999 :                 if (internal) {
#     559                 :       4618 :                     chain.nVersion = CHDChain::VERSION_HD_CHAIN_SPLIT;
#     560                 :       4618 :                     chain.nInternalChainCounter = std::max(chain.nInternalChainCounter, index + 1);
#     561                 :       6381 :                 } else {
#     562                 :       6381 :                     chain.nExternalChainCounter = std::max(chain.nExternalChainCounter, index + 1);
#     563                 :       6381 :                 }
#     564                 :      10999 :             }
#     565         [ +  + ]:      18441 :         } else if (strType == DBKeys::WATCHMETA) {
#     566                 :        258 :             CScript script;
#     567                 :        258 :             ssKey >> script;
#     568                 :        258 :             CKeyMetadata keyMeta;
#     569                 :        258 :             ssValue >> keyMeta;
#     570                 :        258 :             wss.nKeyMeta++;
#     571                 :        258 :             pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
#     572         [ -  + ]:      18183 :         } else if (strType == DBKeys::DEFAULTKEY) {
#     573                 :            :             // We don't want or need the default key, but if there is one set,
#     574                 :            :             // we want to make sure that it is valid so that we can detect corruption
#     575                 :          0 :             CPubKey vchPubKey;
#     576                 :          0 :             ssValue >> vchPubKey;
#     577         [ #  # ]:          0 :             if (!vchPubKey.IsValid()) {
#     578                 :          0 :                 strErr = "Error reading wallet database: Default Key corrupt";
#     579                 :          0 :                 return false;
#     580                 :          0 :             }
#     581         [ +  + ]:      18183 :         } else if (strType == DBKeys::POOL) {
#     582                 :       8009 :             int64_t nIndex;
#     583                 :       8009 :             ssKey >> nIndex;
#     584                 :       8009 :             CKeyPool keypool;
#     585                 :       8009 :             ssValue >> keypool;
#     586                 :            : 
#     587                 :       8009 :             pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
#     588         [ +  + ]:      10174 :         } else if (strType == DBKeys::CSCRIPT) {
#     589                 :       2868 :             uint160 hash;
#     590                 :       2868 :             ssKey >> hash;
#     591                 :       2868 :             CScript script;
#     592                 :       2868 :             ssValue >> script;
#     593         [ -  + ]:       2868 :             if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script))
#     594                 :          0 :             {
#     595                 :          0 :                 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
#     596                 :          0 :                 return false;
#     597                 :          0 :             }
#     598         [ +  + ]:       7306 :         } else if (strType == DBKeys::ORDERPOSNEXT) {
#     599                 :        168 :             ssValue >> pwallet->nOrderPosNext;
#     600         [ -  + ]:       7138 :         } else if (strType == DBKeys::DESTDATA) {
#     601                 :          0 :             std::string strAddress, strKey, strValue;
#     602                 :          0 :             ssKey >> strAddress;
#     603                 :          0 :             ssKey >> strKey;
#     604                 :          0 :             ssValue >> strValue;
#     605                 :          0 :             pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue);
#     606         [ +  + ]:       7138 :         } else if (strType == DBKeys::HDCHAIN) {
#     607                 :        209 :             CHDChain chain;
#     608                 :        209 :             ssValue >> chain;
#     609                 :        209 :             pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain);
#     610         [ -  + ]:       6929 :         } else if (strType == DBKeys::OLD_KEY) {
#     611                 :          0 :             strErr = "Found unsupported 'wkey' record, try loading with version 0.18";
#     612                 :          0 :             return false;
#     613 [ +  + ][ +  + ]:       6929 :         } else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
#     614                 :        926 :             uint8_t type;
#     615                 :        926 :             ssKey >> type;
#     616                 :        926 :             uint256 id;
#     617                 :        926 :             ssValue >> id;
#     618                 :            : 
#     619                 :        926 :             bool internal = strType == DBKeys::ACTIVEINTERNALSPK;
#     620         [ +  + ]:        926 :             auto& spk_mans = internal ? wss.m_active_internal_spks : wss.m_active_external_spks;
#     621         [ -  + ]:        926 :             if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
#     622                 :          0 :                 strErr = "Multiple ScriptPubKeyMans specified for a single type";
#     623                 :          0 :                 return false;
#     624                 :          0 :             }
#     625                 :        926 :             spk_mans[static_cast<OutputType>(type)] = id;
#     626         [ +  + ]:       6003 :         } else if (strType == DBKeys::WALLETDESCRIPTOR) {
#     627                 :       1077 :             uint256 id;
#     628                 :       1077 :             ssKey >> id;
#     629                 :       1077 :             WalletDescriptor desc;
#     630                 :       1077 :             ssValue >> desc;
#     631         [ +  + ]:       1077 :             if (wss.m_descriptor_caches.count(id) == 0) {
#     632                 :        100 :                 wss.m_descriptor_caches[id] = DescriptorCache();
#     633                 :        100 :             }
#     634                 :       1077 :             pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
#     635         [ +  + ]:       4926 :         } else if (strType == DBKeys::WALLETDESCRIPTORCACHE) {
#     636                 :       1005 :             bool parent = true;
#     637                 :       1005 :             uint256 desc_id;
#     638                 :       1005 :             uint32_t key_exp_index;
#     639                 :       1005 :             uint32_t der_index;
#     640                 :       1005 :             ssKey >> desc_id;
#     641                 :       1005 :             ssKey >> key_exp_index;
#     642                 :            : 
#     643                 :            :             // if the der_index exists, it's a derived xpub
#     644                 :       1005 :             try
#     645                 :       1005 :             {
#     646                 :       1005 :                 ssKey >> der_index;
#     647                 :       1005 :                 parent = false;
#     648                 :       1005 :             }
#     649                 :       1005 :             catch (...) {}
#     650                 :            : 
#     651                 :       1005 :             std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
#     652                 :       1005 :             ssValue >> ser_xpub;
#     653                 :       1005 :             CExtPubKey xpub;
#     654                 :       1005 :             xpub.Decode(ser_xpub.data());
#     655         [ +  - ]:       1005 :             if (parent) {
#     656                 :       1005 :                 wss.m_descriptor_caches[desc_id].CacheParentExtPubKey(key_exp_index, xpub);
#     657                 :       1005 :             } else {
#     658                 :          0 :                 wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey(key_exp_index, der_index, xpub);
#     659                 :          0 :             }
#     660         [ +  + ]:       3921 :         } else if (strType == DBKeys::WALLETDESCRIPTORLHCACHE) {
#     661                 :        992 :             uint256 desc_id;
#     662                 :        992 :             uint32_t key_exp_index;
#     663                 :        992 :             ssKey >> desc_id;
#     664                 :        992 :             ssKey >> key_exp_index;
#     665                 :            : 
#     666                 :        992 :             std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
#     667                 :        992 :             ssValue >> ser_xpub;
#     668                 :        992 :             CExtPubKey xpub;
#     669                 :        992 :             xpub.Decode(ser_xpub.data());
#     670                 :        992 :             wss.m_descriptor_caches[desc_id].CacheLastHardenedExtPubKey(key_exp_index, xpub);
#     671         [ +  + ]:       2929 :         } else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
#     672                 :        907 :             uint256 desc_id;
#     673                 :        907 :             CPubKey pubkey;
#     674                 :        907 :             ssKey >> desc_id;
#     675                 :        907 :             ssKey >> pubkey;
#     676         [ -  + ]:        907 :             if (!pubkey.IsValid())
#     677                 :          0 :             {
#     678                 :          0 :                 strErr = "Error reading wallet database: CPubKey corrupt";
#     679                 :          0 :                 return false;
#     680                 :          0 :             }
#     681                 :        907 :             CKey key;
#     682                 :        907 :             CPrivKey pkey;
#     683                 :        907 :             uint256 hash;
#     684                 :            : 
#     685                 :        907 :             wss.nKeys++;
#     686                 :        907 :             ssValue >> pkey;
#     687                 :        907 :             ssValue >> hash;
#     688                 :            : 
#     689                 :            :             // hash pubkey/privkey to accelerate wallet load
#     690                 :        907 :             std::vector<unsigned char> to_hash;
#     691                 :        907 :             to_hash.reserve(pubkey.size() + pkey.size());
#     692                 :        907 :             to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
#     693                 :        907 :             to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
#     694                 :            : 
#     695         [ -  + ]:        907 :             if (Hash(to_hash) != hash)
#     696                 :          0 :             {
#     697                 :          0 :                 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
#     698                 :          0 :                 return false;
#     699                 :          0 :             }
#     700                 :            : 
#     701         [ -  + ]:        907 :             if (!key.Load(pkey, pubkey, true))
#     702                 :          0 :             {
#     703                 :          0 :                 strErr = "Error reading wallet database: CPrivKey corrupt";
#     704                 :          0 :                 return false;
#     705                 :          0 :             }
#     706                 :        907 :             wss.m_descriptor_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key));
#     707         [ +  + ]:       2022 :         } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
#     708                 :        151 :             uint256 desc_id;
#     709                 :        151 :             CPubKey pubkey;
#     710                 :        151 :             ssKey >> desc_id;
#     711                 :        151 :             ssKey >> pubkey;
#     712         [ -  + ]:        151 :             if (!pubkey.IsValid())
#     713                 :          0 :             {
#     714                 :          0 :                 strErr = "Error reading wallet database: CPubKey corrupt";
#     715                 :          0 :                 return false;
#     716                 :          0 :             }
#     717                 :        151 :             std::vector<unsigned char> privkey;
#     718                 :        151 :             ssValue >> privkey;
#     719                 :        151 :             wss.nCKeys++;
#     720                 :            : 
#     721                 :        151 :             wss.m_descriptor_crypt_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(pubkey, privkey)));
#     722                 :        151 :             wss.fIsEncrypted = true;
#     723         [ +  + ]:       1871 :         } else if (strType == DBKeys::LOCKED_UTXO) {
#     724                 :          4 :             uint256 hash;
#     725                 :          4 :             uint32_t n;
#     726                 :          4 :             ssKey >> hash;
#     727                 :          4 :             ssKey >> n;
#     728                 :          4 :             pwallet->LockCoin(COutPoint(hash, n));
#     729 [ +  + ][ +  + ]:       1867 :         } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
#     730 [ +  + ][ +  - ]:       1867 :                    strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
#     731 [ +  + ][ +  - ]:       1867 :                    strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
#     732         [ -  + ]:       1867 :                    strType != DBKeys::FLAGS) {
#     733                 :          0 :             wss.m_unknown_records++;
#     734                 :          0 :         }
#     735                 :      60788 :     } catch (const std::exception& e) {
#     736         [ #  # ]:          0 :         if (strErr.empty()) {
#     737                 :          0 :             strErr = e.what();
#     738                 :          0 :         }
#     739                 :          0 :         return false;
#     740                 :          0 :     } catch (...) {
#     741         [ #  # ]:          0 :         if (strErr.empty()) {
#     742                 :          0 :             strErr = "Caught unknown exception in ReadKeyValue";
#     743                 :          0 :         }
#     744                 :          0 :         return false;
#     745                 :          0 :     }
#     746                 :      60788 :     return true;
#     747                 :      60798 : }
#     748                 :            : 
#     749                 :            : bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
#     750                 :         14 : {
#     751                 :         14 :     CWalletScanState dummy_wss;
#     752                 :         14 :     LOCK(pwallet->cs_wallet);
#     753                 :         14 :     return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
#     754                 :         14 : }
#     755                 :            : 
#     756                 :            : bool WalletBatch::IsKeyType(const std::string& strType)
#     757                 :         28 : {
#     758         [ +  + ]:         28 :     return (strType == DBKeys::KEY ||
#     759 [ -  + ][ -  + ]:         28 :             strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY);
#     760                 :         28 : }
#     761                 :            : 
#     762                 :            : DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
#     763                 :        838 : {
#     764                 :        838 :     CWalletScanState wss;
#     765                 :        838 :     bool fNoncriticalErrors = false;
#     766                 :        838 :     bool rescan_required = false;
#     767                 :        838 :     DBErrors result = DBErrors::LOAD_OK;
#     768                 :            : 
#     769                 :        838 :     LOCK(pwallet->cs_wallet);
#     770                 :        838 :     try {
#     771                 :        838 :         int nMinVersion = 0;
#     772         [ +  + ]:        838 :         if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
#     773         [ -  + ]:        343 :             if (nMinVersion > FEATURE_LATEST)
#     774                 :          0 :                 return DBErrors::TOO_NEW;
#     775                 :        343 :             pwallet->LoadMinVersion(nMinVersion);
#     776                 :        343 :         }
#     777                 :            : 
#     778                 :            :         // Load wallet flags, so they are known when processing other records.
#     779                 :            :         // The FLAGS key is absent during wallet creation.
#     780                 :        838 :         uint64_t flags;
#     781         [ +  + ]:        838 :         if (m_batch->Read(DBKeys::FLAGS, flags)) {
#     782         [ -  + ]:        343 :             if (!pwallet->LoadWalletFlags(flags)) {
#     783                 :          0 :                 pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
#     784                 :          0 :                 return DBErrors::CORRUPT;
#     785                 :          0 :             }
#     786                 :        343 :         }
#     787                 :            : 
#     788                 :            : #ifndef ENABLE_EXTERNAL_SIGNER
#     789                 :            :         if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
#     790                 :            :             pwallet->WalletLogPrintf("Error: External signer wallet being loaded without external signer support compiled\n");
#     791                 :            :             return DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED;
#     792                 :            :         }
#     793                 :            : #endif
#     794                 :            : 
#     795                 :            :         // Get cursor
#     796         [ -  + ]:        838 :         if (!m_batch->StartCursor())
#     797                 :          0 :         {
#     798                 :          0 :             pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
#     799                 :          0 :             return DBErrors::CORRUPT;
#     800                 :          0 :         }
#     801                 :            : 
#     802                 :      61622 :         while (true)
#     803                 :      61622 :         {
#     804                 :            :             // Read next record
#     805                 :      61622 :             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     806                 :      61622 :             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
#     807                 :      61622 :             bool complete;
#     808                 :      61622 :             bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
#     809         [ +  + ]:      61622 :             if (complete) {
#     810                 :        838 :                 break;
#     811                 :        838 :             }
#     812         [ -  + ]:      60784 :             else if (!ret)
#     813                 :          0 :             {
#     814                 :          0 :                 m_batch->CloseCursor();
#     815                 :          0 :                 pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
#     816                 :          0 :                 return DBErrors::CORRUPT;
#     817                 :          0 :             }
#     818                 :            : 
#     819                 :            :             // Try to be tolerant of single corrupt records:
#     820                 :      60784 :             std::string strType, strErr;
#     821         [ -  + ]:      60784 :             if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
#     822                 :          0 :             {
#     823                 :            :                 // losing keys is considered a catastrophic error, anything else
#     824                 :            :                 // we assume the user can live with:
#     825 [ #  # ][ #  # ]:          0 :                 if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
#     826                 :          0 :                     result = DBErrors::CORRUPT;
#     827         [ #  # ]:          0 :                 } else if (strType == DBKeys::FLAGS) {
#     828                 :            :                     // reading the wallet flags can only fail if unknown flags are present
#     829                 :          0 :                     result = DBErrors::TOO_NEW;
#     830         [ #  # ]:          0 :                 } else if (wss.tx_corrupt) {
#     831                 :          0 :                     pwallet->WalletLogPrintf("Error: Corrupt transaction found. This can be fixed by removing transactions from wallet and rescanning.\n");
#     832                 :            :                     // Set tx_corrupt back to false so that the error is only printed once (per corrupt tx)
#     833                 :          0 :                     wss.tx_corrupt = false;
#     834                 :          0 :                     result = DBErrors::CORRUPT;
#     835                 :          0 :                 } else {
#     836                 :            :                     // Leave other errors alone, if we try to fix them we might make things worse.
#     837                 :          0 :                     fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
#     838         [ #  # ]:          0 :                     if (strType == DBKeys::TX)
#     839                 :            :                         // Rescan if there is a bad transaction record:
#     840                 :          0 :                         rescan_required = true;
#     841                 :          0 :                 }
#     842                 :          0 :             }
#     843         [ -  + ]:      60784 :             if (!strErr.empty())
#     844                 :          0 :                 pwallet->WalletLogPrintf("%s\n", strErr);
#     845                 :      60784 :         }
#     846                 :        838 :     } catch (...) {
#     847                 :          0 :         result = DBErrors::CORRUPT;
#     848                 :          0 :     }
#     849                 :        838 :     m_batch->CloseCursor();
#     850                 :            : 
#     851                 :            :     // Set the active ScriptPubKeyMans
#     852         [ +  + ]:        838 :     for (auto spk_man_pair : wss.m_active_external_spks) {
#     853                 :        464 :         pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /*internal=*/false);
#     854                 :        464 :     }
#     855         [ +  + ]:        838 :     for (auto spk_man_pair : wss.m_active_internal_spks) {
#     856                 :        462 :         pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /*internal=*/true);
#     857                 :        462 :     }
#     858                 :            : 
#     859                 :            :     // Set the descriptor caches
#     860         [ +  + ]:       1077 :     for (auto desc_cache_pair : wss.m_descriptor_caches) {
#     861                 :       1077 :         auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first);
#     862                 :       1077 :         assert(spk_man);
#     863                 :          0 :         ((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second);
#     864                 :       1077 :     }
#     865                 :            : 
#     866                 :            :     // Set the descriptor keys
#     867         [ +  + ]:        907 :     for (auto desc_key_pair : wss.m_descriptor_keys) {
#     868                 :        907 :         auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
#     869                 :        907 :         ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second);
#     870                 :        907 :     }
#     871         [ +  + ]:        838 :     for (auto desc_key_pair : wss.m_descriptor_crypt_keys) {
#     872                 :        151 :         auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
#     873                 :        151 :         ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second);
#     874                 :        151 :     }
#     875                 :            : 
#     876 [ -  + ][ #  # ]:        838 :     if (rescan_required && result == DBErrors::LOAD_OK) {
#     877                 :          0 :         result = DBErrors::NEED_RESCAN;
#     878 [ -  + ][ #  # ]:        838 :     } else if (fNoncriticalErrors && result == DBErrors::LOAD_OK) {
#     879                 :          0 :         result = DBErrors::NONCRITICAL_ERROR;
#     880                 :          0 :     }
#     881                 :            : 
#     882                 :            :     // Any wallet corruption at all: skip any rewriting or
#     883                 :            :     // upgrading, we don't want to make it worse.
#     884         [ -  + ]:        838 :     if (result != DBErrors::LOAD_OK)
#     885                 :          0 :         return result;
#     886                 :            : 
#     887                 :            :     // Last client version to open this wallet, was previously the file version number
#     888                 :        838 :     int last_client = CLIENT_VERSION;
#     889                 :        838 :     m_batch->Read(DBKeys::VERSION, last_client);
#     890                 :            : 
#     891                 :        838 :     int wallet_version = pwallet->GetVersion();
#     892         [ +  - ]:        838 :     pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
#     893                 :            : 
#     894                 :        838 :     pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
#     895                 :        838 :            wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
#     896                 :            : 
#     897                 :            :     // nTimeFirstKey is only reliable if all keys have metadata
#     898 [ +  + ][ +  + ]:        838 :     if (pwallet->IsLegacy() && (wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) {
#     899                 :          3 :         auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan();
#     900         [ +  - ]:          3 :         if (spk_man) {
#     901                 :          3 :             LOCK(spk_man->cs_KeyStore);
#     902                 :          3 :             spk_man->UpdateTimeFirstKey(1);
#     903                 :          3 :         }
#     904                 :          3 :     }
#     905                 :            : 
#     906         [ -  + ]:        838 :     for (const uint256& hash : wss.vWalletUpgrade)
#     907                 :          0 :         WriteTx(pwallet->mapWallet.at(hash));
#     908                 :            : 
#     909                 :            :     // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
#     910 [ +  + ][ -  + ]:        838 :     if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
#                 [ -  + ]
#     911                 :          0 :         return DBErrors::NEED_REWRITE;
#     912                 :            : 
#     913         [ -  + ]:        838 :     if (last_client < CLIENT_VERSION) // Update
#     914                 :          0 :         m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
#     915                 :            : 
#     916         [ -  + ]:        838 :     if (wss.fAnyUnordered)
#     917                 :          0 :         result = pwallet->ReorderTransactions();
#     918                 :            : 
#     919                 :            :     // Upgrade all of the wallet keymetadata to have the hd master key id
#     920                 :            :     // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
#     921                 :        838 :     try {
#     922                 :        838 :         pwallet->UpgradeKeyMetadata();
#     923                 :        838 :     } catch (...) {
#     924                 :          0 :         result = DBErrors::CORRUPT;
#     925                 :          0 :     }
#     926                 :            : 
#     927                 :            :     // Upgrade all of the descriptor caches to cache the last hardened xpub
#     928                 :            :     // This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
#     929                 :        838 :     try {
#     930                 :        838 :         pwallet->UpgradeDescriptorCache();
#     931                 :        838 :     } catch (...) {
#     932                 :          0 :         result = DBErrors::CORRUPT;
#     933                 :          0 :     }
#     934                 :            : 
#     935                 :            :     // Set the inactive chain
#     936         [ +  + ]:        838 :     if (wss.m_hd_chains.size() > 0) {
#     937                 :        208 :         LegacyScriptPubKeyMan* legacy_spkm = pwallet->GetLegacyScriptPubKeyMan();
#     938         [ -  + ]:        208 :         if (!legacy_spkm) {
#     939                 :          0 :             pwallet->WalletLogPrintf("Inactive HD Chains found but no Legacy ScriptPubKeyMan\n");
#     940                 :          0 :             return DBErrors::CORRUPT;
#     941                 :          0 :         }
#     942         [ +  + ]:        222 :         for (const auto& chain_pair : wss.m_hd_chains) {
#     943         [ +  + ]:        222 :             if (chain_pair.first != pwallet->GetLegacyScriptPubKeyMan()->GetHDChain().seed_id) {
#     944                 :         14 :                 pwallet->GetLegacyScriptPubKeyMan()->AddInactiveHDChain(chain_pair.second);
#     945                 :         14 :             }
#     946                 :        222 :         }
#     947                 :        208 :     }
#     948                 :            : 
#     949                 :        838 :     return result;
#     950                 :        838 : }
#     951                 :            : 
#     952                 :            : DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
#     953                 :          7 : {
#     954                 :          7 :     DBErrors result = DBErrors::LOAD_OK;
#     955                 :            : 
#     956                 :          7 :     try {
#     957                 :          7 :         int nMinVersion = 0;
#     958         [ +  - ]:          7 :         if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
#     959         [ -  + ]:          7 :             if (nMinVersion > FEATURE_LATEST)
#     960                 :          0 :                 return DBErrors::TOO_NEW;
#     961                 :          7 :         }
#     962                 :            : 
#     963                 :            :         // Get cursor
#     964         [ -  + ]:          7 :         if (!m_batch->StartCursor())
#     965                 :          0 :         {
#     966                 :          0 :             LogPrintf("Error getting wallet database cursor\n");
#     967                 :          0 :             return DBErrors::CORRUPT;
#     968                 :          0 :         }
#     969                 :            : 
#     970                 :        250 :         while (true)
#     971                 :        250 :         {
#     972                 :            :             // Read next record
#     973                 :        250 :             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     974                 :        250 :             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
#     975                 :        250 :             bool complete;
#     976                 :        250 :             bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
#     977         [ +  + ]:        250 :             if (complete) {
#     978                 :          7 :                 break;
#     979         [ -  + ]:        243 :             } else if (!ret) {
#     980                 :          0 :                 m_batch->CloseCursor();
#     981                 :          0 :                 LogPrintf("Error reading next record from wallet database\n");
#     982                 :          0 :                 return DBErrors::CORRUPT;
#     983                 :          0 :             }
#     984                 :            : 
#     985                 :        243 :             std::string strType;
#     986                 :        243 :             ssKey >> strType;
#     987         [ +  + ]:        243 :             if (strType == DBKeys::TX) {
#     988                 :          7 :                 uint256 hash;
#     989                 :          7 :                 ssKey >> hash;
#     990                 :          7 :                 vTxHash.push_back(hash);
#     991                 :          7 :                 vWtx.emplace_back(/*tx=*/nullptr, TxStateInactive{});
#     992                 :          7 :                 ssValue >> vWtx.back();
#     993                 :          7 :             }
#     994                 :        243 :         }
#     995                 :          7 :     } catch (...) {
#     996                 :          0 :         result = DBErrors::CORRUPT;
#     997                 :          0 :     }
#     998                 :          7 :     m_batch->CloseCursor();
#     999                 :            : 
#    1000                 :          7 :     return result;
#    1001                 :          7 : }
#    1002                 :            : 
#    1003                 :            : DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
#    1004                 :          7 : {
#    1005                 :            :     // build list of wallet TXs and hashes
#    1006                 :          7 :     std::vector<uint256> vTxHash;
#    1007                 :          7 :     std::list<CWalletTx> vWtx;
#    1008                 :          7 :     DBErrors err = FindWalletTx(vTxHash, vWtx);
#    1009         [ -  + ]:          7 :     if (err != DBErrors::LOAD_OK) {
#    1010                 :          0 :         return err;
#    1011                 :          0 :     }
#    1012                 :            : 
#    1013                 :          7 :     std::sort(vTxHash.begin(), vTxHash.end());
#    1014                 :          7 :     std::sort(vTxHashIn.begin(), vTxHashIn.end());
#    1015                 :            : 
#    1016                 :            :     // erase each matching wallet TX
#    1017                 :          7 :     bool delerror = false;
#    1018                 :          7 :     std::vector<uint256>::iterator it = vTxHashIn.begin();
#    1019         [ +  + ]:          7 :     for (const uint256& hash : vTxHash) {
#    1020 [ +  + ][ +  + ]:          8 :         while (it < vTxHashIn.end() && (*it) < hash) {
#                 [ +  + ]
#    1021                 :          1 :             it++;
#    1022                 :          1 :         }
#    1023         [ +  + ]:          7 :         if (it == vTxHashIn.end()) {
#    1024                 :          1 :             break;
#    1025                 :          1 :         }
#    1026         [ +  + ]:          6 :         else if ((*it) == hash) {
#    1027         [ -  + ]:          5 :             if(!EraseTx(hash)) {
#    1028         [ #  # ]:          0 :                 LogPrint(BCLog::WALLETDB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
#    1029                 :          0 :                 delerror = true;
#    1030                 :          0 :             }
#    1031                 :          5 :             vTxHashOut.push_back(hash);
#    1032                 :          5 :         }
#    1033                 :          7 :     }
#    1034                 :            : 
#    1035         [ -  + ]:          7 :     if (delerror) {
#    1036                 :          0 :         return DBErrors::CORRUPT;
#    1037                 :          0 :     }
#    1038                 :          7 :     return DBErrors::LOAD_OK;
#    1039                 :          7 : }
#    1040                 :            : 
#    1041                 :            : void MaybeCompactWalletDB(WalletContext& context)
#    1042                 :      21245 : {
#    1043                 :      21245 :     static std::atomic<bool> fOneThread(false);
#    1044         [ -  + ]:      21245 :     if (fOneThread.exchange(true)) {
#    1045                 :          0 :         return;
#    1046                 :          0 :     }
#    1047                 :            : 
#    1048         [ +  + ]:      21245 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
#    1049                 :      18855 :         WalletDatabase& dbh = pwallet->GetDatabase();
#    1050                 :            : 
#    1051                 :      18855 :         unsigned int nUpdateCounter = dbh.nUpdateCounter;
#    1052                 :            : 
#    1053         [ +  + ]:      18855 :         if (dbh.nLastSeen != nUpdateCounter) {
#    1054                 :       5146 :             dbh.nLastSeen = nUpdateCounter;
#    1055                 :       5146 :             dbh.nLastWalletUpdate = GetTime();
#    1056                 :       5146 :         }
#    1057                 :            : 
#    1058 [ +  + ][ +  + ]:      18855 :         if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
#    1059         [ +  + ]:       3415 :             if (dbh.PeriodicFlush()) {
#    1060                 :        264 :                 dbh.nLastFlushed = nUpdateCounter;
#    1061                 :        264 :             }
#    1062                 :       3415 :         }
#    1063                 :      18855 :     }
#    1064                 :            : 
#    1065                 :      21245 :     fOneThread = false;
#    1066                 :      21245 : }
#    1067                 :            : 
#    1068                 :            : bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
#    1069                 :         47 : {
#    1070                 :         47 :     return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value);
#    1071                 :         47 : }
#    1072                 :            : 
#    1073                 :            : bool WalletBatch::EraseDestData(const std::string &address, const std::string &key)
#    1074                 :          1 : {
#    1075                 :          1 :     return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)));
#    1076                 :          1 : }
#    1077                 :            : 
#    1078                 :            : 
#    1079                 :            : bool WalletBatch::WriteHDChain(const CHDChain& chain)
#    1080                 :      19868 : {
#    1081                 :      19868 :     return WriteIC(DBKeys::HDCHAIN, chain);
#    1082                 :      19868 : }
#    1083                 :            : 
#    1084                 :            : bool WalletBatch::WriteWalletFlags(const uint64_t flags)
#    1085                 :      15625 : {
#    1086                 :      15625 :     return WriteIC(DBKeys::FLAGS, flags);
#    1087                 :      15625 : }
#    1088                 :            : 
#    1089                 :            : bool WalletBatch::TxnBegin()
#    1090                 :         33 : {
#    1091                 :         33 :     return m_batch->TxnBegin();
#    1092                 :         33 : }
#    1093                 :            : 
#    1094                 :            : bool WalletBatch::TxnCommit()
#    1095                 :         33 : {
#    1096                 :         33 :     return m_batch->TxnCommit();
#    1097                 :         33 : }
#    1098                 :            : 
#    1099                 :            : bool WalletBatch::TxnAbort()
#    1100                 :          0 : {
#    1101                 :          0 :     return m_batch->TxnAbort();
#    1102                 :          0 : }
#    1103                 :            : 
#    1104                 :            : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
#    1105                 :       1604 : {
#    1106                 :       1604 :     bool exists;
#    1107                 :       1604 :     try {
#    1108                 :       1604 :         exists = fs::symlink_status(path).type() != fs::file_type::not_found;
#    1109                 :       1604 :     } catch (const fs::filesystem_error& e) {
#    1110                 :          0 :         error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e)));
#    1111                 :          0 :         status = DatabaseStatus::FAILED_BAD_PATH;
#    1112                 :          0 :         return nullptr;
#    1113                 :          0 :     }
#    1114                 :            : 
#    1115                 :       1604 :     std::optional<DatabaseFormat> format;
#    1116         [ +  + ]:       1604 :     if (exists) {
#    1117         [ +  + ]:       1272 :         if (IsBDBFile(BDBDataFile(path))) {
#    1118                 :        329 :             format = DatabaseFormat::BERKELEY;
#    1119                 :        329 :         }
#    1120         [ +  + ]:       1272 :         if (IsSQLiteFile(SQLiteDataFile(path))) {
#    1121         [ -  + ]:        174 :             if (format) {
#    1122                 :          0 :                 error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", fs::PathToString(path)));
#    1123                 :          0 :                 status = DatabaseStatus::FAILED_BAD_FORMAT;
#    1124                 :          0 :                 return nullptr;
#    1125                 :          0 :             }
#    1126                 :        174 :             format = DatabaseFormat::SQLITE;
#    1127                 :        174 :         }
#    1128         [ +  + ]:       1272 :     } else if (options.require_existing) {
#    1129                 :          6 :         error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", fs::PathToString(path)));
#    1130                 :          6 :         status = DatabaseStatus::FAILED_NOT_FOUND;
#    1131                 :          6 :         return nullptr;
#    1132                 :          6 :     }
#    1133                 :            : 
#    1134 [ +  + ][ +  + ]:       1598 :     if (!format && options.require_existing) {
#    1135                 :        617 :         error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", fs::PathToString(path)));
#    1136                 :        617 :         status = DatabaseStatus::FAILED_BAD_FORMAT;
#    1137                 :        617 :         return nullptr;
#    1138                 :        617 :     }
#    1139                 :            : 
#    1140 [ +  + ][ +  + ]:        981 :     if (format && options.require_create) {
#    1141                 :          5 :         error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(path)));
#    1142                 :          5 :         status = DatabaseStatus::FAILED_ALREADY_EXISTS;
#    1143                 :          5 :         return nullptr;
#    1144                 :          5 :     }
#    1145                 :            : 
#    1146                 :            :     // A db already exists so format is set, but options also specifies the format, so make sure they agree
#    1147 [ +  + ][ +  + ]:        976 :     if (format && options.require_format && format != options.require_format) {
#                 [ -  + ]
#    1148                 :          0 :         error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", fs::PathToString(path)));
#    1149                 :          0 :         status = DatabaseStatus::FAILED_BAD_FORMAT;
#    1150                 :          0 :         return nullptr;
#    1151                 :          0 :     }
#    1152                 :            : 
#    1153                 :            :     // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
#    1154 [ +  + ][ +  + ]:        976 :     if (!format && options.require_format) format = options.require_format;
#    1155                 :            : 
#    1156                 :            :     // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
#    1157         [ +  + ]:        976 :     if (!format) {
#    1158                 :        269 : #ifdef USE_SQLITE
#    1159                 :        269 :         format = DatabaseFormat::SQLITE;
#    1160                 :        269 : #endif
#    1161                 :        269 : #ifdef USE_BDB
#    1162                 :        269 :         format = DatabaseFormat::BERKELEY;
#    1163                 :        269 : #endif
#    1164                 :        269 :     }
#    1165                 :            : 
#    1166         [ +  + ]:        976 :     if (format == DatabaseFormat::SQLITE) {
#    1167                 :        374 : #ifdef USE_SQLITE
#    1168                 :        374 :         return MakeSQLiteDatabase(path, options, status, error);
#    1169                 :          0 : #endif
#    1170                 :          0 :         error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", fs::PathToString(path)));
#    1171                 :          0 :         status = DatabaseStatus::FAILED_BAD_FORMAT;
#    1172                 :          0 :         return nullptr;
#    1173                 :        374 :     }
#    1174                 :            : 
#    1175                 :        602 : #ifdef USE_BDB
#    1176                 :        602 :     return MakeBerkeleyDatabase(path, options, status, error);
#    1177                 :          0 : #endif
#    1178                 :          0 :     error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
#    1179                 :          0 :     status = DatabaseStatus::FAILED_BAD_FORMAT;
#    1180                 :          0 :     return nullptr;
#    1181                 :        976 : }
#    1182                 :            : 
#    1183                 :            : /** Return object for accessing dummy database with no read/write capabilities. */
#    1184                 :            : std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
#    1185                 :         32 : {
#    1186                 :         32 :     return std::make_unique<DummyDatabase>();
#    1187                 :         32 : }
#    1188                 :            : 
#    1189                 :            : /** Return object for accessing temporary in-memory database. */
#    1190                 :            : std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
#    1191                 :         20 : {
#    1192                 :         20 :     DatabaseOptions options;
#    1193                 :         20 : #ifdef USE_SQLITE
#    1194                 :         20 :     return std::make_unique<SQLiteDatabase>("", "", options, true);
#    1195                 :            : #elif USE_BDB
#    1196                 :            :     return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "", options);
#    1197                 :            : #endif
#    1198                 :         20 : }
#    1199                 :            : } // namespace wallet

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a