LCOV - code coverage report
Current view: top level - src/node - coinstats.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 112 120 93.3 %
Date: 2022-04-21 14:51:19 Functions: 16 16 100.0 %
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: 62 88 70.5 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <node/coinstats.h>
#       7                 :            : 
#       8                 :            : #include <coins.h>
#       9                 :            : #include <crypto/muhash.h>
#      10                 :            : #include <hash.h>
#      11                 :            : #include <index/coinstatsindex.h>
#      12                 :            : #include <serialize.h>
#      13                 :            : #include <uint256.h>
#      14                 :            : #include <util/overflow.h>
#      15                 :            : #include <util/system.h>
#      16                 :            : #include <validation.h>
#      17                 :            : 
#      18                 :            : #include <map>
#      19                 :            : 
#      20                 :            : namespace node {
#      21                 :            : // Database-independent metric indicating the UTXO set size
#      22                 :            : uint64_t GetBogoSize(const CScript& script_pub_key)
#      23                 :       4246 : {
#      24                 :       4246 :     return 32 /* txid */ +
#      25                 :       4246 :            4 /* vout index */ +
#      26                 :       4246 :            4 /* height + coinbase */ +
#      27                 :       4246 :            8 /* amount */ +
#      28                 :       4246 :            2 /* scriptPubKey len */ +
#      29                 :       4246 :            script_pub_key.size() /* scriptPubKey */;
#      30                 :       4246 : }
#      31                 :            : 
#      32                 :       1518 : CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
#      33                 :       1518 :     CDataStream ss(SER_DISK, PROTOCOL_VERSION);
#      34                 :       1518 :     ss << outpoint;
#      35                 :       1518 :     ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
#      36                 :       1518 :     ss << coin.out;
#      37                 :       1518 :     return ss;
#      38                 :       1518 : }
#      39                 :            : 
#      40                 :            : //! Warning: be very careful when changing this! assumeutxo and UTXO snapshot
#      41                 :            : //! validation commitments are reliant on the hash constructed by this
#      42                 :            : //! function.
#      43                 :            : //!
#      44                 :            : //! If the construction of this hash is changed, it will invalidate
#      45                 :            : //! existing UTXO snapshots. This will not result in any kind of consensus
#      46                 :            : //! failure, but it will force clients that were expecting to make use of
#      47                 :            : //! assumeutxo to do traditional IBD instead.
#      48                 :            : //!
#      49                 :            : //! It is also possible, though very unlikely, that a change in this
#      50                 :            : //! construction could cause a previously invalid (and potentially malicious)
#      51                 :            : //! UTXO snapshot to be considered valid.
#      52                 :            : static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
#      53                 :       2411 : {
#      54         [ +  + ]:       4837 :     for (auto it = outputs.begin(); it != outputs.end(); ++it) {
#      55         [ +  + ]:       2426 :         if (it == outputs.begin()) {
#      56                 :       2411 :             ss << hash;
#      57         [ +  - ]:       2411 :             ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
#      58                 :       2411 :         }
#      59                 :            : 
#      60                 :       2426 :         ss << VARINT(it->first + 1);
#      61                 :       2426 :         ss << it->second.out.scriptPubKey;
#      62                 :       2426 :         ss << VARINT_MODE(it->second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
#      63                 :            : 
#      64         [ +  + ]:       2426 :         if (it == std::prev(outputs.end())) {
#      65                 :       2411 :             ss << VARINT(0u);
#      66                 :       2411 :         }
#      67                 :       2426 :     }
#      68                 :       2411 : }
#      69                 :            : 
#      70                 :        302 : static void ApplyHash(std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs) {}
#      71                 :            : 
#      72                 :            : static void ApplyHash(MuHash3072& muhash, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
#      73                 :        734 : {
#      74         [ +  + ]:       1471 :     for (auto it = outputs.begin(); it != outputs.end(); ++it) {
#      75                 :        737 :         COutPoint outpoint = COutPoint(hash, it->first);
#      76                 :        737 :         Coin coin = it->second;
#      77                 :        737 :         muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
#      78                 :        737 :     }
#      79                 :        734 : }
#      80                 :            : 
#      81                 :            : static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
#      82                 :       3447 : {
#      83                 :       3447 :     assert(!outputs.empty());
#      84                 :          0 :     stats.nTransactions++;
#      85         [ +  + ]:       6912 :     for (auto it = outputs.begin(); it != outputs.end(); ++it) {
#      86                 :       3465 :         stats.nTransactionOutputs++;
#      87         [ +  - ]:       3465 :         if (stats.total_amount.has_value()) {
#      88                 :       3465 :             stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
#      89                 :       3465 :         }
#      90                 :       3465 :         stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
#      91                 :       3465 :     }
#      92                 :       3447 : }
#      93                 :            : 
#      94                 :            : //! Calculate statistics about the unspent transaction output set
#      95                 :            : template <typename T>
#      96                 :            : static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point, const CBlockIndex* pindex)
#      97                 :         69 : {
#      98                 :         69 :     std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
#      99                 :         69 :     assert(pcursor);
#     100                 :            : 
#     101 [ -  + ][ +  + ]:         69 :     if (!pindex) {
#                 [ -  + ]
#     102                 :         13 :         LOCK(cs_main);
#     103                 :         13 :         pindex = blockman.LookupBlockIndex(view->GetBestBlock());
#     104                 :         13 :     }
#     105                 :         69 :     stats.nHeight = Assert(pindex)->nHeight;
#     106                 :         69 :     stats.hashBlock = pindex->GetBlockHash();
#     107                 :            : 
#     108                 :            :     // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
#     109 [ -  + ][ -  + ]:         69 :     if ((stats.m_hash_type == CoinStatsHashType::MUHASH || stats.m_hash_type == CoinStatsHashType::NONE) && g_coin_stats_index && stats.index_requested) {
#         [ +  - ][ #  # ]
#         [ -  + ][ +  - ]
#         [ #  # ][ +  + ]
#         [ +  + ][ #  # ]
#         [ +  + ][ +  - ]
#     110                 :         42 :         stats.index_used = true;
#     111                 :         42 :         return g_coin_stats_index->LookUpStats(pindex, stats);
#     112                 :         42 :     }
#     113                 :            : 
#     114                 :         27 :     PrepareHash(hash_obj, stats);
#     115                 :            : 
#     116                 :         27 :     uint256 prevkey;
#     117                 :         27 :     std::map<uint32_t, Coin> outputs;
#     118 [ +  + ][ +  + ]:       3492 :     while (pcursor->Valid()) {
#                 [ +  + ]
#     119                 :       3465 :         interruption_point();
#     120                 :       3465 :         COutPoint key;
#     121                 :       3465 :         Coin coin;
#     122 [ +  - ][ +  - ]:       3465 :         if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
#         [ +  - ][ +  - ]
#         [ +  - ][ +  - ]
#     123 [ +  + ][ +  + ]:       3465 :             if (!outputs.empty() && key.hash != prevkey) {
#         [ +  + ][ +  + ]
#         [ +  + ][ +  - ]
#     124                 :       3421 :                 ApplyStats(stats, prevkey, outputs);
#     125                 :       3421 :                 ApplyHash(hash_obj, prevkey, outputs);
#     126                 :       3421 :                 outputs.clear();
#     127                 :       3421 :             }
#     128                 :       3465 :             prevkey = key.hash;
#     129                 :       3465 :             outputs[key.n] = std::move(coin);
#     130                 :       3465 :             stats.coins_count++;
#     131                 :       3465 :         } else {
#     132                 :          0 :             return error("%s: unable to read value", __func__);
#     133                 :          0 :         }
#     134                 :       3465 :         pcursor->Next();
#     135                 :       3465 :     }
#     136 [ +  + ][ +  - ]:         27 :     if (!outputs.empty()) {
#                 [ +  - ]
#     137                 :         26 :         ApplyStats(stats, prevkey, outputs);
#     138                 :         26 :         ApplyHash(hash_obj, prevkey, outputs);
#     139                 :         26 :     }
#     140                 :            : 
#     141                 :         27 :     FinalizeHash(hash_obj, stats);
#     142                 :            : 
#     143                 :         27 :     stats.nDiskSize = view->EstimateSize();
#     144                 :         27 :     return true;
#     145                 :         27 : }
#     146                 :            : 
#     147                 :            : bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const std::function<void()>& interruption_point, const CBlockIndex* pindex)
#     148                 :         69 : {
#     149         [ -  + ]:         69 :     switch (stats.m_hash_type) {
#     150         [ +  + ]:         19 :     case(CoinStatsHashType::HASH_SERIALIZED): {
#     151                 :         19 :         CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
#     152                 :         19 :         return GetUTXOStats(view, blockman, stats, ss, interruption_point, pindex);
#     153                 :          0 :     }
#     154         [ +  + ]:         35 :     case(CoinStatsHashType::MUHASH): {
#     155                 :         35 :         MuHash3072 muhash;
#     156                 :         35 :         return GetUTXOStats(view, blockman, stats, muhash, interruption_point, pindex);
#     157                 :          0 :     }
#     158         [ +  + ]:         15 :     case(CoinStatsHashType::NONE): {
#     159                 :         15 :         return GetUTXOStats(view, blockman, stats, nullptr, interruption_point, pindex);
#     160                 :          0 :     }
#     161                 :         69 :     } // no default case, so the compiler can warn about missing cases
#     162                 :          0 :     assert(false);
#     163                 :          0 : }
#     164                 :            : 
#     165                 :            : // The legacy hash serializes the hashBlock
#     166                 :            : static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
#     167                 :         19 : {
#     168                 :         19 :     ss << stats.hashBlock;
#     169                 :         19 : }
#     170                 :            : // MuHash does not need the prepare step
#     171                 :          6 : static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
#     172                 :          2 : static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
#     173                 :            : 
#     174                 :            : static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
#     175                 :         19 : {
#     176                 :         19 :     stats.hashSerialized = ss.GetHash();
#     177                 :         19 : }
#     178                 :            : static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
#     179                 :          6 : {
#     180                 :          6 :     uint256 out;
#     181                 :          6 :     muhash.Finalize(out);
#     182                 :          6 :     stats.hashSerialized = out;
#     183                 :          6 : }
#     184                 :          2 : static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
#     185                 :            : } // namespace node

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a