LCOV - code coverage report
Current view: top level - src/wallet - wallet.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 2128 2625 81.1 %
Date: 2025-02-23 09:33:43 Functions: 224 267 83.9 %

          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-2022 The PIVX Core developers
       5             : // Distributed under the MIT software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #include "optional.h"
       9             : #include "validation.h"
      10             : #if defined(HAVE_CONFIG_H)
      11             : #include "config/pivx-config.h"
      12             : #endif
      13             : 
      14             : #include "wallet/wallet.h"
      15             : 
      16             : #include "checkpoints.h"
      17             : #include "coincontrol.h"
      18             : #include "evo/providertx.h"
      19             : #include "guiinterfaceutil.h"
      20             : #include "policy/policy.h"
      21             : #include "sapling/key_io_sapling.h"
      22             : #include "script/sign.h"
      23             : #include "scheduler.h"
      24             : #include "shutdown.h"
      25             : #include "spork.h"
      26             : #include "util/validation.h"
      27             : #include "utilmoneystr.h"
      28             : #include "wallet/fees.h"
      29             : 
      30             : #include <future>
      31             : #include <boost/algorithm/string/replace.hpp>
      32             : 
      33             : std::vector<CWalletRef> vpwallets;
      34             : /**
      35             :  * Settings
      36             :  */
      37             : CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
      38             : CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
      39             : unsigned int nTxConfirmTarget = 1;
      40             : bool bdisableSystemnotifications = false; // Those bubbles can be annoying and slow down the UI when you get lots of trx
      41             : bool fPayAtLeastCustomFee = true;
      42             : bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
      43             : 
      44             : /**
      45             :  * Fees smaller than this (in upiv) are considered zero fee (for transaction creation)
      46             :  * We are ~100 times smaller then bitcoin now (2015-06-23), set minTxFee 10 times higher
      47             :  * so it's still 10 times lower comparing to bitcoin.
      48             :  * Override with -mintxfee
      49             :  */
      50             : CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
      51             : 
      52             : /**
      53             :  * minimum accpeted value for stake split threshold
      54             :  */
      55             : CAmount CWallet::minStakeSplitThreshold = DEFAULT_MIN_STAKE_SPLIT_THRESHOLD;
      56             : 
      57             : const uint256 CWalletTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
      58             : 
      59             : /** @defgroup mapWallet
      60             :  *
      61             :  * @{
      62             :  */
      63             : 
      64             : struct CompareValueOnly {
      65     1595958 :     bool operator()(const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t1,
      66             :         const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t2) const
      67             :     {
      68     1555120 :         return t1.first < t2.first;
      69             :     }
      70             : };
      71             : 
      72           0 : std::string COutput::ToString() const
      73             : {
      74           0 :     return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
      75             : }
      76             : 
      77             : class CAffectedKeysVisitor : public boost::static_visitor<void>
      78             : {
      79             : private:
      80             :     const CKeyStore& keystore;
      81             :     std::vector<CKeyID>& vKeys;
      82             : 
      83             : public:
      84     1135032 :     CAffectedKeysVisitor(const CKeyStore& keystoreIn, std::vector<CKeyID>& vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
      85             : 
      86     1135052 :     void Process(const CScript& script)
      87             :     {
      88     1135052 :         txnouttype type;
      89     2270094 :         std::vector<CTxDestination> vDest;
      90     1135052 :         int nRequired;
      91     1135052 :         if (ExtractDestinations(script, type, vDest, nRequired)) {
      92     2265416 :             for (const CTxDestination& dest : vDest)
      93     1132783 :                 boost::apply_visitor(*this, dest);
      94             :         }
      95     1135052 :     }
      96             : 
      97     1132723 :     void operator()(const CKeyID& keyId)
      98             :     {
      99     1132723 :         if (keystore.HaveKey(keyId))
     100     1127952 :             vKeys.push_back(keyId);
     101     1132723 :     }
     102             : 
     103          10 :     void operator()(const CExchangeKeyID& keyId) {
     104          10 :         if (keystore.HaveKey(keyId))
     105           4 :             vKeys.push_back(keyId);
     106          10 :     }
     107             : 
     108          46 :     void operator()(const CScriptID& scriptId)
     109             :     {
     110          46 :         CScript script;
     111          46 :         if (keystore.GetCScript(scriptId, script))
     112          13 :             Process(script);
     113          46 :     }
     114             : 
     115           0 :     void operator()(const CNoDestination& none) {}
     116             : };
     117             : 
     118     1135032 : std::vector<CKeyID> CWallet::GetAffectedKeys(const CScript& spk)
     119             : {
     120     1135032 :     std::vector<CKeyID> ret;
     121           0 :     std::vector<CKeyID> vAffected;
     122     1135032 :     CAffectedKeysVisitor(*this, vAffected).Process(spk);
     123     2262994 :     for (const CKeyID& keyid : vAffected) {
     124     1127952 :         ret.emplace_back(keyid);
     125             :     }
     126     2262964 :     return ret;
     127             : }
     128             : 
     129             : ////////////////////////////////////////////////////////////////////////////////////////////////////
     130             : 
     131             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     132             : 
     133         235 : bool CWallet::SetupSPKM(bool newKeypool, bool memOnly)
     134             : {
     135         235 :     if (m_spk_man->SetupGeneration(newKeypool, true, memOnly)) {
     136         235 :         LogPrintf("%s : spkm setup completed\n", __func__);
     137         235 :         return ActivateSaplingWallet(memOnly);
     138             :     }
     139             :     return false;
     140             : }
     141             : 
     142         237 : bool CWallet::ActivateSaplingWallet(bool memOnly)
     143             : {
     144         237 :     if (m_sspk_man->SetupGeneration(m_spk_man->GetHDChain().GetID(), true, memOnly)) {
     145         237 :         LogPrintf("%s : sapling spkm setup completed\n", __func__);
     146             :         // Just to be triple sure, if the version isn't updated, set it.
     147         237 :         if (!SetMinVersion(WalletFeature::FEATURE_SAPLING)) {
     148           0 :             LogPrintf("%s : ERROR: wallet cannot upgrade to sapling features. Try to upgrade using the 'upgradewallet' RPC command\n", __func__);
     149           0 :             return false;
     150             :         }
     151             :         return true;
     152             :     }
     153             :     return false;
     154             : }
     155             : 
     156          66 : bool CWallet::IsHDEnabled() const
     157             : {
     158          66 :     return m_spk_man->IsHDEnabled();
     159             : }
     160             : 
     161           0 : bool CWallet::IsSaplingUpgradeEnabled() const
     162             : {
     163           0 :     return m_sspk_man->IsEnabled();
     164             : }
     165             : 
     166     1004436 : const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
     167             : {
     168     1004436 :     LOCK(cs_wallet);
     169     1004436 :     std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
     170     1004436 :     if (it == mapWallet.end())
     171             :         return nullptr;
     172     1004336 :     return &(it->second);
     173             : }
     174             : 
     175           0 : std::vector<CWalletTx> CWallet::getWalletTxs()
     176             : {
     177           0 :     LOCK(cs_wallet);
     178           0 :     std::vector<CWalletTx> result;
     179           0 :     result.reserve(mapWallet.size());
     180           0 :     for (const auto& entry : mapWallet) {
     181           0 :         result.emplace_back(entry.second);
     182             :     }
     183           0 :     return result;
     184             : }
     185             : 
     186           9 : CallResult<CTxDestination> CWallet::getNewAddress(const std::string& label)
     187             : {
     188          18 :     return getNewAddress(label, AddressBook::AddressBookPurpose::RECEIVE);
     189             : }
     190             : 
     191           0 : CallResult<CTxDestination> CWallet::getNewStakingAddress(const std::string& label)
     192             : {
     193           0 :     return getNewAddress(label, AddressBook::AddressBookPurpose::COLD_STAKING, CChainParams::Base58Type::STAKING_ADDRESS);
     194             : }
     195             : 
     196        2288 : CallResult<CTxDestination> CWallet::getNewAddress(const std::string& addressLabel, const std::string purpose,
     197             :                                          const CChainParams::Base58Type addrType)
     198             : {
     199        4576 :     LOCK(cs_wallet);
     200             : 
     201             :     // Refill keypool if wallet is unlocked
     202        2288 :     if (!IsLocked())
     203        2274 :         TopUpKeyPool();
     204             : 
     205        2288 :     uint8_t type = (addrType == CChainParams::Base58Type::STAKING_ADDRESS ? HDChain::ChangeType::STAKING : HDChain::ChangeType::EXTERNAL);
     206        2288 :     CPubKey newKey;
     207             :     // Get a key
     208        2288 :     if (!GetKeyFromPool(newKey, type)) {
     209             :         // inform the user to top-up the keypool or unlock the wallet
     210           6 :         return CallResult<CTxDestination>(std::string(
     211           3 :                         _("Keypool ran out, please call keypoolrefill first, or unlock the wallet.")));
     212             :     }
     213        2285 :     CKeyID keyID = newKey.GetID();
     214             : 
     215        2285 :     if (!SetAddressBook(keyID, addressLabel, purpose))
     216           0 :         throw std::runtime_error("CWallet::getNewAddress() : SetAddressBook failed");
     217             : 
     218        2285 :     return CallResult<CTxDestination>(CTxDestination(keyID));
     219             : }
     220             : 
     221           0 : int64_t CWallet::GetKeyCreationTime(const CWDestination& dest)
     222             : {
     223           0 :     auto shieldDest = Standard::GetShieldedDestination(dest);
     224           0 :     auto transpDest = Standard::GetTransparentDestination(dest);
     225           0 :     return shieldDest ? GetKeyCreationTime(*shieldDest) : transpDest ? GetKeyCreationTime(*transpDest) : 0;
     226             : }
     227             : 
     228           0 : int64_t CWallet::GetKeyCreationTime(CPubKey pubkey)
     229             : {
     230           0 :     return mapKeyMetadata[pubkey.GetID()].nCreateTime;
     231             : }
     232             : 
     233           0 : int64_t CWallet::GetKeyCreationTime(const CTxDestination& address)
     234             : {
     235           0 :     const CKeyID* keyID = boost::get<CKeyID>(&address);
     236           0 :     if (keyID) {
     237           0 :         CPubKey keyRet;
     238           0 :         if (GetPubKey(*keyID, keyRet)) {
     239           0 :             return GetKeyCreationTime(keyRet);
     240             :         }
     241             :     }
     242             :     return 0;
     243             : }
     244             : 
     245           0 : int64_t CWallet::GetKeyCreationTime(const libzcash::SaplingPaymentAddress& address)
     246             : {
     247           0 :     libzcash::SaplingIncomingViewingKey ivk;
     248           0 :     return GetSaplingIncomingViewingKey(address, ivk) ?
     249           0 :             GetSaplingScriptPubKeyMan()->GetKeyCreationTime(ivk) : 0;
     250             : }
     251             : 
     252       11871 : bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey& pubkey)
     253             : {
     254       11871 :     AssertLockHeld(cs_wallet); // mapKeyMetadata
     255       11871 :     if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
     256             :         return false;
     257             : 
     258             :     // TODO: Move the follow block entirely inside the spkm (including WriteKey to AddKeyPubKeyWithDB)
     259             :     // check if we need to remove from watch-only
     260       23742 :     CScript script;
     261       11871 :     script = GetScriptForDestination(pubkey.GetID());
     262       11871 :     if (HaveWatchOnly(script))
     263           1 :         RemoveWatchOnly(script);
     264             : 
     265       11871 :     script = GetScriptForRawPubKey(pubkey);
     266       11871 :     if (HaveWatchOnly(script)) {
     267           0 :         RemoveWatchOnly(script);
     268             :     }
     269             : 
     270       11871 :     if (!IsCrypted()) {
     271       35592 :         return WalletBatch(*database).WriteKey(
     272             :                 pubkey,
     273       11864 :                 secret.GetPrivKey(),
     274       23728 :                 mapKeyMetadata[pubkey.GetID()]);
     275             :     }
     276             :     return true;
     277             : }
     278             : 
     279        1746 : bool CWallet::AddCryptedKey(const CPubKey& vchPubKey,
     280             :     const std::vector<unsigned char>& vchCryptedSecret)
     281             : {
     282        1746 :     if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
     283             :         return false;
     284        1746 :     {
     285        3492 :         LOCK(cs_wallet);
     286        1746 :         if (encrypted_batch)
     287         778 :             return encrypted_batch->WriteCryptedKey(vchPubKey,
     288             :                 vchCryptedSecret,
     289        1556 :                 mapKeyMetadata[vchPubKey.GetID()]);
     290             :         else
     291         968 :             return WalletBatch(*database).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
     292             :     }
     293             :     return false;
     294             : }
     295             : 
     296        8389 : bool CWallet::LoadKeyMetadata(const CPubKey& pubkey, const CKeyMetadata& meta)
     297             : {
     298        8389 :     AssertLockHeld(cs_wallet); // mapKeyMetadata
     299        8389 :     if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
     300         501 :         nTimeFirstKey = meta.nCreateTime;
     301             : 
     302        8389 :     mapKeyMetadata[pubkey.GetID()] = meta;
     303        8389 :     return true;
     304             : }
     305             : 
     306         602 : bool CWallet::LoadCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret)
     307             : {
     308         602 :     return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
     309             : }
     310             : 
     311             : /**
     312             :  * Update wallet first key creation time. This should be called whenever keys
     313             :  * are added to the wallet, with the oldest key creation time.
     314             :  */
     315          13 : void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
     316             : {
     317          13 :     AssertLockHeld(cs_wallet);
     318          13 :     if (nCreateTime <= 1) {
     319             :         // Cannot determine birthday information, so set the wallet birthday to
     320             :         // the beginning of time.
     321           9 :         nTimeFirstKey = 1;
     322           4 :     } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
     323           4 :         nTimeFirstKey = nCreateTime;
     324             :     }
     325          13 : }
     326             : 
     327          15 : bool CWallet::AddCScript(const CScript& redeemScript)
     328             : {
     329          15 :     if (!CCryptoKeyStore::AddCScript(redeemScript))
     330             :         return false;
     331          15 :     return WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript);
     332             : }
     333             : 
     334           2 : bool CWallet::LoadCScript(const CScript& redeemScript)
     335             : {
     336             :     /* A sanity check was added in pull #3843 to avoid adding redeemScripts
     337             :      * that never can be redeemed. However, old wallets may still contain
     338             :      * these. Do not add them to the wallet and warn. */
     339           4 :     if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) {
     340           0 :         std::string strAddr = EncodeDestination(CScriptID(redeemScript));
     341           0 :         LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
     342           0 :             __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
     343           0 :         return true;
     344             :     }
     345             : 
     346           2 :     return CCryptoKeyStore::AddCScript(redeemScript);
     347             : }
     348             : 
     349          41 : bool CWallet::AddWatchOnly(const CScript& dest)
     350             : {
     351          41 :     if (!CCryptoKeyStore::AddWatchOnly(dest))
     352             :         return false;
     353          41 :     nTimeFirstKey = 1; // No birthday information for watch-only keys.
     354          41 :     NotifyWatchonlyChanged(true);
     355          41 :     return WalletBatch(*database).WriteWatchOnly(dest);
     356             : }
     357             : 
     358           1 : bool CWallet::RemoveWatchOnly(const CScript& dest)
     359             : {
     360           1 :     AssertLockHeld(cs_wallet);
     361           1 :     if (!CCryptoKeyStore::RemoveWatchOnly(dest))
     362             :         return false;
     363           1 :     if (!HaveWatchOnly())
     364           1 :         NotifyWatchonlyChanged(false);
     365           1 :     if (!WalletBatch(*database).EraseWatchOnly(dest))
     366           0 :         return false;
     367             : 
     368             :     return true;
     369             : }
     370             : 
     371          11 : bool CWallet::LoadWatchOnly(const CScript& dest)
     372             : {
     373          11 :     return CCryptoKeyStore::AddWatchOnly(dest);
     374             : }
     375             : 
     376          25 : bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool stakingOnly)
     377             : {
     378          25 :     CCrypter crypter;
     379          50 :     CKeyingMaterial vMasterKey;
     380             : 
     381          25 :     {
     382          25 :         LOCK(cs_wallet);
     383          27 :         for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys) {
     384          25 :             if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     385          23 :                 return false;
     386          25 :             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
     387           2 :                 continue; // try another master key
     388          23 :             if (Unlock(vMasterKey)) {
     389          23 :                 fWalletUnlockStaking = stakingOnly;
     390          23 :                 return true;
     391             :             }
     392             :         }
     393             :     }
     394           2 :     return false;
     395             : }
     396             : 
     397          23 : bool CWallet::Lock()
     398             : {
     399          23 :     if (!SetCrypted())
     400             :         return false;
     401             : 
     402          23 :     {
     403          23 :         LOCK(cs_KeyStore);
     404          38 :         vMasterKey.clear();
     405             :     }
     406             : 
     407          23 :     NotifyStatusChanged(this);
     408          23 :     return true;
     409             : }
     410             : 
     411          24 : bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn)
     412             : {
     413          24 :     {
     414          24 :         LOCK(cs_KeyStore);
     415          24 :         if (!SetCrypted())
     416           0 :             return false;
     417             : 
     418          24 :         bool keyPass = false;
     419          24 :         bool keyFail = false;
     420          24 :         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
     421        1404 :         for (; mi != mapCryptedKeys.end(); ++mi) {
     422        1396 :             const CPubKey& vchPubKey = (*mi).second.first;
     423        1396 :             const std::vector<unsigned char>& vchCryptedSecret = (*mi).second.second;
     424        2776 :             CKey key;
     425        1396 :             if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key)) {
     426             :                 keyFail = true;
     427          16 :                 break;
     428             :             }
     429        1396 :             keyPass = true;
     430        1396 :             if (fDecryptionThoroughlyChecked)
     431             :                 break;
     432             :         }
     433             : 
     434          24 :         if (keyPass && keyFail) {
     435           0 :             LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
     436           0 :             throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
     437             :         }
     438             : 
     439          24 :         if (keyFail || !keyPass)
     440             :             return false;
     441             : 
     442             :         // Sapling
     443          24 :         if (!UnlockSaplingKeys(vMasterKeyIn, fDecryptionThoroughlyChecked)) {
     444             :             // If Sapling key encryption fail, let's unencrypt the rest of the keys
     445           0 :             LogPrintf("Sapling wallet unlock keys failed\n");
     446           0 :             throw std::runtime_error("Error unlocking wallet: some Sapling keys decrypt but not all. Your wallet file may be corrupt.");
     447             :         }
     448             : 
     449          24 :         vMasterKey = vMasterKeyIn;
     450          24 :         fDecryptionThoroughlyChecked = true;
     451             :     }
     452             : 
     453          24 :     NotifyStatusChanged(this);
     454          24 :     return true;
     455             : }
     456             : 
     457           1 : bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
     458             : {
     459           1 :     bool fWasLocked = IsLocked();
     460           2 :     SecureString strOldWalletPassphraseFinal = strOldWalletPassphrase;
     461             : 
     462           1 :     {
     463           1 :         LOCK(cs_wallet);
     464           1 :         Lock();
     465             : 
     466           1 :         CCrypter crypter;
     467           1 :         CKeyingMaterial vMasterKey;
     468           1 :         for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys) {
     469           1 :             if (!crypter.SetKeyFromPassphrase(strOldWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     470           1 :                 return false;
     471           1 :             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
     472             :                 return false;
     473           1 :             if (Unlock(vMasterKey)) {
     474           1 :                 int64_t nStartTime = GetTimeMillis();
     475           1 :                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
     476           1 :                 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
     477             : 
     478           1 :                 nStartTime = GetTimeMillis();
     479           1 :                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
     480           1 :                 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
     481             : 
     482           1 :                 if (pMasterKey.second.nDeriveIterations < 25000)
     483           0 :                     pMasterKey.second.nDeriveIterations = 25000;
     484             : 
     485           1 :                 LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
     486             : 
     487           1 :                 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     488             :                     return false;
     489           1 :                 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
     490             :                     return false;
     491           1 :                 WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second);
     492           1 :                 if (fWasLocked)
     493           1 :                     Lock();
     494             : 
     495           1 :                 return true;
     496             :             }
     497             :         }
     498             :     }
     499             : 
     500           0 :     return false;
     501             : }
     502             : 
     503       42129 : void CWallet::ChainTipAdded(const CBlockIndex *pindex,
     504             :                             const CBlock *pblock,
     505             :                             SaplingMerkleTree saplingTree)
     506             : {
     507       42129 :     IncrementNoteWitnesses(pindex, pblock, saplingTree);
     508       42129 :     m_sspk_man->UpdateSaplingNullifierNoteMapForBlock(pblock);
     509       42129 : }
     510             : 
     511         327 : void CWallet::SetBestChain(const CBlockLocator& loc)
     512             : {
     513         327 :     WalletBatch batch(*database);
     514         327 :     SetBestChainInternal(batch, loc);
     515         327 : }
     516             : 
     517         327 : void CWallet::SetBestChainInternal(WalletBatch& batch, const CBlockLocator& loc)
     518             : {
     519         327 :     if (!batch.TxnBegin()) {
     520             :         // This needs to be done atomically, so don't do it at all
     521           0 :         LogPrintf("%s: Couldn't start atomic write\n", __func__);
     522           0 :         return;
     523             :     }
     524             : 
     525             :     // Store the best block
     526         327 :     if (!batch.WriteBestBlock(loc)) {
     527           0 :         LogPrintf("SetBestChain(): Failed to write best block, aborting atomic write\n");
     528           0 :         batch.TxnAbort();
     529           0 :         return;
     530             :     }
     531             : 
     532             :     // For performance reasons, we update the witnesses data here and not when each transaction arrives
     533        6478 :     for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
     534       12302 :         auto wtx = wtxItem.second;
     535             :         // We skip transactions for which mapSaplingNoteData is empty.
     536             :         // This covers transactions that have no Sapling data
     537             :         // (i.e. are purely transparent), as well as shielding and unshielding
     538             :         // transactions in which we only have transparent addresses involved.
     539        6151 :         if (!wtx.mapSaplingNoteData.empty()) {
     540             :             // Sanity check
     541          33 :             if (!wtx.tx->isSaplingVersion()) {
     542           0 :                 LogPrintf("SetBestChain(): ERROR, Invalid tx version found with sapling data\n");
     543           0 :                 batch.TxnAbort();
     544           0 :                 uiInterface.ThreadSafeMessageBox(
     545           0 :                         _("A fatal internal error occurred, see debug.log for details"),
     546             :                         "Error", CClientUIInterface::MSG_ERROR);
     547           0 :                 StartShutdown();
     548           0 :                 return;
     549             :             }
     550             : 
     551          33 :             if (!batch.WriteTx(wtx)) {
     552           0 :                 LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
     553           0 :                 batch.TxnAbort();
     554             :                 return;
     555             :             }
     556             :         }
     557             :     }
     558             : 
     559             :     // Store sapling witness cache size
     560         327 :     if (m_sspk_man->nWitnessCacheNeedsUpdate) {
     561         327 :         if (!batch.WriteWitnessCacheSize(m_sspk_man->nWitnessCacheSize)) {
     562           0 :             LogPrintf("%s: Failed to write nWitnessCacheSize\n", __func__);
     563           0 :             batch.TxnAbort();
     564           0 :             return;
     565             :         }
     566             :     }
     567             : 
     568         327 :     if (!batch.TxnCommit()) {
     569             :         // Couldn't commit all to db, but in-memory state is fine
     570           0 :         LogPrintf("%s: Couldn't commit atomic write\n", __func__);
     571           0 :         return;
     572             :     }
     573             : 
     574             :     // Reset cache if the commit succeed and is needed.
     575         327 :     if (m_sspk_man->nWitnessCacheNeedsUpdate) {
     576         327 :         m_sspk_man->nWitnessCacheNeedsUpdate = false;
     577             :     }
     578             : }
     579             : 
     580       11886 : bool CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in, bool fExplicit)
     581             : {
     582       23772 :     LOCK(cs_wallet); // nWalletVersion
     583       11886 :     if (nWalletVersion >= nVersion)
     584             :         return true;
     585             : 
     586             :     // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
     587         238 :     if (fExplicit && nVersion > nWalletMaxVersion)
     588           0 :         nVersion = FEATURE_LATEST;
     589             : 
     590         238 :     nWalletVersion = nVersion;
     591             : 
     592         238 :     if (nVersion > nWalletMaxVersion)
     593         238 :         nWalletMaxVersion = nVersion;
     594             : 
     595         238 :     {
     596         238 :         WalletBatch* batch = batch_in ? batch_in : new WalletBatch(*database);
     597         238 :         if (nWalletVersion > 40000)
     598         238 :             batch->WriteMinVersion(nWalletVersion);
     599         238 :         if (!batch_in)
     600         476 :             delete batch;
     601             :     }
     602             : 
     603             :     return true;
     604             : }
     605             : 
     606         203 : bool CWallet::SetMaxVersion(int nVersion)
     607             : {
     608         203 :     LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion
     609             :     // cannot downgrade below current version
     610         203 :     if (nWalletVersion > nVersion)
     611             :         return false;
     612             : 
     613         203 :     nWalletMaxVersion = nVersion;
     614             : 
     615         203 :     return true;
     616             : }
     617             : 
     618         397 : std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
     619             : {
     620         397 :     std::set<uint256> result;
     621         397 :     AssertLockHeld(cs_wallet);
     622             : 
     623         397 :     std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
     624         397 :     if (it == mapWallet.end())
     625             :         return result;
     626         395 :     const CWalletTx& wtx = it->second;
     627             : 
     628         395 :     std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
     629             : 
     630         840 :     for (const CTxIn& txin : wtx.tx->vin) {
     631         445 :         if (mapTxSpends.count(txin.prevout) <= 1 || wtx.tx->HasZerocoinSpendInputs())
     632         436 :             continue; // No conflict if zero or one spends
     633           9 :         range = mapTxSpends.equal_range(txin.prevout);
     634          27 :         for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
     635          18 :             result.insert(_it->second);
     636             :     }
     637             : 
     638             :     // Sapling
     639         395 :     if (HasSaplingSPKM()) {
     640         395 :         m_sspk_man->GetConflicts(wtx, result);
     641             :     }
     642             : 
     643             :     return result;
     644             : }
     645             : 
     646         144 : void CWallet::SyncMetaDataN(std::pair<TxSpendMap<uint256>::iterator, TxSpendMap<uint256>::iterator> range)
     647             : {
     648         144 :     SyncMetaData<uint256>(range);
     649         144 : }
     650             : 
     651             : template <class T>
     652      207717 : void CWallet::SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator> range)
     653             : {
     654             :     // We want all the wallet transactions in range to have the same metadata as
     655             :     // the oldest (smallest nOrderPos).
     656             :     // So: find smallest nOrderPos:
     657             : 
     658      207717 :     int nMinOrderPos = std::numeric_limits<int>::max();
     659      207717 :     const CWalletTx* copyFrom = nullptr;
     660      440006 :     for (typename TxSpendMap<T>::iterator it = range.first; it != range.second; ++it) {
     661      232289 :         const CWalletTx* wtx = &mapWallet.at(it->second);
     662      232289 :         int n = wtx->nOrderPos;
     663      232289 :         if (n < nMinOrderPos) {
     664      207719 :             nMinOrderPos = n;
     665      207719 :             copyFrom = wtx;
     666             :         }
     667             :     }
     668             : 
     669      207717 :     if (!copyFrom) {
     670             :         return;
     671             :     }
     672             : 
     673             :     // Now copy data from copyFrom to rest:
     674      440006 :     for (auto it = range.first; it != range.second; ++it) {
     675      232289 :         const uint256& hash = it->second;
     676      232289 :         CWalletTx* copyTo = &mapWallet.at(hash);
     677      232289 :         if (copyFrom == copyTo) continue;
     678             :         assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
     679             :         //if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
     680       24338 :         copyTo->mapValue = copyFrom->mapValue;
     681       24338 :         copyTo->vOrderForm = copyFrom->vOrderForm;
     682             :         // fTimeReceivedIsTxTime not copied on purpose
     683             :         // nTimeReceived not copied on purpose
     684       24338 :         copyTo->nTimeSmart = copyFrom->nTimeSmart;
     685       24338 :         copyTo->fFromMe = copyFrom->fFromMe;
     686             :         // nOrderPos not copied on purpose
     687             :         // cached members not copied on purpose
     688             :     }
     689             : }
     690             : 
     691         963 : const CKeyingMaterial& CWallet::GetEncryptionKey() const
     692             : {
     693         963 :     return vMasterKey;
     694             : }
     695             : 
     696       11507 : bool CWallet::HasEncryptionKeys() const
     697             : {
     698       11507 :     return !mapMasterKeys.empty();
     699             : }
     700             : 
     701        8831 : ScriptPubKeyMan* CWallet::GetScriptPubKeyMan() const
     702             : {
     703        8831 :     return m_spk_man.get();
     704             : }
     705             : 
     706     1543914 : bool CWallet::HasSaplingSPKM() const
     707             : {
     708     1543914 :     return GetSaplingScriptPubKeyMan()->IsEnabled();
     709             : }
     710             : 
     711           2 : bool CWallet::IsSaplingSpent(const SaplingOutPoint& op) const
     712             : {
     713           2 :     return m_sspk_man->IsSaplingSpent(op);
     714             : }
     715             : 
     716             : /**
     717             :  * Outpoint is spent if any non-conflicted transaction
     718             :  * spends it:
     719             :  */
     720     9652734 : bool CWallet::IsSpent(const COutPoint& outpoint) const
     721             : {
     722     9652734 :     AssertLockHeld(cs_wallet);
     723     9652734 :     std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
     724     9652734 :     range = mapTxSpends.equal_range(outpoint);
     725     9653109 :     for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
     726     5740154 :         const uint256& wtxid = it->second;
     727     5740154 :         std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
     728     5740154 :         if (mit != mapWallet.end()) {
     729     5740154 :             bool fConflicted;
     730     5740154 :             const int nDepth = mit->second.GetDepthAndMempool(fConflicted);
     731             :             // not in mempool txes can spend coins only if not coinstakes
     732     5740154 :             const bool fConflictedCoinstake = fConflicted && mit->second.IsCoinStake();
     733     5740154 :             if (nDepth > 0  || (nDepth == 0 && !mit->second.isAbandoned() && !fConflictedCoinstake) )
     734     5739779 :                 return true; // Spent
     735             :         }
     736             :     }
     737     3912955 :     return false;
     738             : }
     739             : 
     740     9639819 : bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
     741             : {
     742     9639819 :     return IsSpent(COutPoint(hash, n));
     743             : }
     744             : 
     745      207573 : void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
     746             : {
     747      207573 :     mapTxSpends.emplace(outpoint, wtxid);
     748      207573 :     setLockedCoins.erase(outpoint);
     749             : 
     750      207573 :     std::pair<TxSpends::iterator, TxSpends::iterator> range;
     751      207573 :     range = mapTxSpends.equal_range(outpoint);
     752      207573 :     SyncMetaData<COutPoint>(range);
     753      207573 : }
     754             : 
     755      125882 : void CWallet::AddToSpends(const uint256& wtxid)
     756             : {
     757      125882 :     auto it = mapWallet.find(wtxid);
     758      125882 :     assert(it != mapWallet.end());
     759      125882 :     CWalletTx& thisTx = it->second;
     760      125882 :     if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
     761       18821 :         return;
     762             : 
     763      314634 :     for (const CTxIn& txin : thisTx.tx->vin)
     764      207573 :         AddToSpends(txin.prevout, wtxid);
     765             : 
     766      107061 :     if (CanSupportFeature(FEATURE_SAPLING) && thisTx.tx->sapData) {
     767      107205 :         for (const SpendDescription &spend : thisTx.tx->sapData->vShieldedSpend) {
     768         144 :             GetSaplingScriptPubKeyMan()->AddToSaplingSpends(spend.nullifier, wtxid);
     769             :         }
     770             :     }
     771             : }
     772             : 
     773           7 : bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
     774             : {
     775           7 :     if (IsCrypted())
     776             :         return false;
     777             : 
     778          14 :     CKeyingMaterial vMasterKey;
     779             : 
     780           7 :     vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
     781           7 :     GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
     782             : 
     783          14 :     CMasterKey kMasterKey;
     784             : 
     785           7 :     kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
     786           7 :     GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
     787             : 
     788          14 :     CCrypter crypter;
     789           7 :     int64_t nStartTime = GetTimeMillis();
     790           7 :     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
     791           7 :     kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
     792             : 
     793           7 :     nStartTime = GetTimeMillis();
     794           7 :     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
     795           7 :     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
     796             : 
     797           7 :     if (kMasterKey.nDeriveIterations < 25000)
     798           0 :         kMasterKey.nDeriveIterations = 25000;
     799             : 
     800           7 :     LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
     801             : 
     802           7 :     if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
     803             :         return false;
     804           7 :     if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
     805             :         return false;
     806             : 
     807           7 :     {
     808           7 :         LOCK(cs_wallet);
     809           7 :         mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
     810           7 :         assert(!encrypted_batch);
     811           7 :         encrypted_batch = new WalletBatch(*database);
     812           7 :         if (!encrypted_batch->TxnBegin()) {
     813           0 :             delete encrypted_batch;
     814           0 :             encrypted_batch = nullptr;
     815           0 :             return false;
     816             :         }
     817           7 :         encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
     818             : 
     819             : 
     820           7 :         if (!EncryptKeys(vMasterKey) || (m_sspk_man->IsEnabled() && !m_sspk_man->EncryptSaplingKeys(vMasterKey))) {
     821           0 :             encrypted_batch->TxnAbort();
     822           0 :             delete encrypted_batch;
     823             :             // We now probably have half of our keys encrypted in memory, and half not...
     824             :             // die and let the user reload their unencrypted wallet.
     825           0 :             assert(false);
     826             :         }
     827             : 
     828             :         // Encryption was introduced in version 0.4.0
     829           7 :         SetMinVersion(FEATURE_WALLETCRYPT, encrypted_batch, true);
     830             : 
     831           7 :         if (!encrypted_batch->TxnCommit()) {
     832           0 :             delete encrypted_batch;
     833             :             // We now have keys encrypted in memory, but not on disk...
     834             :             // die to avoid confusion and let the user reload their unencrypted wallet.
     835           0 :             assert(false);
     836             :         }
     837             : 
     838          14 :         delete encrypted_batch;
     839           7 :         encrypted_batch = nullptr;
     840             : 
     841           7 :         Lock();
     842           7 :         Unlock(strWalletPassphrase);
     843             :         // if we are using HD, replace the HD seed with a new one
     844           7 :         if (m_spk_man->IsHDEnabled()) {
     845           7 :             if (!m_spk_man->SetupGeneration(true, true)) {
     846             :                 return false;
     847             :             }
     848             :         }
     849           7 :         Lock();
     850             : 
     851             :         // Need to completely rewrite the wallet file; if we don't, bdb might keep
     852             :         // bits of the unencrypted private key in slack space in the database file.
     853           7 :         database->Rewrite();
     854             : 
     855             :         // BDB seems to have a bad habit of writing old data into
     856             :         // slack space in .dat files; that is bad if the old data is
     857             :         // unencrypted private keys. So:
     858           7 :         database->ReloadDbEnv();
     859             : 
     860             :     }
     861           7 :     NotifyStatusChanged(this);
     862             : 
     863             :     return true;
     864             : }
     865             : 
     866      119200 : int64_t CWallet::IncOrderPosNext(WalletBatch* batch)
     867             : {
     868      119200 :     AssertLockHeld(cs_wallet); // nOrderPosNext
     869      119200 :     int64_t nRet = nOrderPosNext++;
     870      119200 :     if (batch) {
     871      119200 :         batch->WriteOrderPosNext(nOrderPosNext);
     872             :     } else {
     873           0 :         WalletBatch(*database).WriteOrderPosNext(nOrderPosNext);
     874             :     }
     875      119200 :     return nRet;
     876             : }
     877             : 
     878           0 : bool CWallet::IsKeyUsed(const CPubKey& vchPubKey) const
     879             : {
     880           0 :     if (vchPubKey.IsValid()) {
     881           0 :         const CScript& scriptPubKey = GetScriptForDestination(vchPubKey.GetID());
     882           0 :         for (const auto& entry : mapWallet) {
     883           0 :             const CWalletTx& wtx = entry.second;
     884           0 :             for (const CTxOut& txout : wtx.tx->vout)
     885           0 :                 if (txout.scriptPubKey == scriptPubKey)
     886           0 :                     return true;
     887             :         }
     888             :     }
     889             :     return false;
     890             : }
     891             : 
     892        1073 : void CWallet::MarkDirty()
     893             : {
     894        1073 :     {
     895        1073 :         LOCK(cs_wallet);
     896        5651 :         for (std::pair<const uint256, CWalletTx> & item : mapWallet)
     897        4578 :             item.second.MarkDirty();
     898             :     }
     899        1073 : }
     900             : 
     901      396555 : bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
     902             : {
     903      793110 :     LOCK(cs_wallet);
     904      793110 :     WalletBatch batch(*database, "r+", fFlushOnClose);
     905      396555 :     const uint256& hash = wtxIn.GetHash();
     906             : 
     907             :     // Inserts only if not already there, returns tx inserted or tx found
     908      396555 :     std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.emplace(hash, wtxIn);
     909      396555 :     CWalletTx& wtx = (*ret.first).second;
     910      396555 :     wtx.BindWallet(this);
     911             :     // Sapling
     912      396555 :     m_sspk_man->UpdateNullifierNoteMapWithTx(wtx);
     913      396555 :     bool fInsertedNew = ret.second;
     914      396555 :     if (fInsertedNew) {
     915      119200 :         wtx.nTimeReceived = GetAdjustedTime();
     916      119200 :         wtx.nOrderPos = IncOrderPosNext(&batch);
     917      119200 :         wtxOrdered.emplace(wtx.nOrderPos, &wtx);
     918      119200 :         wtx.UpdateTimeSmart();
     919      119200 :         AddToSpends(hash);
     920             :     }
     921             : 
     922      396555 :     bool fUpdated = false;
     923      396555 :     if (!fInsertedNew) {
     924      277355 :         if (wtxIn.m_confirm.status != wtx.m_confirm.status) {
     925      216137 :             wtx.m_confirm.status = wtxIn.m_confirm.status;
     926      216137 :             wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
     927      216137 :             wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
     928      216137 :             wtx.m_confirm.block_height = wtxIn.m_confirm.block_height;
     929      216137 :             wtx.UpdateTimeSmart();
     930             :             fUpdated = true;
     931             :         } else {
     932       61218 :             assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
     933       61218 :             assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
     934       61218 :             assert(wtx.m_confirm.block_height == wtxIn.m_confirm.block_height);
     935             :         }
     936      277355 :         if (HasSaplingSPKM() && m_sspk_man->UpdatedNoteData(wtxIn, wtx)) {
     937             :             fUpdated = true;
     938             :         }
     939      277355 :         if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) {
     940           0 :             wtx.fFromMe = wtxIn.fFromMe;
     941           0 :             fUpdated = true;
     942             :         }
     943             :     }
     944             : 
     945             :     //// debug print
     946      734023 :     LogPrintf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
     947             : 
     948             :     // Write to disk
     949      396555 :     if (fInsertedNew || fUpdated) {
     950      336442 :         if (!batch.WriteTx(wtx))
     951             :             return false;
     952             :     }
     953             : 
     954             :     // Break debit/credit balance caches:
     955      396555 :     wtx.MarkDirty();
     956             : 
     957             :     // Notify UI of new or updated transaction
     958      673910 :     NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
     959             : 
     960             :     // notify an external script when a wallet transaction comes in or is updated
     961     1189665 :     std::string strCmd = gArgs.GetArg("-walletnotify", "");
     962             : 
     963      396555 :     if (!strCmd.empty()) {
     964          73 :         boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
     965         146 :         std::thread t(runCommand, strCmd);
     966          73 :         t.detach(); // thread runs free
     967             :     }
     968      396555 :     return true;
     969             : }
     970             : 
     971             : // Internal function for now, this will be part of a chain interface class in the future.
     972        6526 : static Optional<int> getTipBlockHeight(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
     973             : {
     974        6526 :     AssertLockHeld(cs_main);
     975             : 
     976        6526 :     CBlockIndex* pindex = LookupBlockIndex(hash);
     977       12890 :     if (pindex && chainActive.Contains(pindex)) {
     978        6346 :         return Optional<int>(pindex->nHeight);
     979             :     }
     980         180 :     return nullopt;
     981             : }
     982             : 
     983        6682 : bool CWallet::LoadToWallet(CWalletTx& wtxIn)
     984             : {
     985       13364 :     LOCK2(cs_main, cs_wallet);
     986             :     // If tx hasn't been reorged out of chain while wallet being shutdown
     987             :     // change tx status to UNCONFIRMED and reset hashBlock/nIndex.
     988       18226 :     if (!wtxIn.m_confirm.hashBlock.IsNull()) {
     989        6526 :         Optional<int> block_height = getTipBlockHeight(wtxIn.m_confirm.hashBlock);
     990        6526 :         if (block_height) {
     991             :             // Update cached block height variable since it not stored in the
     992             :             // serialized transaction.
     993        6346 :             wtxIn.m_confirm.block_height = *block_height;
     994         180 :         } else if (wtxIn.isConflicted() || wtxIn.isConfirmed()) {
     995             :             // If tx block (or conflicting block) was reorged out of chain
     996             :             // while the wallet was shutdown, change tx status to UNCONFIRMED
     997             :             // and reset block height, hash, and index. ABANDONED tx don't have
     998             :             // associated blocks and don't need to be updated. The case where a
     999             :             // transaction was reorged out while online and then reconfirmed
    1000             :             // while offline is covered by the rescan logic.
    1001         180 :             wtxIn.setUnconfirmed();
    1002         180 :             wtxIn.m_confirm.hashBlock = UINT256_ZERO;
    1003         180 :             wtxIn.m_confirm.block_height = 0;
    1004         180 :             wtxIn.m_confirm.nIndex = 0;
    1005             :         }
    1006             :     }
    1007        6682 :     const uint256& hash = wtxIn.GetHash();
    1008        6682 :     CWalletTx& wtx = mapWallet.emplace(hash, wtxIn).first->second;
    1009        6682 :     wtx.BindWallet(this);
    1010             :     // Sapling
    1011        6682 :     m_sspk_man->UpdateNullifierNoteMapWithTx(wtx);
    1012        6682 :     wtxOrdered.emplace(wtx.nOrderPos, &wtx);
    1013        6682 :     AddToSpends(hash);
    1014       13483 :     for (const CTxIn& txin : wtx.tx->vin) {
    1015        6801 :         auto it = mapWallet.find(txin.prevout.hash);
    1016        6801 :         if (it != mapWallet.end()) {
    1017         133 :             CWalletTx& prevtx = it->second;
    1018         133 :             if (prevtx.isConflicted()) {
    1019           0 :                 MarkConflicted(prevtx.m_confirm.hashBlock, prevtx.m_confirm.block_height, wtx.GetHash());
    1020             :             }
    1021             :         }
    1022             :     }
    1023       13364 :     return true;
    1024             : }
    1025             : 
    1026      647495 : bool CWallet::FindNotesDataAndAddMissingIVKToKeystore(const CTransaction& tx, Optional<mapSaplingNoteData_t>& saplingNoteData)
    1027             : {
    1028      647495 :     auto saplingNoteDataAndAddressesToAdd = m_sspk_man->FindMySaplingNotes(tx);
    1029      647495 :     saplingNoteData = saplingNoteDataAndAddressesToAdd.first;
    1030     1294986 :     auto addressesToAdd = saplingNoteDataAndAddressesToAdd.second;
    1031             :     // Add my addresses
    1032      647495 :     for (const auto& addressToAdd : addressesToAdd) {
    1033           0 :         if (!m_sspk_man->AddSaplingIncomingViewingKey(addressToAdd.second, addressToAdd.first)) {
    1034           0 :             return false;
    1035             :         }
    1036             :     }
    1037      647495 :     return true;
    1038             : }
    1039             : 
    1040        1810 : void CWallet::AddExternalNotesDataToTx(CWalletTx& wtx) const
    1041             : {
    1042        1810 :     if (HasSaplingSPKM() && wtx.tx->IsShieldedTx()) {
    1043        1810 :         const uint256& txId = wtx.GetHash();
    1044             :         // Add the external outputs.
    1045        1810 :         SaplingOutPoint op {txId, 0};
    1046        3796 :         for (unsigned int i = 0; i < wtx.tx->sapData->vShieldedOutput.size(); i++) {
    1047        1986 :             op.n = i;
    1048        3873 :             if (wtx.mapSaplingNoteData.count(op)) continue;     // internal output
    1049         198 :             auto recovered = GetSaplingScriptPubKeyMan()->TryToRecoverNote(wtx, op);
    1050          99 :             if (recovered) {
    1051             :                 // Always true for 'IsFromMe' transactions
    1052          95 :                 wtx.mapSaplingNoteData[op].address = recovered->second;
    1053          95 :                 wtx.mapSaplingNoteData[op].amount = recovered->first.value();
    1054          95 :                 const auto& memo = recovered->first.memo();
    1055             :                 // don't save empty memo (starting with 0xF6)
    1056          95 :                 if (memo[0] < 0xF6) {
    1057          99 :                     wtx.mapSaplingNoteData[op].memo = memo;
    1058             :                 }
    1059             :             }
    1060             :         }
    1061             :     }
    1062        1810 : }
    1063             : 
    1064             : /**
    1065             :  * Add a transaction to the wallet, or update it. pIndex and posInBlock should
    1066             :  * be set when the transaction was known to be included in a block.  When
    1067             :  * pIndex == nullptr, then wallet state is not updated in AddToWallet, but
    1068             :  * notifications happen and cached balances are marked dirty.
    1069             :  *
    1070             :  * If fUpdate is true, existing transactions will be updated.
    1071             :  * TODO: One exception to this is that the abandoned state is cleared under the
    1072             :  * assumption that any further notification of a transaction that was considered
    1073             :  * abandoned is an indication that it is not safe to be considered abandoned.
    1074             :  * Abandoned state should probably be more carefully tracked via different
    1075             :  * posInBlock signals or by checking mempool presence when necessary.
    1076             :  */
    1077      647707 : bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CWalletTx::Confirmation& confirm, bool fUpdate)
    1078             : {
    1079      647707 :     const CTransaction& tx = *ptx;
    1080      647707 :     {
    1081      647707 :         AssertLockHeld(cs_wallet);
    1082             : 
    1083     1295416 :         if (!confirm.hashBlock.IsNull() && !tx.HasZerocoinSpendInputs() && !tx.IsCoinBase()) {
    1084      909198 :             for (const CTxIn& txin : tx.vin) {
    1085      588830 :                 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
    1086      894131 :                 while (range.first != range.second) {
    1087      305301 :                     if (range.first->second != tx.GetHash()) {
    1088          48 :                         LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), confirm.hashBlock.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
    1089          12 :                         MarkConflicted(confirm.hashBlock, confirm.block_height, range.first->second);
    1090             :                     }
    1091      894131 :                     range.first++;
    1092             :                 }
    1093             :             }
    1094             :         }
    1095             : 
    1096      647707 :         bool fExisted = mapWallet.count(tx.GetHash()) != 0;
    1097      647707 :         if (fExisted && !fUpdate) return false;
    1098             : 
    1099             :         // Check tx for Sapling notes
    1100      647707 :         Optional<mapSaplingNoteData_t> saplingNoteData {nullopt};
    1101      647707 :         if (HasSaplingSPKM()) {
    1102      647489 :             if (!FindNotesDataAndAddMissingIVKToKeystore(tx, saplingNoteData)) {
    1103      395104 :                 return false; // error adding incoming viewing key.
    1104             :             }
    1105             :         }
    1106             : 
    1107             :         // If this is a ProRegTx and the wallet owns the collateral, lock the corresponding coin
    1108      647707 :         LockIfMyCollateral(ptx);
    1109             : 
    1110      647707 :         bool isFromMe = IsFromMe(ptx);
    1111      647707 :         if (fExisted || IsMine(ptx) || isFromMe || (saplingNoteData && !saplingNoteData->empty())) {
    1112             : 
    1113             :             /* Check if any keys in the wallet keypool that were supposed to be unused
    1114             :              * have appeared in a new transaction. If so, remove those keys from the keypool.
    1115             :              * This can happen when restoring an old wallet backup that does not contain
    1116             :              * the mostly recently created transactions from newer versions of the wallet.
    1117             :              */
    1118             : 
    1119             :             // loop though all outputs
    1120     1530141 :             for (const CTxOut& txout: tx.vout) {
    1121     1135032 :                 m_spk_man->MarkUnusedAddresses(txout.scriptPubKey);
    1122             :             }
    1123             : 
    1124      790208 :             CWalletTx wtx(this, MakeTransactionRef(tx));
    1125      395104 :             if (wtx.tx->IsShieldedTx()) {
    1126        1955 :                 if (saplingNoteData && !saplingNoteData->empty()) {
    1127        1896 :                     wtx.SetSaplingNoteData(*saplingNoteData);
    1128             :                 }
    1129             : 
    1130             :                 // Add external notes info if we are sending
    1131        1955 :                 if (isFromMe) AddExternalNotesDataToTx(wtx);
    1132             :             }
    1133             : 
    1134             :             // Block disconnection override an abandoned tx as unconfirmed
    1135             :             // which means user may have to call abandontransaction again
    1136      395104 :             wtx.m_confirm = confirm;
    1137             : 
    1138      395104 :             return AddToWallet(wtx, false);
    1139             :         }
    1140             :     }
    1141      252603 :     return false;
    1142             : }
    1143             : 
    1144           6 : bool CWallet::AbandonTransaction(const uint256& hashTx)
    1145             : {
    1146          12 :     LOCK(cs_wallet);
    1147             : 
    1148          12 :     WalletBatch batch(*database, "r+");
    1149             : 
    1150          12 :     std::set<uint256> todo;
    1151           6 :     std::set<uint256> done;
    1152             : 
    1153             :     // Can't mark abandoned if confirmed or in mempool
    1154           6 :     auto it = mapWallet.find(hashTx);
    1155           6 :     assert(it != mapWallet.end());
    1156           6 :     CWalletTx& origtx = it->second;
    1157           6 :     if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
    1158             :         return false;
    1159             :     }
    1160             : 
    1161           5 :     todo.insert(hashTx);
    1162             : 
    1163          12 :     while (!todo.empty()) {
    1164           7 :         uint256 now = *todo.begin();
    1165           7 :         todo.erase(now);
    1166           7 :         done.insert(now);
    1167           7 :         auto it2 = mapWallet.find(now);
    1168           7 :         assert(it2 != mapWallet.end());
    1169           7 :         CWalletTx& wtx = it2->second;
    1170           7 :         int currentconfirm = wtx.GetDepthInMainChain();
    1171             :         // If the orig tx was not in block, none of its spends can be
    1172           7 :         assert(currentconfirm <= 0);
    1173             :         // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
    1174           7 :         if (currentconfirm == 0 && !wtx.isAbandoned()) {
    1175             :             // If the orig tx was not in block/mempool, none of its spends can be in mempool
    1176           7 :             assert(!wtx.InMempool());
    1177           7 :             wtx.setAbandoned();
    1178           7 :             wtx.MarkDirty();
    1179           7 :             batch.WriteTx(wtx);
    1180           7 :             NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
    1181             :             // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
    1182           7 :             TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
    1183           8 :             while (iter != mapTxSpends.end() && iter->first.hash == now) {
    1184           2 :                 if (!done.count(iter->second)) {
    1185           2 :                     todo.insert(iter->second);
    1186             :                 }
    1187           9 :                 iter++;
    1188             :             }
    1189             :             // If a transaction changes 'conflicted' state, that changes the balance
    1190             :             // available of the outputs it spends. So force those to be recomputed
    1191          14 :             for (const CTxIn& txin : wtx.tx->vin) {
    1192           7 :                 auto _it = mapWallet.find(txin.prevout.hash);
    1193           7 :                 if (_it != mapWallet.end()) {
    1194           7 :                     _it->second.MarkDirty();
    1195             :                 }
    1196             :             }
    1197             :         }
    1198             :     }
    1199             : 
    1200             :     return true;
    1201             : }
    1202             : 
    1203          12 : void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx)
    1204             : {
    1205          24 :     LOCK(cs_wallet);
    1206             : 
    1207          12 :     int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
    1208             :     // If number of conflict confirms cannot be determined, this means
    1209             :     // that the block is still unknown or not yet part of the main chain,
    1210             :     // for example when loading the wallet during a reindex. Do nothing in that
    1211             :     // case.
    1212          12 :     if (conflictconfirms >= 0)
    1213           0 :         return;
    1214             : 
    1215             :     // Do not flush the wallet here for performance reasons
    1216          24 :     WalletBatch batch(*database, "r+", false);
    1217             : 
    1218          24 :     std::set<uint256> todo;
    1219          12 :     std::set<uint256> done;
    1220             : 
    1221          12 :     todo.insert(hashTx);
    1222             : 
    1223          26 :     while (!todo.empty()) {
    1224          14 :         uint256 now = *todo.begin();
    1225          14 :         todo.erase(now);
    1226          14 :         done.insert(now);
    1227          14 :         auto it = mapWallet.find(now);
    1228          14 :         assert(it != mapWallet.end());
    1229          14 :         CWalletTx& wtx = it->second;
    1230          14 :         int currentconfirm = wtx.GetDepthInMainChain();
    1231          14 :         if (conflictconfirms < currentconfirm) {
    1232             :             // Block is 'more conflicted' than current confirm; update.
    1233             :             // Mark transaction as conflicted with this block.
    1234          13 :             wtx.m_confirm.nIndex = 0;
    1235          13 :             wtx.m_confirm.hashBlock = hashBlock;
    1236          13 :             wtx.m_confirm.block_height = conflicting_height;
    1237          13 :             wtx.setConflicted();
    1238          13 :             wtx.MarkDirty();
    1239          13 :             batch.WriteTx(wtx);
    1240             :             // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
    1241          13 :             TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
    1242          13 :             while (iter != mapTxSpends.end() && iter->first.hash == now) {
    1243           2 :                  if (!done.count(iter->second)) {
    1244           2 :                      todo.insert(iter->second);
    1245             :                  }
    1246          15 :                  iter++;
    1247             :             }
    1248             :             // If a transaction changes 'conflicted' state, that changes the balance
    1249             :             // available of the outputs it spends. So force those to be recomputed
    1250          28 :             for (const CTxIn& txin : wtx.tx->vin) {
    1251          15 :                 auto _it = mapWallet.find(txin.prevout.hash);
    1252          15 :                 if (_it != mapWallet.end()) {
    1253          12 :                     _it->second.MarkDirty();
    1254             :                 }
    1255             :             }
    1256             :         }
    1257             :     }
    1258             : }
    1259             : 
    1260      559149 : void CWallet::SyncTransaction(const CTransactionRef& ptx, const CWalletTx::Confirmation& confirm)
    1261             : {
    1262      559149 :     if (!AddToWalletIfInvolvingMe(ptx, confirm, true)) {
    1263             :         return; // Not one of ours
    1264             :     }
    1265             : 
    1266      386417 :     MarkAffectedTransactionsDirty(*ptx);
    1267             : }
    1268             : 
    1269      171150 : void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx)
    1270             : {
    1271      171150 :     LOCK(cs_wallet);
    1272      342300 :     CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
    1273      171150 :     SyncTransaction(ptx, confirm);
    1274             : 
    1275      171150 :     auto it = mapWallet.find(ptx->GetHash());
    1276      171150 :     if (it != mapWallet.end()) {
    1277      155879 :         it->second.fInMempool = true;
    1278             :     }
    1279      171150 : }
    1280             : 
    1281      300729 : void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) {
    1282      300729 :     LOCK(cs_wallet);
    1283      300729 :     auto it = mapWallet.find(ptx->GetHash());
    1284      300729 :     if (it != mapWallet.end()) {
    1285      170178 :         it->second.fInMempool = false;
    1286             :     }
    1287             :     // Handle transactions that were removed from the mempool because they
    1288             :     // conflict with transactions in a newly connected block.
    1289      300729 :     if (reason == MemPoolRemovalReason::CONFLICT) {
    1290             :         // Call SyncNotifications, so external -walletnotify notifications will
    1291             :         // be triggered for these transactions. Set Status::UNCONFIRMED instead
    1292             :         // of Status::CONFLICTED for a few reasons:
    1293             :         //
    1294             :         // 1. The transactionRemovedFromMempool callback does not currently
    1295             :         //    provide the conflicting block's hash and height, and for backwards
    1296             :         //    compatibility reasons it may not be not safe to store conflicted
    1297             :         //    wallet transactions with a null block hash. See
    1298             :         //    https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993.
    1299             :         // 2. For most of these transactions, the wallet's internal conflict
    1300             :         //    detection in the blockConnected handler will subsequently call
    1301             :         //    MarkConflicted and update them with CONFLICTED status anyway. This
    1302             :         //    applies to any wallet transaction that has inputs spent in the
    1303             :         //    block, or that has ancestors in the wallet with inputs spent by
    1304             :         //    the block.
    1305             :         // 3. Longstanding behavior since the sync implementation in
    1306             :         //    https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync
    1307             :         //    implementation before that was to mark these transactions
    1308             :         //    unconfirmed rather than conflicted.
    1309             :         //
    1310             :         // Nothing described above should be seen as an unchangeable requirement
    1311             :         // when improving this code in the future. The wallet's heuristics for
    1312             :         // distinguishing between conflicted and unconfirmed transactions are
    1313             :         // imperfect, and could be improved in general, see
    1314             :         // https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
    1315           6 :         SyncTransaction(ptx, {CWalletTx::Status::UNCONFIRMED, /* block height  */ 0, /* block hash */ {}, /* index */ 0});
    1316             :     }
    1317      300729 : }
    1318             : 
    1319       40375 : void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex)
    1320             : {
    1321       40375 :     {
    1322       80750 :         LOCK2(cs_main, cs_wallet);
    1323             : 
    1324       40375 :         m_last_block_processed = pindex->GetBlockHash();
    1325       40375 :         m_last_block_processed_time = pindex->GetBlockTime();
    1326       40375 :         m_last_block_processed_height = pindex->nHeight;
    1327      339698 :         for (size_t index = 0; index < pblock->vtx.size(); index++) {
    1328      299323 :             CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_last_block_processed_height,
    1329      299323 :                                             m_last_block_processed, index);
    1330      299323 :             SyncTransaction(pblock->vtx[index], confirm);
    1331      299323 :             TransactionRemovedFromMempool(pblock->vtx[index], MemPoolRemovalReason::BLOCK);
    1332             :         }
    1333             : 
    1334             :         // Sapling: notify about the connected block
    1335             :         // Get prev block tree anchor
    1336       40375 :         CBlockIndex* pprev = pindex->pprev;
    1337       80750 :         SaplingMerkleTree oldSaplingTree;
    1338       80552 :         bool isSaplingActive = (pprev) != nullptr &&
    1339       40177 :                                Params().GetConsensus().NetworkUpgradeActive(pprev->nHeight,
    1340       40375 :                                                                             Consensus::UPGRADE_V5_0);
    1341       40375 :         if (isSaplingActive) {
    1342       19402 :             assert(pcoinsTip->GetSaplingAnchorAt(pprev->hashFinalSaplingRoot, oldSaplingTree));
    1343             :         } else {
    1344       41946 :             assert(pcoinsTip->GetSaplingAnchorAt(SaplingMerkleTree::empty_root(), oldSaplingTree));
    1345             :         }
    1346             : 
    1347             :         // Sapling: Update cached incremental witnesses
    1348       80750 :         ChainTipAdded(pindex, pblock.get(), oldSaplingTree);
    1349             :     } // cs_wallet lock end
    1350             : 
    1351             :     // Auto-combine functionality
    1352             :     // If turned on Auto Combine will scan wallet for dust to combine
    1353             :     // Outside of the cs_wallet lock because requires cs_main for now
    1354             :     // due CreateTransaction/CommitTransaction dependency.
    1355       40375 :     if (fCombineDust && pindex->nHeight % frequency == 0) {
    1356           1 :         AutoCombineDust(g_connman.get());
    1357             :     }
    1358       40375 : }
    1359             : 
    1360         327 : void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const uint256& blockHash, int nBlockHeight, int64_t blockTime)
    1361             : {
    1362         327 :     LOCK(cs_wallet);
    1363             : 
    1364             :     // At block disconnection, this will change an abandoned transaction to
    1365             :     // be unconfirmed, whether or not the transaction is added back to the mempool.
    1366             :     // User may have to call abandontransaction again. It may be addressed in the
    1367             :     // future with a stickier abandoned state or even removing abandontransaction call.
    1368         327 :     m_last_block_processed_height = nBlockHeight - 1;
    1369         327 :     m_last_block_processed_time = blockTime;
    1370         327 :     m_last_block_processed = blockHash;
    1371       89000 :     for (const CTransactionRef& ptx : pblock->vtx) {
    1372      177346 :         CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
    1373       88673 :         SyncTransaction(ptx, confirm);
    1374             :     }
    1375             : 
    1376         327 :     if (Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V5_0)) {
    1377             :         // Update Sapling cached incremental witnesses
    1378         183 :         m_sspk_man->DecrementNoteWitnesses(mapBlockIndex[blockHash]);
    1379         183 :         m_sspk_man->UpdateSaplingNullifierNoteMapForBlock(pblock.get());
    1380             :     }
    1381         327 : }
    1382             : 
    1383        4187 : void CWallet::BlockUntilSyncedToCurrentChain() {
    1384        4187 :     AssertLockNotHeld(cs_main);
    1385        4187 :     AssertLockNotHeld(cs_wallet);
    1386             : 
    1387        4187 :     {
    1388             :         // Skip the queue-draining stuff if we know we're caught up with
    1389             :         // chainActive.Tip()...
    1390             :         // We could also take cs_wallet here, and call m_last_block_processed
    1391             :         // protected by cs_wallet instead of cs_main, but as long as we need
    1392             :         // cs_main here anyway, its easier to just call it cs_main-protected.
    1393        8374 :         uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
    1394        4187 :         LOCK(cs_main);
    1395        4187 :         const CBlockIndex* initialChainTip = chainActive.Tip();
    1396        8374 :         if (!last_block_hash.IsNull() && initialChainTip &&
    1397        4187 :             last_block_hash == initialChainTip->GetBlockHash()) {
    1398        6380 :                 return;
    1399             :         }
    1400             :     }
    1401             : 
    1402             :     // ...otherwise put a callback in the validation interface queue and wait
    1403             :     // for the queue to drain enough to execute it (indicating we are caught up
    1404             :     // at least with the time we entered this function).
    1405         997 :     SyncWithValidationInterfaceQueue();
    1406             : }
    1407             : 
    1408      386419 : void CWallet::MarkAffectedTransactionsDirty(const CTransaction& tx)
    1409             : {
    1410             :     // If a transaction changes 'conflicted' state, that changes the balance
    1411             :     // available of the outputs it spends. So force those to be
    1412             :     // recomputed, also:
    1413     1136922 :     for (const CTxIn& txin : tx.vin) {
    1414      750503 :         if (!txin.IsZerocoinSpend()) {
    1415      750503 :             auto it = mapWallet.find(txin.prevout.hash);
    1416      750503 :             if (it != mapWallet.end()) {
    1417      737252 :                 it->second.MarkDirty();
    1418             :             }
    1419             :         }
    1420             :     }
    1421             : 
    1422             :     // Sapling
    1423      386419 :     if (HasSaplingSPKM() && tx.IsShieldedTx()) {
    1424        2053 :         for (const SpendDescription &spend : tx.sapData->vShieldedSpend) {
    1425         178 :             const uint256& nullifier = spend.nullifier;
    1426         178 :             auto nit = m_sspk_man->mapSaplingNullifiersToNotes.find(nullifier);
    1427         178 :             if (nit != m_sspk_man->mapSaplingNullifiersToNotes.end()) {
    1428         115 :                 auto it = mapWallet.find(nit->second.hash);
    1429         115 :                 if (it != mapWallet.end()) {
    1430         115 :                     it->second.MarkDirty();
    1431             :                 }
    1432             :             }
    1433             :         }
    1434             :     }
    1435      386419 : }
    1436             : 
    1437           0 : void CWallet::EraseFromWallet(const uint256& hash)
    1438             : {
    1439           0 :     {
    1440           0 :         LOCK(cs_wallet);
    1441           0 :         if (mapWallet.erase(hash))
    1442           0 :             WalletBatch(*database).EraseTx(hash);
    1443           0 :         LogPrintf("%s: Erased wtx %s from wallet\n", __func__, hash.GetHex());
    1444             :     }
    1445           0 :     return;
    1446             : }
    1447             : 
    1448         102 : isminetype CWallet::IsMine(const CTxIn& txin) const
    1449             : {
    1450         102 :     {
    1451         102 :         LOCK(cs_wallet);
    1452         102 :         std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
    1453         102 :         if (mi != mapWallet.end()) {
    1454           0 :             const CWalletTx& prev = (*mi).second;
    1455           0 :             if (txin.prevout.n < prev.tx->vout.size())
    1456           0 :                 return IsMine(prev.tx->vout[txin.prevout.n]);
    1457             :         }
    1458             :     }
    1459         102 :     return ISMINE_NO;
    1460             : }
    1461             : 
    1462           0 : bool CWallet::IsUsed(const CTxDestination address) const
    1463             : {
    1464           0 :     LOCK(cs_wallet);
    1465           0 :     CScript scriptPubKey = GetScriptForDestination(address);
    1466           0 :     if (!::IsMine(*this, scriptPubKey)) {
    1467             :         return false;
    1468             :     }
    1469             : 
    1470           0 :     for (const auto& it : mapWallet) {
    1471           0 :         const CWalletTx& wtx = it.second;
    1472           0 :         if (wtx.IsCoinBase()) {
    1473           0 :             continue;
    1474             :         }
    1475           0 :         for (const CTxOut& txout : wtx.tx->vout) {
    1476           0 :             if (txout.scriptPubKey == scriptPubKey)
    1477           0 :                 return true;
    1478             :         }
    1479             :     }
    1480           0 :     return false;
    1481             : }
    1482             : 
    1483           0 : bool CWallet::IsUsed(const libzcash::SaplingPaymentAddress address) const
    1484             : {
    1485           0 :     LOCK(cs_wallet);
    1486           0 :     if (!::IsMine(*this, address)) {
    1487             :         return false;
    1488             :     }
    1489             : 
    1490           0 :     for (const auto& it : mapWallet) {
    1491           0 :         const CWalletTx& wtx = it.second;
    1492           0 :         for (const auto& txout : wtx.mapSaplingNoteData) {
    1493           0 :             if (txout.second.address && *txout.second.address == address)
    1494           0 :                 return true;
    1495             :         }
    1496             :     }
    1497           0 :     return false;
    1498             : }
    1499             : 
    1500     1186966 : CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const
    1501             : {
    1502     1186966 :     {
    1503     1186966 :         LOCK(cs_wallet);
    1504     1186966 :         std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
    1505     1186966 :         if (mi != mapWallet.end()) {
    1506      751466 :             const CWalletTx& prev = (*mi).second;
    1507      751466 :             if (txin.prevout.n < prev.tx->vout.size())
    1508      751466 :                 if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
    1509     1479522 :                     return prev.tx->vout[txin.prevout.n].nValue;
    1510             :         }
    1511             :     }
    1512      447208 :     return 0;
    1513             : }
    1514             : 
    1515         239 : bool CWallet::IsChange(const CTxOut& txout) const
    1516             : {
    1517             :     // TODO: fix handling of 'change' outputs. The assumption is that any
    1518             :     // payment to a script that is ours, but is not in the address book
    1519             :     // is change. That assumption is likely to break when we implement multisignature
    1520             :     // wallets that return change back into a multi-signature-protected address;
    1521             :     // a better way of identifying which outputs are 'the send' and which are
    1522             :     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
    1523             :     // which output, if any, was change).
    1524         239 :     if (::IsMine(*this, txout.scriptPubKey)) {
    1525         310 :         CTxDestination address;
    1526         155 :         if (!ExtractDestination(txout.scriptPubKey, address))
    1527             :             return true;
    1528             : 
    1529         155 :         return IsChange(address);
    1530             :     }
    1531             :     return false;
    1532             : }
    1533             : 
    1534         647 : bool CWallet::IsChange(const CTxDestination& address) const
    1535             : {
    1536             :     // Read the current assumptions in IsChange(const CTxOut&)
    1537             :     // this can definitely be different in the short future.
    1538        1941 :     return WITH_LOCK(cs_wallet, return !HasAddressBook(address));
    1539             : }
    1540             : 
    1541         472 : int64_t CWalletTx::GetTxTime() const
    1542             : {
    1543         472 :     int64_t n = nTimeSmart;
    1544         472 :     return n ? n : nTimeReceived;
    1545             : }
    1546             : 
    1547             : /**
    1548             :  * Update smart timestamp for a transaction being added to the wallet.
    1549             :  *
    1550             :  * Logic:
    1551             :  * - If the transaction is not yet part of a block, assign its timestamp to the current time.
    1552             :  * - Else assign its timestamp to the block time
    1553             :  */
    1554      335337 : void CWalletTx::UpdateTimeSmart()
    1555             : {
    1556      335337 :     nTimeSmart = nTimeReceived;
    1557      670674 :     if (!m_confirm.hashBlock.IsNull()) {
    1558      169344 :         if (mapBlockIndex.count(m_confirm.hashBlock)) {
    1559      169344 :             nTimeSmart = mapBlockIndex.at(m_confirm.hashBlock)->GetBlockTime();
    1560             :         } else
    1561           0 :             LogPrintf("%s : found %s in block %s not in index\n", __func__, GetHash().ToString(), m_confirm.hashBlock.ToString());
    1562             :     }
    1563      335337 : }
    1564             : 
    1565     5208067 : CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const
    1566             : {
    1567     5208067 :     auto& amount = m_amounts[type];
    1568    10410192 :     if (recalculate || !amount.m_cached[filter]) {
    1569       30008 :         amount.Set(filter, type == DEBIT ? pwallet->GetDebit(tx, filter) : pwallet->GetCredit(*this, filter));
    1570             :     }
    1571     5208067 :     return amount.m_value[filter];
    1572             : }
    1573             : 
    1574          17 : bool CWalletTx::IsAmountCached(AmountType type, const isminefilter& filter) const
    1575             : {
    1576          17 :     return m_amounts[type].m_cached[filter];
    1577             : }
    1578             : 
    1579             : //! filter decides which addresses will count towards the debit
    1580     1519674 : CAmount CWalletTx::GetDebit(const isminefilter& filter) const
    1581             : {
    1582     1519674 :     if (tx->vin.empty() && (tx->sapData && tx->sapData->vShieldedSpend.empty())) {
    1583             :         return 0;
    1584             :     }
    1585             : 
    1586     1040874 :     CAmount debit = 0;
    1587     1040874 :     if (filter & ISMINE_SPENDABLE) {
    1588     1040533 :         debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE);
    1589             :     }
    1590     1040874 :     if (filter & ISMINE_WATCH_ONLY) {
    1591     1040240 :         debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY);
    1592             :     }
    1593     1040874 :     if (filter & ISMINE_COLD) {
    1594     1040410 :         debit += GetCachableAmount(DEBIT, ISMINE_COLD);
    1595             :     }
    1596     1040874 :     if (filter & ISMINE_SPENDABLE_DELEGATED) {
    1597     1040410 :         debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE_DELEGATED);
    1598             :     }
    1599     1040874 :     if (filter & ISMINE_SPENDABLE_SHIELDED) {
    1600     1040151 :         debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE_SHIELDED);
    1601             :     }
    1602             : 
    1603             :     return debit;
    1604             : }
    1605             : 
    1606           0 : CAmount CWalletTx::GetColdStakingDebit(bool fUseCache) const
    1607             : {
    1608           0 :     return GetCachableAmount(DEBIT, ISMINE_COLD, !fUseCache);
    1609             : }
    1610             : 
    1611           0 : CAmount CWalletTx::GetStakeDelegationDebit(bool fUseCache) const
    1612             : {
    1613           0 :     return GetCachableAmount(DEBIT, ISMINE_SPENDABLE_DELEGATED, !fUseCache);
    1614             : }
    1615             : 
    1616          90 : CAmount CWalletTx::GetCredit(const isminefilter& filter, bool recalculate) const
    1617             : {
    1618          90 :     CAmount credit = 0;
    1619          90 :     if (filter & ISMINE_SPENDABLE) {
    1620             :         // GetBalance can assume transactions in mapWallet won't change
    1621          89 :         credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE, recalculate);
    1622             :     }
    1623          90 :     if (filter & ISMINE_WATCH_ONLY) {
    1624           9 :         credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY, recalculate);
    1625             :     }
    1626          90 :     if (filter & ISMINE_COLD) {
    1627          84 :         credit += GetCachableAmount(CREDIT, ISMINE_COLD, recalculate);
    1628             :     }
    1629          90 :     if (filter & ISMINE_SPENDABLE_DELEGATED) {
    1630          87 :         credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE_DELEGATED, recalculate);
    1631             :     }
    1632          90 :     if (filter & ISMINE_SPENDABLE_SHIELDED) {
    1633          88 :         credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE_SHIELDED, recalculate);
    1634             :     }
    1635          90 :     return credit;
    1636             : }
    1637             : 
    1638       14062 : CAmount CWalletTx::GetImmatureCredit(bool fUseCache, const isminefilter& filter) const
    1639             : {
    1640       14062 :     if (IsInMainChainImmature()) {
    1641        5970 :         return GetCachableAmount(IMMATURE_CREDIT, filter, !fUseCache);
    1642             :     }
    1643             : 
    1644             :     return 0;
    1645             : }
    1646             : 
    1647      465365 : CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const
    1648             : {
    1649      465365 :     if (!pwallet)
    1650             :         return 0;
    1651             : 
    1652             :     // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
    1653      930730 :     bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY ||
    1654      465365 :             filter == ISMINE_SPENDABLE_SHIELDED || filter == ISMINE_WATCH_ONLY_SHIELDED;
    1655             : 
    1656             :     // Must wait until coinbase/coinstake is safely deep enough in the chain before valuing it
    1657      465365 :     if (GetBlocksToMaturity() > 0)
    1658             :         return 0;
    1659             : 
    1660      431080 :     if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
    1661       99809 :         return m_amounts[AVAILABLE_CREDIT].m_value[filter];
    1662             :     }
    1663             : 
    1664      229260 :     CAmount nCredit = 0;
    1665             :     // If the filter is only for shielded amounts, do not calculate the regular outputs
    1666      229260 :     if (filter != ISMINE_SPENDABLE_SHIELDED && filter != ISMINE_WATCH_ONLY_SHIELDED) {
    1667             : 
    1668      229242 :         const uint256& hashTx = GetHash();
    1669      498610 :         for (unsigned int i = 0; i < tx->vout.size(); i++) {
    1670      269368 :             if (!pwallet->IsSpent(hashTx, i)) {
    1671      172295 :                 const CTxOut &txout = tx->vout[i];
    1672      172295 :                 nCredit += pwallet->GetCredit(txout, filter);
    1673      441663 :                 if (!Params().GetConsensus().MoneyRange(nCredit))
    1674           0 :                     throw std::runtime_error(std::string(__func__) + " : value out of range");
    1675             :             }
    1676             :         }
    1677             : 
    1678             :     }
    1679             : 
    1680      229260 :     if (pwallet->HasSaplingSPKM()) {
    1681             :         // Can calculate the shielded available balance.
    1682      229260 :         if (filter & ISMINE_SPENDABLE_SHIELDED || filter & ISMINE_WATCH_ONLY_SHIELDED) {
    1683       21360 :             nCredit += pwallet->GetSaplingScriptPubKeyMan()->GetCredit(*this, filter, true);
    1684             :         }
    1685             :     }
    1686             : 
    1687      229260 :     if (allow_cache) {
    1688      467569 :         m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
    1689             :     }
    1690             : 
    1691             :     return nCredit;
    1692             : }
    1693             : 
    1694      139551 : CAmount CWalletTx::GetColdStakingCredit(bool fUseCache) const
    1695             : {
    1696      139551 :     return GetAvailableCredit(fUseCache, ISMINE_COLD);
    1697             : }
    1698             : 
    1699      140072 : CAmount CWalletTx::GetStakeDelegationCredit(bool fUseCache) const
    1700             : {
    1701      140072 :     return GetAvailableCredit(fUseCache, ISMINE_SPENDABLE_DELEGATED);
    1702             : }
    1703             : 
    1704             : // Return sum of locked coins
    1705      138880 : CAmount CWalletTx::GetLockedCredit() const
    1706             : {
    1707      138880 :     if (pwallet == 0)
    1708             :         return 0;
    1709             : 
    1710             :     // Must wait until coinbase is safely deep enough in the chain before valuing it
    1711      138880 :     if (IsCoinBase() && GetBlocksToMaturity() > 0)
    1712             :         return 0;
    1713             : 
    1714      119972 :     CAmount nCredit = 0;
    1715      119972 :     uint256 hashTx = GetHash();
    1716      119972 :     const CAmount collAmt = Params().GetConsensus().nMNCollateralAmt;
    1717      274451 :     for (unsigned int i = 0; i < tx->vout.size(); i++) {
    1718      154479 :         const CTxOut& txout = tx->vout[i];
    1719             : 
    1720             :         // Skip spent coins
    1721      154479 :         if (pwallet->IsSpent(hashTx, i)) continue;
    1722             : 
    1723             :         // Add locked coins
    1724      111495 :         if (pwallet->IsLockedCoin(hashTx, i)) {
    1725          51 :             nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE_ALL);
    1726             :         }
    1727             : 
    1728             :         // Add masternode collaterals which are handled like locked coins
    1729      111444 :         else if (fMasterNode && tx->vout[i].nValue == collAmt) {
    1730           0 :             nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
    1731             :         }
    1732             : 
    1733      265974 :         if (!Params().GetConsensus().MoneyRange(nCredit))
    1734           0 :             throw std::runtime_error("CWalletTx::GetLockedCredit() : value out of range");
    1735             :     }
    1736             : 
    1737             :     return nCredit;
    1738             : }
    1739             : 
    1740           0 : CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
    1741             : {
    1742           0 :     if (IsInMainChainImmature()) {
    1743           0 :         return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
    1744             :     }
    1745             : 
    1746             :     return 0;
    1747             : }
    1748             : 
    1749           0 : CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool fUseCache) const
    1750             : {
    1751           0 :     return GetAvailableCredit(fUseCache, ISMINE_WATCH_ONLY);
    1752             : }
    1753             : 
    1754         342 : void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
    1755             :     std::list<COutputEntry>& listSent,
    1756             :     CAmount& nFee,
    1757             :     const isminefilter& filter) const
    1758             : {
    1759         342 :     nFee = 0;
    1760         342 :     listReceived.clear();
    1761         342 :     listSent.clear();
    1762             : 
    1763             :     // Compute fee:
    1764         342 :     CAmount nDebit = GetDebit(filter);
    1765         342 :     bool isFromMyTaddr = nDebit > 0; // debit>0 means we signed/sent this transaction
    1766             : 
    1767         342 :     if (isFromMyTaddr) {// debit>0 means we signed/sent this transaction
    1768         108 :         CAmount nValueOut = tx->GetValueOut(); // transasparent outputs plus the negative Sapling valueBalance
    1769         108 :         CAmount nValueIn = tx->GetShieldedValueIn();
    1770         108 :         nFee = nDebit - nValueOut + nValueIn;
    1771             : 
    1772             :         // If we sent utxos from this transaction, create output for value taken from (negative valueBalance)
    1773             :         // or added (positive valueBalance) to the transparent value pool by Sapling shielding and unshielding.
    1774         108 :         if (tx->sapData) {
    1775         108 :             if (tx->sapData->valueBalance < 0) {
    1776           8 :                 COutputEntry output = {CNoDestination(), -tx->sapData->valueBalance, (int) tx->vout.size()};
    1777           4 :                 listSent.push_back(output);
    1778         104 :             } else if (tx->sapData->valueBalance > 0) {
    1779           0 :                 COutputEntry output = {CNoDestination(), tx->sapData->valueBalance, (int) tx->vout.size()};
    1780           0 :                 listReceived.push_back(output);
    1781             :             }
    1782             :         }
    1783             :     }
    1784             : 
    1785             :     // Sent/received.
    1786         342 :     bool hasZerocoinSpends = tx->HasZerocoinSpendInputs();
    1787         833 :     for (unsigned int i = 0; i < tx->vout.size(); ++i) {
    1788         491 :         const CTxOut& txout = tx->vout[i];
    1789         491 :         isminetype fIsMine = pwallet->IsMine(txout);
    1790             :         // Only need to handle txouts if AT LEAST one of these is true:
    1791             :         //   1) they debit from us (sent)
    1792             :         //   2) the output is to us (received)
    1793         491 :         if (nDebit > 0) {
    1794             :             // Don't report 'change' txouts
    1795         215 :             if (pwallet->IsChange(txout))
    1796         125 :                 continue;
    1797         276 :         } else if (!(fIsMine & filter) && !hasZerocoinSpends)
    1798          39 :             continue;
    1799             : 
    1800             :         // In either case, we need to get the destination address
    1801         366 :         const bool fColdStake = (filter & ISMINE_COLD);
    1802         732 :         CTxDestination address;
    1803         366 :         if (txout.IsZerocoinMint()) {
    1804           0 :             address = CNoDestination();
    1805         366 :         } else if (!ExtractDestination(txout.scriptPubKey, address, fColdStake)) {
    1806          34 :             if (!IsCoinStake() && !IsCoinBase()) {
    1807          34 :                 LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString());
    1808             :             }
    1809          17 :             address = CNoDestination();
    1810             :         }
    1811             : 
    1812         732 :         COutputEntry output = {address, txout.nValue, (int)i};
    1813             : 
    1814             :         // If we are debited by the transaction, add the output as a "sent" entry
    1815         366 :         if (nDebit > 0)
    1816         129 :             listSent.push_back(output);
    1817             : 
    1818             :         // If we are receiving the output, add it as a "received" entry
    1819         366 :         if (fIsMine & filter)
    1820         366 :             listReceived.push_back(output);
    1821             :     }
    1822         342 : }
    1823             : 
    1824           2 : bool CWallet::Upgrade(std::string& error, const int prevVersion)
    1825             : {
    1826           6 :     LOCK2(cs_wallet, cs_KeyStore);
    1827             : 
    1828             :     // Do not upgrade versions if we are already in the last one
    1829           2 :     if (prevVersion >= FEATURE_SAPLING) {
    1830           0 :         error = strprintf(_("Cannot upgrade to Sapling wallet (already running Sapling support). Version: %d"), prevVersion);
    1831           0 :         return false;
    1832             :     }
    1833             : 
    1834             :     // Check if we need to upgrade to HD
    1835           2 :     if (prevVersion < FEATURE_PRE_SPLIT_KEYPOOL) {
    1836           2 :         if (!m_spk_man->Upgrade(prevVersion, error)) {
    1837             :             return false;
    1838             :         }
    1839             :     }
    1840             : 
    1841             :     // Now upgrade to Sapling manager
    1842           2 :     if (prevVersion < FEATURE_SAPLING) {
    1843           2 :         if (!ActivateSaplingWallet()) {
    1844           0 :             return false;
    1845             :         }
    1846             :     }
    1847             : 
    1848             :     return true;
    1849             : }
    1850             : 
    1851             : /**
    1852             :  * Scan active chain for relevant transactions after importing keys. This should
    1853             :  * be called whenever new keys are added to the wallet, with the oldest key
    1854             :  * creation time.
    1855             :  *
    1856             :  * @return Earliest timestamp that could be successfully scanned from. Timestamp
    1857             :  * returned will be higher than startTime if relevant blocks could not be read.
    1858             :  */
    1859          40 : int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
    1860             : {
    1861             :     // Find starting block. May be null if nCreateTime is greater than the
    1862             :     // highest blockchain timestamp, in which case there is nothing that needs
    1863             :     // to be scanned.
    1864          40 :     CBlockIndex* startBlock = nullptr;
    1865          40 :     {
    1866          40 :         LOCK(cs_main);
    1867          40 :         startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
    1868          40 :         LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
    1869             :     }
    1870             : 
    1871          40 :     if (startBlock) {
    1872          40 :         const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
    1873          40 :         if (failedBlock) {
    1874           0 :             return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
    1875             :         }
    1876             :     }
    1877             :     return startTime;
    1878             : }
    1879             : 
    1880             : /**
    1881             :  * Scan the block chain (starting in pindexStart) for transactions
    1882             :  * from or to us. If fUpdate is true, found transactions that already
    1883             :  * exist in the wallet will be updated.
    1884             :  *
    1885             :  * Returns null if scan was successful. Otherwise, if a complete rescan was not
    1886             :  * possible (due to pruning or corruption), returns pointer to the most recent
    1887             :  * block that could not be scanned.
    1888             :  *
    1889             :  * If pindexStop is not a nullptr, the scan will stop at the block-index
    1890             :  * defined by pindexStop
    1891             :  *
    1892             :  * Caller needs to make sure pindexStop (and the optional pindexStart) are on
    1893             :  * the main chain after to the addition of any new keys you want to detect
    1894             :  * transactions for.
    1895             :  */
    1896        1179 : CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate, bool fromStartup)
    1897             : {
    1898        1179 :     int64_t nNow = GetTime();
    1899             : 
    1900        1179 :     assert(reserver.isReserved());
    1901        1179 :     if (pindexStop) {
    1902           1 :         assert(pindexStop->nHeight >= pindexStart->nHeight);
    1903             :     }
    1904             : 
    1905        1179 :     CBlockIndex* pindex = pindexStart;
    1906        1179 :     CBlockIndex* ret = nullptr;
    1907        1179 :     {
    1908        1179 :         ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
    1909        1179 :         CBlockIndex* tip = nullptr;
    1910        1179 :         double dProgressStart;
    1911        1179 :         double dProgressTip;
    1912        1179 :         {
    1913        1179 :             LOCK(cs_main);
    1914        1179 :             tip = chainActive.Tip();
    1915        1179 :             dProgressStart = Checkpoints::GuessVerificationProgress(pindex, false);
    1916        1179 :             dProgressTip = Checkpoints::GuessVerificationProgress(tip, false);
    1917             :         }
    1918             : 
    1919        1179 :         std::vector<uint256> myTxHashes;
    1920       28318 :         while (pindex && !fAbortRescan) {
    1921       27140 :             double gvp = 0;
    1922       27140 :             if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) {
    1923         867 :                 gvp = WITH_LOCK(cs_main, return Checkpoints::GuessVerificationProgress(pindex, false); );
    1924         954 :                 ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((gvp - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
    1925             :             }
    1926       27140 :             if (GetTime() >= nNow + 60) {
    1927           0 :                 nNow = GetTime();
    1928           0 :                 LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, gvp);
    1929             :             }
    1930       27140 :             if (fromStartup && ShutdownRequested()) {
    1931             :                 break;
    1932             :             }
    1933             : 
    1934       27140 :             CBlock block;
    1935       27140 :             if (ReadBlockFromDisk(block, pindex)) {
    1936       81420 :                 LOCK2(cs_main, cs_wallet);
    1937       54280 :                 if (pindex && !chainActive.Contains(pindex)) {
    1938             :                      // Abort scan if current block is no longer active, to prevent
    1939             :                      // marking transactions as coming from the wrong block.
    1940           0 :                      ret = pindex;
    1941           0 :                      break;
    1942             :                  }
    1943      115698 :                 for (int posInBlock = 0; posInBlock < (int) block.vtx.size(); posInBlock++) {
    1944       88558 :                     const auto& tx = block.vtx[posInBlock];
    1945       88558 :                     CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, pindex->nHeight, pindex->GetBlockHash(), posInBlock);
    1946       88558 :                     if (AddToWalletIfInvolvingMe(tx, confirm, fUpdate)) {
    1947        8687 :                         myTxHashes.push_back(tx->GetHash());
    1948             :                     }
    1949             :                 }
    1950             : 
    1951             :                 // Sapling
    1952             :                 // This should never fail: we should always be able to get the tree
    1953             :                 // state on the path to the tip of our chain
    1954       27140 :                 if (pindex->pprev) {
    1955       26105 :                     if (Params().GetConsensus().NetworkUpgradeActive(pindex->pprev->nHeight, Consensus::UPGRADE_V5_0)) {
    1956        3508 :                         SaplingMerkleTree saplingTree;
    1957        1754 :                         assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree));
    1958             :                         // Increment note witness caches
    1959        3508 :                         ChainTipAdded(pindex, &block, saplingTree);
    1960             :                     }
    1961             :                 }
    1962             :             } else {
    1963           0 :                 ret = pindex;
    1964             :             }
    1965       27140 :             if (pindex == pindexStop) {
    1966             :                 break;
    1967             :             }
    1968       27139 :             {
    1969       54278 :                 LOCK(cs_main);
    1970       27139 :                 pindex = chainActive.Next(pindex);
    1971       54278 :                 if (tip != chainActive.Tip()) {
    1972           0 :                     tip = chainActive.Tip();
    1973             :                     // in case the tip has changed, update progress max
    1974           0 :                     dProgressTip = Checkpoints::GuessVerificationProgress(tip, false);
    1975             :                 }
    1976             :             }
    1977             :         }
    1978             : 
    1979             :         // Sapling
    1980             :         // After rescanning, persist Sapling note data that might have changed, e.g. nullifiers.
    1981             :         // Do not flush the wallet here for performance reasons.
    1982        2358 :         WalletBatch batch(*database, "r+", false);
    1983        9866 :         for (const auto& hash : myTxHashes) {
    1984        8687 :             CWalletTx& wtx = mapWallet.at(hash);
    1985        8687 :             if (!wtx.mapSaplingNoteData.empty()) {
    1986          77 :                 if (!batch.WriteTx(wtx)) {
    1987           0 :                     LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString());
    1988             :                 }
    1989             :             }
    1990             :         }
    1991             : 
    1992        1179 :         if (pindex && fAbortRescan) {
    1993           0 :             LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(pindex, false));
    1994             :         }
    1995        2358 :         ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
    1996             :     }
    1997        1179 :     return ret;
    1998             : }
    1999             : 
    2000         387 : void CWallet::ReacceptWalletTransactions(bool fFirstLoad)
    2001             : {
    2002         774 :     LOCK2(cs_main, cs_wallet);
    2003         774 :     std::map<int64_t, CWalletTx*> mapSorted;
    2004             : 
    2005             :     // Sort pending wallet transactions based on their initial wallet insertion order
    2006        9114 :     for (std::pair<const uint256, CWalletTx>& item: mapWallet) {
    2007        8727 :         const uint256& wtxid = item.first;
    2008        8727 :         CWalletTx& wtx = item.second;
    2009        8727 :         assert(wtx.GetHash() == wtxid);
    2010             : 
    2011        8727 :         int nDepth = wtx.GetDepthInMainChain();
    2012        9352 :         if (!wtx.IsCoinBase() && !wtx.IsCoinStake() && nDepth == 0  && !wtx.isAbandoned()) {
    2013          38 :             mapSorted.emplace(wtx.nOrderPos, &wtx);
    2014             :         }
    2015             :     }
    2016             : 
    2017             :     // Try to add wallet transactions to memory pool
    2018         425 :     for (std::pair<const int64_t, CWalletTx*>& item: mapSorted) {
    2019          38 :         CWalletTx& wtx = *(item.second);
    2020             : 
    2021          76 :         CValidationState state;
    2022          38 :         bool fSuccess = wtx.AcceptToMemoryPool(state);
    2023          38 :         if (!fSuccess && fFirstLoad && GetTime() - wtx.GetTxTime() > 12*60*60) {
    2024             :             //First load of wallet, failed to accept to mempool, and older than 12 hours... not likely to ever
    2025             :             //make it in to mempool
    2026           0 :             AbandonTransaction(wtx.GetHash());
    2027             :         }
    2028             :     }
    2029         387 : }
    2030             : 
    2031     3410575 : bool CWalletTx::InMempool() const
    2032             : {
    2033     3410575 :     return fInMempool;
    2034             : }
    2035             : 
    2036       23838 : void CWalletTx::RelayWalletTransaction(CConnman* connman)
    2037             : {
    2038       51933 :     if (!connman || IsCoinBase() || IsCoinStake()) {
    2039             :         // Nothing to do. Return early
    2040       21782 :         return;
    2041             :     }
    2042        2056 :     if (GetDepthInMainChain() == 0 && !isAbandoned()) {
    2043        1426 :         const uint256& hash = GetHash();
    2044        1426 :         LogPrintf("Relaying wtx %s\n", hash.ToString());
    2045        1426 :         CInv inv(MSG_TX, hash);
    2046        1426 :         connman->ForEachNode([&inv](CNode* pnode) {
    2047        2229 :           pnode->PushInventory(inv);
    2048        2229 :         });
    2049             :     }
    2050             : }
    2051             : 
    2052         393 : std::set<uint256> CWalletTx::GetConflicts() const
    2053             : {
    2054         393 :     std::set<uint256> result;
    2055         393 :     if (pwallet != nullptr) {
    2056         393 :         uint256 myHash = GetHash();
    2057         786 :         result = pwallet->GetConflicts(myHash);
    2058         393 :         result.erase(myHash);
    2059             :     }
    2060         393 :     return result;
    2061             : }
    2062             : 
    2063         726 : void CWallet::Flush(bool shutdown)
    2064             : {
    2065         726 :     database->Flush(shutdown);
    2066         726 : }
    2067             : 
    2068     1789460 : void CWallet::ResendWalletTransactions(CConnman* connman)
    2069             : {
    2070             :     // Do this infrequently and randomly to avoid giving away
    2071             :     // that these are our transactions.
    2072     1789460 :     if (GetTime() < nNextResend) {
    2073             :         return;
    2074             :     }
    2075         816 :     bool fFirst = (nNextResend == 0);
    2076         816 :     nNextResend = GetTime() + GetRand(30 * 60);
    2077         816 :     if (fFirst) {
    2078             :         return;
    2079             :     }
    2080             : 
    2081             :     // Only do it if there's been a new block since last time
    2082         598 :     if (nTimeBestReceived < nLastResend) {
    2083             :         return;
    2084             :     }
    2085         570 :     nLastResend = GetTime();
    2086             : 
    2087             :     // Rebroadcast any of our txes that aren't in a block yet
    2088         570 :     LogPrintf("ResendWalletTransactions()\n");
    2089         570 :     {
    2090        1140 :         LOCK(cs_wallet);
    2091             :         // Sort them in chronological order
    2092        1140 :         std::multimap<unsigned int, CWalletTx*> mapSorted;
    2093       24619 :         for (std::pair<const uint256, CWalletTx> & item : mapWallet) {
    2094       24049 :             CWalletTx& wtx = item.second;
    2095             :             // Don't rebroadcast until it's had plenty of time that
    2096             :             // it should have gotten in already by now.
    2097       24049 :             if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) {
    2098       22401 :                 mapSorted.emplace(wtx.nTimeReceived, &wtx);
    2099             :             }
    2100             :         }
    2101       22971 :         for (std::pair<const unsigned int, CWalletTx*> & item : mapSorted) {
    2102       22401 :             CWalletTx& wtx = *item.second;
    2103       22401 :             wtx.RelayWalletTransaction(connman);
    2104             :         }
    2105             :     }
    2106             : }
    2107             : 
    2108       40278 : void CWallet::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
    2109             : {
    2110       40278 :     nTimeBestReceived = GetTime();
    2111       40278 : }
    2112             : 
    2113             : /** @} */ // end of mapWallet
    2114             : 
    2115             : 
    2116             : /** @defgroup Actions
    2117             :  *
    2118             :  * @{
    2119             :  */
    2120             : 
    2121           0 : CWallet::Balance CWallet::GetBalance(const int min_depth) const
    2122             : {
    2123           0 :     Balance ret;
    2124           0 :     {
    2125           0 :         LOCK(cs_wallet);
    2126           0 :         std::set<uint256> trusted_parents;
    2127           0 :         for (const auto& entry : mapWallet) {
    2128           0 :             const CWalletTx& wtx = entry.second;
    2129           0 :             const bool is_trusted{wtx.IsTrusted()};
    2130           0 :             const int tx_depth{wtx.GetDepthInMainChain()};
    2131           0 :             const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE_TRANSPARENT)};
    2132           0 :             const CAmount tx_credit_shield_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE_SHIELDED)};
    2133           0 :             if (is_trusted && tx_depth >= min_depth) {
    2134           0 :                 ret.m_mine_trusted += tx_credit_mine;
    2135           0 :                 ret.m_mine_trusted_shield += tx_credit_shield_mine;
    2136           0 :                 if (wtx.tx->HasP2CSOutputs()) {
    2137           0 :                     ret.m_mine_cs_delegated_trusted += wtx.GetStakeDelegationCredit();
    2138             :                 }
    2139             :             }
    2140           0 :             if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
    2141           0 :                 ret.m_mine_untrusted_pending += tx_credit_mine;
    2142           0 :                 ret.m_mine_untrusted_shielded_balance += tx_credit_shield_mine;
    2143             :             }
    2144           0 :             ret.m_mine_immature += wtx.GetImmatureCredit();
    2145             :         }
    2146             :     }
    2147           0 :     return ret;
    2148             : }
    2149             : 
    2150        1525 : CAmount CWallet::loopTxsBalance(const std::function<void(const uint256&, const CWalletTx&, CAmount&)>& method) const
    2151             : {
    2152        1525 :     CAmount nTotal = 0;
    2153        1525 :     {
    2154        1525 :         LOCK(cs_wallet);
    2155      226613 :         for (const auto& it : mapWallet) {
    2156      225088 :             method(it.first, it.second, nTotal);
    2157             :         }
    2158             :     }
    2159        1525 :     return nTotal;
    2160             : }
    2161             : 
    2162         406 : CAmount CWallet::GetAvailableBalance(bool fIncludeDelegated, bool fIncludeShielded) const
    2163             : {
    2164         406 :     isminefilter filter;
    2165         406 :     if (fIncludeDelegated && fIncludeShielded) {
    2166         406 :         filter = ISMINE_SPENDABLE_ALL;
    2167           0 :     } else if (fIncludeDelegated) {
    2168           0 :         filter = ISMINE_SPENDABLE_TRANSPARENT;
    2169           0 :     } else if (fIncludeShielded) {
    2170           0 :         filter = ISMINE_SPENDABLE_NO_DELEGATED;
    2171             :     } else {
    2172           0 :         filter = ISMINE_SPENDABLE;
    2173             :     }
    2174         406 :     return GetAvailableBalance(filter, true, 0);
    2175             : }
    2176             : 
    2177         544 : CAmount CWallet::GetAvailableBalance(isminefilter& filter, bool useCache, int minDepth) const
    2178             : {
    2179         544 :     return loopTxsBalance([filter, useCache, minDepth](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal){
    2180       46928 :         bool fConflicted;
    2181       46928 :         int depth;
    2182       46928 :         if (pcoin.IsTrusted(depth, fConflicted) && depth >= minDepth) {
    2183       46853 :             nTotal += pcoin.GetAvailableCredit(useCache, filter);
    2184             :         }
    2185         544 :     });
    2186             : }
    2187             : 
    2188          75 : CAmount CWallet::GetColdStakingBalance() const
    2189             : {
    2190          75 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2191        5126 :         if (pcoin.tx->HasP2CSOutputs() && pcoin.IsTrusted())
    2192         412 :             nTotal += pcoin.GetColdStakingCredit();
    2193          75 :     });
    2194             : }
    2195             : 
    2196         561 : CAmount CWallet::GetStakingBalance(const bool fIncludeColdStaking) const
    2197             : {
    2198         561 :     return std::max(CAmount(0), loopTxsBalance(
    2199      287848 :             [fIncludeColdStaking](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2200      148968 :         if (pcoin.IsTrusted() && pcoin.GetDepthInMainChain() >= Params().GetConsensus().nStakeMinDepth) {
    2201      138880 :             nTotal += pcoin.GetAvailableCredit();       // available coins
    2202      138880 :             nTotal -= pcoin.GetStakeDelegationCredit(); // minus delegated coins, if any
    2203      138880 :             nTotal -= pcoin.GetLockedCredit();          // minus locked coins, if any
    2204      138880 :             if (fIncludeColdStaking)
    2205      138880 :                 nTotal += pcoin.GetColdStakingCredit(); // plus cold coins, if any and if requested
    2206             :         }
    2207        1122 :     }));
    2208             : }
    2209             : 
    2210          74 : CAmount CWallet::GetDelegatedBalance() const
    2211             : {
    2212          74 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2213        5122 :             if (pcoin.tx->HasP2CSOutputs() && pcoin.IsTrusted())
    2214         422 :                 nTotal += pcoin.GetStakeDelegationCredit();
    2215          74 :     });
    2216             : }
    2217             : 
    2218           0 : CAmount CWallet::GetLockedCoins() const
    2219             : {
    2220           0 :     LOCK(cs_wallet);
    2221           0 :     if (setLockedCoins.empty()) return 0;
    2222             : 
    2223           0 :     CAmount ret = 0;
    2224           0 :     for (const auto& coin : setLockedCoins) {
    2225           0 :         auto it = mapWallet.find(coin.hash);
    2226           0 :         if (it != mapWallet.end()) {
    2227           0 :             const CWalletTx& pcoin = it->second;
    2228           0 :             if (pcoin.IsTrusted() && pcoin.GetDepthInMainChain() > 0) {
    2229           0 :                 ret += it->second.tx->vout.at(coin.n).nValue;
    2230             :             }
    2231             :         }
    2232             :     }
    2233           0 :     return ret;
    2234             : }
    2235             : 
    2236           0 : CAmount CWallet::GetLockedShieldCoins() const
    2237             : {
    2238           0 :     LOCK(cs_wallet);
    2239           0 :     if (setLockedNotes.empty()) return 0;
    2240             : 
    2241           0 :     CAmount ret = 0;
    2242           0 :     for (const auto& op : setLockedNotes) {
    2243           0 :         auto it = mapWallet.find(op.hash);
    2244           0 :         if (it != mapWallet.end()) {
    2245           0 :             const CWalletTx& pcoin = it->second;
    2246           0 :             if (pcoin.IsTrusted() && pcoin.GetDepthInMainChain() > 0) {
    2247           0 :                 Optional<CAmount> val = pcoin.mapSaplingNoteData.at(op).amount;
    2248           0 :                 if (val) {
    2249           0 :                     ret += *val;
    2250             :                 }
    2251             :             }
    2252             :         }
    2253             :     }
    2254           0 :     return ret;
    2255             : }
    2256             : 
    2257             : 
    2258          71 : CAmount CWallet::GetUnconfirmedBalance(isminetype filter) const
    2259             : {
    2260          71 :     return loopTxsBalance([filter](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2261        4882 :             if (!pcoin.IsTrusted() && pcoin.GetDepthInMainChain() == 0 && pcoin.InMempool())
    2262           3 :                 nTotal += pcoin.GetCredit(filter);
    2263          71 :     });
    2264             : }
    2265             : 
    2266          68 : CAmount CWallet::GetImmatureBalance() const
    2267             : {
    2268          68 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2269        4762 :             nTotal += pcoin.GetImmatureCredit(false);
    2270          68 :     });
    2271             : }
    2272             : 
    2273          66 : CAmount CWallet::GetImmatureColdStakingBalance() const
    2274             : {
    2275          66 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2276        4650 :             nTotal += pcoin.GetImmatureCredit(false, ISMINE_COLD);
    2277          66 :     });
    2278             : }
    2279             : 
    2280          66 : CAmount CWallet::GetImmatureDelegatedBalance() const
    2281             : {
    2282          66 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2283        4650 :             nTotal += pcoin.GetImmatureCredit(false, ISMINE_SPENDABLE_DELEGATED);
    2284          66 :     });
    2285             : }
    2286             : 
    2287           0 : CAmount CWallet::GetWatchOnlyBalance() const
    2288             : {
    2289           0 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2290           0 :             if (pcoin.IsTrusted())
    2291           0 :                 nTotal += pcoin.GetAvailableWatchOnlyCredit();
    2292           0 :     });
    2293             : }
    2294             : 
    2295           0 : CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
    2296             : {
    2297           0 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2298           0 :             if (!pcoin.IsTrusted() && pcoin.GetDepthInMainChain() == 0 && pcoin.InMempool())
    2299           0 :                 nTotal += pcoin.GetAvailableWatchOnlyCredit();
    2300           0 :     });
    2301             : }
    2302             : 
    2303           0 : CAmount CWallet::GetImmatureWatchOnlyBalance() const
    2304             : {
    2305           0 :     return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
    2306           0 :             nTotal += pcoin.GetImmatureWatchOnlyCredit();
    2307           0 :     });
    2308             : }
    2309             : 
    2310             : // Calculate total balance in a different way from GetBalance. The biggest
    2311             : // difference is that GetBalance sums up all unspent TxOuts paying to the
    2312             : // wallet, while this sums up both spent and unspent TxOuts paying to the
    2313             : // wallet, and then subtracts the values of TxIns spending from the wallet. This
    2314             : // also has fewer restrictions on which unconfirmed transactions are considered
    2315             : // trusted.
    2316           6 : CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const
    2317             : {
    2318           6 :     LOCK(cs_wallet);
    2319             : 
    2320           6 :     CAmount balance = 0;
    2321         378 :     for (const auto& entry : mapWallet) {
    2322         372 :         const CWalletTx& wtx = entry.second;
    2323         372 :         bool fConflicted;
    2324         372 :         const int depth = wtx.GetDepthAndMempool(fConflicted);
    2325         372 :         if (!IsFinalTx(wtx.tx, m_last_block_processed_height) || wtx.GetBlocksToMaturity() > 0 || depth < 0 || fConflicted) {
    2326         252 :             continue;
    2327             :         }
    2328             : 
    2329             :         // Loop through tx outputs and add incoming payments. For outgoing txs,
    2330             :         // treat change outputs specially, as part of the amount debited.
    2331         120 :         CAmount debit = wtx.GetDebit(filter);
    2332         120 :         const bool outgoing = debit > 0;
    2333         288 :         for (const CTxOut& out : wtx.tx->vout) {
    2334         168 :             if (outgoing && IsChange(out)) {
    2335          12 :                 debit -= out.nValue;
    2336         156 :             } else if (IsMine(out) & filter && depth >= minDepth) {
    2337         115 :                 balance += out.nValue;
    2338             :             }
    2339             :         }
    2340             : 
    2341             :         // For outgoing txs, subtract amount debited.
    2342         120 :         if (outgoing) {
    2343          12 :             balance -= debit;
    2344             :         }
    2345             :     }
    2346             : 
    2347          12 :     return balance;
    2348             : }
    2349             : 
    2350             : // Sapling
    2351           1 : CAmount CWallet::GetAvailableShieldedBalance(bool fUseCache) const
    2352             : {
    2353           1 :     isminefilter filter = ISMINE_SPENDABLE_SHIELDED;
    2354           1 :     return GetAvailableBalance(filter, fUseCache);
    2355             : };
    2356             : 
    2357           1 : CAmount CWallet::GetUnconfirmedShieldedBalance() const
    2358             : {
    2359           1 :     return GetUnconfirmedBalance(ISMINE_SPENDABLE_SHIELDED);
    2360             : };
    2361             : 
    2362           0 : void CWallet::GetAvailableP2CSCoins(std::vector<COutput>& vCoins) const {
    2363           0 :     vCoins.clear();
    2364           0 :     {
    2365           0 :         LOCK(cs_wallet);
    2366           0 :         for (const auto& it : mapWallet) {
    2367           0 :             const uint256& wtxid = it.first;
    2368           0 :             const CWalletTx* pcoin = &it.second;
    2369             : 
    2370           0 :             bool fConflicted;
    2371           0 :             int nDepth = pcoin->GetDepthAndMempool(fConflicted);
    2372             : 
    2373           0 :             if (fConflicted || nDepth < 0)
    2374           0 :                 continue;
    2375             : 
    2376           0 :             bool fSafe = pcoin->IsTrusted();
    2377             : 
    2378           0 :             if (pcoin->tx->HasP2CSOutputs()) {
    2379           0 :                 for (int i = 0; i < (int) pcoin->tx->vout.size(); i++) {
    2380           0 :                     const auto &utxo = pcoin->tx->vout[i];
    2381             : 
    2382           0 :                     if (IsSpent(wtxid, i))
    2383           0 :                         continue;
    2384             : 
    2385           0 :                     if (utxo.scriptPubKey.IsPayToColdStaking()) {
    2386           0 :                         isminetype mine = IsMine(utxo);
    2387           0 :                         bool isMineSpendable = mine & ISMINE_SPENDABLE_DELEGATED;
    2388           0 :                         if (mine & ISMINE_COLD || isMineSpendable)
    2389             :                             // Depth and solvability members are not used, no need waste resources and set them for now.
    2390           0 :                             vCoins.emplace_back(pcoin, i, 0, isMineSpendable, true, fSafe);
    2391             :                     }
    2392             :                 }
    2393             :             }
    2394             :         }
    2395             :     }
    2396             : 
    2397           0 : }
    2398             : 
    2399             : /**
    2400             :  * Test if the transaction is spendable.
    2401             :  */
    2402     4337965 : static bool CheckTXAvailabilityInternal(const CWalletTx* pcoin, bool fOnlySafe, int& nDepth, bool& safeTx)
    2403             : {
    2404     4337965 :     safeTx = pcoin->IsTrusted();
    2405     4337965 :     if (fOnlySafe && !safeTx) return false;
    2406     4337826 :     if (pcoin->GetBlocksToMaturity() > 0) return false;
    2407             : 
    2408     4067476 :     nDepth = pcoin->GetDepthInMainChain();
    2409             : 
    2410             :     // We should not consider coins which aren't at least in our mempool
    2411             :     // It's possible for these to be conflicted via ancestors which we may never be able to detect
    2412     4067476 :     if (nDepth == 0 && !pcoin->InMempool()) return false;
    2413             : 
    2414             :     return true;
    2415             : }
    2416             : 
    2417             : // cs_main lock required
    2418      983733 : static bool CheckTXAvailability(const CWalletTx* pcoin, bool fOnlySafe, int& nDepth, bool& safeTx)
    2419             : {
    2420      983733 :     AssertLockHeld(cs_main);
    2421      983733 :     if (!CheckFinalTx(pcoin->tx)) return false;
    2422      983733 :     return CheckTXAvailabilityInternal(pcoin, fOnlySafe, nDepth, safeTx);
    2423             : }
    2424             : 
    2425             : // cs_main lock NOT required
    2426     3354232 : static bool CheckTXAvailability(const CWalletTx* pcoin,
    2427             :                          bool fOnlySafe,
    2428             :                          int& nDepth,
    2429             :                          bool& safeTx,
    2430             :                          int nBlockHeight)
    2431             : {
    2432             :     // Mimic CheckFinalTx without cs_main lock
    2433     3354232 :     if (!IsFinalTx(pcoin->tx, nBlockHeight + 1, GetAdjustedTime())) return false;
    2434     3354232 :     return CheckTXAvailabilityInternal(pcoin, fOnlySafe, nDepth, safeTx);
    2435             : }
    2436             : 
    2437          14 : bool CWallet::GetMasternodeVinAndKeys(CPubKey& pubKeyRet,
    2438             :                                       CKey& keyRet,
    2439             :                                       const COutPoint& collateralOut,
    2440             :                                       bool fValidateCollateral,
    2441             :                                       std::string& strError)
    2442             : {
    2443             :     // wait for reindex and/or import to finish
    2444          14 :     if (fImporting || fReindex) return false;
    2445             : 
    2446             :     // Find specific vin
    2447          14 :     const CWalletTx* wtx = GetWalletTx(collateralOut.hash);
    2448          14 :     if (!wtx) {
    2449           0 :         strError = "collateral tx not found in the wallet";
    2450           0 :         return error("%s: %s", __func__, strError);
    2451             :     }
    2452             : 
    2453             :     // Verify index limits
    2454          14 :     if (collateralOut.n < 0 || collateralOut.n >= (uint32_t) wtx->tx->vout.size()) {
    2455           0 :         strError = "Invalid masternode output index";
    2456           0 :         return error("%s: output index %d not found in %s", __func__, collateralOut.n, collateralOut.hash.GetHex());
    2457             :     }
    2458             : 
    2459          28 :     CTxOut txOut = wtx->tx->vout[collateralOut.n];
    2460             : 
    2461             :     // Masternode collateral value
    2462          14 :     const auto& consensus = Params().GetConsensus();
    2463          14 :     if (txOut.nValue != consensus.nMNCollateralAmt) {
    2464           0 :         strError = strprintf("Invalid collateral tx value, must be %s PIV", FormatMoney(Params().GetConsensus().nMNCollateralAmt));
    2465           0 :         return error("%s: tx %s, index %d not a masternode collateral", __func__, collateralOut.hash.GetHex(), collateralOut.n);
    2466             :     }
    2467             : 
    2468          14 :     if (fValidateCollateral) {
    2469          14 :         int nDepth = 0;
    2470          14 :         {
    2471          14 :             LOCK(cs_wallet);
    2472             :             // Check availability
    2473          14 :             bool safeTx = false;
    2474          14 :             if (!CheckTXAvailability(wtx, true, nDepth, safeTx, m_last_block_processed_height)) {
    2475           0 :                 strError = "Not available collateral transaction";
    2476           0 :                 return error("%s: tx %s not available", __func__, collateralOut.hash.GetHex());
    2477             :             }
    2478             : 
    2479             :             // Skip spent coins
    2480          14 :             if (IsSpent(collateralOut.hash, collateralOut.n)) {
    2481           0 :                 strError = "Error: collateral already spent";
    2482           0 :                 return error("%s: tx %s already spent", __func__, collateralOut.hash.GetHex());
    2483             :             }
    2484             :         }
    2485             : 
    2486             :         // Depth must be at least MASTERNODE_MIN_CONFIRMATIONS
    2487          14 :         if (nDepth < consensus.MasternodeCollateralMinConf()) {
    2488           0 :             strError = strprintf("Collateral tx must have at least %d confirmations, has %d",
    2489           0 :                                  consensus.MasternodeCollateralMinConf(), nDepth);
    2490           0 :             return error("%s: %s", __func__, strError);
    2491             :         }
    2492             :     }
    2493             : 
    2494          28 :     CTxDestination destCollateral;
    2495          14 :     ExtractDestination(txOut.scriptPubKey, destCollateral, false);
    2496          14 :     const CKeyID* keyID = boost::get<CKeyID>(&destCollateral);
    2497          14 :     if (!keyID) {
    2498           0 :         LogPrintf("%s: Address does not refer to a key\n", __func__);
    2499             :         return false;
    2500             :     }
    2501             : 
    2502          14 :     if (!GetKey(*keyID, keyRet)) {
    2503           0 :         LogPrintf("%s: Private key for address is not known\n", __func__);
    2504             :         return false;
    2505             :     }
    2506             : 
    2507          14 :     pubKeyRet = keyRet.GetPubKey();
    2508             :     return true;
    2509             : }
    2510             : 
    2511     9215932 : CWallet::OutputAvailabilityResult CWallet::CheckOutputAvailability(
    2512             :         const CTxOut& output,
    2513             :         const unsigned int outIndex,
    2514             :         const uint256& wtxid,
    2515             :         const CCoinControl* coinControl,
    2516             :         const bool fCoinsSelected,
    2517             :         const bool fIncludeColdStaking,
    2518             :         const bool fIncludeDelegated,
    2519             :         const bool fIncludeLocked) const
    2520             : {
    2521     9215932 :     OutputAvailabilityResult res;
    2522             : 
    2523             :     // Check if the utxo was spent.
    2524     9215932 :     if (IsSpent(wtxid, outIndex)) return res;
    2525             : 
    2526     3616248 :     isminetype mine = IsMine(output);
    2527             : 
    2528             :     // Check If not mine
    2529     3616248 :     if (mine == ISMINE_NO) return res;
    2530             : 
    2531             :     // Skip locked utxo
    2532     3319028 :     if (!fIncludeLocked && IsLockedCoin(wtxid, outIndex)) return res;
    2533             : 
    2534             :     // Check if we should include zero value utxo
    2535     3318408 :     if (output.nValue <= 0) return res;
    2536     3318408 :     if (fCoinsSelected && coinControl && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(wtxid, outIndex)))
    2537           0 :         return res;
    2538             : 
    2539             :     // --Skip P2CS outputs
    2540             :     // skip cold coins
    2541     3318408 :     if (mine == ISMINE_COLD && (!fIncludeColdStaking || !HasDelegator(output))) return res;
    2542             :     // skip delegated coins
    2543     3318388 :     if (mine == ISMINE_SPENDABLE_DELEGATED && !fIncludeDelegated) return res;
    2544             : 
    2545     3318188 :     res.solvable = IsSolvable(*this, output.scriptPubKey, mine == ISMINE_COLD);
    2546             : 
    2547     6636966 :     res.spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
    2548     3318188 :                      (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && res.solvable)) ||
    2549        1176 :                      ((mine & ((fIncludeColdStaking ? ISMINE_COLD : ISMINE_NO) |
    2550         588 :                                (fIncludeDelegated ? ISMINE_SPENDABLE_DELEGATED : ISMINE_NO) )) != ISMINE_NO);
    2551     3318188 :     res.available = true;
    2552     3318188 :     return res;
    2553             : }
    2554             : 
    2555        2731 : bool CWallet::AvailableCoins(std::vector<COutput>* pCoins,      // --> populates when != nullptr
    2556             :                              const CCoinControl* coinControl,   // Default: nullptr
    2557             :                              AvailableCoinsFilter coinsFilter) const
    2558             : {
    2559        2731 :     if (pCoins) pCoins->clear();
    2560        2731 :     const bool fCoinsSelected = (coinControl != nullptr) && coinControl->HasSelected();
    2561             :     // include delegated coins when coinControl is active
    2562        2731 :     if (!coinsFilter.fIncludeDelegated && fCoinsSelected)
    2563           8 :         coinsFilter.fIncludeDelegated = true;
    2564             : 
    2565        2731 :     {
    2566        5462 :         LOCK(cs_wallet);
    2567        2731 :         CAmount nTotal = 0;
    2568     3356945 :         for (const auto& entry : mapWallet) {
    2569     3354222 :             const uint256& wtxid = entry.first;
    2570     3354222 :             const CWalletTx* pcoin = &entry.second;
    2571             : 
    2572             :             // Check if the tx is selectable
    2573     3354222 :             int nDepth = 0;
    2574     3354222 :             bool safeTx = false;
    2575     3354222 :             if (!CheckTXAvailability(pcoin, coinsFilter.fOnlySafe, nDepth, safeTx, m_last_block_processed_height))
    2576     1152807 :                 continue;
    2577             : 
    2578             :             // Check min depth filtering requirements
    2579     3200565 :             if (nDepth < coinsFilter.minDepth) continue;
    2580             : 
    2581    10370210 :             for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
    2582     8168845 :                 const auto& output = pcoin->tx->vout[i];
    2583             : 
    2584             :                 // Filter by value if needed
    2585     8168845 :                 if (coinsFilter.nMaxOutValue > 0 && output.nValue > coinsFilter.nMaxOutValue) {
    2586     5179500 :                     continue;
    2587             :                 }
    2588     8168785 :                 if (coinsFilter.nMinOutValue > 0 && output.nValue < coinsFilter.nMinOutValue) {
    2589          41 :                     continue;
    2590             :                 }
    2591             : 
    2592             :                 // Filter by specific destinations if needed
    2593     8168745 :                 if (coinsFilter.onlyFilteredDest && !coinsFilter.onlyFilteredDest->empty()) {
    2594         783 :                     CTxDestination address;
    2595        1362 :                     if (!ExtractDestination(output.scriptPubKey, address) || !coinsFilter.onlyFilteredDest->count(address)) {
    2596         579 :                         continue;
    2597             :                     }
    2598             :                 }
    2599             : 
    2600             :                 // Now check for chain availability
    2601     8168165 :                 auto res = CheckOutputAvailability(
    2602             :                         output,
    2603             :                         i,
    2604             :                         wtxid,
    2605             :                         coinControl,
    2606             :                         fCoinsSelected,
    2607     8168165 :                         coinsFilter.fIncludeColdStaking,
    2608     8168165 :                         coinsFilter.fIncludeDelegated,
    2609     8168165 :                         coinsFilter.fIncludeLocked);
    2610             : 
    2611     8168165 :                 if (!res.available) continue;
    2612     2989355 :                 if (coinsFilter.fOnlySpendable && !res.spendable) continue;
    2613             : 
    2614             :                 // found valid coin
    2615     2989355 :                 if (!pCoins) return true;
    2616     2989355 :                 pCoins->emplace_back(pcoin, (int) i, nDepth, res.spendable, res.solvable, safeTx);
    2617             : 
    2618             :                 // Checks the sum amount of all UTXO's.
    2619     2989355 :                 if (coinsFilter.nMinimumSumAmount != 0) {
    2620          17 :                     nTotal += output.nValue;
    2621             : 
    2622          17 :                     if (nTotal >= coinsFilter.nMinimumSumAmount) {
    2623             :                         return true;
    2624             :                     }
    2625             :                 }
    2626             : 
    2627             :                 // Checks the maximum number of UTXO's.
    2628     2989345 :                 if (coinsFilter.nMaximumCount > 0 && pCoins->size() >= coinsFilter.nMaximumCount) {
    2629             :                     return true;
    2630             :                 }
    2631             :             }
    2632             :         }
    2633        2726 :         return (pCoins && !pCoins->empty());
    2634             :     }
    2635             : }
    2636             : 
    2637           1 : std::map<CTxDestination , std::vector<COutput> > CWallet::AvailableCoinsByAddress(bool fOnlySafe, CAmount maxCoinValue, bool fIncludeColdStaking)
    2638             : {
    2639           1 :     CWallet::AvailableCoinsFilter coinFilter;
    2640           1 :     coinFilter.fIncludeColdStaking = true;
    2641           1 :     coinFilter.fOnlySafe = fOnlySafe;
    2642           1 :     coinFilter.fIncludeColdStaking = fIncludeColdStaking;
    2643           1 :     coinFilter.nMaxOutValue = maxCoinValue;
    2644           1 :     std::vector<COutput> vCoins;
    2645           1 :     AvailableCoins(&vCoins, nullptr, coinFilter);
    2646             : 
    2647           1 :     std::map<CTxDestination, std::vector<COutput> > mapCoins;
    2648          11 :     for (const COutput& out : vCoins) {
    2649          20 :         CTxDestination address;
    2650          10 :         bool fColdStakeAddr = false;
    2651          10 :         if (!ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address, fColdStakeAddr)) {
    2652           0 :             bool isP2CS = out.tx->tx->vout[out.i].scriptPubKey.IsPayToColdStaking();
    2653           0 :             if (isP2CS && !fIncludeColdStaking) {
    2654             :                 // It must never happen as the coin filtering process shouldn't had added the P2CS in the first place
    2655           0 :                 assert(false);
    2656             :             }
    2657             :             // if this is a P2CS we don't have the owner key - check if we have the staking key
    2658           0 :             fColdStakeAddr = true;
    2659           0 :             if (!isP2CS || !ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address, fColdStakeAddr) )
    2660           0 :                 continue;
    2661             :         }
    2662             : 
    2663          10 :         mapCoins[address].emplace_back(out);
    2664             :     }
    2665             : 
    2666           2 :     return mapCoins;
    2667             : }
    2668             : 
    2669        2934 : static void ApproximateBestSubset(const std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > >& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
    2670             :                                   std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
    2671             : {
    2672        2934 :     std::vector<char> vfIncluded;
    2673             : 
    2674        2934 :     vfBest.assign(vValue.size(), true);
    2675        2934 :     nBest = nTotalLower;
    2676             : 
    2677        2934 :     FastRandomContext insecure_rand;
    2678             : 
    2679     1835059 :     for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) {
    2680     1832125 :         vfIncluded.assign(vValue.size(), false);
    2681     1832125 :         CAmount nTotal = 0;
    2682     1832125 :         bool fReachedTarget = false;
    2683     4610395 :         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) {
    2684   349975270 :             for (unsigned int i = 0; i < vValue.size(); i++) {
    2685             :                 //The solver here uses a randomized algorithm,
    2686             :                 //the randomness serves no real security purpose but is just
    2687             :                 //needed to prevent degenerate behavior and it is important
    2688             :                 //that the rng is fast. We do not use a constant random sequence,
    2689             :                 //because there may be some privacy improvement by making
    2690             :                 //the selection random.
    2691   690506320 :                 if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i]) {
    2692   173969615 :                     nTotal += vValue[i].first;
    2693   173969615 :                     vfIncluded[i] = true;
    2694   173969615 :                     if (nTotal >= nTargetValue) {
    2695   163518819 :                         fReachedTarget = true;
    2696   163518819 :                         if (nTotal < nBest) {
    2697        4515 :                             nBest = nTotal;
    2698        4515 :                             vfBest = vfIncluded;
    2699             :                         }
    2700   163518819 :                         nTotal -= vValue[i].first;
    2701   163518819 :                         vfIncluded[i] = false;
    2702             :                     }
    2703             :                 }
    2704             :             }
    2705             :         }
    2706             :     }
    2707        2934 : }
    2708             : 
    2709        2486 : bool CWallet::StakeableCoins(std::vector<CStakeableOutput>* pCoins)
    2710             : {
    2711        4955 :     const bool fIncludeColdStaking = !sporkManager.IsSporkActive(SPORK_19_COLDSTAKING_MAINTENANCE) &&
    2712        7424 :                                      gArgs.GetBoolArg("-coldstaking", DEFAULT_COLDSTAKING);
    2713             : 
    2714        2486 :     if (pCoins) pCoins->clear();
    2715             : 
    2716        7458 :     LOCK2(cs_main, cs_wallet);
    2717      986219 :     for (const auto& it : mapWallet) {
    2718      983733 :         const uint256& wtxid = it.first;
    2719      983733 :         const CWalletTx* pcoin = &(it).second;
    2720             : 
    2721             :         // Check if the tx is selectable
    2722      983733 :         int nDepth = 0;
    2723      983733 :         bool safeTx = false;
    2724      983733 :         if (!CheckTXAvailability(pcoin, true, nDepth, safeTx))
    2725      231013 :             continue;
    2726             : 
    2727             :         // Check min depth requirement for stake inputs
    2728      754566 :         if (nDepth < Params().GetConsensus().nStakeMinDepth) continue;
    2729             : 
    2730      752720 :         const CBlockIndex* pindex = nullptr;
    2731     1800484 :         for (unsigned int index = 0; index < pcoin->tx->vout.size(); index++) {
    2732             : 
    2733     1047767 :             auto res = CheckOutputAvailability(
    2734     1047767 :                     pcoin->tx->vout[index],
    2735             :                     index,
    2736             :                     wtxid,
    2737             :                     nullptr, // coin control
    2738             :                     false,   // fIncludeDelegated
    2739             :                     fIncludeColdStaking,
    2740             :                     false,
    2741     1047767 :                     false);   // fIncludeLocked
    2742             : 
    2743     1047767 :             if (!res.available || !res.spendable) continue;
    2744             : 
    2745             :             // found valid coin
    2746      328438 :             if (!pCoins) return true;
    2747      328438 :             if (!pindex) pindex = mapBlockIndex.at(pcoin->m_confirm.hashBlock);
    2748      328438 :             pCoins->emplace_back(pcoin, (int) index, nDepth, pindex);
    2749             :         }
    2750             :     }
    2751        2486 :     return (pCoins && !pCoins->empty());
    2752             : }
    2753             : 
    2754        6921 : bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*, unsigned int> >& setCoinsRet, CAmount& nValueRet) const
    2755             : {
    2756        6921 :     setCoinsRet.clear();
    2757        6921 :     nValueRet = 0;
    2758             : 
    2759             :     // List of values less than target
    2760        6921 :     std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> > coinLowestLarger;
    2761        6921 :     coinLowestLarger.first = std::numeric_limits<CAmount>::max();
    2762        6921 :     coinLowestLarger.second.first = nullptr;
    2763       13842 :     std::vector<std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> > > vValue;
    2764        6921 :     CAmount nTotalLower = 0;
    2765             : 
    2766        6921 :     Shuffle(vCoins.begin(), vCoins.end(), FastRandomContext());
    2767             : 
    2768      522588 :     for (const COutput& output : vCoins) {
    2769      516793 :         if (!output.fSpendable)
    2770        5590 :             continue;
    2771             : 
    2772      516793 :         const CWalletTx* pcoin = output.tx;
    2773             : 
    2774     1025580 :         if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs)) {
    2775        4913 :             continue;
    2776             :         }
    2777             : 
    2778      511880 :         if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors)) {
    2779         677 :             continue;
    2780             :         }
    2781             : 
    2782      511203 :         int i = output.i;
    2783      511203 :         CAmount n = pcoin->tx->vout[i].nValue;
    2784             : 
    2785      511203 :         std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> > coin = std::make_pair(n, std::make_pair(pcoin, i));
    2786             : 
    2787      511203 :         if (n == nTargetValue) {
    2788        1126 :             setCoinsRet.insert(coin.second);
    2789        1126 :             nValueRet += coin.first;
    2790        1126 :             return true;
    2791      510077 :         } else if (n < nTargetValue + MIN_CHANGE) {
    2792      241030 :             vValue.push_back(coin);
    2793      241030 :             nTotalLower += n;
    2794      269047 :         } else if (n < coinLowestLarger.first) {
    2795      510077 :             coinLowestLarger = coin;
    2796             :         }
    2797             :     }
    2798             : 
    2799        5795 :     if (nTotalLower == nTargetValue) {
    2800        2409 :         for (unsigned int i = 0; i < vValue.size(); ++i) {
    2801        1906 :             setCoinsRet.insert(vValue[i].second);
    2802        1906 :             nValueRet += vValue[i].first;
    2803             :         }
    2804             :         return true;
    2805             :     }
    2806             : 
    2807        5292 :     if (nTotalLower < nTargetValue) {
    2808        3309 :         if (coinLowestLarger.second.first == nullptr)
    2809             :                 return false;
    2810        2397 :         setCoinsRet.insert(coinLowestLarger.second);
    2811        2397 :         nValueRet += coinLowestLarger.first;
    2812        2397 :         return true;
    2813             :     }
    2814             : 
    2815             :     // Solve subset sum by stochastic approximation
    2816        1983 :     std::sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
    2817        8904 :     std::vector<char> vfBest;
    2818        1983 :     CAmount nBest;
    2819             : 
    2820        1983 :     ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
    2821        1983 :     if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
    2822         951 :         ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
    2823             : 
    2824             :     // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
    2825             :     //                                   or the next bigger coin is closer), return the bigger coin
    2826        1983 :     if (coinLowestLarger.second.first &&
    2827         946 :         ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest)) {
    2828         316 :         setCoinsRet.insert(coinLowestLarger.second);
    2829         316 :         nValueRet += coinLowestLarger.first;
    2830             :     } else {
    2831        3334 :         std::string s = "CWallet::SelectCoinsMinConf best subset: ";
    2832      231258 :         for (unsigned int i = 0; i < vValue.size(); i++) {
    2833      229591 :             if (vfBest[i]) {
    2834       88293 :                 setCoinsRet.insert(vValue[i].second);
    2835       88293 :                 nValueRet += vValue[i].first;
    2836      176586 :                 s += FormatMoney(vValue[i].first) + " ";
    2837             :             }
    2838             :         }
    2839        3334 :         LogPrintf("%s - total %s\n", s, FormatMoney(nBest));
    2840             :     }
    2841             : 
    2842        1983 :     return true;
    2843             : }
    2844             : 
    2845        1088 : bool CWallet::SelectCoinsToSpend(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*, unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
    2846             : {
    2847             :     // Note: this function should never be used for "always free" tx types like dstx
    2848        2176 :     std::vector<COutput> vCoins(vAvailableCoins);
    2849             : 
    2850             :     // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
    2851        1088 :     if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) {
    2852          40 :         for (const COutput& out : vCoins) {
    2853          22 :             if (!out.fSpendable)
    2854           0 :                 continue;
    2855             : 
    2856          22 :             nValueRet += out.tx->tx->vout[out.i].nValue;
    2857          44 :             setCoinsRet.emplace(out.tx, out.i);
    2858             :         }
    2859          18 :         return (nValueRet >= nTargetValue);
    2860             :     }
    2861             : 
    2862             :     // calculate value from preset inputs and store them
    2863        2158 :     std::set<std::pair<const CWalletTx*, uint32_t> > setPresetCoins;
    2864        1070 :     CAmount nValueFromPresetInputs = 0;
    2865             : 
    2866        2140 :     std::vector<OutPointWrapper> vPresetInputs;
    2867        1070 :     if (coinControl)
    2868         319 :         coinControl->ListSelected(vPresetInputs);
    2869        1088 :     for (const auto& outpoint : vPresetInputs) {
    2870          19 :         std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.outPoint.hash);
    2871          19 :         if (it != mapWallet.end()) {
    2872          18 :             const CWalletTx* pcoin = &it->second;
    2873             :             // Clearly invalid input, fail
    2874          18 :             if (pcoin->tx->vout.size() <= outpoint.outPoint.n)
    2875           0 :                 return false;
    2876          18 :             nValueFromPresetInputs += pcoin->tx->vout[outpoint.outPoint.n].nValue;
    2877          18 :             setPresetCoins.emplace(pcoin, outpoint.outPoint.n);
    2878             :         } else
    2879             :             return false; // TODO: Allow non-wallet inputs
    2880             :     }
    2881             : 
    2882             :     // remove preset inputs from vCoins
    2883        2171 :     for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) {
    2884          47 :         if (setPresetCoins.count(std::make_pair(it->tx, it->i)))
    2885          18 :             it = vCoins.erase(it);
    2886             :         else
    2887        1145 :             ++it;
    2888             :     }
    2889             : 
    2890        2138 :     size_t nMaxChainLength = std::min(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
    2891             : 
    2892        1010 :     bool res = nTargetValue <= nValueFromPresetInputs ||
    2893        1168 :             SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) ||
    2894        1302 :             SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) ||
    2895        1144 :             (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) ||
    2896        1130 :             (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) ||
    2897        2163 :             (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) ||
    2898        1100 :             (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet));
    2899             : 
    2900             :     // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
    2901        1069 :     setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
    2902             : 
    2903             :     // add preset inputs to the total value selected
    2904        1069 :     nValueRet += nValueFromPresetInputs;
    2905             : 
    2906        1069 :     return res;
    2907             : }
    2908             : 
    2909           0 : std::map<std::pair<CTxDestination, Optional<CTxDestination>>, std::vector<COutput>> CWallet::ListCoins() const
    2910             : {
    2911           0 :     std::map<std::pair<CTxDestination, Optional<CTxDestination>>, std::vector<COutput>> result;
    2912             : 
    2913           0 :     CWallet::AvailableCoinsFilter filter;
    2914           0 :     filter.fIncludeLocked = true;
    2915           0 :     filter.fOnlySpendable = true;
    2916           0 :     std::vector<COutput> availableCoins;
    2917           0 :     AvailableCoins(&availableCoins, nullptr, filter);
    2918             : 
    2919           0 :     for (const COutput& coin : availableCoins) {
    2920           0 :         const CScript& scriptPubKey = coin.tx->tx->vout[coin.i].scriptPubKey;
    2921           0 :         txnouttype type; std::vector<CTxDestination> addresses; int nRequired;
    2922           0 :         if (ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
    2923           0 :             if (addresses.size() == 1) {
    2924             :                 // P2PK, P2PKH scripts
    2925           0 :                 const auto& addrpair = std::make_pair(addresses[0], nullopt);
    2926           0 :                 result[addrpair].emplace_back(std::move(coin));
    2927           0 :             } else if (type == TX_COLDSTAKE) {
    2928             :                 // P2CS scripts
    2929           0 :                 assert(addresses.size() == 2);
    2930           0 :                 const auto& addrpair = std::make_pair(addresses[1], Optional<CTxDestination>(addresses[0]));
    2931           0 :                 result[addrpair].emplace_back(std::move(coin));
    2932             :             }
    2933             :         }
    2934             :     }
    2935             : 
    2936           0 :     return result;
    2937             : }
    2938             : 
    2939           0 : std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> CWallet::ListNotes() const
    2940             : {
    2941           0 :     return m_sspk_man->ListNotes();
    2942             : }
    2943             : 
    2944          22 : bool CWallet::CreateBudgetFeeTX(CTransactionRef& tx, const uint256& hash, CReserveKey& keyChange, CAmount fee)
    2945             : {
    2946          44 :     CScript scriptChange;
    2947          22 :     scriptChange << OP_RETURN << ToByteVector(hash);
    2948             : 
    2949          22 :     CAmount nFeeRet = 0;
    2950          44 :     std::string strFail = "";
    2951          44 :     std::vector<CRecipient> vecSend;
    2952          22 :     vecSend.emplace_back(scriptChange, fee, false);
    2953             : 
    2954          22 :     CCoinControl* coinControl = nullptr;
    2955          22 :     int nChangePosInOut = -1;
    2956          22 :     bool success = CreateTransaction(vecSend, tx, keyChange, nFeeRet, nChangePosInOut, strFail, coinControl, true, (CAmount)0);
    2957          22 :     if (!success) {
    2958           0 :         LogPrintf("%s: Error - %s\n", __func__, strFail);
    2959             :         return false;
    2960             :     }
    2961             : 
    2962             :     return true;
    2963             : }
    2964             : 
    2965         130 : bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, const CTxDestination& destChange)
    2966             : {
    2967         130 :     std::vector<CRecipient> vecSend;
    2968             : 
    2969             :     // Turn the txout set into a CRecipient vector.
    2970         275 :     for (size_t idx = 0; idx < tx.vout.size(); idx++) {
    2971         145 :         const CTxOut& txOut = tx.vout[idx];
    2972         290 :         vecSend.emplace_back(txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1);
    2973             :     }
    2974             : 
    2975         260 :     CCoinControl coinControl;
    2976         130 :     coinControl.destChange = destChange;
    2977         130 :     coinControl.fAllowOtherInputs = true;
    2978         130 :     coinControl.fAllowWatchOnly = includeWatching;
    2979         130 :     coinControl.fOverrideFeeRate = overrideEstimatedFeeRate;
    2980         130 :     coinControl.nFeeRate = specificFeeRate;
    2981             : 
    2982         130 :     const int nExtraSize = tx.isSaplingVersion() ?
    2983          94 :             (int)(GetSerializeSize(tx.sapData) + GetSerializeSize(tx.extraPayload)) : 0;
    2984             : 
    2985         140 :     for (const CTxIn& txin : tx.vin) {
    2986          10 :         coinControl.Select(txin.prevout);
    2987             :     }
    2988             : 
    2989             :     // Acquire the locks to prevent races to the new locked unspents between the
    2990             :     // CreateTransaction call and LockCoin calls (when lockUnspents is true).
    2991         390 :     LOCK2(cs_main, cs_wallet);
    2992             : 
    2993         260 :     CReserveKey reservekey(this);
    2994         130 :     CTransactionRef wtx;
    2995         130 :     if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false, 0, false, nullptr, nExtraSize)) {
    2996             :         return false;
    2997             :     }
    2998             : 
    2999         128 :     if (nChangePosInOut != -1) {
    3000         124 :         tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx->vout[nChangePosInOut]);
    3001             :         // We don't have the normal Create/Commit cycle, and don't want to risk
    3002             :         // reusing change, so just remove the key from the keypool here.
    3003         124 :         reservekey.KeepKey();
    3004             :     }
    3005             : 
    3006             :     // Copy output sizes from new transaction; they may have had the fee
    3007             :     // subtracted from them.
    3008         395 :     for (unsigned int idx = 0; idx < tx.vout.size(); idx++) {
    3009         267 :         tx.vout[idx].nValue = wtx->vout[idx].nValue;
    3010             :     }
    3011             : 
    3012             :     // Add new txins while keeping original txin scriptSig/order.
    3013         313 :     for (const CTxIn& txin : wtx->vin) {
    3014         185 :         if (!coinControl.IsSelected(txin.prevout)) {
    3015         176 :             tx.vin.emplace_back(txin);
    3016         176 :             if (lockUnspents) LockCoin(txin.prevout);
    3017             :         }
    3018             :     }
    3019             : 
    3020         128 :     return true;
    3021             : }
    3022             : 
    3023           9 : std::vector<COutput> CWallet::GetOutputsFromCoinControl(const CCoinControl* coinControl)
    3024             : {
    3025           9 :     assert(coinControl);
    3026           9 :     LOCK(cs_wallet);
    3027           9 :     std::vector<COutput> vCoinsRet;
    3028           9 :     std::vector<OutPointWrapper> vPresetInputs;
    3029           9 :     coinControl->ListSelected(vPresetInputs);
    3030          20 :     for (const auto& out : vPresetInputs) {
    3031          11 :         auto it = mapWallet.find(out.outPoint.hash);
    3032          11 :         if (it != mapWallet.end()) {
    3033          11 :             assert(it->second.tx->vout.size() > out.outPoint.n);
    3034          11 :             vCoinsRet.emplace_back(COutput(&(it->second), out.outPoint.n, 0, true, true, true));
    3035             :         }
    3036             :     }
    3037          18 :     return vCoinsRet;
    3038             : }
    3039             : 
    3040         506 : bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
    3041             :     CTransactionRef& txRet,
    3042             :     CReserveKey& reservekey,
    3043             :     CAmount& nFeeRet,
    3044             :     int& nChangePosInOut,
    3045             :     std::string& strFailReason,
    3046             :     const CCoinControl* coinControl,
    3047             :     bool sign,
    3048             :     CAmount nFeePay,
    3049             :     bool fIncludeDelegated,
    3050             :     bool* fStakeDelegationVoided,
    3051             :     int nExtraSize,
    3052             :     int nMinDepth)
    3053             : {
    3054         506 :     CAmount nValue = 0;
    3055         506 :     int nChangePosRequest = nChangePosInOut;
    3056         506 :     unsigned int nSubtractFeeFromAmount = 0;
    3057        1036 :     for (const CRecipient& rec : vecSend) {
    3058         530 :         if (nValue < 0 || rec.nAmount < 0) {
    3059           0 :             strFailReason = _("Transaction amounts must be positive");
    3060           0 :             return false;
    3061             :         }
    3062         530 :         nValue += rec.nAmount;
    3063         530 :         if (rec.fSubtractFeeFromAmount)
    3064           9 :             nSubtractFeeFromAmount++;
    3065             :     }
    3066         506 :     if (vecSend.empty()) {
    3067           0 :         strFailReason = _("Transaction must have at least one recipient");
    3068           0 :         return false;
    3069             :     }
    3070             : 
    3071         506 :     CMutableTransaction txNew;
    3072        1012 :     CScript scriptChange;
    3073             : 
    3074         506 :     CWallet::AvailableCoinsFilter coinFilter;
    3075         506 :     coinFilter.fOnlySpendable = true;
    3076         506 :     coinFilter.fIncludeDelegated = fIncludeDelegated;
    3077         506 :     coinFilter.minDepth = nMinDepth;
    3078             : 
    3079         506 :     {
    3080         506 :         std::set<std::pair<const CWalletTx*,unsigned int> > setCoins;
    3081        1512 :         LOCK2(cs_main, cs_wallet);
    3082         506 :         {
    3083         506 :             std::vector<COutput> vAvailableCoins;
    3084         506 :             if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) {
    3085             :                 // Select only the outputs that the caller pre-selected.
    3086          18 :                 vAvailableCoins = GetOutputsFromCoinControl(coinControl);
    3087             :             } else {
    3088             :                 // Regular selection
    3089         497 :                 AvailableCoins(&vAvailableCoins, coinControl, coinFilter);
    3090             :             }
    3091             : 
    3092         506 :             nFeeRet = 0;
    3093         506 :             if (nFeePay > 0) nFeeRet = nFeePay;
    3094        1088 :             while (true) {
    3095        1088 :                 nChangePosInOut = nChangePosRequest;
    3096        1088 :                 txNew.vin.clear();
    3097        1088 :                 txNew.vout.clear();
    3098        1088 :                 bool fFirst = true;
    3099             : 
    3100        1088 :                 CAmount nValueToSelect = nValue;
    3101        1088 :                 if (nSubtractFeeFromAmount == 0)
    3102        1074 :                     nValueToSelect += nFeeRet;
    3103             : 
    3104             :                 // Fill outputs
    3105        2227 :                 for (const CRecipient& rec : vecSend) {
    3106        2278 :                     CTxOut txout(rec.nAmount, rec.scriptPubKey);
    3107        1139 :                     if (rec.fSubtractFeeFromAmount) {
    3108          18 :                         assert(nSubtractFeeFromAmount != 0);
    3109          18 :                         txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
    3110             : 
    3111          18 :                         if (fFirst) {
    3112             :                             // first receiver pays the remainder not divisible by output count
    3113          14 :                             fFirst = false;
    3114          14 :                             txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
    3115             :                         }
    3116             :                     }
    3117        1139 :                     if (IsDust(txout, dustRelayFee)) {
    3118           0 :                         strFailReason = _("Transaction amount too small");
    3119           0 :                         return false;
    3120             :                     }
    3121        1139 :                     txNew.vout.emplace_back(txout);
    3122             :                 }
    3123             : 
    3124             :                 // Choose coins to use
    3125        1088 :                 CAmount nValueIn = 0;
    3126        1088 :                 setCoins.clear();
    3127             : 
    3128        1088 :                 if (!SelectCoinsToSpend(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl)) {
    3129           2 :                     strFailReason = _("Insufficient funds.");
    3130           2 :                     return false;
    3131             :                 }
    3132             : 
    3133             :                 // Change
    3134        1086 :                 CAmount nChange = nValueIn - nValueToSelect;
    3135        1086 :                 if (nChange > 0) {
    3136             :                     // Fill a vout to ourself
    3137             :                     // TODO: pass in scriptChange instead of reservekey so
    3138             :                     // change transaction isn't always pay-to-pivx-address
    3139        1000 :                     bool combineChange = false;
    3140             : 
    3141             :                     // coin control: send change to custom address
    3142        1000 :                     if (coinControl && IsValidDestination(coinControl->destChange)) {
    3143           4 :                         scriptChange = GetScriptForDestination(coinControl->destChange);
    3144             : 
    3145           4 :                         std::vector<CTxOut>::iterator it = txNew.vout.begin();
    3146           6 :                         while (it != txNew.vout.end()) {
    3147           4 :                             if (scriptChange == it->scriptPubKey) {
    3148           2 :                                 it->nValue += nChange;
    3149           2 :                                 nChange = 0;
    3150           2 :                                 reservekey.ReturnKey();
    3151             :                                 combineChange = true;
    3152             :                                 break;
    3153             :                             }
    3154           6 :                             ++it;
    3155             :                         }
    3156             :                     }
    3157             : 
    3158             :                     // no coin control: send change to newly generated address
    3159             :                     else {
    3160             :                         // Note: We use a new key here to keep it from being obvious which side is the change.
    3161             :                         //  The drawback is that by not reusing a previous key, the change may be lost if a
    3162             :                         //  backup is restored, if the backup doesn't have the new private key for the change.
    3163             :                         //  If we reused the old key, it would be possible to add code to look for and
    3164             :                         //  rediscover unknown transactions that were written with keys of ours to recover
    3165             :                         //  post-backup change.
    3166             : 
    3167             :                         // Reserve a new key pair from key pool. If it fails, provide a dummy
    3168         996 :                         CPubKey vchPubKey;
    3169         996 :                         if (!reservekey.GetReservedKey(vchPubKey, true)) {
    3170           3 :                             strFailReason = _("Can't generate a change-address key. Please call keypoolrefill first.");
    3171           3 :                             scriptChange = CScript();
    3172             :                         } else {
    3173         993 :                             scriptChange = GetScriptForDestination(vchPubKey.GetID());
    3174             :                         }
    3175             :                     }
    3176             : 
    3177        1000 :                     if (!combineChange) {
    3178        1996 :                         CTxOut newTxOut(nChange, scriptChange);
    3179             : 
    3180             :                         // Never create dust outputs; if we would, just
    3181             :                         // add the dust to the fee.
    3182         998 :                         if (IsDust(newTxOut, dustRelayFee)) {
    3183           3 :                             nFeeRet += nChange;
    3184           3 :                             nChange = 0;
    3185           3 :                             reservekey.ReturnKey();
    3186           3 :                             nChangePosInOut = -1;
    3187             :                         } else {
    3188         995 :                             if (nChangePosInOut == -1) {
    3189             :                                 // Insert change txn at random position:
    3190         993 :                                 nChangePosInOut = GetRandInt(txNew.vout.size()+1);
    3191           2 :                             } else if (nChangePosInOut < 0 || (unsigned int) nChangePosInOut > txNew.vout.size()) {
    3192           0 :                                 strFailReason = _("Change index out of range");
    3193           0 :                                 return false;
    3194             :                             }
    3195         995 :                             std::vector<CTxOut>::iterator position = txNew.vout.begin() + nChangePosInOut;
    3196         995 :                             txNew.vout.insert(position, newTxOut);
    3197             :                         }
    3198             :                     }
    3199             :                 } else {
    3200          86 :                     reservekey.ReturnKey();
    3201          86 :                     nChangePosInOut = -1;
    3202             :                 }
    3203             : 
    3204             :                 // Fill vin
    3205        2572 :                 for (const std::pair<const CWalletTx*, unsigned int>& coin : setCoins) {
    3206        1486 :                     if(fStakeDelegationVoided && coin.first->tx->vout[coin.second].scriptPubKey.IsPayToColdStaking()) {
    3207           0 :                         *fStakeDelegationVoided = true;
    3208             :                     }
    3209        1486 :                     txNew.vin.emplace_back(coin.first->GetHash(), coin.second);
    3210             :                 }
    3211             : 
    3212             :                 // Fill in dummy signatures for fee calculation.
    3213        1086 :                 int nIn = 0;
    3214        2572 :                 for (const auto & coin : setCoins) {
    3215        1486 :                     const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
    3216        2972 :                     SignatureData sigdata;
    3217        2972 :                     if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, txNew.GetRequiredSigVersion(), false)) {
    3218           0 :                         strFailReason = _("Signing transaction failed");
    3219           0 :                         return false;
    3220             :                     } else {
    3221        1486 :                         UpdateTransaction(txNew, nIn, sigdata);
    3222             :                     }
    3223        1486 :                     nIn++;
    3224             :                 }
    3225             : 
    3226             :                 // account for additional payloads in fee calculation
    3227        1086 :                 const unsigned int nBytes = ::GetSerializeSize(txNew, PROTOCOL_VERSION) + nExtraSize;
    3228        1086 :                 CAmount nFeeNeeded = std::max(nFeePay, GetMinimumFee(nBytes, nTxConfirmTarget, mempool));
    3229             : 
    3230             :                 // Remove scriptSigs to eliminate the fee calculation dummy signatures
    3231        2572 :                 for (CTxIn& vin : txNew.vin) {
    3232        2972 :                     vin.scriptSig = CScript();
    3233             :                 }
    3234             : 
    3235        1086 :                 if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
    3236           0 :                     nFeeNeeded = coinControl->nMinimumTotalFee;
    3237             :                 }
    3238        1086 :                 if (coinControl && coinControl->fOverrideFeeRate)
    3239           8 :                     nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
    3240             : 
    3241             :                 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
    3242             :                 // because we must be at the maximum allowed fee.
    3243        1086 :                 if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes)) {
    3244           0 :                     strFailReason = _("Transaction too large for fee policy");
    3245           0 :                     return false;
    3246             :                 }
    3247             : 
    3248        1086 :                 if (nFeeRet >= nFeeNeeded) // Done, enough fee included
    3249             :                     break;
    3250             : 
    3251             :                 // Include more fee and try again.
    3252         582 :                 nFeeRet = nFeeNeeded;
    3253         582 :                 continue;
    3254         582 :             }
    3255             : 
    3256             :             // Give up if change keypool ran out and we failed to find a solution without change:
    3257         504 :             if (scriptChange.empty() && nChangePosInOut != -1) {
    3258             :                 return false;
    3259             :             }
    3260             :         }
    3261             : 
    3262         503 :         if (sign) {
    3263         750 :             CTransaction txNewConst(txNew);
    3264         375 :             int nIn = 0;
    3265         890 :             for (const auto& coin : setCoins) {
    3266         515 :                 const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
    3267        1030 :                 SignatureData sigdata;
    3268         515 :                 bool haveKey = coin.first->GetStakeDelegationCredit() > 0;
    3269             : 
    3270         515 :                 if (!ProduceSignature(
    3271        1030 :                         TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL),
    3272             :                         scriptPubKey,
    3273             :                         sigdata,
    3274             :                         txNewConst.GetRequiredSigVersion(),
    3275         515 :                         !haveKey    // fColdStake
    3276             :                         )) {
    3277           0 :                     strFailReason = _("Signing transaction failed");
    3278           0 :                     return false;
    3279             :                 } else {
    3280         515 :                     UpdateTransaction(txNew, nIn, sigdata);
    3281             :                 }
    3282         515 :                 nIn++;
    3283             :             }
    3284             :         }
    3285             : 
    3286             :         // Limit size
    3287         503 :         if (::GetSerializeSize(txNew, PROTOCOL_VERSION) >= MAX_STANDARD_TX_SIZE) {
    3288           0 :             strFailReason = _("Transaction too large");
    3289           0 :             return false;
    3290             :         }
    3291             : 
    3292             :         // Embed the constructed transaction data in wtxNew.
    3293         503 :         txRet = MakeTransactionRef(std::move(txNew));
    3294             :     }
    3295             : 
    3296             :     // Lastly, ensure this tx will pass the mempool's chain limits
    3297        1009 :     CTxMemPoolEntry entry(txRet, 0, 0, 0, false, 0);
    3298        1006 :     CTxMemPool::setEntries setAncestors;
    3299         503 :     size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
    3300         503 :     size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
    3301         503 :     size_t nLimitDescendants = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
    3302         503 :     size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
    3303        1006 :     std::string errString;
    3304         503 :     if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
    3305           0 :         strFailReason = _("Transaction has too long of a mempool chain");
    3306           0 :         return false;
    3307             :     }
    3308             : 
    3309             :     return true;
    3310             : }
    3311             : 
    3312          43 : bool CWallet::CreateTransaction(CScript scriptPubKey, const CAmount& nValue, CTransactionRef& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, CAmount nFeePay, bool fIncludeDelegated, bool* fStakeDelegationVoided, int nExtraSize, int nMinDepth)
    3313             : {
    3314          86 :     std::vector<CRecipient> vecSend;
    3315          43 :     vecSend.emplace_back(scriptPubKey, nValue, false);
    3316          43 :     int nChangePosInOut = -1;
    3317          86 :     return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, true, nFeePay, fIncludeDelegated, fStakeDelegationVoided, nExtraSize, nMinDepth);
    3318             : }
    3319             : 
    3320       12319 : int CWallet::GetLastBlockHeightLockWallet() const
    3321             : {
    3322       24638 :     return WITH_LOCK(cs_wallet, return m_last_block_processed_height;);
    3323             : }
    3324             : 
    3325        1919 : bool CWallet::CreateCoinstakeOuts(const CPivStake& stakeInput, std::vector<CTxOut>& vout, CAmount nTotal) const
    3326             : {
    3327        1919 :     std::vector<valtype> vSolutions;
    3328        1919 :     txnouttype whichType;
    3329        3838 :     CTxOut stakePrevout;
    3330        1919 :     if (!stakeInput.GetTxOutFrom(stakePrevout)) {
    3331           0 :         return error("%s: failed to get stake input", __func__);
    3332             :     }
    3333        3838 :     CScript scriptPubKeyKernel = stakePrevout.scriptPubKey;
    3334        1919 :     if (!Solver(scriptPubKeyKernel, whichType, vSolutions))
    3335           0 :         return error("%s: failed to parse kernel", __func__);
    3336             : 
    3337        1919 :     if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH && whichType != TX_COLDSTAKE)
    3338           0 :         return error("%s: type=%d (%s) not supported for scriptPubKeyKernel", __func__, whichType, GetTxnOutputType(whichType));
    3339             : 
    3340        3838 :     CKey key;
    3341        1919 :     if (whichType == TX_PUBKEYHASH || whichType == TX_COLDSTAKE) {
    3342             :         // if P2PKH or P2CS check that we have the input private key
    3343        1869 :         if (!GetKey(CKeyID(uint160(vSolutions[0])), key))
    3344           0 :             return error("%s: Unable to get staking private key", __func__);
    3345             :     }
    3346             : 
    3347        1919 :     vout.emplace_back(0, scriptPubKeyKernel);
    3348             : 
    3349             :     // Calculate if we need to split the output
    3350        1919 :     if (nStakeSplitThreshold > 0) {
    3351        1919 :         int nSplit = static_cast<int>(nTotal / nStakeSplitThreshold);
    3352        1919 :         if (nSplit > 1) {
    3353             :             // if nTotal is twice or more of the threshold; create more outputs
    3354          19 :             int txSizeMax = MAX_STANDARD_TX_SIZE >> 11; // limit splits to <10% of the max TX size (/2048)
    3355          19 :             if (nSplit > txSizeMax)
    3356           0 :                 nSplit = txSizeMax;
    3357          67 :             for (int i = nSplit; i > 1; i--) {
    3358          48 :                 LogPrintf("%s: StakeSplit: nTotal = %d; adding output %d of %d\n", __func__, nTotal, (nSplit-i)+2, nSplit);
    3359          48 :                 vout.emplace_back(0, scriptPubKeyKernel);
    3360             :             }
    3361             :         }
    3362             :     }
    3363             : 
    3364             :     return true;
    3365             : }
    3366             : 
    3367        1925 : bool CWallet::CreateCoinStake(
    3368             :         const CBlockIndex* pindexPrev,
    3369             :         unsigned int nBits,
    3370             :         CMutableTransaction& txNew,
    3371             :         int64_t& nTxNewTime,
    3372             :         std::vector<CStakeableOutput>* availableCoins,
    3373             :         bool stopOnNewBlock) const
    3374             : {
    3375             :     // shuffle coins
    3376        1925 :     if (availableCoins && Params().IsRegTestNet()) {
    3377        1925 :         Shuffle(availableCoins->begin(), availableCoins->end(), FastRandomContext());
    3378             :     }
    3379             : 
    3380             :     // Mark coin stake transaction
    3381        1925 :     txNew.vin.clear();
    3382        1925 :     txNew.vout.clear();
    3383        1925 :     txNew.vout.emplace_back(0, CScript());
    3384             : 
    3385             :     // update staker status (hash)
    3386        1925 :     pStakerStatus->SetLastTip(pindexPrev);
    3387        1925 :     pStakerStatus->SetLastCoins((int) availableCoins->size());
    3388             : 
    3389             :     // Kernel Search
    3390        1925 :     CAmount nCredit;
    3391        1925 :     CAmount nMasternodePayment;
    3392        3850 :     CScript scriptPubKeyKernel;
    3393        1925 :     bool fKernelFound = false;
    3394        1925 :     int nAttempts = 0;
    3395       12775 :     for (auto it = availableCoins->begin(); it != availableCoins->end();) {
    3396       12769 :         COutPoint outPoint = COutPoint(it->tx->GetHash(), it->i);
    3397       12769 :         CPivStake stakeInput(it->tx->tx->vout[it->i],
    3398             :                              outPoint,
    3399       12769 :                              it->pindex);
    3400             : 
    3401             :         // New block came in, move on
    3402       12769 :         if (stopOnNewBlock && GetLastBlockHeightLockWallet() != pindexPrev->nHeight) return false;
    3403             : 
    3404             :         // Make sure the wallet is unlocked and shutdown hasn't been requested
    3405       12769 :         if (IsLocked() || ShutdownRequested()) return false;
    3406             : 
    3407             :         // Make sure the stake input hasn't been spent since last check
    3408       38307 :         if (WITH_LOCK(cs_wallet, return IsSpent(outPoint))) {
    3409             :             // remove it from the available coins
    3410          43 :             it = availableCoins->erase(it);
    3411       10893 :             continue;
    3412             :         }
    3413             : 
    3414       12726 :         nCredit = 0;
    3415             : 
    3416       12726 :         nAttempts++;
    3417       12726 :         fKernelFound = Stake(pindexPrev, &stakeInput, nBits, nTxNewTime);
    3418             : 
    3419             :         // update staker status (time, attempts)
    3420       12726 :         pStakerStatus->SetLastTime(nTxNewTime);
    3421       12726 :         pStakerStatus->SetLastTries(nAttempts);
    3422             : 
    3423       12726 :         if (!fKernelFound) {
    3424       10807 :             it++;
    3425       10807 :             continue;
    3426             :         }
    3427             : 
    3428             :         // Found a kernel
    3429        1919 :         LogPrintf("CreateCoinStake : kernel found\n");
    3430        1919 :         nCredit += stakeInput.GetValue();
    3431             : 
    3432             :         // Add block reward to the credit
    3433        1919 :         nCredit += GetBlockValue(pindexPrev->nHeight + 1);
    3434        1919 :         nMasternodePayment = GetMasternodePayment(pindexPrev->nHeight + 1);
    3435             : 
    3436             :         // Create the output transaction(s)
    3437        1919 :         std::vector<CTxOut> vout;
    3438        1919 :         if (!CreateCoinstakeOuts(stakeInput, vout, nCredit - nMasternodePayment)) {
    3439           0 :             LogPrintf("%s : failed to create output\n", __func__);
    3440           0 :             it++;
    3441           0 :             continue;
    3442             :         }
    3443        1919 :         txNew.vout.insert(txNew.vout.end(), vout.begin(), vout.end());
    3444             : 
    3445             :         // Set output amount
    3446        1919 :         int outputs = (int) txNew.vout.size() - 1;
    3447        1919 :         CAmount nRemaining = nCredit;
    3448        1919 :         if (outputs > 1) {
    3449             :             // Split the stake across the outputs
    3450          19 :             CAmount nShare = nRemaining / outputs;
    3451          67 :             for (int i = 1; i < outputs; i++) {
    3452             :                 // loop through all but the last one.
    3453          48 :                 txNew.vout[i].nValue = nShare;
    3454          48 :                 nRemaining -= nShare;
    3455             :             }
    3456             :         }
    3457             :         // put the remaining on the last output (which all into the first if only one output)
    3458        1919 :         txNew.vout[outputs].nValue += nRemaining;
    3459             : 
    3460             :         // Set coinstake input
    3461        1919 :         txNew.vin.emplace_back(stakeInput.GetTxIn());
    3462             : 
    3463             :         // Limit size
    3464        1919 :         unsigned int nBytes = ::GetSerializeSize(txNew, PROTOCOL_VERSION);
    3465        1919 :         if (nBytes >= DEFAULT_BLOCK_MAX_SIZE / 5)
    3466           0 :             return error("%s : exceeded coinstake size limit", __func__);
    3467             : 
    3468        1919 :         break;
    3469             :     }
    3470        1925 :     LogPrint(BCLog::STAKING, "%s: attempted staking %d times\n", __func__, nAttempts);
    3471             : 
    3472             :     return fKernelFound;
    3473             : }
    3474             : 
    3475        1919 : bool CWallet::SignCoinStake(CMutableTransaction& txNew) const
    3476             : {
    3477             :     // Sign it
    3478        1919 :     int nIn = 0;
    3479        3838 :     for (const CTxIn& txIn : txNew.vin) {
    3480        1919 :         const CWalletTx* wtx = GetWalletTx(txIn.prevout.hash);
    3481        1919 :         if (!wtx || !SignSignature(*this, *(wtx->tx), txNew, nIn++, SIGHASH_ALL, true))
    3482           0 :             return error("%s : failed to sign coinstake", __func__);
    3483             :     }
    3484             : 
    3485             :     // Successfully signed coinstake
    3486        1919 :     return true;
    3487             : }
    3488             : 
    3489           7 : std::string CWallet::CommitResult::ToString() const
    3490             : {
    3491          21 :     std::string strErrRet = strprintf(_("Failed to accept tx in the memory pool (reason: %s)\n"), FormatStateMessage(state));
    3492             : 
    3493           7 :     switch (status) {
    3494           0 :         case CWallet::CommitStatus::OK:
    3495           0 :             return _("No error");
    3496           7 :         case CWallet::CommitStatus::Abandoned:
    3497          14 :             strErrRet += _("Transaction canceled.");
    3498           7 :             break;
    3499           0 :         case CWallet::CommitStatus::NotAccepted:
    3500           0 :             strErrRet += strprintf(_("WARNING: The transaction has been signed and recorded, so the wallet will try to re-send it. "
    3501           0 :                     "Use 'abandontransaction' to cancel it. (txid: %s)"), hashTx.ToString());
    3502           0 :             break;
    3503           0 :         default:
    3504           0 :             return _("Invalid status error.");
    3505             :     }
    3506             : 
    3507          14 :     return strErrRet;
    3508             : }
    3509             : 
    3510         374 : CWallet::CommitResult CWallet::CommitTransaction(CTransactionRef tx, CReserveKey& opReservekey, CConnman* connman)
    3511             : {
    3512         748 :     return CommitTransaction(std::move(tx), &opReservekey, connman);
    3513             : }
    3514             : 
    3515             : /**
    3516             :  * Call after CreateTransaction unless you want to abort
    3517             :  */
    3518        1441 : CWallet::CommitResult CWallet::CommitTransaction(CTransactionRef tx, CReserveKey* opReservekey, CConnman* connman, mapValue_t* extras)
    3519             : {
    3520        1441 :     CommitResult res;
    3521             : 
    3522        2882 :     CWalletTx wtxNew(this, std::move(tx));
    3523        1441 :     wtxNew.fTimeReceivedIsTxTime = true;
    3524        1441 :     wtxNew.BindWallet(this);
    3525        1441 :     wtxNew.fFromMe = true;
    3526        1441 :     wtxNew.fStakeDelegationVoided = wtxNew.tx->HasP2CSOutputs();
    3527        1441 :     if (extras) wtxNew.mapValue.insert(extras->begin(), extras->end());
    3528             : 
    3529        1441 :     {
    3530        4315 :         LOCK2(cs_main, cs_wallet);
    3531        1441 :         LogPrintf("%s: %s\n", __func__, wtxNew.tx->ToString());
    3532        1441 :         {
    3533             :             // Take key pair from key pool so it won't be used again
    3534        1441 :             if (opReservekey) opReservekey->KeepKey();
    3535             : 
    3536             :             // Add tx to wallet, because if it has change it's also ours,
    3537             :             // otherwise just for transaction history.
    3538        1441 :             AddToWallet(wtxNew);
    3539             : 
    3540             :             // Notify that old coins are spent
    3541        1441 :             if (!wtxNew.tx->HasZerocoinSpendInputs()) {
    3542        2882 :                 std::set<uint256> updated_hashes;
    3543        3011 :                 for (const CTxIn& txin : wtxNew.tx->vin) {
    3544             :                     // notify only once
    3545        1570 :                     if (updated_hashes.find(txin.prevout.hash) != updated_hashes.end()) continue;
    3546             : 
    3547        1566 :                     CWalletTx& coin = mapWallet.at(txin.prevout.hash);
    3548        1566 :                     coin.BindWallet(this);
    3549        1566 :                     NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
    3550        3136 :                     updated_hashes.insert(txin.prevout.hash);
    3551             :                 }
    3552             :             }
    3553             :         }
    3554             : 
    3555        1441 :         res.hashTx = wtxNew.GetHash();
    3556             : 
    3557             :         // Get the inserted-CWalletTx from mapWallet so that the
    3558             :         // fInMempool flag is cached properly
    3559        1441 :         CWalletTx& wtx = mapWallet.at(wtxNew.GetHash());
    3560             : 
    3561             :         // Try ATMP. This must not fail. The transaction has already been signed and recorded.
    3562        2878 :         CValidationState state;
    3563        1441 :         if (!wtx.AcceptToMemoryPool(state)) {
    3564           4 :             res.state = state;
    3565             :             // Abandon the transaction
    3566           4 :             if (AbandonTransaction(res.hashTx)) {
    3567           4 :                 res.status = CWallet::CommitStatus::Abandoned;
    3568             :                 // Return the change key
    3569           4 :                 if (opReservekey) opReservekey->ReturnKey();
    3570             :             }
    3571             : 
    3572           4 :             LogPrintf("%s: ERROR: %s\n", __func__, res.ToString());
    3573           4 :             return res;
    3574             :         }
    3575             : 
    3576        1437 :         res.status = CWallet::CommitStatus::OK;
    3577             : 
    3578             :         // Broadcast
    3579        1437 :         wtx.RelayWalletTransaction(connman);
    3580             :     }
    3581             :     return res;
    3582             : }
    3583             : 
    3584         404 : DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
    3585             : {
    3586        1211 :     LOCK2(cs_main, cs_wallet);
    3587             : 
    3588         404 :     DBErrors nLoadWalletRet = WalletBatch(*database, "cr+").LoadWallet(this);
    3589         403 :     if (nLoadWalletRet == DB_NEED_REWRITE) {
    3590           0 :         if (database->Rewrite( "\x04pool")) {
    3591             :             // TODO: Implement spk_man->RewriteDB().
    3592           0 :             m_spk_man->set_pre_split_keypool.clear();
    3593             :             // Note: can't top-up keypool here, because wallet is locked.
    3594             :             // User will be prompted to unlock wallet the next operation
    3595             :             // the requires a new key.
    3596             :         }
    3597             :     }
    3598             : 
    3599             :     // This wallet is in its first run if all of these are empty
    3600         403 :     fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapMasterKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
    3601             : 
    3602         403 :     if (nLoadWalletRet != DB_LOAD_OK)
    3603             :         return nLoadWalletRet;
    3604             : 
    3605         403 :     uiInterface.LoadWallet(this);
    3606             : 
    3607             :     return DB_LOAD_OK;
    3608             : }
    3609             : 
    3610             : 
    3611           5 : DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
    3612             : {
    3613           5 :     DBErrors nZapWalletTxRet = WalletBatch(*database, "cr+").ZapWalletTx(this, vWtx);
    3614           5 :     if (nZapWalletTxRet == DB_NEED_REWRITE) {
    3615           0 :         if (database->Rewrite("\x04pool")) {
    3616           0 :             LOCK(cs_wallet);
    3617           0 :             m_spk_man->set_pre_split_keypool.clear();
    3618             :             // Note: can't top-up keypool here, because wallet is locked.
    3619             :             // User will be prompted to unlock wallet the next operation
    3620             :             // that requires a new key.
    3621             :         }
    3622             :     }
    3623             : 
    3624           5 :     if (nZapWalletTxRet != DB_LOAD_OK)
    3625           0 :         return nZapWalletTxRet;
    3626             : 
    3627             :     return DB_LOAD_OK;
    3628             : }
    3629             : 
    3630        3768 : std::string CWallet::ParseIntoAddress(const CWDestination& dest, const std::string& purpose) {
    3631        3768 :     CChainParams::Base58Type addrType;
    3632        3768 :     if (AddressBook::IsColdStakingPurpose(purpose)) {
    3633             :         addrType = CChainParams::STAKING_ADDRESS;
    3634        3741 :     } else if (AddressBook::IsExchangePurpose(purpose)) {
    3635             :         addrType = CChainParams::EXCHANGE_ADDRESS;
    3636             :     } else {
    3637        3741 :         addrType = CChainParams::PUBKEY_ADDRESS;
    3638             :     }
    3639        3768 :     return Standard::EncodeDestination(dest, addrType);
    3640             : }
    3641             : 
    3642        3768 : bool CWallet::SetAddressBook(const CWDestination& address, const std::string& strName, const std::string& strPurpose)
    3643             : {
    3644        3768 :     bool fUpdated = HasAddressBook(address);
    3645        3768 :     {
    3646        3768 :         LOCK(cs_wallet); // mapAddressBook
    3647        3768 :         mapAddressBook[address].name = strName;
    3648        3768 :         if (!strPurpose.empty()) /* update purpose only if requested */
    3649        3768 :             mapAddressBook[address].purpose = strPurpose;
    3650             :     }
    3651        7536 :     NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
    3652        3768 :             mapAddressBook.at(address).purpose, (fUpdated ? CT_UPDATED : CT_NEW));
    3653        7536 :     std::string addressStr = ParseIntoAddress(address, mapAddressBook.at(address).purpose);
    3654        7518 :     if (!strPurpose.empty() && !WalletBatch(*database).WritePurpose(addressStr, strPurpose))
    3655             :         return false;
    3656        3768 :     return WalletBatch(*database).WriteName(addressStr, strName);
    3657             : }
    3658             : 
    3659           0 : bool CWallet::DelAddressBook(const CWDestination& address, const CChainParams::Base58Type addrType)
    3660             : {
    3661           0 :     std::string strAddress = Standard::EncodeDestination(address, addrType);
    3662           0 :     std::string purpose = GetPurposeForAddressBookEntry(address);
    3663           0 :     {
    3664           0 :         LOCK(cs_wallet); // mapAddressBook
    3665             : 
    3666             :         // Delete destdata tuples associated with address
    3667           0 :         for (const std::pair<std::string, std::string> & item : mapAddressBook[address].destdata) {
    3668           0 :             WalletBatch(*database).EraseDestData(strAddress, item.first);
    3669             :         }
    3670           0 :         mapAddressBook.erase(address);
    3671             :     }
    3672             : 
    3673           0 :     NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, purpose, CT_DELETED);
    3674             : 
    3675           0 :     WalletBatch(*database).ErasePurpose(strAddress);
    3676           0 :     return WalletBatch(*database).EraseName(strAddress);
    3677             : }
    3678             : 
    3679           0 : std::string CWallet::GetPurposeForAddressBookEntry(const CWDestination& address) const
    3680             : {
    3681           0 :     LOCK(cs_wallet);
    3682           0 :     auto it = mapAddressBook.find(address);
    3683           0 :     return it != mapAddressBook.end() ? it->second.purpose : "";
    3684             : }
    3685             : 
    3686     1925350 : std::string CWallet::GetNameForAddressBookEntry(const CWDestination& address) const
    3687             : {
    3688     1925350 :     LOCK(cs_wallet);
    3689     1925350 :     auto it = mapAddressBook.find(address);
    3690     5776050 :     return it != mapAddressBook.end() ? it->second.name : "";
    3691             : }
    3692             : 
    3693         553 : Optional<AddressBook::CAddressBookData> CWallet::GetAddressBookEntry(const CWDestination& dest) const
    3694             : {
    3695         553 :     LOCK(cs_wallet);
    3696         553 :     auto it = mapAddressBook.find(dest);
    3697        1534 :     return it != mapAddressBook.end() ? Optional<AddressBook::CAddressBookData>(it->second) : nullopt;
    3698             : }
    3699             : 
    3700         260 : void CWallet::LoadAddressBookName(const CWDestination& dest, const std::string& strName)
    3701             : {
    3702         260 :     mapAddressBook[dest].name = strName;
    3703         260 : }
    3704             : 
    3705         260 : void CWallet::LoadAddressBookPurpose(const CWDestination& dest, const std::string& strPurpose)
    3706             : {
    3707         260 :     mapAddressBook[dest].purpose = strPurpose;
    3708         260 : }
    3709             : 
    3710     1976303 : bool CWallet::HasAddressBook(const CWDestination& address) const
    3711             : {
    3712     7905232 :     return WITH_LOCK(cs_wallet, return mapAddressBook.count(address));
    3713             : }
    3714             : 
    3715          91 : bool CWallet::HasDelegator(const CTxOut& out) const
    3716             : {
    3717         182 :     CTxDestination delegator;
    3718          91 :     if (!ExtractDestination(out.scriptPubKey, delegator, false))
    3719             :         return false;
    3720          91 :     {
    3721         182 :         LOCK(cs_wallet); // mapAddressBook
    3722          91 :         const auto mi = mapAddressBook.find(delegator);
    3723          91 :         if (mi == mapAddressBook.end())
    3724             :             return false;
    3725          91 :         return (*mi).second.purpose == AddressBook::AddressBookPurpose::DELEGATOR;
    3726             :     }
    3727             : }
    3728             : 
    3729          67 : size_t CWallet::KeypoolCountExternalKeys()
    3730             : {
    3731          67 :     return m_spk_man->KeypoolCountExternalKeys();
    3732             : }
    3733             : 
    3734        2499 : bool CWallet::TopUpKeyPool(unsigned int kpSize)
    3735             : {
    3736        2499 :     return m_spk_man->TopUp(kpSize);
    3737             : }
    3738             : 
    3739        4186 : void CWallet::KeepKey(int64_t nIndex)
    3740             : {
    3741        4186 :     m_spk_man->KeepDestination(nIndex);
    3742        4186 : }
    3743             : 
    3744          15 : void CWallet::ReturnKey(int64_t nIndex, const bool internal, const bool staking)
    3745             : {
    3746             :     // Return to key pool
    3747          15 :     CTxDestination address; // This is not needed for now.
    3748          15 :     uint8_t changeType = staking ? HDChain::ChangeType::STAKING : (internal ? HDChain::ChangeType::INTERNAL : HDChain::ChangeType::EXTERNAL);
    3749          15 :     m_spk_man->ReturnDestination(nIndex, changeType, address);
    3750          15 : }
    3751             : 
    3752        2289 : bool CWallet::GetKeyFromPool(CPubKey& result, const uint8_t& type)
    3753             : {
    3754        2289 :     return m_spk_man->GetKeyFromPool(result, type);
    3755             : }
    3756             : 
    3757          67 : int64_t CWallet::GetOldestKeyPoolTime()
    3758             : {
    3759         268 :     return WITH_LOCK(cs_wallet, return std::min(std::numeric_limits<int64_t>::max(), m_spk_man->GetOldestKeyPoolTime()));
    3760             : }
    3761             : 
    3762           1 : std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
    3763             : {
    3764           1 :     std::map<CTxDestination, CAmount> balances;
    3765             : 
    3766           1 :     {
    3767           1 :         LOCK(cs_wallet);
    3768         103 :         for (const auto& walletEntry : mapWallet) {
    3769         102 :             const CWalletTx* pcoin = &walletEntry.second;
    3770             : 
    3771         102 :             if (!IsFinalTx(pcoin->tx, m_last_block_processed_height) || !pcoin->IsTrusted())
    3772         100 :                 continue;
    3773             : 
    3774         102 :             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
    3775         100 :                 continue;
    3776             : 
    3777           2 :             bool fConflicted;
    3778           2 :             int nDepth = pcoin->GetDepthAndMempool(fConflicted);
    3779           2 :             if (fConflicted)
    3780           0 :                 continue;
    3781           4 :             if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
    3782           0 :                 continue;
    3783             : 
    3784           4 :             for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
    3785           4 :                 CTxDestination addr;
    3786           2 :                 if (!IsMine(pcoin->tx->vout[i]))
    3787           0 :                     continue;
    3788           2 :                 if ( !ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr) &&
    3789           0 :                         !ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr, true) )
    3790           0 :                     continue;
    3791             : 
    3792           2 :                 CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
    3793             : 
    3794           2 :                 if (!balances.count(addr))
    3795           2 :                     balances[addr] = 0;
    3796           2 :                 balances[addr] += n;
    3797             :             }
    3798             :         }
    3799             :     }
    3800             : 
    3801           1 :     return balances;
    3802             : }
    3803             : 
    3804           1 : std::set<std::set<CTxDestination> > CWallet::GetAddressGroupings()
    3805             : {
    3806           1 :     AssertLockHeld(cs_wallet); // mapWallet
    3807           1 :     std::set<std::set<CTxDestination> > groupings;
    3808           1 :     std::set<CTxDestination> grouping;
    3809             : 
    3810         103 :     for (const auto& walletEntry : mapWallet) {
    3811         102 :         const CWalletTx* pcoin = &walletEntry.second;
    3812             : 
    3813         102 :         if (pcoin->tx->vin.size() > 0) {
    3814         102 :             bool any_mine = false;
    3815             :             // group all input addresses with each other
    3816         204 :             for (CTxIn txin : pcoin->tx->vin) {
    3817         102 :                 CTxDestination address;
    3818         102 :                 if (!IsMine(txin)) /* If this input isn't mine, ignore it */
    3819         204 :                     continue;
    3820           0 :                 if (!ExtractDestination(mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
    3821           0 :                     continue;
    3822           0 :                 grouping.insert(address);
    3823           0 :                 any_mine = true;
    3824             :             }
    3825             : 
    3826             :             // group change with input addresses
    3827         102 :             if (any_mine) {
    3828           0 :                 for (CTxOut txout : pcoin->tx->vout)
    3829           0 :                     if (IsChange(txout)) {
    3830           0 :                         CTxDestination txoutAddr;
    3831           0 :                         if (!ExtractDestination(txout.scriptPubKey, txoutAddr))
    3832           0 :                             continue;
    3833           0 :                         grouping.insert(txoutAddr);
    3834             :                     }
    3835             :             }
    3836         102 :             if (grouping.size() > 0) {
    3837           0 :                 groupings.insert(grouping);
    3838           0 :                 grouping.clear();
    3839             :             }
    3840             :         }
    3841             : 
    3842             :         // group lone addrs by themselves
    3843         204 :         for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
    3844         102 :             if (IsMine(pcoin->tx->vout[i])) {
    3845         204 :                 CTxDestination address;
    3846         102 :                 if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, address))
    3847           0 :                     continue;
    3848         102 :                 grouping.insert(address);
    3849         102 :                 groupings.insert(grouping);
    3850         102 :                 grouping.clear();
    3851             :             }
    3852             :     }
    3853             : 
    3854           2 :     std::set<std::set<CTxDestination>*> uniqueGroupings;        // a set of pointers to groups of addresses
    3855           2 :     std::map<CTxDestination, std::set<CTxDestination>*> setmap; // map addresses to the unique group containing it
    3856           3 :     for (std::set<CTxDestination> grouping : groupings) {
    3857             :         // make a set of all the groups hit by this new group
    3858           4 :         std::set<std::set<CTxDestination>*> hits;
    3859           2 :         std::map<CTxDestination, std::set<CTxDestination>*>::iterator it;
    3860           4 :         for (CTxDestination address : grouping)
    3861           2 :             if ((it = setmap.find(address)) != setmap.end())
    3862           2 :                 hits.insert((*it).second);
    3863             : 
    3864             :         // merge all hit groups into a new single group and delete old groups
    3865           2 :         std::set<CTxDestination>* merged = new std::set<CTxDestination>(grouping);
    3866           2 :         for (std::set<CTxDestination>* hit : hits) {
    3867           0 :             merged->insert(hit->begin(), hit->end());
    3868           0 :             uniqueGroupings.erase(hit);
    3869           0 :             delete hit;
    3870             :         }
    3871           2 :         uniqueGroupings.insert(merged);
    3872             : 
    3873             :         // update setmap
    3874           4 :         for (CTxDestination element : *merged)
    3875           2 :             setmap[element] = merged;
    3876             :     }
    3877             : 
    3878           1 :     std::set<std::set<CTxDestination> > ret;
    3879           3 :     for (std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) {
    3880           2 :         ret.insert(*uniqueGrouping);
    3881           4 :         delete uniqueGrouping;
    3882             :     }
    3883             : 
    3884           2 :     return ret;
    3885             : }
    3886             : 
    3887          14 : std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) const
    3888             : {
    3889          14 :     LOCK(cs_wallet);
    3890          14 :     std::set<CTxDestination> result;
    3891         100 :     for (const auto& item : mapAddressBook) {
    3892          86 :         if (item.second.isShielded()) continue;
    3893          86 :         const auto& address = boost::get<CTxDestination>(item.first);
    3894          86 :         const std::string& strName = item.second.name;
    3895          86 :         if (strName == label)
    3896         117 :             result.insert(address);
    3897             :     }
    3898          28 :     return result;
    3899             : }
    3900             : 
    3901        5731 : bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool _internal)
    3902             : {
    3903             : 
    3904        5731 :     ScriptPubKeyMan* m_spk_man = pwallet->GetScriptPubKeyMan();
    3905        5731 :     if (!m_spk_man) {
    3906             :         return false;
    3907             :     }
    3908             : 
    3909        5731 :     if (nIndex == -1) {
    3910             : 
    3911             :         // Fill the pool if needed
    3912        4205 :         m_spk_man->TopUp();
    3913        4205 :         internal = _internal;
    3914             : 
    3915             :         // Modify this for Staking addresses support if needed.
    3916        4205 :         uint8_t changeType = internal ? HDChain::ChangeType::INTERNAL : HDChain::ChangeType::EXTERNAL;
    3917        4205 :         CKeyPool keypool;
    3918        4205 :         if (!m_spk_man->GetReservedKey(changeType, nIndex, keypool))
    3919           4 :             return false;
    3920             : 
    3921        4201 :         if (nIndex != -1)
    3922        4201 :             vchPubKey = keypool.vchPubKey;
    3923             :         else {
    3924             :             return false;
    3925             :         }
    3926             :     }
    3927        5727 :     assert(vchPubKey.IsValid());
    3928        5727 :     pubkey = vchPubKey;
    3929        5727 :     return true;
    3930             : }
    3931             : 
    3932        4190 : void CReserveKey::KeepKey()
    3933             : {
    3934        4190 :     if (nIndex != -1)
    3935        4186 :         pwallet->KeepKey(nIndex);
    3936        4190 :     nIndex = -1;
    3937        4190 :     vchPubKey = CPubKey();
    3938        4190 : }
    3939             : 
    3940        4306 : void CReserveKey::ReturnKey()
    3941             : {
    3942        4306 :     if (nIndex != -1)
    3943          15 :         pwallet->ReturnKey(nIndex, internal);
    3944        4306 :     nIndex = -1;
    3945        4306 :     vchPubKey = CPubKey();
    3946        4306 : }
    3947             : 
    3948         176 : void CWallet::LockCoin(const COutPoint& output)
    3949             : {
    3950         176 :     AssertLockHeld(cs_wallet); // setLockedCoins
    3951         176 :     setLockedCoins.insert(output);
    3952         176 : }
    3953             : 
    3954           1 : void CWallet::LockNote(const SaplingOutPoint& op)
    3955             : {
    3956           1 :     AssertLockHeld(cs_wallet); // setLockedNotes
    3957           1 :     setLockedNotes.insert(op);
    3958           1 : }
    3959             : 
    3960           1 : void CWallet::UnlockCoin(const COutPoint& output)
    3961             : {
    3962           1 :     AssertLockHeld(cs_wallet); // setLockedCoins
    3963           1 :     setLockedCoins.erase(output);
    3964           1 : }
    3965             : 
    3966           1 : void CWallet::UnlockNote(const SaplingOutPoint& op)
    3967             : {
    3968           1 :     AssertLockHeld(cs_wallet); // setLockedNotes
    3969           1 :     setLockedNotes.erase(op);
    3970           1 : }
    3971             : 
    3972           0 : void CWallet::UnlockAllCoins()
    3973             : {
    3974           0 :     AssertLockHeld(cs_wallet); // setLockedCoins
    3975           0 :     setLockedCoins.clear();
    3976           0 : }
    3977             : 
    3978           0 : void CWallet::UnlockAllNotes()
    3979             : {
    3980           0 :     AssertLockHeld(cs_wallet); // setLockedNotes
    3981           0 :     setLockedNotes.clear();
    3982           0 : }
    3983             : 
    3984     3430538 : bool CWallet::IsLockedCoin(const uint256& hash, unsigned int n) const
    3985             : {
    3986     3430538 :     AssertLockHeld(cs_wallet); // setLockedCoins
    3987     3430538 :     const COutPoint outpt(hash, n);
    3988             : 
    3989     3430538 :     return (setLockedCoins.count(outpt) > 0);
    3990             : }
    3991             : 
    3992         541 : bool CWallet::IsLockedNote(const SaplingOutPoint& op) const
    3993             : {
    3994         541 :     AssertLockHeld(cs_wallet); // setLockedNotes
    3995         541 :     return (setLockedNotes.count(op) > 0);
    3996             : }
    3997             : 
    3998          52 : std::set<COutPoint> CWallet::ListLockedCoins()
    3999             : {
    4000          52 :     AssertLockHeld(cs_wallet); // setLockedCoins
    4001          52 :     return setLockedCoins;
    4002             : }
    4003             : 
    4004          52 : std::set<SaplingOutPoint> CWallet::ListLockedNotes()
    4005             : {
    4006          52 :     AssertLockHeld(cs_wallet); // setLockedNotes
    4007          52 :     return setLockedNotes;
    4008             : }
    4009             : 
    4010           0 : bool CWallet::SetStakeSplitThreshold(const CAmount sst)
    4011             : {
    4012           0 :     LOCK(cs_wallet);
    4013           0 :     if (nStakeSplitThreshold != sst) {
    4014           0 :         nStakeSplitThreshold = sst;
    4015           0 :         if (!WalletBatch(*database).WriteStakeSplitThreshold(sst)) {
    4016             :             return false;
    4017             :         }
    4018           0 :         NotifySSTChanged(sst);
    4019             :     }
    4020             :     return true;
    4021             : }
    4022             : 
    4023             : /** @} */ // end of Actions
    4024             : 
    4025             : 
    4026           8 : void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const
    4027             : {
    4028           8 :     AssertLockHeld(cs_wallet); // mapKeyMetadata
    4029           8 :     mapKeyBirth.clear();
    4030             : 
    4031             :     // get birth times for keys with metadata
    4032        1981 :     for (const auto& entry : mapKeyMetadata) {
    4033        1973 :         if (entry.second.nCreateTime) mapKeyBirth[entry.first] = entry.second.nCreateTime;
    4034             :     }
    4035             : 
    4036             :     // map in which we'll infer heights of other keys
    4037          10 :     CBlockIndex* pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
    4038           8 :     std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
    4039        1981 :     for (const CKeyID& keyid : GetKeys()) {
    4040        3946 :         if (mapKeyBirth.count(keyid) == 0)
    4041           0 :             mapKeyFirstBlock[keyid] = pindexMax;
    4042             :     }
    4043             : 
    4044             :     // if there are no such keys, we're done
    4045           8 :     if (mapKeyFirstBlock.empty())
    4046           8 :         return;
    4047             : 
    4048             :     // find first block that affects those keys, if there are any left
    4049           0 :     std::vector<CKeyID> vAffected;
    4050           0 :     for (const auto& entry : mapWallet) {
    4051             :         // iterate over all wallet transactions...
    4052           0 :         const CWalletTx& wtx = entry.second;
    4053           0 :         CBlockIndex* pindex = LookupBlockIndex(wtx.m_confirm.hashBlock);
    4054           0 :         if (pindex && chainActive.Contains(pindex)) {
    4055             :             // ... which are already in a block
    4056           0 :             int nHeight = pindex->nHeight;
    4057           0 :             for (const CTxOut& txout : wtx.tx->vout) {
    4058             :                 // iterate over all their outputs
    4059           0 :                 CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
    4060           0 :                 for (const CKeyID& keyid : vAffected) {
    4061             :                     // ... and all their affected keys
    4062           0 :                     std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
    4063           0 :                     if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
    4064           0 :                         rit->second = pindex;
    4065             :                 }
    4066           0 :                 vAffected.clear();
    4067             :             }
    4068             :         }
    4069             :     }
    4070             : 
    4071             :     // Extract block timestamps for those keys
    4072           0 :     for (const auto& entry : mapKeyFirstBlock)
    4073           0 :         mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
    4074             : }
    4075             : 
    4076           0 : bool CWallet::AddDestData(const CTxDestination& dest, const std::string& key, const std::string& value)
    4077             : {
    4078           0 :     if (!IsValidDestination(dest))
    4079             :         return false;
    4080             : 
    4081           0 :     mapAddressBook[dest].destdata.emplace(key, value);
    4082           0 :     return WalletBatch(*database).WriteDestData(EncodeDestination(dest), key, value);
    4083             : }
    4084             : 
    4085           0 : bool CWallet::EraseDestData(const CTxDestination& dest, const std::string& key)
    4086             : {
    4087           0 :     if (!mapAddressBook[dest].destdata.erase(key))
    4088             :         return false;
    4089           0 :     return WalletBatch(*database).EraseDestData(EncodeDestination(dest), key);
    4090             : }
    4091             : 
    4092           0 : bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value)
    4093             : {
    4094           0 :     mapAddressBook[dest].destdata.emplace(key, value);
    4095           0 :     return true;
    4096             : }
    4097             : 
    4098           0 : std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
    4099             : {
    4100           0 :     LOCK(cs_wallet);
    4101           0 :     std::vector<std::string> values;
    4102           0 :     for (const auto& address : mapAddressBook) {
    4103           0 :         for (const auto& data : address.second.destdata) {
    4104           0 :             if (!data.first.compare(0, prefix.size(), prefix)) {
    4105           0 :                 values.emplace_back(data.second);
    4106             :             }
    4107             :         }
    4108             :     }
    4109           0 :     return values;
    4110             : }
    4111             : 
    4112           1 : void CWallet::AutoCombineDust(CConnman* connman)
    4113             : {
    4114           1 :     {
    4115           1 :         LOCK(cs_wallet);
    4116           1 :         if (m_last_block_processed.IsNull() ||
    4117           2 :             m_last_block_processed_time < (GetAdjustedTime() - 300) ||
    4118           1 :             IsLocked()) {
    4119           0 :             return;
    4120             :         }
    4121             :     }
    4122             : 
    4123           1 :     std::map<CTxDestination, std::vector<COutput> > mapCoinsByAddress =
    4124           2 :             AvailableCoinsByAddress(true, nAutoCombineThreshold, false);
    4125             : 
    4126             :     //coins are sectioned by address. This combination code only wants to combine inputs that belong to the same address
    4127           2 :     for (const auto& entry : mapCoinsByAddress) {
    4128           3 :         std::vector<COutput> vCoins, vRewardCoins;
    4129           1 :         bool maxSize = false;
    4130           1 :         vCoins = entry.second;
    4131             : 
    4132             :         // We don't want the tx to be refused for being too large
    4133             :         // we use 50 bytes as a base tx size (2 output: 2*34 + overhead: 10 -> 90 to be certain)
    4134           1 :         unsigned int txSizeEstimate = 90;
    4135             : 
    4136             :         //find masternode rewards that need to be combined
    4137           1 :         CCoinControl* coinControl = new CCoinControl();
    4138           1 :         CAmount nTotalRewardsValue = 0;
    4139           3 :         for (const COutput& out : vCoins) {
    4140           3 :             if (!out.fSpendable)
    4141           0 :                 continue;
    4142             : 
    4143           3 :             COutPoint outpt(out.tx->GetHash(), out.i);
    4144           3 :             coinControl->Select(outpt);
    4145           3 :             vRewardCoins.push_back(out);
    4146           3 :             nTotalRewardsValue += out.Value();
    4147             : 
    4148             :             // Combine to the threshold and not way above considering the safety margin.
    4149           3 :             if ((nTotalRewardsValue - (nTotalRewardsValue / 10)) > nAutoCombineThreshold)
    4150             :                 break;
    4151             : 
    4152             :             // Around 180 bytes per input. We use 190 to be certain
    4153           2 :             txSizeEstimate += 190;
    4154           2 :             if (txSizeEstimate >= MAX_STANDARD_TX_SIZE - 200) {
    4155             :                 maxSize = true;
    4156             :                 break;
    4157             :             }
    4158             :         }
    4159             : 
    4160             :         //if no inputs found then return
    4161           1 :         if (!coinControl->HasSelected())
    4162           0 :             continue;
    4163             : 
    4164             :         //we cannot combine one coin with itself
    4165           1 :         if (vRewardCoins.size() <= 1)
    4166           0 :             continue;
    4167             : 
    4168           2 :         std::vector<CRecipient> vecSend;
    4169           2 :         const CScript& scriptPubKey = GetScriptForDestination(entry.first);
    4170           1 :         vecSend.emplace_back(scriptPubKey, nTotalRewardsValue, false);
    4171             : 
    4172             :         //Send change to same address
    4173           2 :         CTxDestination destMyAddress;
    4174           1 :         if (!ExtractDestination(scriptPubKey, destMyAddress)) {
    4175           0 :             LogPrintf("AutoCombineDust: failed to extract destination\n");
    4176           0 :             continue;
    4177             :         }
    4178           1 :         coinControl->destChange = destMyAddress;
    4179             : 
    4180             :         // Create the transaction and commit it to the network
    4181           1 :         CTransactionRef wtx;
    4182           2 :         CReserveKey keyChange(this); // this change address does not end up being used, because change is returned with coin control switch
    4183           2 :         std::string strErr;
    4184           1 :         CAmount nFeeRet = 0;
    4185           1 :         int nChangePosInOut = -1;
    4186             : 
    4187             :         // 10% safety margin to avoid "Insufficient funds" errors
    4188           1 :         vecSend[0].nAmount = nTotalRewardsValue - (nTotalRewardsValue / 10);
    4189             : 
    4190           1 :         {
    4191             :             // For now, CreateTransaction requires cs_main lock.
    4192           2 :             LOCK2(cs_main, cs_wallet);
    4193           1 :             if (!CreateTransaction(vecSend, wtx, keyChange, nFeeRet, nChangePosInOut, strErr, coinControl,
    4194             :                                    true, false, CAmount(0))) {
    4195           0 :                 LogPrintf("AutoCombineDust createtransaction failed, reason: %s\n", strErr);
    4196           0 :                 continue;
    4197             :             }
    4198             :         }
    4199             : 
    4200             :         //we don't combine below the threshold unless the fees are 0 to avoid paying fees over fees over fees
    4201           1 :         if (!maxSize && vecSend[0].nAmount < nAutoCombineThreshold && nFeeRet > 0)
    4202           0 :             continue;
    4203             : 
    4204           2 :         const CWallet::CommitResult& res = CommitTransaction(wtx, keyChange, connman);
    4205           1 :         if (res.status != CWallet::CommitStatus::OK) {
    4206           0 :             LogPrintf("AutoCombineDust transaction commit failed\n");
    4207           0 :             continue;
    4208             :         }
    4209             : 
    4210           1 :         LogPrintf("AutoCombineDust sent transaction. Fee=%d, Total value=%d, Sending=%d\n", nFeeRet, nTotalRewardsValue, vecSend[0].nAmount);
    4211             : 
    4212           2 :         delete coinControl;
    4213             :     }
    4214             : }
    4215             : 
    4216          12 : void CWallet::LockOutpointIfMineWithMutex(const CTransactionRef& ptx, const COutPoint& c)
    4217             : {
    4218          36 :     WITH_LOCK(cs_wallet, LockOutpointIfMine(ptx, c));
    4219          12 : }
    4220             : 
    4221         739 : void CWallet::LockOutpointIfMine(const CTransactionRef& ptx, const COutPoint& c)
    4222             : {
    4223         739 :     AssertLockHeld(cs_wallet);
    4224         739 :     CTxOut txout;
    4225         739 :     if (ptx && c.hash == ptx->GetHash() && c.n < ptx->vout.size()) {
    4226             :         // the collateral is an output of this tx
    4227         311 :         txout = ptx->vout[c.n];
    4228             :     } else {
    4229             :         // the collateral is a reference to an utxo inside this wallet
    4230         428 :         const auto& it = mapWallet.find(c.hash);
    4231         428 :         if (it != mapWallet.end()) {
    4232         554 :             txout = it->second.tx->vout[c.n];
    4233             :         }
    4234             :     }
    4235         739 :     if (!txout.IsNull() && IsMine(txout) != ISMINE_NO && !IsSpent(c)) {
    4236         154 :         LockCoin(c);
    4237             :     }
    4238         739 : }
    4239             : 
    4240             : // Called from AddToWalletIfInvolvingMe
    4241      647707 : void CWallet::LockIfMyCollateral(const CTransactionRef& ptx)
    4242             : {
    4243      647707 :     AssertLockHeld(cs_wallet);
    4244             : 
    4245      647707 :     COutPoint o;
    4246      647707 :     if (GetProRegCollateral(ptx, o)) {
    4247         727 :         LockOutpointIfMine(ptx, o);
    4248             :     }
    4249      647707 : }
    4250             : 
    4251         363 : CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path)
    4252             : {
    4253         363 :     const std::string& walletFile = name;
    4254             : 
    4255             :     // needed to restore wallet transaction meta data after -zapwallettxes
    4256         363 :     std::vector<CWalletTx> vWtx;
    4257             : 
    4258         363 :     if (gArgs.GetBoolArg("-zapwallettxes", false)) {
    4259           5 :         uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
    4260             : 
    4261          10 :         std::unique_ptr<CWallet> tempWallet = std::make_unique<CWallet>(name, WalletDatabase::Create(path));
    4262           5 :         DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
    4263           5 :         if (nZapWalletRet != DB_LOAD_OK) {
    4264           0 :             UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
    4265           0 :             return nullptr;
    4266             :         }
    4267             :     }
    4268             : 
    4269         363 :     uiInterface.InitMessage(_("Loading wallet..."));
    4270             : 
    4271         363 :     int64_t nStart = GetTimeMillis();
    4272         363 :     bool fFirstRun = true;
    4273         726 :     CWallet *walletInstance = new CWallet(name, WalletDatabase::Create(path));
    4274         363 :     DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
    4275         362 :     if (nLoadWalletRet != DB_LOAD_OK) {
    4276           0 :         if (nLoadWalletRet == DB_CORRUPT) {
    4277           0 :             UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
    4278           0 :             return nullptr;
    4279           0 :         } else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) {
    4280           0 :             UIWarning(strprintf(_("Warning: error reading %s! All keys read correctly, but transaction data"
    4281             :                          " or address book entries might be missing or incorrect."), walletFile));
    4282           0 :         } else if (nLoadWalletRet == DB_TOO_NEW) {
    4283           0 :             UIError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME));
    4284           0 :             return nullptr;
    4285           0 :         } else if (nLoadWalletRet == DB_NEED_REWRITE) {
    4286           0 :             UIError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME));
    4287           0 :             return nullptr;
    4288             :         } else {
    4289           0 :             UIError(strprintf(_("Error loading %s\n"), walletFile));
    4290           0 :             return nullptr;
    4291             :         }
    4292             :     }
    4293             : 
    4294             :     // check minimum stake split threshold
    4295         362 :     if (walletInstance->nStakeSplitThreshold && walletInstance->nStakeSplitThreshold < CWallet::minStakeSplitThreshold) {
    4296           0 :         LogPrintf("WARNING: stake split threshold value %s too low. Restoring to minimum value %s.\n",
    4297           0 :                 FormatMoney(walletInstance->nStakeSplitThreshold), FormatMoney(CWallet::minStakeSplitThreshold));
    4298           0 :         walletInstance->nStakeSplitThreshold = CWallet::minStakeSplitThreshold;
    4299             :     }
    4300             : 
    4301         362 :     int prev_version = walletInstance->GetVersion();
    4302             : 
    4303             :     // Forced upgrade
    4304         362 :     const bool fLegacyWallet = gArgs.GetBoolArg("-legacywallet", false);
    4305        1045 :     if (gArgs.GetBoolArg("-upgradewallet", fFirstRun && !fLegacyWallet) ||
    4306         320 :             (!walletInstance->IsLocked() && prev_version == FEATURE_PRE_SPLIT_KEYPOOL)) {
    4307         202 :         if (prev_version <= FEATURE_PRE_PIVX && walletInstance->IsLocked()) {
    4308             :             // Cannot upgrade a locked wallet
    4309           0 :             UIError(_("Cannot upgrade a locked wallet."));
    4310           0 :             return nullptr;
    4311             :         }
    4312             : 
    4313         202 :         int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
    4314         202 :         if (nMaxVersion == 0) // the -upgradewallet without argument case
    4315             :         {
    4316         202 :             LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
    4317         202 :             nMaxVersion = FEATURE_LATEST;
    4318         202 :             walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
    4319             :         } else {
    4320           0 :             LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
    4321             :         }
    4322         202 :         if (nMaxVersion < walletInstance->GetVersion()) {
    4323           0 :             UIError(_("Cannot downgrade wallet."));
    4324           0 :             return nullptr;
    4325             :         }
    4326         202 :         walletInstance->SetMaxVersion(nMaxVersion);
    4327             :     }
    4328             : 
    4329             :     // Upgrade to HD only if explicit upgrade was requested
    4330             :     // or if we are running an HD wallet and need to upgrade to Sapling.
    4331        1085 :     if (gArgs.GetBoolArg("-upgradewallet", false) ||
    4332         722 :         (!walletInstance->IsLocked() && prev_version == FEATURE_PRE_SPLIT_KEYPOOL)) {
    4333           2 :         std::string upgradeError;
    4334           1 :         if (!walletInstance->Upgrade(upgradeError, prev_version)) {
    4335           0 :             UIError(upgradeError);
    4336           0 :             return nullptr;
    4337             :         }
    4338             :     }
    4339             : 
    4340         362 :     if (fFirstRun) {
    4341         201 :         if (!fLegacyWallet) {
    4342             :             // Create new HD Wallet
    4343         201 :             LogPrintf("Creating HD Wallet\n");
    4344             :             // Ensure this wallet can only be opened by clients supporting HD.
    4345         201 :             walletInstance->SetMinVersion(FEATURE_LATEST);
    4346         201 :             walletInstance->SetupSPKM();
    4347             :         } else {
    4348           0 :             if (!Params().IsRegTestNet()) {
    4349           0 :                 UIError("Legacy wallets can only be created on RegTest.");
    4350           0 :                 return nullptr;
    4351             :             }
    4352             :             // Create legacy wallet
    4353           0 :             LogPrintf("Creating Pre-HD Wallet\n");
    4354           0 :             walletInstance->SetMaxVersion(FEATURE_PRE_PIVX);
    4355             :         }
    4356             : 
    4357             :         // Top up the keypool
    4358         201 :         if (!walletInstance->TopUpKeyPool()) {
    4359             :             // Error generating keys
    4360           0 :             UIError(_("Unable to generate initial key!"));
    4361           0 :             return nullptr;
    4362             :         }
    4363             : 
    4364         804 :         walletInstance->SetBestChain(WITH_LOCK(cs_main, return chainActive.GetLocator()));
    4365             :     }
    4366             : 
    4367         363 :     LogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart);
    4368             : 
    4369         724 :     LOCK(cs_main);
    4370         362 :     CBlockIndex* pindexRescan = chainActive.Genesis();
    4371             : 
    4372         362 :     if (gArgs.GetBoolArg("-rescan", false)) {
    4373             :         // clear note witness cache before a full rescan
    4374          11 :         walletInstance->ClearNoteWitnessCache();
    4375             :     } else {
    4376         702 :         WalletBatch batch(*walletInstance->database);
    4377         702 :         CBlockLocator locator;
    4378         351 :         if (batch.ReadBestBlock(locator))
    4379         351 :             pindexRescan = FindForkInGlobalIndex(chainActive, locator);
    4380             :     }
    4381             : 
    4382         362 :     {
    4383         362 :         LOCK(walletInstance->cs_wallet);
    4384         528 :         const CBlockIndex* tip = chainActive.Tip();
    4385         166 :         if (tip) {
    4386         166 :             walletInstance->m_last_block_processed = tip->GetBlockHash();
    4387         166 :             walletInstance->m_last_block_processed_height = tip->nHeight;
    4388         166 :             walletInstance->m_last_block_processed_time = tip->GetBlockTime();
    4389             :         }
    4390             :     }
    4391         362 :     RegisterValidationInterface(walletInstance);
    4392             : 
    4393         488 :     if (chainActive.Tip() && chainActive.Tip() != pindexRescan) {
    4394         126 :         uiInterface.InitMessage(_("Rescanning..."));
    4395         126 :         LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
    4396             : 
    4397             :         // no need to read and scan block, if block was created before
    4398             :         // our wallet birthday (as adjusted for block time variability)
    4399         236 :         while (pindexRescan && walletInstance->nTimeFirstKey &&
    4400         236 :                 pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW)) {
    4401         110 :             pindexRescan = chainActive.Next(pindexRescan);
    4402             :         }
    4403         126 :         const int64_t nWalletRescanTime = GetTimeMillis();
    4404         126 :         {
    4405         252 :             WalletRescanReserver reserver(walletInstance);
    4406         126 :             if (!reserver.reserve()) {
    4407           0 :                 UIError(_("Failed to rescan the wallet during initialization"));
    4408           0 :                 return nullptr;
    4409             :             }
    4410         126 :             if (walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true, true) != nullptr) {
    4411           0 :                 UIError(_("Shutdown requested over the txs scan. Exiting."));
    4412           0 :                 return nullptr;
    4413             :             }
    4414             :         }
    4415         126 :         LogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nWalletRescanTime);
    4416         126 :         walletInstance->SetBestChain(chainActive.GetLocator());
    4417         126 :         walletInstance->database->IncrementUpdateCounter();
    4418             : 
    4419             :         // Restore wallet transaction metadata after -zapwallettxes=1
    4420         143 :         if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2") {
    4421           6 :             WalletBatch batch(*walletInstance->database);
    4422         110 :             for (const CWalletTx& wtxOld : vWtx) {
    4423         107 :                 uint256 hash = wtxOld.GetHash();
    4424         107 :                 std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
    4425         107 :                 if (mi != walletInstance->mapWallet.end()) {
    4426         105 :                     const CWalletTx* copyFrom = &wtxOld;
    4427         105 :                     CWalletTx* copyTo = &mi->second;
    4428         105 :                     copyTo->mapValue = copyFrom->mapValue;
    4429         105 :                     copyTo->vOrderForm = copyFrom->vOrderForm;
    4430         105 :                     copyTo->nTimeReceived = copyFrom->nTimeReceived;
    4431         105 :                     copyTo->nTimeSmart = copyFrom->nTimeSmart;
    4432         105 :                     copyTo->fFromMe = copyFrom->fFromMe;
    4433         105 :                     copyTo->nOrderPos = copyFrom->nOrderPos;
    4434         105 :                     batch.WriteTx(*copyTo);
    4435             :                 }
    4436             :             }
    4437             :         }
    4438             :     }
    4439             : 
    4440             :     return walletInstance;
    4441             : }
    4442             : 
    4443             : 
    4444             : std::atomic<bool> CWallet::fFlushScheduled(false);
    4445             : 
    4446         361 : void CWallet::postInitProcess(CScheduler& scheduler)
    4447             : {
    4448             :     // Add wallet transactions that aren't already in a block to mapTransactions
    4449         361 :     ReacceptWalletTransactions(/*fFirstLoad*/true);
    4450             : 
    4451             :     // Run a thread to flush wallet periodically
    4452         361 :     if (!CWallet::fFlushScheduled.exchange(true)) {
    4453         686 :         scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
    4454             :     }
    4455         361 : }
    4456             : 
    4457         296 : bool CWallet::BackupWallet(const std::string& strDest)
    4458             : {
    4459         296 :     return database->Backup(strDest);
    4460             : }
    4461             : 
    4462        9115 : CKeyPool::CKeyPool()
    4463             : {
    4464        9115 :     nTime = GetTime();
    4465        9115 :     type = HDChain::ChangeType::EXTERNAL;
    4466        9115 :     m_pre_split = false;
    4467        9115 : }
    4468             : 
    4469       11506 : CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, const uint8_t& _type)
    4470             : {
    4471       11506 :     nTime = GetTime();
    4472       11506 :     vchPubKey = vchPubKeyIn;
    4473       11506 :     type = _type;
    4474       11506 :     m_pre_split = false;
    4475       11506 : }
    4476             : 
    4477    16221668 : int CWalletTx::GetDepthInMainChain() const
    4478             : {
    4479    16221668 :     assert(pwallet != nullptr);
    4480    16221668 :     AssertLockHeld(pwallet->cs_wallet);
    4481    16221668 :     if (isUnconfirmed() || isAbandoned()) return 0;
    4482             : 
    4483    25617120 :     return (pwallet->GetLastBlockHeight() - m_confirm.block_height + 1) * (isConflicted() ? -1 : 1);
    4484             : }
    4485             : 
    4486     4909335 : int CWalletTx::GetBlocksToMaturity() const
    4487             : {
    4488     8631050 :     if (!(IsCoinBase() || IsCoinStake()))
    4489             :         return 0;
    4490     2120733 :     return std::max(0, (Params().GetConsensus().nCoinbaseMaturity + 1) - GetDepthInMainChain());
    4491             : }
    4492             : 
    4493       14062 : bool CWalletTx::IsInMainChainImmature() const
    4494             : {
    4495       18163 :     if (!IsCoinBase() && !IsCoinStake()) return false;
    4496       12271 :     const int depth = GetDepthInMainChain();
    4497       12271 :     return (depth > 0 && depth <= Params().GetConsensus().nCoinbaseMaturity);
    4498             : }
    4499             : 
    4500             : 
    4501        1479 : bool CWalletTx::AcceptToMemoryPool(CValidationState& state)
    4502             : {
    4503        1479 :     AssertLockHeld(cs_main);
    4504             : 
    4505             :     // Quick check to avoid re-setting fInMempool to false
    4506        1479 :     if (mempool.exists(tx->GetHash())) {
    4507             :         return false;
    4508             :     }
    4509             : 
    4510             :     // We must set fInMempool here - while it will be re-set to true by the
    4511             :     // entered-mempool callback, if we did not there would be a race where a
    4512             :     // user could call sendmoney in a loop and hit spurious out of funds errors
    4513             :     // because we think that the transaction they just generated's change is
    4514             :     // unavailable as we're not yet aware its in mempool.
    4515        1472 :     bool fMissingInputs;
    4516        1472 :     bool fAccepted = ::AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, true, false);
    4517        1472 :     fInMempool = fAccepted;
    4518        1472 :     if (!fAccepted) {
    4519          35 :         if (fMissingInputs) {
    4520             :             // For now, "missing inputs" error is not returning the proper state, so need to set it manually here.
    4521             :             // TODO: clean this setting the proper invalid state inside AcceptToMemoryPool (btc#15921).
    4522          52 :             state.Invalid(false, REJECT_INVALID, "Missing inputs");
    4523             :         }
    4524          70 :         LogPrintf("%s : %s\n", __func__, state.GetRejectReason());
    4525             :     }
    4526             :     return fAccepted;
    4527             : }
    4528             : 
    4529         361 : std::string CWallet::GetUniqueWalletBackupName() const
    4530             : {
    4531         361 :     std::string name = !m_name.empty() ? SanitizeString(m_name, SAFE_CHARS_FILENAME) : "wallet_backup";
    4532         724 :     return strprintf("%s%s", name, FormatISO8601DateTimeForBackup(GetTime()));
    4533             : }
    4534             : 
    4535        1010 : CWallet::CWallet(std::string name, std::unique_ptr<WalletDatabase> database) : m_name(std::move(name)), database(std::move(database))
    4536             : {
    4537         505 :     SetNull();
    4538         505 : }
    4539             : 
    4540        4406 : CWallet::~CWallet()
    4541             : {
    4542         504 :     delete encrypted_batch;
    4543         504 :     delete pStakerStatus;
    4544         876 : }
    4545             : 
    4546         505 : void CWallet::SetNull()
    4547             : {
    4548         505 :     nWalletVersion = FEATURE_BASE;
    4549         505 :     nWalletMaxVersion = FEATURE_BASE;
    4550         505 :     nMasterKeyMaxID = 0;
    4551         505 :     encrypted_batch = nullptr;
    4552         505 :     nOrderPosNext = 0;
    4553         505 :     nNextResend = 0;
    4554         505 :     nLastResend = 0;
    4555         505 :     nTimeFirstKey = 0;
    4556         505 :     nRelockTime = 0;
    4557         505 :     fAbortRescan = false;
    4558         505 :     fScanningWallet = false;
    4559         505 :     fWalletUnlockStaking = false;
    4560             : 
    4561             :     // Staker status (last hashed block and time)
    4562         505 :     if (pStakerStatus) {
    4563           0 :         pStakerStatus->SetNull();
    4564             :     } else {
    4565         505 :         pStakerStatus = new CStakerStatus();
    4566             :     }
    4567             :     // Stake split threshold
    4568         505 :     nStakeSplitThreshold = DEFAULT_STAKE_SPLIT_THRESHOLD;
    4569             : 
    4570             :     // User-defined fee PIV/kb
    4571         505 :     fUseCustomFee = false;
    4572         505 :     nCustomFee = CWallet::minTxFee.GetFeePerK();
    4573             : 
    4574             :     //Auto Combine Dust
    4575         505 :     fCombineDust = false;
    4576         505 :     nAutoCombineThreshold = 0;
    4577         505 :     frequency = 30;
    4578             : 
    4579             :     // Sapling.
    4580         505 :     m_sspk_man->nWitnessCacheSize = 0;
    4581         505 :     m_sspk_man->nWitnessCacheNeedsUpdate = true;
    4582         505 : }
    4583             : 
    4584      118580 : bool CWallet::CanSupportFeature(enum WalletFeature wf)
    4585             : {
    4586      118580 :     AssertLockHeld(cs_wallet);
    4587      118580 :     return nWalletMaxVersion >= wf;
    4588             : }
    4589             : 
    4590         167 : bool CWallet::LoadMinVersion(int nVersion)
    4591             : {
    4592         167 :     AssertLockHeld(cs_wallet);
    4593         167 :     nWalletVersion = nVersion;
    4594         167 :     nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion);
    4595         167 :     return true;
    4596             : }
    4597             : 
    4598     6242023 : isminetype CWallet::IsMine(const CTxOut& txout) const
    4599             : {
    4600     6242023 :     return ::IsMine(*this, txout.scriptPubKey);
    4601             : }
    4602             : 
    4603      179777 : CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
    4604             : {
    4605      179777 :     if (!Params().GetConsensus().MoneyRange(txout.nValue))
    4606           0 :         throw std::runtime_error("CWallet::GetCredit() : value out of range");
    4607      179777 :     return ((IsMine(txout) & filter) ? txout.nValue : 0);
    4608             : }
    4609             : 
    4610           0 : CAmount CWallet::GetChange(const CTxOut& txout) const
    4611             : {
    4612           0 :     if (!Params().GetConsensus().MoneyRange(txout.nValue))
    4613           0 :         throw std::runtime_error("CWallet::GetChange() : value out of range");
    4614           0 :     return (IsChange(txout) ? txout.nValue : 0);
    4615             : }
    4616             : 
    4617      370355 : bool CWallet::IsMine(const CTransactionRef& tx) const
    4618             : {
    4619      943689 :     for (const CTxOut& txout : tx->vout)
    4620      690939 :         if (IsMine(txout))
    4621      117605 :             return true;
    4622      252750 :     return false;
    4623             : }
    4624             : 
    4625      647709 : bool CWallet::IsFromMe(const CTransactionRef& tx) const
    4626             : {
    4627      647709 :     if (GetDebit(tx, ISMINE_ALL) > 0) {
    4628             :         return true;
    4629             :     }
    4630             : 
    4631      273970 :     if (tx->IsShieldedTx()) {
    4632        2132 :         for (const SpendDescription& spend : tx->sapData->vShieldedSpend) {
    4633         191 :             if (m_sspk_man->IsSaplingNullifierFromMe(spend.nullifier)) {
    4634           0 :                 return true;
    4635             :             }
    4636             :         }
    4637             :     }
    4638             : 
    4639             :     return false;
    4640             : }
    4641             : 
    4642      671398 : CAmount CWallet::GetDebit(const CTransactionRef& tx, const isminefilter& filter) const
    4643             : {
    4644      671398 :     CAmount nDebit = 0;
    4645     1858368 :     for (const CTxIn& txin : tx->vin) {
    4646     1186966 :         nDebit += GetDebit(txin, filter);
    4647     2373932 :         if (!Params().GetConsensus().MoneyRange(nDebit))
    4648           0 :             throw std::runtime_error("CWallet::GetDebit() : value out of range");
    4649             :     }
    4650             : 
    4651             :     // Shielded debit
    4652      671398 :     if (filter & ISMINE_SPENDABLE_SHIELDED || filter & ISMINE_WATCH_ONLY_SHIELDED) {
    4653      652403 :         if (tx->hasSaplingData()) {
    4654        4786 :             nDebit += m_sspk_man->GetDebit(*tx, filter);
    4655             :         }
    4656             :     }
    4657             : 
    4658      671398 :     return nDebit;
    4659             : }
    4660             : 
    4661        6319 : CAmount CWallet::GetCredit(const CWalletTx& tx, const isminefilter& filter) const
    4662             : {
    4663        6319 :     CAmount nCredit = 0;
    4664       13750 :     for (unsigned int i = 0; i < tx.tx->vout.size(); i++) {
    4665        7431 :         nCredit += GetCredit(tx.tx->vout[i], filter);
    4666             :     }
    4667             : 
    4668             :     // Shielded credit
    4669        6319 :     if (filter & ISMINE_SPENDABLE_SHIELDED || filter & ISMINE_WATCH_ONLY_SHIELDED) {
    4670        2144 :         if (tx.tx->hasSaplingData()) {
    4671          10 :             nCredit += m_sspk_man->GetCredit(tx, filter, false);
    4672             :         }
    4673             :     }
    4674             : 
    4675        6319 :     if (!Params().GetConsensus().MoneyRange(nCredit))
    4676           0 :         throw std::runtime_error("CWallet::GetCredit() : value out of range");
    4677        6319 :     return nCredit;
    4678             : }
    4679             : 
    4680           0 : CAmount CWallet::GetChange(const CTransactionRef& tx) const
    4681             : {
    4682           0 :     CAmount nChange = 0;
    4683           0 :     for (const CTxOut& txout : tx->vout) {
    4684           0 :         nChange += GetChange(txout);
    4685           0 :         if (!Params().GetConsensus().MoneyRange(nChange))
    4686           0 :             throw std::runtime_error("CWallet::GetChange() : value out of range");
    4687             :     }
    4688           0 :     return nChange;
    4689             : }
    4690             : 
    4691         434 : unsigned int CWallet::GetKeyPoolSize()
    4692             : {
    4693         434 :     return m_spk_man->GetKeyPoolSize();
    4694             : }
    4695             : 
    4696          65 : unsigned int CWallet::GetStakingKeyPoolSize()
    4697             : {
    4698          65 :     return m_spk_man->GetStakingKeyPoolSize();
    4699             : }
    4700             : 
    4701         868 : int CWallet::GetVersion()
    4702             : {
    4703         868 :     LOCK(cs_wallet);
    4704         868 :     return nWalletVersion;
    4705             : }
    4706             : 
    4707             : ///////////////// Sapling Methods //////////////////////////
    4708             : ////////////////////////////////////////////////////////////
    4709             : 
    4710        1246 : libzcash::SaplingPaymentAddress CWallet::GenerateNewSaplingZKey(std::string label) {
    4711        1246 :     if (!m_sspk_man->IsEnabled()) {
    4712           1 :         throw std::runtime_error("Cannot generate shielded addresses. Start with -upgradewallet in order to upgrade a non-HD wallet to HD and Sapling features");
    4713             :     }
    4714             : 
    4715        1245 :     auto address = m_sspk_man->GenerateNewSaplingZKey();
    4716        1244 :     SetAddressBook(address, label, AddressBook::AddressBookPurpose::SHIELDED_RECEIVE);
    4717        1244 :     return address;
    4718             : }
    4719             : 
    4720       42368 : void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
    4721             :                             const CBlock* pblock,
    4722       42368 :                             SaplingMerkleTree& saplingTree) { m_sspk_man->IncrementNoteWitnesses(pindex, pblock, saplingTree); }
    4723             : 
    4724           5 : void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex) { m_sspk_man->DecrementNoteWitnesses(pindex); }
    4725             : 
    4726          11 : void CWallet::ClearNoteWitnessCache() { m_sspk_man->ClearNoteWitnessCache(); }
    4727             : 
    4728        1020 : bool CWallet::AddSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key) { return m_sspk_man->AddSaplingZKey(key); }
    4729             : 
    4730           1 : bool CWallet::AddSaplingIncomingViewingKeyW(
    4731             :         const libzcash::SaplingIncomingViewingKey &ivk,
    4732           1 :         const libzcash::SaplingPaymentAddress &addr) { return m_sspk_man->AddSaplingIncomingViewingKey(ivk, addr); }
    4733             : 
    4734           0 : bool CWallet::AddCryptedSaplingSpendingKeyW(
    4735             :         const libzcash::SaplingExtendedFullViewingKey &extfvk,
    4736           0 :         const std::vector<unsigned char> &vchCryptedSecret) { return m_sspk_man->AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret); }
    4737             : 
    4738        3692 : bool CWallet::HaveSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &zaddr) const { return m_sspk_man->HaveSpendingKeyForPaymentAddress(zaddr); }
    4739          36 : bool CWallet::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key) { return m_sspk_man->LoadSaplingZKey(key); }
    4740          38 : bool CWallet::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta) { return m_sspk_man->LoadSaplingZKeyMetadata(ivk, meta); }
    4741           2 : bool CWallet::LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
    4742           2 :                             const std::vector<unsigned char> &vchCryptedSecret) { return m_sspk_man->LoadCryptedSaplingZKey(extfvk, vchCryptedSecret); }
    4743             : 
    4744           1 : bool CWallet::LoadSaplingPaymentAddress(
    4745             :         const libzcash::SaplingPaymentAddress &addr,
    4746           1 :         const libzcash::SaplingIncomingViewingKey &ivk) { return m_sspk_man->LoadSaplingPaymentAddress(addr, ivk); }
    4747             : 
    4748             : ///////////////// End Sapling Methods //////////////////////
    4749             : ////////////////////////////////////////////////////////////
    4750             : 
    4751      757450 : CWalletTx::CWalletTx(const CWallet* pwalletIn, CTransactionRef arg)
    4752     3787240 :     : tx(std::move(arg))
    4753             : {
    4754      757450 :     Init(pwalletIn);
    4755      757450 : }
    4756             : 
    4757      764213 : void CWalletTx::Init(const CWallet* pwalletIn)
    4758             : {
    4759      764213 :     pwallet = pwalletIn;
    4760      764213 :     mapValue.clear();
    4761      764213 :     mapSaplingNoteData.clear();
    4762      764213 :     vOrderForm.clear();
    4763      764213 :     fTimeReceivedIsTxTime = false;
    4764      764213 :     nTimeReceived = 0;
    4765      764213 :     nTimeSmart = 0;
    4766      764213 :     fFromMe = false;
    4767      764213 :     fChangeCached = false;
    4768      764213 :     fInMempool = false;
    4769      764213 :     nChangeCached = 0;
    4770      764213 :     fStakeDelegationVoided = false;
    4771      764213 :     fShieldedChangeCached = false;
    4772      764213 :     nShieldedChangeCached = 0;
    4773      764213 :     nOrderPos = -1;
    4774      764213 :     m_confirm = Confirmation{};
    4775      764213 : }
    4776             : 
    4777     4493103 : bool CWalletTx::IsTrusted() const
    4778             : {
    4779     4493103 :     bool fConflicted = false;
    4780     4493103 :     int nDepth = 0;
    4781     4493103 :     return IsTrusted(nDepth, fConflicted);
    4782             : }
    4783             : 
    4784     4540030 : bool CWalletTx::IsTrusted(int& nDepth, bool& fConflicted) const
    4785             : {
    4786     4540030 :     {
    4787     4540030 :         LOCK(pwallet->cs_wallet); // future: receive block height instead of locking here.
    4788             :         // Quick answer in most cases
    4789     4540030 :         if (!IsFinalTx(tx, pwallet->GetLastBlockHeight()))
    4790           0 :             return false;
    4791             :     }
    4792             : 
    4793     4540030 :     nDepth = GetDepthAndMempool(fConflicted);
    4794             : 
    4795     4540030 :     if (fConflicted) // Don't trust unconfirmed transactions from us unless they are in the mempool.
    4796             :         return false;
    4797     4427201 :     if (nDepth >= 1)
    4798             :         return true;
    4799     1002048 :     if (nDepth < 0)
    4800             :         return false;
    4801     1001838 :     if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
    4802          16 :         return false;
    4803             : 
    4804             :     // Trusted if all inputs are from us and are in the mempool:
    4805     2004134 :     for (const CTxIn& txin : tx->vin) {
    4806             :         // Transactions not sent by us: not trusted
    4807     1002317 :         const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
    4808     1002317 :         if (parent == nullptr)
    4809           0 :             return false;
    4810     1002317 :         const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
    4811     1002317 :         if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
    4812             :             return false;
    4813             :     }
    4814     1001817 :     return true;
    4815             : }
    4816             : 
    4817    10280524 : int CWalletTx::GetDepthAndMempool(bool& fConflicted) const
    4818             : {
    4819    10280524 :     int ret = GetDepthInMainChain();
    4820    10280524 :     fConflicted = (ret == 0 && !InMempool());  // not in chain nor in mempool
    4821    10280524 :     return ret;
    4822             : }
    4823             : 
    4824           0 : bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
    4825             : {
    4826           0 :     CMutableTransaction tx1 {*tx};
    4827           0 :     CMutableTransaction tx2 {*_tx.tx};
    4828           0 :     for (auto& txin : tx1.vin) txin.scriptSig = CScript();
    4829           0 :     for (auto& txin : tx2.vin) txin.scriptSig = CScript();
    4830           0 :     return CTransaction(tx1) == CTransaction(tx2);
    4831             : }
    4832             : 
    4833     1544786 : void CWalletTx::MarkDirty()
    4834             : {
    4835     1544786 :     m_amounts[DEBIT].Reset();
    4836     1544786 :     m_amounts[CREDIT].Reset();
    4837     1544786 :     m_amounts[IMMATURE_CREDIT].Reset();
    4838     1544786 :     m_amounts[AVAILABLE_CREDIT].Reset();
    4839     1544786 :     nChangeCached = 0;
    4840     1544786 :     fChangeCached = false;
    4841     1544786 :     nShieldedChangeCached = 0;
    4842     1544786 :     fShieldedChangeCached = false;
    4843     1544786 :     fStakeDelegationVoided = false;
    4844     1544786 : }
    4845             : 
    4846      406244 : void CWalletTx::BindWallet(CWallet* pwalletIn)
    4847             : {
    4848      406244 :     pwallet = pwalletIn;
    4849      406244 :     MarkDirty();
    4850      406244 : }
    4851             : 
    4852        2030 : void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t &noteData)
    4853             : {
    4854        2030 :     mapSaplingNoteData.clear();
    4855        4203 :     for (const std::pair<SaplingOutPoint, SaplingNoteData> nd : noteData) {
    4856        2174 :         if (nd.first.n < tx->sapData->vShieldedOutput.size()) {
    4857        2173 :             mapSaplingNoteData[nd.first] = nd.second;
    4858             :         } else {
    4859           1 :             throw std::logic_error("CWalletTx::SetSaplingNoteData(): Invalid note");
    4860             :         }
    4861             :     }
    4862        2029 : }
    4863             : 
    4864             : Optional<std::pair<
    4865             :         libzcash::SaplingNotePlaintext,
    4866        1175 :         libzcash::SaplingPaymentAddress>> CWalletTx::DecryptSaplingNote(const SaplingOutPoint& op) const
    4867             : {
    4868             :     // Check whether we can decrypt this SaplingOutPoint with the ivk
    4869        1175 :     auto it = this->mapSaplingNoteData.find(op);
    4870        1175 :     if (it == this->mapSaplingNoteData.end() || !it->second.IsMyNote()) {
    4871           0 :         return nullopt;
    4872             :     }
    4873             : 
    4874        1175 :     auto output = this->tx->sapData->vShieldedOutput[op.n];
    4875        2350 :     auto nd = this->mapSaplingNoteData.at(op);
    4876             : 
    4877        1175 :     auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
    4878             :             output.encCiphertext,
    4879        1175 :             *(nd.ivk),
    4880             :             output.ephemeralKey,
    4881        1175 :             output.cmu);
    4882        1175 :     assert(static_cast<bool>(maybe_pt));
    4883        1175 :     auto notePt = maybe_pt.get();
    4884             : 
    4885        2350 :     auto maybe_pa = nd.ivk->address(notePt.d);
    4886        1175 :     assert(static_cast<bool>(maybe_pa));
    4887        1175 :     auto pa = maybe_pa.get();
    4888             : 
    4889        1175 :     return std::make_pair(notePt, pa);
    4890             : }
    4891             : 
    4892             : Optional<std::pair<
    4893             :         libzcash::SaplingNotePlaintext,
    4894          99 :         libzcash::SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(const SaplingOutPoint& op, const std::set<uint256>& ovks) const
    4895             : {
    4896          99 :     auto output = this->tx->sapData->vShieldedOutput[op.n];
    4897             : 
    4898         107 :     for (const auto& ovk : ovks) {
    4899         103 :         auto outPt = libzcash::SaplingOutgoingPlaintext::decrypt(
    4900             :                 output.outCiphertext,
    4901             :                 ovk,
    4902             :                 output.cv,
    4903             :                 output.cmu,
    4904         103 :                 output.ephemeralKey);
    4905         103 :         if (!outPt) {
    4906           8 :             continue;
    4907             :         }
    4908             : 
    4909          95 :         auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
    4910             :                 output.encCiphertext,
    4911             :                 output.ephemeralKey,
    4912          95 :                 outPt->esk,
    4913          95 :                 outPt->pk_d,
    4914         190 :                 output.cmu);
    4915          95 :         assert(static_cast<bool>(maybe_pt));
    4916          95 :         auto notePt = maybe_pt.get();
    4917             : 
    4918          95 :         return std::make_pair(notePt, libzcash::SaplingPaymentAddress(notePt.d, outPt->pk_d));
    4919             :     }
    4920             : 
    4921             :     // Couldn't recover with any of the provided OutgoingViewingKeys
    4922           4 :     return nullopt;
    4923             : }
    4924             : 
    4925           0 : bool CWalletTx::HasP2CSInputs() const
    4926             : {
    4927           0 :     return GetStakeDelegationDebit(true) > 0 || GetColdStakingDebit(true) > 0;
    4928             : }
    4929             : 
    4930           0 : CAmount CWalletTx::GetChange() const
    4931             : {
    4932           0 :     if (fChangeCached)
    4933           0 :         return nChangeCached;
    4934           0 :     nChangeCached = pwallet->GetChange(tx);
    4935           0 :     fChangeCached = true;
    4936           0 :     return nChangeCached;
    4937             : }
    4938             : 
    4939           3 : CAmount CWalletTx::GetShieldedChange() const
    4940             : {
    4941           3 :     if (fShieldedChangeCached) {
    4942           0 :         return nShieldedChangeCached;
    4943             :     }
    4944           3 :     nShieldedChangeCached = pwallet->GetSaplingScriptPubKeyMan()->GetShieldedChange(*this);
    4945           3 :     fShieldedChangeCached = true;
    4946           3 :     return nShieldedChangeCached;
    4947             : }
    4948             : 
    4949     1519126 : bool CWalletTx::IsFromMe(const isminefilter& filter) const
    4950             : {
    4951     1519126 :     return (GetDebit(filter) > 0);
    4952             : }
    4953             : 
    4954           3 : CAmount CWalletTx::GetShieldedAvailableCredit(bool fUseCache) const
    4955             : {
    4956           3 :     return GetAvailableCredit(fUseCache, ISMINE_SPENDABLE_SHIELDED);
    4957             : }
    4958             : 
    4959         253 : const CTxDestination* CAddressBookIterator::GetCTxDestKey()
    4960             : {
    4961         253 :     return boost::get<CTxDestination>(&it->first);
    4962             : }
    4963             : 
    4964          34 : const libzcash::SaplingPaymentAddress* CAddressBookIterator::GetShieldedDestKey()
    4965             : {
    4966          34 :     return boost::get<libzcash::SaplingPaymentAddress>(&it->first);
    4967             : }
    4968             : 
    4969           0 : const CWDestination* CAddressBookIterator::GetDestKey()
    4970             : {
    4971           0 :     return &it->first;
    4972             : }
    4973             : 
    4974      328438 : CStakeableOutput::CStakeableOutput(const CWalletTx* txIn,
    4975             :                                    int iIn,
    4976             :                                    int nDepthIn,
    4977      328438 :                                    const CBlockIndex*& _pindex) :
    4978             :                        COutput(txIn, iIn, nDepthIn, true /*fSpendable*/, true/*fSolvable*/, true/*fSafe*/),
    4979      328438 :                        pindex(_pindex)
    4980      328438 : {}

Generated by: LCOV version 1.14