LCOV - code coverage report
Current view: top level - src/wallet - receive.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 299 346 86.4 %
Date: 2021-06-29 14:35:33 Functions: 18 21 85.7 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 172 208 82.7 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2021 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/consensus.h>
#       6                 :            : #include <wallet/receive.h>
#       7                 :            : #include <wallet/transaction.h>
#       8                 :            : #include <wallet/wallet.h>
#       9                 :            : 
#      10                 :            : isminetype CWallet::IsMine(const CTxIn &txin) const
#      11                 :        412 : {
#      12                 :        412 :     AssertLockHeld(cs_wallet);
#      13                 :        412 :     std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
#      14         [ +  + ]:        412 :     if (mi != mapWallet.end())
#      15                 :          4 :     {
#      16                 :          4 :         const CWalletTx& prev = (*mi).second;
#      17         [ +  - ]:          4 :         if (txin.prevout.n < prev.tx->vout.size())
#      18                 :          4 :             return IsMine(prev.tx->vout[txin.prevout.n]);
#      19                 :        408 :     }
#      20                 :        408 :     return ISMINE_NO;
#      21                 :        408 : }
#      22                 :            : 
#      23                 :            : bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const
#      24                 :        308 : {
#      25                 :        308 :     LOCK(cs_wallet);
#      26                 :            : 
#      27         [ +  + ]:        308 :     for (const CTxIn& txin : tx.vin)
#      28                 :        598 :     {
#      29                 :        598 :         auto mi = mapWallet.find(txin.prevout.hash);
#      30         [ +  + ]:        598 :         if (mi == mapWallet.end())
#      31                 :          2 :             return false; // any unknown inputs can't be from us
#      32                 :            : 
#      33                 :        596 :         const CWalletTx& prev = (*mi).second;
#      34                 :            : 
#      35         [ -  + ]:        596 :         if (txin.prevout.n >= prev.tx->vout.size())
#      36                 :          0 :             return false; // invalid input!
#      37                 :            : 
#      38         [ -  + ]:        596 :         if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter))
#      39                 :          0 :             return false;
#      40                 :        596 :     }
#      41                 :        308 :     return true;
#      42                 :        308 : }
#      43                 :            : 
#      44                 :            : CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
#      45                 :      91873 : {
#      46         [ -  + ]:      91873 :     if (!MoneyRange(txout.nValue))
#      47                 :          0 :         throw std::runtime_error(std::string(__func__) + ": value out of range");
#      48                 :      91873 :     LOCK(cs_wallet);
#      49         [ +  + ]:      91873 :     return ((IsMine(txout) & filter) ? txout.nValue : 0);
#      50                 :      91873 : }
#      51                 :            : 
#      52                 :            : CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
#      53                 :      13867 : {
#      54                 :      13867 :     CAmount nCredit = 0;
#      55         [ +  + ]:      13867 :     for (const CTxOut& txout : tx.vout)
#      56                 :      27701 :     {
#      57                 :      27701 :         nCredit += GetCredit(txout, filter);
#      58         [ -  + ]:      27701 :         if (!MoneyRange(nCredit))
#      59                 :          0 :             throw std::runtime_error(std::string(__func__) + ": value out of range");
#      60                 :      27701 :     }
#      61                 :      13867 :     return nCredit;
#      62                 :      13867 : }
#      63                 :            : 
#      64                 :            : bool CWallet::IsChange(const CScript& script) const
#      65                 :       2501 : {
#      66                 :            :     // TODO: fix handling of 'change' outputs. The assumption is that any
#      67                 :            :     // payment to a script that is ours, but is not in the address book
#      68                 :            :     // is change. That assumption is likely to break when we implement multisignature
#      69                 :            :     // wallets that return change back into a multi-signature-protected address;
#      70                 :            :     // a better way of identifying which outputs are 'the send' and which are
#      71                 :            :     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
#      72                 :            :     // which output, if any, was change).
#      73                 :       2501 :     AssertLockHeld(cs_wallet);
#      74         [ +  + ]:       2501 :     if (IsMine(script))
#      75                 :       1856 :     {
#      76                 :       1856 :         CTxDestination address;
#      77         [ -  + ]:       1856 :         if (!ExtractDestination(script, address))
#      78                 :          0 :             return true;
#      79         [ +  + ]:       1856 :         if (!FindAddressBookEntry(address)) {
#      80                 :        711 :             return true;
#      81                 :        711 :         }
#      82                 :       1790 :     }
#      83                 :       1790 :     return false;
#      84                 :       1790 : }
#      85                 :            : 
#      86                 :            : bool CWallet::IsChange(const CTxOut& txout) const
#      87                 :       1318 : {
#      88                 :       1318 :     return IsChange(txout.scriptPubKey);
#      89                 :       1318 : }
#      90                 :            : 
#      91                 :            : CAmount CWallet::GetChange(const CTxOut& txout) const
#      92                 :          0 : {
#      93                 :          0 :     AssertLockHeld(cs_wallet);
#      94         [ #  # ]:          0 :     if (!MoneyRange(txout.nValue))
#      95                 :          0 :         throw std::runtime_error(std::string(__func__) + ": value out of range");
#      96         [ #  # ]:          0 :     return (IsChange(txout) ? txout.nValue : 0);
#      97                 :          0 : }
#      98                 :            : 
#      99                 :            : CAmount CWallet::GetChange(const CTransaction& tx) const
#     100                 :          0 : {
#     101                 :          0 :     LOCK(cs_wallet);
#     102                 :          0 :     CAmount nChange = 0;
#     103         [ #  # ]:          0 :     for (const CTxOut& txout : tx.vout)
#     104                 :          0 :     {
#     105                 :          0 :         nChange += GetChange(txout);
#     106         [ #  # ]:          0 :         if (!MoneyRange(nChange))
#     107                 :          0 :             throw std::runtime_error(std::string(__func__) + ": value out of range");
#     108                 :          0 :     }
#     109                 :          0 :     return nChange;
#     110                 :          0 : }
#     111                 :            : 
#     112                 :            : CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const
#     113                 :    2269589 : {
#     114                 :    2269589 :     auto& amount = m_amounts[type];
#     115 [ -  + ][ +  + ]:    2269589 :     if (recalculate || !amount.m_cached[filter]) {
#                 [ +  + ]
#     116         [ +  + ]:      53135 :         amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter));
#     117                 :      53135 :         m_is_cache_empty = false;
#     118                 :      53135 :     }
#     119                 :    2269589 :     return amount.m_value[filter];
#     120                 :    2269589 : }
#     121                 :            : 
#     122                 :            : CAmount CWalletTx::GetCredit(const isminefilter& filter) const
#     123                 :        295 : {
#     124                 :            :     // Must wait until coinbase is safely deep enough in the chain before valuing it
#     125         [ +  + ]:        295 :     if (IsImmatureCoinBase())
#     126                 :         12 :         return 0;
#     127                 :            : 
#     128                 :        283 :     CAmount credit = 0;
#     129         [ +  - ]:        283 :     if (filter & ISMINE_SPENDABLE) {
#     130                 :            :         // GetBalance can assume transactions in mapWallet won't change
#     131                 :        283 :         credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE);
#     132                 :        283 :     }
#     133         [ +  + ]:        283 :     if (filter & ISMINE_WATCH_ONLY) {
#     134                 :         10 :         credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY);
#     135                 :         10 :     }
#     136                 :        283 :     return credit;
#     137                 :        283 : }
#     138                 :            : 
#     139                 :            : CAmount CWalletTx::GetDebit(const isminefilter& filter) const
#     140                 :    1913348 : {
#     141         [ +  + ]:    1913348 :     if (tx->vin.empty())
#     142                 :     799206 :         return 0;
#     143                 :            : 
#     144                 :    1114142 :     CAmount debit = 0;
#     145         [ +  + ]:    1114142 :     if (filter & ISMINE_SPENDABLE) {
#     146                 :    1096263 :         debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE);
#     147                 :    1096263 :     }
#     148         [ +  + ]:    1114142 :     if (filter & ISMINE_WATCH_ONLY) {
#     149                 :    1110313 :         debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY);
#     150                 :    1110313 :     }
#     151                 :    1114142 :     return debit;
#     152                 :    1114142 : }
#     153                 :            : 
#     154                 :            : CAmount CWalletTx::GetChange() const
#     155                 :          0 : {
#     156         [ #  # ]:          0 :     if (fChangeCached)
#     157                 :          0 :         return nChangeCached;
#     158                 :          0 :     nChangeCached = pwallet->GetChange(*tx);
#     159                 :          0 :     fChangeCached = true;
#     160                 :          0 :     return nChangeCached;
#     161                 :          0 : }
#     162                 :            : 
#     163                 :            : CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
#     164                 :     110763 : {
#     165 [ +  + ][ +  + ]:     110763 :     if (IsImmatureCoinBase() && IsInMainChain()) {
#     166                 :      31361 :         return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
#     167                 :      31361 :     }
#     168                 :            : 
#     169                 :      79402 :     return 0;
#     170                 :      79402 : }
#     171                 :            : 
#     172                 :            : CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
#     173                 :     110761 : {
#     174 [ +  + ][ +  + ]:     110761 :     if (IsImmatureCoinBase() && IsInMainChain()) {
#     175                 :      31359 :         return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
#     176                 :      31359 :     }
#     177                 :            : 
#     178                 :      79402 :     return 0;
#     179                 :      79402 : }
#     180                 :            : 
#     181                 :            : CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const
#     182                 :     221522 : {
#     183         [ -  + ]:     221522 :     if (pwallet == nullptr)
#     184                 :          0 :         return 0;
#     185                 :            : 
#     186                 :            :     // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
#     187 [ +  - ][ +  - ]:     221522 :     bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
#     188                 :            : 
#     189                 :            :     // Must wait until coinbase is safely deep enough in the chain before valuing it
#     190         [ +  + ]:     221522 :     if (IsImmatureCoinBase())
#     191                 :      62752 :         return 0;
#     192                 :            : 
#     193 [ +  - ][ +  + ]:     158770 :     if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
#         [ +  - ][ +  + ]
#     194                 :     122488 :         return m_amounts[AVAILABLE_CREDIT].m_value[filter];
#     195                 :     122488 :     }
#     196                 :            : 
#     197 [ +  + ][ +  + ]:      36282 :     bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
#     198                 :      36282 :     CAmount nCredit = 0;
#     199                 :      36282 :     uint256 hashTx = GetHash();
#     200         [ +  + ]:     115600 :     for (unsigned int i = 0; i < tx->vout.size(); i++)
#     201                 :      79318 :     {
#     202 [ +  + ][ +  + ]:      79318 :         if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsSpentKey(hashTx, i))) {
#                 [ +  + ]
#     203                 :      64172 :             const CTxOut &txout = tx->vout[i];
#     204                 :      64172 :             nCredit += pwallet->GetCredit(txout, filter);
#     205         [ -  + ]:      64172 :             if (!MoneyRange(nCredit))
#     206                 :          0 :                 throw std::runtime_error(std::string(__func__) + " : value out of range");
#     207                 :      64172 :         }
#     208                 :      79318 :     }
#     209                 :            : 
#     210         [ +  - ]:      36282 :     if (allow_cache) {
#     211                 :      36282 :         m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
#     212                 :      36282 :         m_is_cache_empty = false;
#     213                 :      36282 :     }
#     214                 :            : 
#     215                 :      36282 :     return nCredit;
#     216                 :      36282 : }
#     217                 :            : 
#     218                 :            : void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
#     219                 :            :                            std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const
#     220                 :      17877 : {
#     221                 :      17877 :     nFee = 0;
#     222                 :      17877 :     listReceived.clear();
#     223                 :      17877 :     listSent.clear();
#     224                 :            : 
#     225                 :            :     // Compute fee:
#     226                 :      17877 :     CAmount nDebit = GetDebit(filter);
#     227         [ +  + ]:      17877 :     if (nDebit > 0) // debit>0 means we signed/sent this transaction
#     228                 :        492 :     {
#     229                 :        492 :         CAmount nValueOut = tx->GetValueOut();
#     230                 :        492 :         nFee = nDebit - nValueOut;
#     231                 :        492 :     }
#     232                 :            : 
#     233                 :      17877 :     LOCK(pwallet->cs_wallet);
#     234                 :            :     // Sent/received.
#     235         [ +  + ]:      53648 :     for (unsigned int i = 0; i < tx->vout.size(); ++i)
#     236                 :      35771 :     {
#     237                 :      35771 :         const CTxOut& txout = tx->vout[i];
#     238                 :      35771 :         isminetype fIsMine = pwallet->IsMine(txout);
#     239                 :            :         // Only need to handle txouts if AT LEAST one of these is true:
#     240                 :            :         //   1) they debit from us (sent)
#     241                 :            :         //   2) the output is to us (received)
#     242         [ +  + ]:      35771 :         if (nDebit > 0)
#     243                 :        981 :         {
#     244                 :            :             // Don't report 'change' txouts
#     245         [ +  + ]:        981 :             if (pwallet->IsChange(txout))
#     246                 :        404 :                 continue;
#     247                 :      34790 :         }
#     248         [ +  + ]:      34790 :         else if (!(fIsMine & filter))
#     249                 :      17399 :             continue;
#     250                 :            : 
#     251                 :            :         // In either case, we need to get the destination address
#     252                 :      17968 :         CTxDestination address;
#     253                 :            : 
#     254 [ +  + ][ -  + ]:      17968 :         if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
#     255                 :          0 :         {
#     256                 :          0 :             pwallet->WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
#     257                 :          0 :                                     this->GetHash().ToString());
#     258                 :          0 :             address = CNoDestination();
#     259                 :          0 :         }
#     260                 :            : 
#     261                 :      17968 :         COutputEntry output = {address, txout.nValue, (int)i};
#     262                 :            : 
#     263                 :            :         // If we are debited by the transaction, add the output as a "sent" entry
#     264         [ +  + ]:      17968 :         if (nDebit > 0)
#     265                 :        577 :             listSent.push_back(output);
#     266                 :            : 
#     267                 :            :         // If we are receiving the output, add it as a "received" entry
#     268         [ +  + ]:      17968 :         if (fIsMine & filter)
#     269                 :      17603 :             listReceived.push_back(output);
#     270                 :      17968 :     }
#     271                 :            : 
#     272                 :      17877 : }
#     273                 :            : 
#     274                 :            : bool CWallet::IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const
#     275                 :    1132439 : {
#     276                 :    1132439 :     AssertLockHeld(cs_wallet);
#     277                 :            :     // Quick answer in most cases
#     278         [ +  + ]:    1132439 :     if (!chain().checkFinalTx(*wtx.tx)) return false;
#     279                 :    1132437 :     int nDepth = wtx.GetDepthInMainChain();
#     280         [ +  + ]:    1132437 :     if (nDepth >= 1) return true;
#     281         [ +  + ]:     172861 :     if (nDepth < 0) return false;
#     282                 :            :     // using wtx's cached debit
#     283 [ +  + ][ +  + ]:     172646 :     if (!m_spend_zero_conf_change || !wtx.IsFromMe(ISMINE_ALL)) return false;
#                 [ +  + ]
#     284                 :            : 
#     285                 :            :     // Don't trust unconfirmed transactions from us unless they are in the mempool.
#     286         [ +  + ]:     167727 :     if (!wtx.InMempool()) return false;
#     287                 :            : 
#     288                 :            :     // Trusted if all inputs are from us and are in the mempool:
#     289         [ +  + ]:     167630 :     for (const CTxIn& txin : wtx.tx->vin)
#     290                 :     182159 :     {
#     291                 :            :         // Transactions not sent by us: not trusted
#     292                 :     182159 :         const CWalletTx* parent = GetWalletTx(txin.prevout.hash);
#     293         [ -  + ]:     182159 :         if (parent == nullptr) return false;
#     294                 :     182159 :         const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
#     295                 :            :         // Check that this specific input being spent is trusted
#     296         [ +  + ]:     182159 :         if (IsMine(parentOut) != ISMINE_SPENDABLE) return false;
#     297                 :            :         // If we've already trusted this parent, continue
#     298         [ +  + ]:     182156 :         if (trusted_parents.count(parent->GetHash())) continue;
#     299                 :            :         // Recurse to check that the parent is also trusted
#     300         [ +  + ]:     144288 :         if (!IsTrusted(*parent, trusted_parents)) return false;
#     301                 :     144234 :         trusted_parents.insert(parent->GetHash());
#     302                 :     144234 :     }
#     303                 :     167630 :     return true;
#     304                 :     167630 : }
#     305                 :            : 
#     306                 :            : bool CWalletTx::IsTrusted() const
#     307                 :        944 : {
#     308                 :        944 :     std::set<uint256> trusted_parents;
#     309                 :        944 :     LOCK(pwallet->cs_wallet);
#     310                 :        944 :     return pwallet->IsTrusted(*this, trusted_parents);
#     311                 :        944 : }
#     312                 :            : 
#     313                 :            : CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) const
#     314                 :       2297 : {
#     315                 :       2297 :     Balance ret;
#     316         [ +  + ]:       2297 :     isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
#     317                 :       2297 :     {
#     318                 :       2297 :         LOCK(cs_wallet);
#     319                 :       2297 :         std::set<uint256> trusted_parents;
#     320         [ +  + ]:       2297 :         for (const auto& entry : mapWallet)
#     321                 :     110761 :         {
#     322                 :     110761 :             const CWalletTx& wtx = entry.second;
#     323                 :     110761 :             const bool is_trusted{IsTrusted(wtx, trusted_parents)};
#     324                 :     110761 :             const int tx_depth{wtx.GetDepthInMainChain()};
#     325                 :     110761 :             const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
#     326                 :     110761 :             const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
#     327 [ +  + ][ +  + ]:     110761 :             if (is_trusted && tx_depth >= min_depth) {
#     328                 :     109596 :                 ret.m_mine_trusted += tx_credit_mine;
#     329                 :     109596 :                 ret.m_watchonly_trusted += tx_credit_watchonly;
#     330                 :     109596 :             }
#     331 [ +  + ][ +  + ]:     110761 :             if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
#                 [ +  + ]
#     332                 :        863 :                 ret.m_mine_untrusted_pending += tx_credit_mine;
#     333                 :        863 :                 ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
#     334                 :        863 :             }
#     335                 :     110761 :             ret.m_mine_immature += wtx.GetImmatureCredit();
#     336                 :     110761 :             ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit();
#     337                 :     110761 :         }
#     338                 :       2297 :     }
#     339                 :       2297 :     return ret;
#     340                 :       2297 : }
#     341                 :            : 
#     342                 :            : std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() const
#     343                 :          4 : {
#     344                 :          4 :     std::map<CTxDestination, CAmount> balances;
#     345                 :            : 
#     346                 :          4 :     {
#     347                 :          4 :         LOCK(cs_wallet);
#     348                 :          4 :         std::set<uint256> trusted_parents;
#     349         [ +  + ]:          4 :         for (const auto& walletEntry : mapWallet)
#     350                 :        410 :         {
#     351                 :        410 :             const CWalletTx& wtx = walletEntry.second;
#     352                 :            : 
#     353         [ -  + ]:        410 :             if (!IsTrusted(wtx, trusted_parents))
#     354                 :          0 :                 continue;
#     355                 :            : 
#     356         [ +  + ]:        410 :             if (wtx.IsImmatureCoinBase())
#     357                 :        400 :                 continue;
#     358                 :            : 
#     359                 :         10 :             int nDepth = wtx.GetDepthInMainChain();
#     360 [ -  + ][ +  + ]:         10 :             if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1))
#     361                 :          0 :                 continue;
#     362                 :            : 
#     363         [ +  + ]:         28 :             for (unsigned int i = 0; i < wtx.tx->vout.size(); i++)
#     364                 :         18 :             {
#     365                 :         18 :                 CTxDestination addr;
#     366         [ +  + ]:         18 :                 if (!IsMine(wtx.tx->vout[i]))
#     367                 :         10 :                     continue;
#     368         [ -  + ]:          8 :                 if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr))
#     369                 :          0 :                     continue;
#     370                 :            : 
#     371         [ +  + ]:          8 :                 CAmount n = IsSpent(walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue;
#     372                 :          8 :                 balances[addr] += n;
#     373                 :          8 :             }
#     374                 :         10 :         }
#     375                 :          4 :     }
#     376                 :            : 
#     377                 :          4 :     return balances;
#     378                 :          4 : }
#     379                 :            : 
#     380                 :            : std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() const
#     381                 :          4 : {
#     382                 :          4 :     AssertLockHeld(cs_wallet);
#     383                 :          4 :     std::set< std::set<CTxDestination> > groupings;
#     384                 :          4 :     std::set<CTxDestination> grouping;
#     385                 :            : 
#     386         [ +  + ]:          4 :     for (const auto& walletEntry : mapWallet)
#     387                 :        410 :     {
#     388                 :        410 :         const CWalletTx& wtx = walletEntry.second;
#     389                 :            : 
#     390         [ +  - ]:        410 :         if (wtx.tx->vin.size() > 0)
#     391                 :        410 :         {
#     392                 :        410 :             bool any_mine = false;
#     393                 :            :             // group all input addresses with each other
#     394         [ +  + ]:        410 :             for (const CTxIn& txin : wtx.tx->vin)
#     395                 :        412 :             {
#     396                 :        412 :                 CTxDestination address;
#     397         [ +  + ]:        412 :                 if(!IsMine(txin)) /* If this input isn't mine, ignore it */
#     398                 :        408 :                     continue;
#     399         [ -  + ]:          4 :                 if(!ExtractDestination(mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
#     400                 :          0 :                     continue;
#     401                 :          4 :                 grouping.insert(address);
#     402                 :          4 :                 any_mine = true;
#     403                 :          4 :             }
#     404                 :            : 
#     405                 :            :             // group change with input addresses
#     406         [ +  + ]:        410 :             if (any_mine)
#     407                 :          2 :             {
#     408         [ +  + ]:          2 :                for (const CTxOut& txout : wtx.tx->vout)
#     409         [ -  + ]:          2 :                    if (IsChange(txout))
#     410                 :          0 :                    {
#     411                 :          0 :                        CTxDestination txoutAddr;
#     412         [ #  # ]:          0 :                        if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
#     413                 :          0 :                            continue;
#     414                 :          0 :                        grouping.insert(txoutAddr);
#     415                 :          0 :                    }
#     416                 :          2 :             }
#     417         [ +  + ]:        410 :             if (grouping.size() > 0)
#     418                 :          2 :             {
#     419                 :          2 :                 groupings.insert(grouping);
#     420                 :          2 :                 grouping.clear();
#     421                 :          2 :             }
#     422                 :        410 :         }
#     423                 :            : 
#     424                 :            :         // group lone addrs by themselves
#     425         [ +  + ]:        410 :         for (const auto& txout : wtx.tx->vout)
#     426         [ +  + ]:        818 :             if (IsMine(txout))
#     427                 :        408 :             {
#     428                 :        408 :                 CTxDestination address;
#     429         [ -  + ]:        408 :                 if(!ExtractDestination(txout.scriptPubKey, address))
#     430                 :          0 :                     continue;
#     431                 :        408 :                 grouping.insert(address);
#     432                 :        408 :                 groupings.insert(grouping);
#     433                 :        408 :                 grouping.clear();
#     434                 :        408 :             }
#     435                 :        410 :     }
#     436                 :            : 
#     437                 :          4 :     std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
#     438                 :          4 :     std::map< CTxDestination, std::set<CTxDestination>* > setmap;  // map addresses to the unique group containing it
#     439         [ +  + ]:          4 :     for (std::set<CTxDestination> _grouping : groupings)
#     440                 :         10 :     {
#     441                 :            :         // make a set of all the groups hit by this new group
#     442                 :         10 :         std::set< std::set<CTxDestination>* > hits;
#     443                 :         10 :         std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
#     444         [ +  + ]:         10 :         for (const CTxDestination& address : _grouping)
#     445         [ +  + ]:         12 :             if ((it = setmap.find(address)) != setmap.end())
#     446                 :          4 :                 hits.insert((*it).second);
#     447                 :            : 
#     448                 :            :         // merge all hit groups into a new single group and delete old groups
#     449                 :         10 :         std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
#     450         [ +  + ]:         10 :         for (std::set<CTxDestination>* hit : hits)
#     451                 :          4 :         {
#     452                 :          4 :             merged->insert(hit->begin(), hit->end());
#     453                 :          4 :             uniqueGroupings.erase(hit);
#     454                 :          4 :             delete hit;
#     455                 :          4 :         }
#     456                 :         10 :         uniqueGroupings.insert(merged);
#     457                 :            : 
#     458                 :            :         // update setmap
#     459         [ +  + ]:         10 :         for (const CTxDestination& element : *merged)
#     460                 :         14 :             setmap[element] = merged;
#     461                 :         10 :     }
#     462                 :            : 
#     463                 :          4 :     std::set< std::set<CTxDestination> > ret;
#     464         [ +  + ]:          4 :     for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
#     465                 :          6 :     {
#     466                 :          6 :         ret.insert(*uniqueGrouping);
#     467                 :          6 :         delete uniqueGrouping;
#     468                 :          6 :     }
#     469                 :            : 
#     470                 :          4 :     return ret;
#     471                 :          4 : }

Generated by: LCOV version 1.14