LCOV - code coverage report
Current view: top level - src/wallet - walletdb.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 352 520 67.7 %
Date: 2025-02-23 09:33:43 Functions: 37 52 71.2 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin developers
       3             : // Copyright (c) 2014-2015 The Dash developers
       4             : // Copyright (c) 2015-2021 The PIVX Core developers
       5             : // Distributed under the MIT/X11 software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #include "wallet/walletdb.h"
       9             : 
      10             : #include "fs.h"
      11             : 
      12             : #include "key_io.h"
      13             : #include "protocol.h"
      14             : #include "reverse_iterate.h"
      15             : #include "sapling/key_io_sapling.h"
      16             : #include "serialize.h"
      17             : #include "sync.h"
      18             : #include "util/system.h"
      19             : #include "utiltime.h"
      20             : #include "wallet/wallet.h"
      21             : #include "wallet/walletutil.h"
      22             : 
      23             : #include <atomic>
      24             : 
      25             : #include <boost/thread.hpp>
      26             : 
      27             : namespace DBKeys {
      28             :     const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
      29             :     const std::string BESTBLOCK{"bestblock"};
      30             :     const std::string CRYPTED_KEY{"ckey"};
      31             :     const std::string CSCRIPT{"cscript"};
      32             :     const std::string DEFAULTKEY{"defaultkey"};
      33             :     const std::string DESTDATA{"destdata"};
      34             :     const std::string HDCHAIN{"hdchain"};
      35             :     const std::string KEYMETA{"keymeta"};
      36             :     const std::string KEY{"key"};
      37             :     const std::string MASTER_KEY{"mkey"};
      38             :     const std::string MINVERSION{"minversion"};
      39             :     const std::string NAME{"name"};
      40             :     const std::string ORDERPOSNEXT{"orderposnext"};
      41             :     const std::string POOL{"pool"};
      42             :     const std::string PURPOSE{"purpose"};
      43             :     const std::string TX{"tx"};
      44             :     const std::string VERSION{"version"};
      45             :     const std::string WATCHS{"watchs"};
      46             : 
      47             :     // Sapling
      48             :     const std::string SAP_KEYMETA{"sapzkeymeta"};
      49             :     const std::string SAP_KEY{"sapzkey"};
      50             :     const std::string SAP_KEY_CRIPTED{"csapzkey"};
      51             :     const std::string SAP_ADDR{"sapzaddr"};
      52             :     const std::string SAP_COMMON_OVK{"commonovk"};
      53             :     const std::string SAP_HDCHAIN{"hdchain_sap"};
      54             :     const std::string SAP_WITNESS_CACHE_SIZE{"witnesscachesize"};
      55             : 
      56             :     // Wallet custom settings
      57             :     const std::string AUTOCOMBINE{"autocombinesettings"};
      58             :     const std::string AUTOCOMBINE_V2{"autocombinesettingsV2"};
      59             :     const std::string STAKE_SPLIT_THRESHOLD{"stakeSplitThreshold"};
      60             :     const std::string USE_CUSTOM_FEE{"fUseCustomFee"};
      61             :     const std::string CUSTOM_FEE_VALUE{"nCustomFee"};
      62             : 
      63             : } // namespace DBKeys
      64             : 
      65             : 
      66             : //
      67             : // WalletBatch
      68             : //
      69             : 
      70        3768 : bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
      71             : {
      72        3768 :     return WriteIC(std::make_pair(std::string(DBKeys::NAME), strAddress), strName);
      73             : }
      74             : 
      75           0 : bool WalletBatch::EraseName(const std::string& strAddress)
      76             : {
      77             :     // This should only be used for sending addresses, never for receiving addresses,
      78             :     // receiving addresses must always have an address book entry if they're not change return.
      79           0 :     return EraseIC(std::make_pair(std::string(DBKeys::NAME), strAddress));
      80             : }
      81             : 
      82        3750 : bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
      83             : {
      84        3750 :     return WriteIC(std::make_pair(std::string(DBKeys::PURPOSE), strAddress), strPurpose);
      85             : }
      86             : 
      87           0 : bool WalletBatch::ErasePurpose(const std::string& strPurpose)
      88             : {
      89           0 :     return EraseIC(std::make_pair(std::string(DBKeys::PURPOSE), strPurpose));
      90             : }
      91             : 
      92      336677 : bool WalletBatch::WriteTx(const CWalletTx& wtx)
      93             : {
      94      673354 :     return WriteIC(std::make_pair(std::string(DBKeys::TX), wtx.GetHash()), wtx);
      95             : }
      96             : 
      97         212 : bool WalletBatch::EraseTx(uint256 hash)
      98             : {
      99         424 :     return EraseIC(std::make_pair(std::string(DBKeys::TX), hash));
     100             : }
     101             : 
     102       11864 : bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
     103             : {
     104       23728 :     if (!WriteIC(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey), keyMeta, false)) {
     105             :         return false;
     106             :     }
     107             : 
     108             :     // hash pubkey/privkey to accelerate wallet load
     109       23728 :     std::vector<unsigned char> vchKey;
     110       11864 :     vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
     111       11864 :     vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
     112       11864 :     vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
     113             : 
     114       59320 :     return WriteIC(std::make_pair(std::string(DBKeys::KEY), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
     115             : }
     116             : 
     117        1746 : bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
     118             :                                 const std::vector<unsigned char>& vchCryptedSecret,
     119             :                                 const CKeyMetadata& keyMeta)
     120             : {
     121        1746 :     const bool fEraseUnencryptedKey = true;
     122             : 
     123        3492 :     if (!WriteIC(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey), keyMeta)) {
     124             :         return false;
     125             :     }
     126             : 
     127        3492 :     if (!WriteIC(std::make_pair(std::string(DBKeys::CRYPTED_KEY), vchPubKey), vchCryptedSecret, false)) {
     128             :         return false;
     129             :     }
     130        1746 :     if (fEraseUnencryptedKey) {
     131        5238 :         EraseIC(std::make_pair(std::string(DBKeys::KEY), vchPubKey));
     132             :     }
     133             : 
     134        1746 :     return true;
     135             : }
     136             : 
     137        2262 : bool WalletBatch::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
     138             :                                  const libzcash::SaplingExtendedSpendingKey &key,
     139             :                                  const CKeyMetadata &keyMeta)
     140             : {
     141        4524 :     if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta)) {
     142             :         return false;
     143             :     }
     144             : 
     145        4524 :     return WriteIC(std::make_pair(std::string(DBKeys::SAP_KEY), ivk), key, false);
     146             : }
     147             : 
     148           1 : bool WalletBatch::WriteSaplingPaymentAddress(const libzcash::SaplingPaymentAddress &addr,
     149             :                                            const libzcash::SaplingIncomingViewingKey &ivk)
     150             : {
     151           2 :     return WriteIC(std::make_pair(std::string(DBKeys::SAP_ADDR), addr), ivk, false);
     152             : }
     153             : 
     154         104 : bool WalletBatch::WriteCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
     155             :                                         const std::vector<unsigned char>& vchCryptedSecret,
     156             :                                         const CKeyMetadata &keyMeta)
     157             : {
     158         104 :     const bool fEraseUnencryptedKey = true;
     159         104 :     auto ivk = extfvk.fvk.in_viewing_key();
     160             : 
     161         208 :     if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta)) {
     162             :         return false;
     163             :     }
     164             : 
     165         312 :     if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEY_CRIPTED), ivk),
     166         208 :                  std::make_pair(extfvk, vchCryptedSecret), false)) {
     167             :         return false;
     168             :     }
     169             : 
     170         104 :     if (fEraseUnencryptedKey) {
     171         312 :         EraseIC(std::make_pair(std::string(DBKeys::SAP_KEY), ivk));
     172             :     }
     173         104 :     return true;
     174             : }
     175             : 
     176         237 : bool WalletBatch::WriteSaplingCommonOVK(const uint256& ovk)
     177             : {
     178         237 :     return WriteIC(std::string(DBKeys::SAP_COMMON_OVK), ovk);
     179             : }
     180             : 
     181           0 : bool WalletBatch::ReadSaplingCommonOVK(uint256& ovkRet)
     182             : {
     183           0 :     return m_batch.Read(std::string(DBKeys::SAP_COMMON_OVK), ovkRet);
     184             : }
     185             : 
     186         327 : bool WalletBatch::WriteWitnessCacheSize(int64_t nWitnessCacheSize)
     187             : {
     188         654 :     return WriteIC(std::string(DBKeys::SAP_WITNESS_CACHE_SIZE), nWitnessCacheSize);
     189             : }
     190             : 
     191           8 : bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
     192             : {
     193          16 :     return WriteIC(std::make_pair(std::string(DBKeys::MASTER_KEY), nID), kMasterKey, true);
     194             : }
     195             : 
     196          15 : bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
     197             : {
     198          30 :     return WriteIC(std::make_pair(std::string(DBKeys::CSCRIPT), hash), redeemScript, false);
     199             : }
     200             : 
     201          41 : bool WalletBatch::WriteWatchOnly(const CScript& dest)
     202             : {
     203          82 :     return WriteIC(std::make_pair(std::string(DBKeys::WATCHS), dest), '1');
     204             : }
     205             : 
     206           1 : bool WalletBatch::EraseWatchOnly(const CScript& dest)
     207             : {
     208           2 :     return EraseIC(std::make_pair(std::string(DBKeys::WATCHS), dest));
     209             : }
     210             : 
     211         327 : bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
     212             : {
     213         981 :     WriteIC(std::string(DBKeys::BESTBLOCK), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
     214         654 :     return WriteIC(std::string(DBKeys::BESTBLOCK_NOMERKLE), locator);
     215             : }
     216             : 
     217         351 : bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
     218             : {
     219        1053 :     if (m_batch.Read(std::string(DBKeys::BESTBLOCK), locator) && !locator.vHave.empty()) {
     220             :         return true;
     221             :     }
     222         702 :     return m_batch.Read(std::string(DBKeys::BESTBLOCK_NOMERKLE), locator);
     223             : }
     224             : 
     225      119200 : bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
     226             : {
     227      119200 :     return WriteIC(std::string(DBKeys::ORDERPOSNEXT), nOrderPosNext);
     228             : }
     229             : 
     230           0 : bool WalletBatch::WriteStakeSplitThreshold(const CAmount& nStakeSplitThreshold)
     231             : {
     232           0 :     return WriteIC(std::string(DBKeys::STAKE_SPLIT_THRESHOLD), nStakeSplitThreshold);
     233             : }
     234             : 
     235           0 : bool WalletBatch::WriteUseCustomFee(bool fUse)
     236             : {
     237           0 :     return WriteIC(std::string(DBKeys::USE_CUSTOM_FEE), fUse);
     238             : }
     239             : 
     240           0 : bool WalletBatch::WriteCustomFeeValue(const CAmount& nFee)
     241             : {
     242           0 :     return WriteIC(std::string(DBKeys::CUSTOM_FEE_VALUE), nFee);
     243             : }
     244             : 
     245           2 : bool WalletBatch::WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold, int frequency)
     246             : {
     247           2 :     std::pair<std::pair<bool, CAmount>, int> pSettings;
     248           2 :     pSettings.first.first = fEnable;
     249           2 :     pSettings.first.second = nCombineThreshold;
     250           2 :     pSettings.second = frequency;
     251           2 :     EraseIC(std::string(DBKeys::AUTOCOMBINE));
     252           4 :     return WriteIC(std::string(DBKeys::AUTOCOMBINE_V2), pSettings, true);
     253             : }
     254             : 
     255        6800 : bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
     256             : {
     257       13600 :     return m_batch.Read(std::make_pair(std::string(DBKeys::POOL), nPool), keypool);
     258             : }
     259             : 
     260       11507 : bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
     261             : {
     262       23014 :     return WriteIC(std::make_pair(std::string(DBKeys::POOL), nPool), keypool);
     263             : }
     264             : 
     265        7216 : bool WalletBatch::ErasePool(int64_t nPool)
     266             : {
     267       14432 :     return EraseIC(std::make_pair(std::string(DBKeys::POOL), nPool));
     268             : }
     269             : 
     270         238 : bool WalletBatch::WriteMinVersion(int nVersion)
     271             : {
     272         238 :     return WriteIC(std::string(DBKeys::MINVERSION), nVersion);
     273             : }
     274             : 
     275       13231 : bool WalletBatch::WriteHDChain(const CHDChain& chain)
     276             : {
     277       13231 :     std::string key = chain.chainType == HDChain::ChainCounterType::Sapling ?
     278       13231 :                         DBKeys::SAP_HDCHAIN : DBKeys::HDCHAIN;
     279       13231 :     return WriteIC(key, chain);
     280             : }
     281             : 
     282           0 : DBErrors WalletBatch::ReorderTransactions(CWallet* pwallet)
     283             : {
     284           0 :     LOCK(pwallet->cs_wallet);
     285             :     // Old wallets didn't have any defined order for transactions
     286             :     // Probably a bad idea to change the output of this
     287             : 
     288             :     // First: get all CWalletTx into a sorted-by-time multimap.
     289           0 :     typedef std::multimap<int64_t, CWalletTx*> TxItems;
     290           0 :     TxItems txByTime;
     291             : 
     292           0 :     for (auto it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) {
     293           0 :         CWalletTx* wtx = &((*it).second);
     294           0 :         txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx));
     295             :     }
     296             : 
     297           0 :     int64_t& nOrderPosNext = pwallet->nOrderPosNext;
     298           0 :     nOrderPosNext = 0;
     299           0 :     std::vector<int64_t> nOrderPosOffsets;
     300           0 :     for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) {
     301           0 :         CWalletTx *const pwtx = (*it).second;
     302           0 :         int64_t& nOrderPos = pwtx->nOrderPos;
     303             : 
     304           0 :         if (nOrderPos == -1) {
     305           0 :             nOrderPos = nOrderPosNext++;
     306           0 :             nOrderPosOffsets.push_back(nOrderPos);
     307             : 
     308           0 :             if (!WriteTx(*pwtx)) return DB_LOAD_FAIL;
     309             : 
     310             :         } else {
     311           0 :             int64_t nOrderPosOff = 0;
     312           0 :             for (const int64_t& nOffsetStart : nOrderPosOffsets) {
     313           0 :                 if (nOrderPos >= nOffsetStart)
     314           0 :                     ++nOrderPosOff;
     315             :             }
     316           0 :             nOrderPos += nOrderPosOff;
     317           0 :             nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
     318             : 
     319           0 :             if (!nOrderPosOff) continue;
     320             : 
     321             :             // Since we're changing the order, write it back
     322           0 :             if (!WriteTx(*pwtx)) return DB_LOAD_FAIL;
     323             :         }
     324             :     }
     325           0 :     WriteOrderPosNext(nOrderPosNext);
     326             : 
     327             :     return DB_LOAD_OK;
     328             : }
     329             : 
     330           0 : class CWalletScanState
     331             : {
     332             : public:
     333             :     unsigned int nKeys;
     334             :     unsigned int nCKeys;
     335             :     unsigned int nKeyMeta;
     336             :     unsigned int nZKeys;
     337             :     unsigned int nZKeyMeta;
     338             :     unsigned int nSapZAddrs;
     339             :     bool fIsEncrypted;
     340             :     bool fAnyUnordered;
     341             :     int nFileVersion;
     342             :     std::vector<uint256> vWalletUpgrade;
     343             : 
     344         403 :     CWalletScanState()
     345         403 :     {
     346         403 :         nKeys = nCKeys = nKeyMeta = nZKeys = nZKeyMeta = nSapZAddrs = 0;
     347         403 :         fIsEncrypted = false;
     348         403 :         fAnyUnordered = false;
     349         403 :         nFileVersion = 0;
     350             :     }
     351             : };
     352             : 
     353       27964 : bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletScanState& wss, std::string& strType, std::string& strErr)
     354             : {
     355       27964 :     try {
     356             :         // Unserialize
     357             :         // Taking advantage of the fact that pair serialization
     358             :         // is just the two items serialized one after the other
     359       27964 :         ssKey >> strType;
     360       27964 :         if (strType == DBKeys::NAME) {
     361         520 :             std::string strAddress;
     362         260 :             ssKey >> strAddress;
     363         520 :             std::string strName;
     364         260 :             ssValue >> strName;
     365         520 :             pwallet->LoadAddressBookName(Standard::DecodeDestination(strAddress), strName);
     366       27704 :         } else if (strType == DBKeys::PURPOSE) {
     367         520 :             std::string strAddress;
     368         260 :             ssKey >> strAddress;
     369         520 :             std::string strPurpose;
     370         260 :             ssValue >> strPurpose;
     371         520 :             pwallet->LoadAddressBookPurpose(Standard::DecodeDestination(strAddress), strPurpose);
     372       27444 :         } else if (strType == DBKeys::TX) {
     373        6551 :             uint256 hash;
     374        6551 :             ssKey >> hash;
     375       13102 :             CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
     376        6551 :             ssValue >> wtx;
     377        6551 :             if (wtx.GetHash() != hash)
     378           0 :                 return false;
     379             : 
     380             :             // Undo serialize changes in 31600
     381        6551 :             if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) {
     382           0 :                 if (!ssValue.empty()) {
     383           0 :                     char fTmp;
     384           0 :                     char fUnused;
     385           0 :                     std::string unused_string;
     386           0 :                     ssValue >> fTmp >> fUnused >> unused_string;
     387           0 :                     strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
     388           0 :                         wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
     389           0 :                     wtx.fTimeReceivedIsTxTime = fTmp;
     390             :                 } else {
     391           0 :                     strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
     392           0 :                     wtx.fTimeReceivedIsTxTime = 0;
     393             :                 }
     394           0 :                 wss.vWalletUpgrade.push_back(hash);
     395             :             }
     396             : 
     397        6551 :             if (wtx.nOrderPos == -1)
     398           0 :                 wss.fAnyUnordered = true;
     399             : 
     400        6551 :             pwallet->LoadToWallet(wtx);
     401       20893 :         } else if (strType == DBKeys::WATCHS) {
     402          22 :             CScript script;
     403          11 :             ssKey >> script;
     404          11 :             char fYes;
     405          11 :             ssValue >> fYes;
     406          11 :             if (fYes == '1')
     407          11 :                 pwallet->LoadWatchOnly(script);
     408             : 
     409             :             // Watch-only addresses have no birthday information for now,
     410             :             // so set the wallet birthday to the beginning of time.
     411          11 :             pwallet->nTimeFirstKey = 1;
     412       20882 :         } else if (strType == DBKeys::KEY) {
     413        7787 :             CPubKey vchPubKey;
     414        7787 :             ssKey >> vchPubKey;
     415        7787 :             if (!vchPubKey.IsValid()) {
     416           0 :                 strErr = "Error reading wallet database: CPubKey corrupt";
     417           0 :                 return false;
     418             :             }
     419       15574 :             CKey key;
     420       15574 :             CPrivKey pkey;
     421        7787 :             uint256 hash;
     422        7787 :             wss.nKeys++;
     423        7787 :             ssValue >> pkey;
     424             : 
     425             :             // Old wallets store keys as "key" [pubkey] => [privkey]
     426             :             // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
     427             :             // using EC operations as a checksum.
     428             :             // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
     429             :             // remaining backwards-compatible.
     430        7787 :             try {
     431        7787 :                 ssValue >> hash;
     432           0 :             } catch (...) {
     433             :             }
     434             : 
     435        7787 :             bool fSkipCheck = false;
     436             : 
     437       15574 :             if (!hash.IsNull()) {
     438             :                 // hash pubkey/privkey to accelerate wallet load
     439       15574 :                 std::vector<unsigned char> vchKey;
     440        7787 :                 vchKey.reserve(vchPubKey.size() + pkey.size());
     441        7787 :                 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
     442        7787 :                 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
     443             : 
     444        7787 :                 if (Hash(vchKey.begin(), vchKey.end()) != hash) {
     445           0 :                     strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
     446           0 :                     return false;
     447             :                 }
     448             : 
     449        7787 :                 fSkipCheck = true;
     450             :             }
     451             : 
     452        7787 :             if (!key.Load(pkey, vchPubKey, fSkipCheck)) {
     453           0 :                 strErr = "Error reading wallet database: CPrivKey corrupt";
     454             :                 return false;
     455             :             }
     456        7787 :             if (!pwallet->LoadKey(key, vchPubKey)) {
     457           0 :                 strErr = "Error reading wallet database: LoadKey failed";
     458             :                 return false;
     459             :             }
     460       13095 :         } else if (strType == DBKeys::MASTER_KEY) {
     461           1 :             unsigned int nID;
     462           1 :             ssKey >> nID;
     463           2 :             CMasterKey kMasterKey;
     464           1 :             ssValue >> kMasterKey;
     465           1 :             if (pwallet->mapMasterKeys.count(nID) != 0) {
     466           0 :                 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
     467           0 :                 return false;
     468             :             }
     469           1 :             pwallet->mapMasterKeys[nID] = kMasterKey;
     470           1 :             if (pwallet->nMasterKeyMaxID < nID)
     471           1 :                 pwallet->nMasterKeyMaxID = nID;
     472       13094 :         } else if (strType == DBKeys::CRYPTED_KEY) {
     473         602 :             CPubKey vchPubKey;
     474         602 :             ssKey >> vchPubKey;
     475        1204 :             std::vector<unsigned char> vchPrivKey;
     476         602 :             ssValue >> vchPrivKey;
     477         602 :             wss.nCKeys++;
     478             : 
     479         602 :             if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) {
     480           0 :                 strErr = "Error reading wallet database: LoadCryptedKey failed";
     481           0 :                 return false;
     482             :             }
     483         602 :             wss.fIsEncrypted = true;
     484       12492 :         } else if (strType == DBKeys::KEYMETA) {
     485        8389 :             CPubKey vchPubKey;
     486        8389 :             ssKey >> vchPubKey;
     487       16778 :             CKeyMetadata keyMeta;
     488        8389 :             ssValue >> keyMeta;
     489        8389 :             wss.nKeyMeta++;
     490             : 
     491        8389 :             pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
     492             : 
     493             :             // find earliest key creation time, as wallet birthday
     494        8389 :             if (!pwallet->nTimeFirstKey ||
     495        8389 :                 (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
     496           0 :                 pwallet->nTimeFirstKey = keyMeta.nCreateTime;
     497        4103 :         } else if (strType == DBKeys::DEFAULTKEY) {
     498             :             // We don't want or need the default key, but if there is one set,
     499             :             // we want to make sure that it is valid so that we can detect corruption
     500           0 :             CPubKey vchPubKey;
     501           0 :             ssValue >> vchPubKey;
     502           0 :             if (!vchPubKey.IsValid()) {
     503           0 :                 strErr = "Error reading wallet database: Default Key corrupt";
     504           0 :                 return false;
     505             :             }
     506        4103 :         } else if (strType == DBKeys::POOL) {
     507        2307 :             int64_t nIndex;
     508        2307 :             ssKey >> nIndex;
     509        2307 :             CKeyPool keypool;
     510        2307 :             ssValue >> keypool;
     511        2307 :             pwallet->GetScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
     512        1796 :         } else if (strType == DBKeys::VERSION) {
     513         403 :             ssValue >> wss.nFileVersion;
     514         403 :             if (wss.nFileVersion == 10300)
     515           0 :                 wss.nFileVersion = 300;
     516        1393 :         } else if (strType == DBKeys::CSCRIPT) {
     517           2 :             uint160 hash;
     518           2 :             ssKey >> hash;
     519           4 :             CScript script;
     520           2 :             ssValue >> script;
     521           2 :             if (!pwallet->LoadCScript(script)) {
     522           0 :                 strErr = "Error reading wallet database: LoadCScript failed";
     523           0 :                 return false;
     524             :             }
     525        1391 :         } else if (strType == DBKeys::ORDERPOSNEXT) {
     526         132 :             ssValue >> pwallet->nOrderPosNext;
     527        1259 :         } else if (strType == DBKeys::STAKE_SPLIT_THRESHOLD) {
     528           0 :             ssValue >> pwallet->nStakeSplitThreshold;
     529             :             // originally saved as integer
     530           0 :             if (pwallet->nStakeSplitThreshold < COIN)
     531           0 :                 pwallet->nStakeSplitThreshold *= COIN;
     532        1259 :         } else if (strType == DBKeys::USE_CUSTOM_FEE) {
     533           0 :             ssValue >> pwallet->fUseCustomFee;
     534        1259 :         } else if (strType == DBKeys::CUSTOM_FEE_VALUE) {
     535           0 :             ssValue >> pwallet->nCustomFee;
     536        1259 :         } else if (strType == DBKeys::AUTOCOMBINE) {
     537           0 :             std::pair<bool, CAmount> pSettings;
     538           0 :             ssValue >> pSettings;
     539           0 :             pwallet->fCombineDust = pSettings.first;
     540           0 :             pwallet->nAutoCombineThreshold = pSettings.second;
     541             :             // Value used for old autocombine
     542           0 :             pwallet->frequency = 1;
     543             :             // originally saved as integer
     544           0 :             if (pwallet->nAutoCombineThreshold < COIN)
     545           0 :                 pwallet->nAutoCombineThreshold *= COIN;
     546        1259 :         } else if (strType == DBKeys::AUTOCOMBINE_V2) {
     547           0 :             std::pair<std::pair<bool, CAmount>, int> pSettings;
     548           0 :             ssValue >> pSettings;
     549           0 :             pwallet->fCombineDust = pSettings.first.first;
     550           0 :             pwallet->nAutoCombineThreshold = pSettings.first.second;
     551           0 :             pwallet->frequency = pSettings.second;
     552        1259 :         } else if (strType == DBKeys::DESTDATA) {
     553           0 :             std::string strAddress, strKey, strValue;
     554           0 :             ssKey >> strAddress;
     555           0 :             ssKey >> strKey;
     556           0 :             ssValue >> strValue;
     557           0 :             if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue)) {
     558           0 :                 strErr = "Error reading wallet database: LoadDestData failed";
     559           0 :                 return false;
     560             :             }
     561        1259 :         } else if (strType == DBKeys::HDCHAIN) { // Regular key chain counter
     562         159 :             CHDChain chain;
     563         159 :             ssValue >> chain;
     564         159 :             pwallet->GetScriptPubKeyMan()->SetHDChain(chain, true);
     565        1100 :         } else if (strType == DBKeys::SAP_HDCHAIN) {
     566         159 :             CHDChain chain;
     567         159 :             ssValue >> chain;
     568         159 :             pwallet->GetSaplingScriptPubKeyMan()->SetHDChain(chain, true);
     569         941 :         } else if (strType == DBKeys::SAP_KEY) {
     570          35 :             libzcash::SaplingIncomingViewingKey ivk;
     571          35 :             ssKey >> ivk;
     572          35 :             libzcash::SaplingExtendedSpendingKey key;
     573          35 :             ssValue >> key;
     574          35 :             if (!pwallet->LoadSaplingZKey(key)) {
     575           0 :                 strErr = "Error reading wallet database: LoadSaplingZKey failed";
     576           0 :                 return false;
     577             :             }
     578             :             //add checks for integrity
     579          35 :             wss.nZKeys++;
     580         906 :         } else if (strType == DBKeys::SAP_COMMON_OVK) {
     581         159 :             uint256 ovk;
     582         159 :             ssValue >> ovk;
     583         318 :             pwallet->GetSaplingScriptPubKeyMan()->setCommonOVK(ovk);
     584         747 :         } else if (strType == DBKeys::SAP_KEY_CRIPTED) {
     585           2 :             libzcash::SaplingIncomingViewingKey ivk;
     586           2 :             ssKey >> ivk;
     587           2 :             libzcash::SaplingExtendedFullViewingKey extfvk;
     588           2 :             ssValue >> extfvk;
     589           4 :             std::vector<unsigned char> vchCryptedSecret;
     590           2 :             ssValue >> vchCryptedSecret;
     591           2 :             wss.nCKeys++;
     592             : 
     593           2 :             if (!pwallet->LoadCryptedSaplingZKey(extfvk, vchCryptedSecret)) {
     594           0 :                 strErr = "Error reading wallet database: LoadCryptedSaplingZKey failed";
     595           0 :                 return false;
     596             :             }
     597           2 :             wss.fIsEncrypted = true;
     598         745 :         } else if (strType == DBKeys::SAP_KEYMETA) {
     599          37 :             libzcash::SaplingIncomingViewingKey ivk;
     600          37 :             ssKey >> ivk;
     601          74 :             CKeyMetadata keyMeta;
     602          37 :             ssValue >> keyMeta;
     603             : 
     604          37 :             wss.nZKeyMeta++;
     605             : 
     606          37 :             pwallet->LoadSaplingZKeyMetadata(ivk, keyMeta);
     607         708 :         } else if (strType == DBKeys::SAP_ADDR) {
     608           0 :             libzcash::SaplingPaymentAddress addr;
     609           0 :             ssKey >> addr;
     610           0 :             libzcash::SaplingIncomingViewingKey ivk;
     611           0 :             ssValue >> ivk;
     612             : 
     613           0 :             wss.nSapZAddrs++;
     614             : 
     615           0 :             if (!pwallet->LoadSaplingPaymentAddress(addr, ivk)) {
     616           0 :                 strErr = "Error reading wallet database: LoadSaplingPaymentAddress failed";
     617           0 :                 return false;
     618             :             }
     619         708 :         } else if (strType == DBKeys::SAP_WITNESS_CACHE_SIZE) {
     620       28122 :             ssValue >> pwallet->GetSaplingScriptPubKeyMan()->nWitnessCacheSize;
     621             :         }
     622           0 :     } catch (...) {
     623           0 :         return false;
     624             :     }
     625             :     return true;
     626             : }
     627             : 
     628           0 : bool WalletBatch::IsKeyType(const std::string& strType)
     629             : {
     630           0 :     return (strType == DBKeys::KEY ||
     631           0 :             strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY ||
     632           0 :             strType == DBKeys::SAP_KEY || strType == DBKeys::SAP_KEY_CRIPTED);
     633             : }
     634             : 
     635         403 : DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
     636             : {
     637         806 :     CWalletScanState wss;
     638         403 :     bool fNoncriticalErrors = false;
     639         403 :     DBErrors result = DB_LOAD_OK;
     640             : 
     641         806 :     LOCK(pwallet->cs_wallet);
     642         403 :     try {
     643         403 :         int nMinVersion = 0;
     644         806 :         if (m_batch.Read((std::string) DBKeys::MINVERSION, nMinVersion)) {
     645         162 :             if (nMinVersion > CLIENT_VERSION) {
     646           0 :                 return DB_TOO_NEW;
     647             :             }
     648         162 :             pwallet->LoadMinVersion(nMinVersion);
     649             :         }
     650             : 
     651             :         // Get cursor
     652         403 :         Dbc* pcursor = m_batch.GetCursor();
     653         403 :         if (!pcursor) {
     654           0 :             LogPrintf("Error getting wallet database cursor\n");
     655             :             return DB_CORRUPT;
     656             :         }
     657             : 
     658       28367 :         while (true) {
     659             :             // Read next record
     660       28367 :             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     661       27964 :             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
     662       28367 :             int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
     663       28367 :             if (ret == DB_NOTFOUND) {
     664             :                 break;
     665       27964 :             } else if (ret != 0) {
     666           0 :                 LogPrintf("Error reading next record from wallet database\n");
     667           0 :                 return DB_CORRUPT;
     668             :             }
     669             : 
     670             :             // Try to be tolerant of single corrupt records:
     671       56247 :             std::string strType, strErr;
     672       27964 :             if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) {
     673             :                 // losing keys is considered a catastrophic error, anything else
     674             :                 // we assume the user can live with:
     675           0 :                 if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
     676             :                     result = DB_CORRUPT;
     677             :                 } else {
     678             :                     // Leave other errors alone, if we try to fix them we might make things worse.
     679           0 :                     fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
     680           0 :                     if (strType == DBKeys::TX)
     681             :                         // Rescan if there is a bad transaction record:
     682           0 :                         gArgs.SoftSetBoolArg("-rescan", true);
     683             :                 }
     684             :             }
     685       27964 :             if (!strErr.empty())
     686           0 :                 LogPrintf("%s\n", strErr);
     687             :         }
     688         403 :         pcursor->close();
     689           0 :     } catch (const boost::thread_interrupted&) {
     690           0 :         throw;
     691           0 :     } catch (...) {
     692           0 :         result = DB_CORRUPT;
     693             :     }
     694             : 
     695         403 :     if (fNoncriticalErrors && result == DB_LOAD_OK)
     696             :         result = DB_NONCRITICAL_ERROR;
     697             : 
     698             :     // Any wallet corruption at all: skip any rewriting or
     699             :     // upgrading, we don't want to make it worse.
     700         403 :     if (result != DB_LOAD_OK)
     701           0 :         return result;
     702             : 
     703         403 :     LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
     704             : 
     705         403 :     LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
     706         403 :         wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
     707             : 
     708         403 :     LogPrintf("ZKeys: %u plaintext, -- encrypted, %u w/metadata, %u total\n",
     709         403 :               wss.nZKeys, wss.nZKeyMeta, wss.nZKeys + 0);
     710             : 
     711             :     // nTimeFirstKey is only reliable if all keys have metadata
     712         403 :     if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
     713           1 :         pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
     714             : 
     715         403 :     for (const uint256& hash : wss.vWalletUpgrade) {
     716           0 :         WriteTx(pwallet->mapWallet.at(hash));
     717             :     }
     718             : 
     719             :     // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
     720         403 :     if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) {
     721             :         return DB_NEED_REWRITE;
     722             :     }
     723             : 
     724         403 :     if (wss.nFileVersion < CLIENT_VERSION) { // Update
     725           2 :         WriteVersion(CLIENT_VERSION);
     726             :     }
     727             : 
     728         403 :     if (wss.fAnyUnordered) {
     729           0 :         result = ReorderTransactions(pwallet);
     730             :     }
     731             : 
     732             :     return result;
     733             : }
     734             : 
     735           5 : DBErrors WalletBatch::FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
     736             : {
     737           5 :     bool fNoncriticalErrors = false;
     738           5 :     DBErrors result = DB_LOAD_OK;
     739             : 
     740           5 :     try {
     741          10 :         LOCK(pwallet->cs_wallet);
     742           5 :         int nMinVersion = 0;
     743          10 :         if (m_batch.Read((std::string) DBKeys::MINVERSION, nMinVersion)) {
     744           5 :             if (nMinVersion > CLIENT_VERSION) {
     745           0 :                 return DB_TOO_NEW;
     746             :             }
     747           5 :             pwallet->LoadMinVersion(nMinVersion);
     748             :         }
     749             : 
     750             :         // Get cursor
     751           5 :         Dbc* pcursor = m_batch.GetCursor();
     752           5 :         if (!pcursor) {
     753           0 :             LogPrintf("Error getting wallet database cursor\n");
     754             :             return DB_CORRUPT;
     755             :         }
     756             : 
     757         388 :         while (true) {
     758             :             // Read next record
     759         388 :             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     760         383 :             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
     761         388 :             int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
     762         388 :             if (ret == DB_NOTFOUND) {
     763             :                 break;
     764         383 :             } else if (ret != 0) {
     765           0 :                 LogPrintf("Error reading next record from wallet database\n");
     766           0 :                 return DB_CORRUPT;
     767             :             }
     768             : 
     769         766 :             std::string strType;
     770         383 :             ssKey >> strType;
     771         383 :             if (strType == DBKeys::TX) {
     772         212 :                 uint256 hash;
     773         212 :                 ssKey >> hash;
     774             : 
     775         424 :                 CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
     776         212 :                 ssValue >> wtx;
     777             : 
     778         212 :                 vTxHash.push_back(hash);
     779         212 :                 vWtx.push_back(wtx);
     780             :             }
     781             :         }
     782           5 :         pcursor->close();
     783           0 :     } catch (const boost::thread_interrupted&) {
     784           0 :         throw;
     785           0 :     } catch (...) {
     786           0 :         result = DB_CORRUPT;
     787             :     }
     788             : 
     789           5 :     if (fNoncriticalErrors && result == DB_LOAD_OK)
     790             :         result = DB_NONCRITICAL_ERROR;
     791             : 
     792           5 :     return result;
     793             : }
     794             : 
     795           5 : DBErrors WalletBatch::ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx)
     796             : {
     797             :     // build list of wallet TXs
     798          10 :     std::vector<uint256> vTxHash;
     799           5 :     DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
     800           5 :     if (err != DB_LOAD_OK) {
     801             :         return err;
     802             :     }
     803             : 
     804             :     // erase each wallet TX
     805         217 :     for (uint256& hash : vTxHash) {
     806         212 :         if (!EraseTx(hash)) return DB_CORRUPT;
     807             :     }
     808             : 
     809           5 :     return DB_LOAD_OK;
     810             : }
     811             : 
     812       38013 : void MaybeCompactWalletDB()
     813             : {
     814       38013 :     static std::atomic<bool> fOneThread;
     815       38013 :     if (fOneThread.exchange(true)) {
     816             :         return;
     817             :     }
     818       38013 :     if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
     819             :         return;
     820             :     }
     821             : 
     822       76060 :     for (CWalletRef pwallet : vpwallets) {
     823       38047 :         WalletDatabase& dbh = pwallet->GetDBHandle();
     824             : 
     825       38047 :         unsigned int nUpdateCounter = dbh.nUpdateCounter;
     826       38047 :         if (dbh.nLastSeen != nUpdateCounter) {
     827        4496 :             dbh.nLastSeen = nUpdateCounter;
     828        4496 :             dbh.nLastWalletUpdate = GetTime();
     829             :         }
     830             : 
     831       38047 :         if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
     832       19004 :             if (BerkeleyBatch::PeriodicFlush(dbh)) {
     833         804 :                 dbh.nLastFlushed = nUpdateCounter;
     834             :             }
     835             :         }
     836             :     }
     837             : 
     838       38013 :     fOneThread = false;
     839             : }
     840             : 
     841             : typedef std::multimap<std::time_t, fs::path> folder_set_t;
     842         287 : static folder_set_t buildBackupsMapSortedByLastWrite(const std::string& strWalletFile, const fs::path& backupsDir)
     843             : {
     844         287 :     folder_set_t folder_set;
     845         574 :     fs::directory_iterator end_iter;
     846             :     // Build map of backup files for current(!) wallet sorted by last write time
     847         744 :     for (fs::directory_iterator dir_iter(backupsDir); dir_iter != end_iter; ++dir_iter) {
     848             :         // Only check regular files
     849         457 :         if (fs::is_regular_file(dir_iter->status())) {
     850             :             // Only add the backups for the current wallet, e.g. wallet.dat.*
     851         462 :             if(dir_iter->path().stem().string() == strWalletFile) {
     852         402 :                 folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
     853             :             }
     854             :         }
     855             :     }
     856         287 :     return folder_set;
     857             : }
     858             : 
     859         287 : static bool cleanWalletBackups(folder_set_t& folder_set, int nWalletBackups, std::string& strBackupWarning)
     860             : {
     861             :     // Loop backward through backup files and keep the N newest ones (1 <= N <= 10)
     862         287 :     int counter = 0;
     863         689 :     for (const std::pair<const std::time_t, fs::path>& file : reverse_iterate(folder_set)) {
     864         402 :         counter++;
     865         402 :         if (counter > nWalletBackups) {
     866             :             // More than nWalletBackups backups: delete oldest one(s)
     867           1 :             try {
     868           1 :                 fs::remove(file.second);
     869           1 :                 LogPrintf("Old backup deleted: %s\n", file.second);
     870           0 :             } catch (fs::filesystem_error &error) {
     871           0 :                 strBackupWarning = strprintf(_("Failed to delete backup, error: %s"), error.what());
     872           0 :                 LogPrintf("%s\n", strBackupWarning);
     873           0 :                 return false;
     874             :             }
     875             :         }
     876             :     }
     877         287 :     return true;
     878             : }
     879             : 
     880         361 : bool AutoBackupWallet(CWallet& wallet, std::string& strBackupWarning, std::string& strBackupError)
     881             : {
     882         361 :     strBackupWarning = strBackupError = "";
     883         722 :     int nWalletBackups = std::max(0, std::min(10, (int)gArgs.GetArg("-createwalletbackups", DEFAULT_CREATEWALLETBACKUPS)));
     884         361 :     if (nWalletBackups == 0) {
     885           0 :         LogPrintf("Automatic wallet backups are disabled!\n");
     886           0 :         return false;
     887             :     }
     888             : 
     889         722 :     fs::path backupsDir = GetDataDir() / "backups";
     890         361 :     backupsDir.make_preferred();
     891         361 :     TryCreateDirectories(backupsDir);
     892         722 :     std::string strWalletFile = wallet.GetUniqueWalletBackupName();
     893        1083 :     fs::path backupFile = backupsDir / strWalletFile;
     894         361 :     backupFile.make_preferred();
     895         648 :     if (fs::exists(backupFile)) {
     896          74 :         LogPrintf("%s\n", _("Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this."));
     897          74 :         return false;
     898             :     }
     899             : 
     900             :     // Try to backup
     901         287 :     if (!wallet.BackupWallet(backupFile.string())) {
     902           0 :         strBackupError = "Failed to backup wallet";
     903             :         return false; // error is logged internally
     904             :     }
     905             : 
     906             :     // Keep only 0 < nWalletBackups <= 10 backups, including the new one of course
     907         648 :     folder_set_t folder_set = buildBackupsMapSortedByLastWrite(backupFile.stem().string(), backupsDir);
     908         287 :     return cleanWalletBackups(folder_set, nWalletBackups, strBackupWarning);
     909             : }
     910             : 
     911             : //
     912             : // Try to (very carefully!) recover wallet file if there is a problem.
     913             : //
     914           0 : bool WalletBatch::Recover(const fs::path& wallet_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
     915             : {
     916           0 :     return BerkeleyBatch::Recover(wallet_path, callbackDataIn, recoverKVcallback, out_backup_filename);
     917             : }
     918             : 
     919           0 : bool WalletBatch::Recover(const fs::path& wallet_path, std::string& out_backup_filename)
     920             : {
     921             :     // recover without a key filter callback
     922             :     // results in recovering all record types
     923           0 :     return WalletBatch::Recover(wallet_path, nullptr, nullptr, out_backup_filename);
     924             : }
     925             : 
     926           0 : bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
     927             : {
     928           0 :     CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
     929           0 :     CWalletScanState dummyWss;
     930           0 :     std::string strType, strErr;
     931           0 :     bool fReadOK;
     932           0 :     {
     933             :         // Required in LoadKeyMetadata():
     934           0 :         LOCK(dummyWallet->cs_wallet);
     935           0 :         fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
     936             :                                dummyWss, strType, strErr);
     937             :     }
     938           0 :     if (!IsKeyType(strType) && strType != DBKeys::HDCHAIN)
     939             :         return false;
     940           0 :     if (!fReadOK)
     941             :     {
     942           0 :         LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr);
     943             :         return false;
     944             :     }
     945             : 
     946             :     return true;
     947             : }
     948             : 
     949         377 : bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr)
     950             : {
     951         377 :     return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr);
     952             : }
     953             : 
     954         374 : bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::string& warningStr, std::string& errorStr)
     955             : {
     956         374 :     return BerkeleyBatch::VerifyDatabaseFile(wallet_path, warningStr, errorStr, WalletBatch::Recover);
     957             : }
     958             : 
     959           0 : bool WalletBatch::WriteDestData(const std::string& address, const std::string& key, const std::string& value)
     960             : {
     961           0 :     return WriteIC(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)), value);
     962             : }
     963             : 
     964           0 : bool WalletBatch::EraseDestData(const std::string& address, const std::string& key)
     965             : {
     966           0 :     return EraseIC(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)));
     967             : }
     968             : 
     969         334 : bool WalletBatch::TxnBegin()
     970             : {
     971         334 :     return m_batch.TxnBegin();
     972             : }
     973             : 
     974         334 : bool WalletBatch::TxnCommit()
     975             : {
     976         334 :     return m_batch.TxnCommit();
     977             : }
     978             : 
     979           0 : bool WalletBatch::TxnAbort()
     980             : {
     981           0 :     return m_batch.TxnAbort();
     982             : }
     983             : 
     984           0 : bool WalletBatch::ReadVersion(int& nVersion)
     985             : {
     986           0 :     return m_batch.ReadVersion(nVersion);
     987             : }
     988             : 
     989           2 : bool WalletBatch::WriteVersion(int nVersion)
     990             : {
     991           2 :     return m_batch.WriteVersion(nVersion);
     992             : }

Generated by: LCOV version 1.14