LCOV - code coverage report
Current view: top level - src/wallet - walletdb.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 512 680 75.3 %
Date: 2020-09-26 01:30:44 Functions: 73 77 94.8 %

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

Generated by: LCOV version 1.15