LCOV - code coverage report
Current view: top level - src/wallet - receive.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 85.3 % 224 191
Test Date: 2025-07-10 05:20:26 Functions: 84.2 % 19 16
Branches: 62.1 % 306 190

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2021-2022 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <consensus/amount.h>
       6                 :             : #include <consensus/consensus.h>
       7                 :             : #include <util/check.h>
       8                 :             : #include <wallet/receive.h>
       9                 :             : #include <wallet/transaction.h>
      10                 :             : #include <wallet/wallet.h>
      11                 :             : 
      12                 :             : namespace wallet {
      13                 :         474 : isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin)
      14                 :             : {
      15                 :         474 :     AssertLockHeld(wallet.cs_wallet);
      16                 :         474 :     const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
      17   [ +  +  +  - ]:         474 :     if (prev && txin.prevout.n < prev->tx->vout.size()) {
      18                 :         270 :         return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
      19                 :             :     }
      20                 :             :     return ISMINE_NO;
      21                 :             : }
      22                 :             : 
      23                 :         115 : bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
      24                 :             : {
      25                 :         115 :     LOCK(wallet.cs_wallet);
      26         [ +  + ]:         382 :     for (const CTxIn& txin : tx.vin) {
      27   [ +  -  +  + ]:         268 :         if (!(InputIsMine(wallet, txin) & filter)) return false;
      28                 :             :     }
      29                 :             :     return true;
      30                 :         115 : }
      31                 :             : 
      32                 :         794 : CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter)
      33                 :             : {
      34         [ -  + ]:         794 :     if (!MoneyRange(txout.nValue))
      35   [ #  #  #  # ]:           0 :         throw std::runtime_error(std::string(__func__) + ": value out of range");
      36                 :         794 :     LOCK(wallet.cs_wallet);
      37   [ +  -  +  +  :         794 :     return ((wallet.IsMine(txout) & filter) ? txout.nValue : 0);
                   +  - ]
      38                 :         794 : }
      39                 :             : 
      40                 :         413 : CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
      41                 :             : {
      42                 :         413 :     CAmount nCredit = 0;
      43         [ +  + ]:        1207 :     for (const CTxOut& txout : tx.vout)
      44                 :             :     {
      45                 :         794 :         nCredit += OutputGetCredit(wallet, txout, filter);
      46         [ -  + ]:         794 :         if (!MoneyRange(nCredit))
      47   [ #  #  #  # ]:           0 :             throw std::runtime_error(std::string(__func__) + ": value out of range");
      48                 :             :     }
      49                 :         413 :     return nCredit;
      50                 :             : }
      51                 :             : 
      52                 :        2085 : bool ScriptIsChange(const CWallet& wallet, const CScript& script)
      53                 :             : {
      54                 :             :     // TODO: fix handling of 'change' outputs. The assumption is that any
      55                 :             :     // payment to a script that is ours, but is not in the address book
      56                 :             :     // is change. That assumption is likely to break when we implement multisignature
      57                 :             :     // wallets that return change back into a multi-signature-protected address;
      58                 :             :     // a better way of identifying which outputs are 'the send' and which are
      59                 :             :     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
      60                 :             :     // which output, if any, was change).
      61                 :        2085 :     AssertLockHeld(wallet.cs_wallet);
      62         [ +  + ]:        2085 :     if (wallet.IsMine(script))
      63                 :             :     {
      64                 :        1429 :         CTxDestination address;
      65   [ +  -  +  + ]:        1429 :         if (!ExtractDestination(script, address))
      66                 :             :             return true;
      67   [ +  -  +  + ]:        1424 :         if (!wallet.FindAddressBookEntry(address)) {
      68                 :             :             return true;
      69                 :             :         }
      70                 :        1429 :     }
      71                 :             :     return false;
      72                 :             : }
      73                 :             : 
      74                 :        1346 : bool OutputIsChange(const CWallet& wallet, const CTxOut& txout)
      75                 :             : {
      76                 :        1346 :     return ScriptIsChange(wallet, txout.scriptPubKey);
      77                 :             : }
      78                 :             : 
      79                 :           0 : CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout)
      80                 :             : {
      81                 :           0 :     AssertLockHeld(wallet.cs_wallet);
      82         [ #  # ]:           0 :     if (!MoneyRange(txout.nValue))
      83   [ #  #  #  # ]:           0 :         throw std::runtime_error(std::string(__func__) + ": value out of range");
      84         [ #  # ]:           0 :     return (OutputIsChange(wallet, txout) ? txout.nValue : 0);
      85                 :             : }
      86                 :             : 
      87                 :           0 : CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
      88                 :             : {
      89                 :           0 :     LOCK(wallet.cs_wallet);
      90                 :           0 :     CAmount nChange = 0;
      91         [ #  # ]:           0 :     for (const CTxOut& txout : tx.vout)
      92                 :             :     {
      93         [ #  # ]:           0 :         nChange += OutputGetChange(wallet, txout);
      94         [ #  # ]:           0 :         if (!MoneyRange(nChange))
      95   [ #  #  #  # ]:           0 :             throw std::runtime_error(std::string(__func__) + ": value out of range");
      96                 :             :     }
      97         [ #  # ]:           0 :     return nChange;
      98                 :           0 : }
      99                 :             : 
     100                 :      254167 : static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter)
     101                 :             : {
     102                 :      254167 :     auto& amount = wtx.m_amounts[type];
     103         [ +  + ]:      254167 :     if (!amount.m_cached[filter]) {
     104         [ +  + ]:       10884 :         amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
     105                 :       10884 :         wtx.m_is_cache_empty = false;
     106                 :             :     }
     107                 :      254167 :     return amount.m_value[filter];
     108                 :             : }
     109                 :             : 
     110                 :         431 : CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
     111                 :             : {
     112                 :         431 :     AssertLockHeld(wallet.cs_wallet);
     113                 :             : 
     114                 :             :     // Must wait until coinbase is safely deep enough in the chain before valuing it
     115         [ +  + ]:         431 :     if (wallet.IsTxImmatureCoinBase(wtx))
     116                 :             :         return 0;
     117                 :             : 
     118                 :         421 :     CAmount credit = 0;
     119                 :         421 :     const isminefilter get_amount_filter{filter & ISMINE_ALL};
     120         [ +  - ]:         421 :     if (get_amount_filter) {
     121                 :             :         // GetBalance can assume transactions in mapWallet won't change
     122                 :         421 :         credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter);
     123                 :             :     }
     124                 :             :     return credit;
     125                 :             : }
     126                 :             : 
     127                 :      253746 : CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
     128                 :             : {
     129         [ +  - ]:      253746 :     if (wtx.tx->vin.empty())
     130                 :             :         return 0;
     131                 :             : 
     132                 :      253746 :     CAmount debit = 0;
     133                 :      253746 :     const isminefilter get_amount_filter{filter & ISMINE_ALL};
     134         [ +  - ]:      253746 :     if (get_amount_filter) {
     135                 :      253746 :         debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter);
     136                 :             :     }
     137                 :             :     return debit;
     138                 :             : }
     139                 :             : 
     140                 :           0 : CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
     141                 :             : {
     142         [ #  # ]:           0 :     if (wtx.fChangeCached)
     143                 :           0 :         return wtx.nChangeCached;
     144                 :           0 :     wtx.nChangeCached = TxGetChange(wallet, *wtx.tx);
     145                 :           0 :     wtx.fChangeCached = true;
     146                 :           0 :     return wtx.nChangeCached;
     147                 :             : }
     148                 :             : 
     149                 :        1899 : void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
     150                 :             :                   std::list<COutputEntry>& listReceived,
     151                 :             :                   std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter,
     152                 :             :                   bool include_change)
     153                 :             : {
     154                 :        1899 :     nFee = 0;
     155                 :        1899 :     listReceived.clear();
     156                 :        1899 :     listSent.clear();
     157                 :             : 
     158                 :             :     // Compute fee:
     159                 :        1899 :     CAmount nDebit = CachedTxGetDebit(wallet, wtx, filter);
     160         [ +  + ]:        1899 :     if (nDebit > 0) // debit>0 means we signed/sent this transaction
     161                 :             :     {
     162                 :         567 :         CAmount nValueOut = wtx.tx->GetValueOut();
     163                 :         567 :         nFee = nDebit - nValueOut;
     164                 :             :     }
     165                 :             : 
     166                 :        1899 :     LOCK(wallet.cs_wallet);
     167                 :             :     // Sent/received.
     168         [ +  + ]:        5678 :     for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
     169                 :             :     {
     170         [ +  - ]:        3779 :         const CTxOut& txout = wtx.tx->vout[i];
     171         [ +  - ]:        3779 :         isminetype fIsMine = wallet.IsMine(txout);
     172                 :             :         // Only need to handle txouts if AT LEAST one of these is true:
     173                 :             :         //   1) they debit from us (sent)
     174                 :             :         //   2) the output is to us (received)
     175         [ +  + ]:        3779 :         if (nDebit > 0)
     176                 :             :         {
     177   [ +  +  +  -  :        1116 :             if (!include_change && OutputIsChange(wallet, txout))
                   +  + ]
     178                 :         439 :                 continue;
     179                 :             :         }
     180         [ +  + ]:        2663 :         else if (!(fIsMine & filter))
     181                 :        1321 :             continue;
     182                 :             : 
     183                 :             :         // In either case, we need to get the destination address
     184                 :        2019 :         CTxDestination address;
     185                 :             : 
     186   [ +  -  +  +  :        2019 :         if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
                   -  + ]
     187                 :             :         {
     188         [ #  # ]:           0 :             wallet.WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
     189   [ #  #  #  # ]:           0 :                                     wtx.GetHash().ToString());
     190                 :           0 :             address = CNoDestination();
     191                 :             :         }
     192                 :             : 
     193         [ +  - ]:        2019 :         COutputEntry output = {address, txout.nValue, (int)i};
     194                 :             : 
     195                 :             :         // If we are debited by the transaction, add the output as a "sent" entry
     196         [ +  + ]:        2019 :         if (nDebit > 0)
     197         [ +  - ]:         677 :             listSent.push_back(output);
     198                 :             : 
     199                 :             :         // If we are receiving the output, add it as a "received" entry
     200         [ +  + ]:        2019 :         if (fIsMine & filter)
     201         [ +  - ]:        1553 :             listReceived.push_back(output);
     202                 :        2019 :     }
     203                 :             : 
     204                 :        1899 : }
     205                 :             : 
     206                 :      251416 : bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
     207                 :             : {
     208                 :      251416 :     return (CachedTxGetDebit(wallet, wtx, filter) > 0);
     209                 :             : }
     210                 :             : 
     211                 :             : // NOLINTNEXTLINE(misc-no-recursion)
     212                 :      578219 : bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents)
     213                 :             : {
     214                 :      578219 :     AssertLockHeld(wallet.cs_wallet);
     215                 :             : 
     216                 :             :     // This wtx is already trusted
     217         [ +  + ]:      578219 :     if (trusted_parents.contains(wtx.GetHash())) return true;
     218                 :             : 
     219         [ +  + ]:      528411 :     if (wtx.isConfirmed()) return true;
     220         [ +  + ]:       76534 :     if (wtx.isBlockConflicted()) return false;
     221                 :             :     // using wtx's cached debit
     222   [ +  +  +  + ]:       76459 :     if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
     223                 :             : 
     224                 :             :     // Don't trust unconfirmed transactions from us unless they are in the mempool.
     225         [ +  + ]:       73543 :     if (!wtx.InMempool()) return false;
     226                 :             : 
     227                 :             :     // Trusted if all inputs are from us and are in the mempool:
     228         [ +  + ]:      152291 :     for (const CTxIn& txin : wtx.tx->vin)
     229                 :             :     {
     230                 :             :         // Transactions not sent by us: not trusted
     231                 :       79173 :         const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
     232         [ +  + ]:       79173 :         if (parent == nullptr) return false;
     233                 :       79164 :         const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
     234                 :             :         // Check that this specific input being spent is trusted
     235         [ +  + ]:       79164 :         if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false;
     236                 :             :         // If we've already trusted this parent, continue
     237         [ +  + ]:       79162 :         if (trusted_parents.count(parent->GetHash())) continue;
     238                 :             :         // Recurse to check that the parent is also trusted
     239         [ +  + ]:       72514 :         if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
     240                 :       72186 :         trusted_parents.insert(parent->GetHash());
     241                 :             :     }
     242                 :             :     return true;
     243                 :             : }
     244                 :             : 
     245                 :         643 : bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
     246                 :             : {
     247         [ +  - ]:         643 :     std::set<Txid> trusted_parents;
     248         [ +  - ]:         643 :     LOCK(wallet.cs_wallet);
     249   [ +  -  +  - ]:         643 :     return CachedTxIsTrusted(wallet, wtx, trusted_parents);
     250                 :         643 : }
     251                 :             : 
     252                 :        1082 : Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
     253                 :             : {
     254                 :        1082 :     Balance ret;
     255   [ +  +  +  + ]:        1082 :     bool allow_used_addresses = !avoid_reuse || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
     256                 :        1082 :     {
     257                 :        1082 :         LOCK(wallet.cs_wallet);
     258                 :        1082 :         std::set<Txid> trusted_parents;
     259   [ +  +  +  - ]:       82887 :         for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
     260         [ +  - ]:       81805 :             const CWalletTx& wtx = txo.GetWalletTx();
     261                 :             : 
     262         [ +  - ]:       81805 :             const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
     263         [ +  - ]:       81805 :             const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
     264                 :             : 
     265   [ +  -  +  +  :       81805 :             if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) {
          +  +  +  -  +  
                      + ]
     266                 :             :                 // Get the amounts for mine
     267                 :       32740 :                 CAmount credit_mine = 0;
     268         [ +  - ]:       32740 :                 if (txo.GetIsMine() == ISMINE_SPENDABLE) {
     269                 :       32740 :                     credit_mine = txo.GetTxOut().nValue;
     270                 :             :                 } else {
     271                 :             :                     // We shouldn't see any other isminetypes
     272                 :             :                     Assume(false);
     273                 :             :                 }
     274                 :             : 
     275                 :             :                 // Set the amounts in the return object
     276   [ +  -  +  + ]:       32740 :                 if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
     277                 :       20811 :                     ret.m_mine_immature += credit_mine;
     278         [ +  + ]:       11929 :                 } else if (is_trusted && tx_depth >= min_depth) {
     279                 :       11375 :                     ret.m_mine_trusted += credit_mine;
     280   [ +  +  +  -  :         554 :                 } else if (!is_trusted && wtx.InMempool()) {
                   +  + ]
     281                 :         383 :                     ret.m_mine_untrusted_pending += credit_mine;
     282                 :             :                 }
     283                 :             :             }
     284                 :             :         }
     285         [ +  - ]:        1082 :     }
     286                 :        1082 :     return ret;
     287                 :             : }
     288                 :             : 
     289                 :           2 : std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
     290                 :             : {
     291         [ +  - ]:           2 :     std::map<CTxDestination, CAmount> balances;
     292                 :             : 
     293                 :           2 :     {
     294         [ +  - ]:           2 :         LOCK(wallet.cs_wallet);
     295                 :           2 :         std::set<Txid> trusted_parents;
     296   [ +  +  +  - ]:         206 :         for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
     297         [ +  - ]:         204 :             const CWalletTx& wtx = txo.GetWalletTx();
     298                 :             : 
     299   [ -  +  +  - ]:         204 :             if (!CachedTxIsTrusted(wallet, wtx, trusted_parents)) continue;
     300   [ +  -  +  + ]:         204 :             if (wallet.IsTxImmatureCoinBase(wtx)) continue;
     301                 :             : 
     302         [ +  - ]:           4 :             int nDepth = wallet.GetTxDepthInMainChain(wtx);
     303   [ +  -  +  -  :           8 :             if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1)) continue;
                   -  + ]
     304                 :             : 
     305                 :           4 :             CTxDestination addr;
     306         [ +  - ]:           4 :             Assume(wallet.IsMine(txo.GetTxOut()));
     307   [ +  -  -  + ]:           4 :             if(!ExtractDestination(txo.GetTxOut().scriptPubKey, addr)) continue;
     308                 :             : 
     309   [ +  -  +  + ]:           4 :             CAmount n = wallet.IsSpent(outpoint) ? 0 : txo.GetTxOut().nValue;
     310         [ +  - ]:           4 :             balances[addr] += n;
     311                 :           4 :         }
     312         [ +  - ]:           2 :     }
     313                 :             : 
     314                 :           2 :     return balances;
     315                 :           0 : }
     316                 :             : 
     317                 :           2 : std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
     318                 :             : {
     319                 :           2 :     AssertLockHeld(wallet.cs_wallet);
     320                 :           2 :     std::set< std::set<CTxDestination> > groupings;
     321                 :           2 :     std::set<CTxDestination> grouping;
     322                 :             : 
     323   [ +  +  +  - ]:         207 :     for (const auto& walletEntry : wallet.mapWallet)
     324                 :             :     {
     325                 :         205 :         const CWalletTx& wtx = walletEntry.second;
     326                 :             : 
     327         [ +  - ]:         205 :         if (wtx.tx->vin.size() > 0)
     328                 :             :         {
     329                 :         205 :             bool any_mine = false;
     330                 :             :             // group all input addresses with each other
     331         [ +  + ]:         411 :             for (const CTxIn& txin : wtx.tx->vin)
     332                 :             :             {
     333                 :         206 :                 CTxDestination address;
     334   [ +  -  +  + ]:         206 :                 if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
     335                 :         204 :                     continue;
     336   [ +  -  +  -  :           2 :                 if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
                   -  + ]
     337                 :           0 :                     continue;
     338         [ +  - ]:           2 :                 grouping.insert(address);
     339                 :           2 :                 any_mine = true;
     340                 :         206 :             }
     341                 :             : 
     342                 :             :             // group change with input addresses
     343         [ +  + ]:         205 :             if (any_mine)
     344                 :             :             {
     345         [ +  + ]:           2 :                for (const CTxOut& txout : wtx.tx->vout)
     346   [ +  -  -  + ]:           1 :                    if (OutputIsChange(wallet, txout))
     347                 :             :                    {
     348                 :           0 :                        CTxDestination txoutAddr;
     349   [ #  #  #  # ]:           0 :                        if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
     350                 :           0 :                            continue;
     351         [ #  # ]:           0 :                        grouping.insert(txoutAddr);
     352                 :           0 :                    }
     353                 :             :             }
     354         [ +  + ]:         205 :             if (grouping.size() > 0)
     355                 :             :             {
     356         [ +  - ]:           1 :                 groupings.insert(grouping);
     357                 :           1 :                 grouping.clear();
     358                 :             :             }
     359                 :             :         }
     360                 :             : 
     361                 :             :         // group lone addrs by themselves
     362         [ +  + ]:         614 :         for (const auto& txout : wtx.tx->vout)
     363   [ +  -  +  + ]:         409 :             if (wallet.IsMine(txout))
     364                 :             :             {
     365                 :         204 :                 CTxDestination address;
     366   [ +  -  -  + ]:         204 :                 if(!ExtractDestination(txout.scriptPubKey, address))
     367                 :           0 :                     continue;
     368         [ +  - ]:         204 :                 grouping.insert(address);
     369         [ +  - ]:         204 :                 groupings.insert(grouping);
     370                 :         204 :                 grouping.clear();
     371                 :         204 :             }
     372                 :             :     }
     373                 :             : 
     374                 :           2 :     std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
     375                 :           2 :     std::map< CTxDestination, std::set<CTxDestination>* > setmap;  // map addresses to the unique group containing it
     376         [ +  + ]:           7 :     for (const std::set<CTxDestination>& _grouping : groupings)
     377                 :             :     {
     378                 :             :         // make a set of all the groups hit by this new group
     379                 :           5 :         std::set< std::set<CTxDestination>* > hits;
     380                 :           5 :         std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
     381         [ +  + ]:          11 :         for (const CTxDestination& address : _grouping)
     382         [ +  + ]:           6 :             if ((it = setmap.find(address)) != setmap.end())
     383         [ +  - ]:           2 :                 hits.insert((*it).second);
     384                 :             : 
     385                 :             :         // merge all hit groups into a new single group and delete old groups
     386   [ +  -  +  - ]:           5 :         std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
     387         [ +  + ]:           7 :         for (std::set<CTxDestination>* hit : hits)
     388                 :             :         {
     389         [ +  - ]:           2 :             merged->insert(hit->begin(), hit->end());
     390                 :           2 :             uniqueGroupings.erase(hit);
     391         [ +  - ]:           4 :             delete hit;
     392                 :             :         }
     393         [ +  - ]:           5 :         uniqueGroupings.insert(merged);
     394                 :             : 
     395                 :             :         // update setmap
     396         [ +  + ]:          12 :         for (const CTxDestination& element : *merged)
     397         [ +  - ]:           7 :             setmap[element] = merged;
     398                 :           5 :     }
     399                 :             : 
     400                 :           2 :     std::set< std::set<CTxDestination> > ret;
     401         [ +  + ]:           5 :     for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
     402                 :             :     {
     403         [ +  - ]:           3 :         ret.insert(*uniqueGrouping);
     404         [ +  - ]:           6 :         delete uniqueGrouping;
     405                 :             :     }
     406                 :             : 
     407                 :           2 :     return ret;
     408                 :           2 : }
     409                 :             : } // namespace wallet
        

Generated by: LCOV version 2.0-1