LCOV - code coverage report
Current view: top level - src/wallet - walletdb.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 567 786 72.1 %
Date: 2021-06-29 14:35:33 Functions: 41 45 91.1 %
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: 226 324 69.8 %

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

Generated by: LCOV version 1.14