LCOV - code coverage report
Current view: top level - src/node - coinstats.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 113 121 93.4 %
Date: 2021-06-29 14:35:33 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: 63 86 73.3 %

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

Generated by: LCOV version 1.14