Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-06-01 16:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/zip/work/bitcoin/src/kernel/coinstats.cpp
Line
Count
Source
1
// Copyright (c) 2022-present 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 <kernel/coinstats.h>
6
7
#include <chain.h>
8
#include <coins.h>
9
#include <crypto/muhash.h>
10
#include <hash.h>
11
#include <node/blockstorage.h>
12
#include <primitives/transaction.h>
13
#include <script/script.h>
14
#include <span.h>
15
#include <streams.h>
16
#include <sync.h>
17
#include <uint256.h>
18
#include <util/check.h>
19
#include <util/log.h>
20
#include <util/overflow.h>
21
#include <validation.h>
22
23
#include <cstddef>
24
#include <map>
25
#include <memory>
26
#include <utility>
27
28
namespace kernel {
29
30
CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)
31
0
    : nHeight(block_height),
32
0
      hashBlock(block_hash) {}
33
34
// Database-independent metric indicating the UTXO set size
35
uint64_t GetBogoSize(const CScript& script_pub_key)
36
0
{
37
0
    return 32 /* txid */ +
38
0
           4 /* vout index */ +
39
0
           4 /* height + coinbase */ +
40
0
           8 /* amount */ +
41
0
           2 /* scriptPubKey len */ +
42
0
           script_pub_key.size() /* scriptPubKey */;
43
0
}
44
45
template <typename T>
46
static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
47
0
{
48
0
    ss << outpoint;
49
0
    ss << ((uint32_t{coin.nHeight} << 1) | uint32_t{coin.fCoinBase});
50
0
    ss << coin.out;
51
0
}
Unexecuted instantiation: coinstats.cpp:void kernel::TxOutSer<HashWriter>(HashWriter&, COutPoint const&, Coin const&)
Unexecuted instantiation: coinstats.cpp:void kernel::TxOutSer<DataStream>(DataStream&, COutPoint const&, Coin const&)
52
53
static void ApplyCoinHash(HashWriter& ss, const COutPoint& outpoint, const Coin& coin)
54
0
{
55
0
    TxOutSer(ss, outpoint, coin);
56
0
}
57
58
void ApplyCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
59
0
{
60
0
    DataStream ss{};
61
0
    TxOutSer(ss, outpoint, coin);
62
0
    muhash.Insert(MakeUCharSpan(ss));
63
0
}
64
65
void RemoveCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
66
0
{
67
0
    DataStream ss{};
68
0
    TxOutSer(ss, outpoint, coin);
69
0
    muhash.Remove(MakeUCharSpan(ss));
70
0
}
71
72
0
static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin& coin) {}
73
74
//! Warning: be very careful when changing this! assumeutxo and UTXO snapshot
75
//! validation commitments are reliant on the hash constructed by this
76
//! function.
77
//!
78
//! If the construction of this hash is changed, it will invalidate
79
//! existing UTXO snapshots. This will not result in any kind of consensus
80
//! failure, but it will force clients that were expecting to make use of
81
//! assumeutxo to do traditional IBD instead.
82
//!
83
//! It is also possible, though very unlikely, that a change in this
84
//! construction could cause a previously invalid (and potentially malicious)
85
//! UTXO snapshot to be considered valid.
86
template <typename T>
87
static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)
88
0
{
89
0
    for (auto it = outputs.begin(); it != outputs.end(); ++it) {
90
0
        COutPoint outpoint = COutPoint(hash, it->first);
91
0
        Coin coin = it->second;
92
0
        ApplyCoinHash(hash_obj, outpoint, coin);
93
0
    }
94
0
}
Unexecuted instantiation: coinstats.cpp:void kernel::ApplyHash<HashWriter>(HashWriter&, transaction_identifier<false> const&, std::map<unsigned int, Coin, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, Coin> > > const&)
Unexecuted instantiation: coinstats.cpp:void kernel::ApplyHash<MuHash3072>(MuHash3072&, transaction_identifier<false> const&, std::map<unsigned int, Coin, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, Coin> > > const&)
Unexecuted instantiation: coinstats.cpp:void kernel::ApplyHash<std::nullptr_t>(std::nullptr_t&, transaction_identifier<false> const&, std::map<unsigned int, Coin, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, Coin> > > const&)
95
96
static void ApplyStats(CCoinsStats& stats, const std::map<uint32_t, Coin>& outputs)
97
0
{
98
0
    assert(!outputs.empty());
99
0
    stats.nTransactions++;
100
0
    for (auto it = outputs.begin(); it != outputs.end(); ++it) {
101
0
        stats.nTransactionOutputs++;
102
0
        if (stats.total_amount.has_value()) {
103
0
            stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
104
0
        }
105
0
        stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
106
0
    }
107
0
}
108
109
//! Calculate statistics about the unspent transaction output set
110
template <typename T>
111
static std::optional<CCoinsStats> ComputeUTXOStats(T hash_obj, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
112
0
{
113
0
    std::unique_ptr<CCoinsViewCursor> pcursor;
114
0
    CBlockIndex* pindex;
115
0
    {
116
0
        LOCK(::cs_main);
Line
Count
Source
268
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(::cs_main);
Line
Count
Source
268
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(::cs_main);
Line
Count
Source
268
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
117
0
        pcursor = view->Cursor();
118
0
        pindex = blockman.LookupBlockIndex(pcursor->GetBestBlock());
119
0
    }
120
0
    assert(pcursor);
121
0
    CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
Line
Count
Source
116
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
    CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
Line
Count
Source
116
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
    CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
Line
Count
Source
116
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
122
123
0
    Txid prevkey;
124
0
    std::map<uint32_t, Coin> outputs;
125
0
    while (pcursor->Valid()) {
126
0
        if (interruption_point) interruption_point();
127
0
        COutPoint key;
128
0
        Coin coin;
129
0
        if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
130
0
            if (!outputs.empty() && key.hash != prevkey) {
131
0
                ApplyStats(stats, outputs);
132
0
                ApplyHash(hash_obj, prevkey, outputs);
133
0
                outputs.clear();
134
0
            }
135
0
            prevkey = key.hash;
136
0
            outputs[key.n] = std::move(coin);
137
0
            stats.coins_count++;
138
0
        } else {
139
0
            LogError("%s: unable to read value\n", __func__);
Line
Count
Source
127
0
#define LogError(...) detail_LogWithSrcLoc(BCLog::LogFlags::ALL, util::log::Level::Error, __VA_ARGS__)
Line
Count
Source
119
0
#define detail_LogWithSrcLoc(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
            LogError("%s: unable to read value\n", __func__);
Line
Count
Source
127
0
#define LogError(...) detail_LogWithSrcLoc(BCLog::LogFlags::ALL, util::log::Level::Error, __VA_ARGS__)
Line
Count
Source
119
0
#define detail_LogWithSrcLoc(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
            LogError("%s: unable to read value\n", __func__);
Line
Count
Source
127
0
#define LogError(...) detail_LogWithSrcLoc(BCLog::LogFlags::ALL, util::log::Level::Error, __VA_ARGS__)
Line
Count
Source
119
0
#define detail_LogWithSrcLoc(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
140
0
            return std::nullopt;
141
0
        }
142
0
        pcursor->Next();
143
0
    }
144
0
    if (!outputs.empty()) {
145
0
        ApplyStats(stats, outputs);
146
0
        ApplyHash(hash_obj, prevkey, outputs);
147
0
    }
148
149
0
    FinalizeHash(hash_obj, stats);
150
151
0
    stats.nDiskSize = view->EstimateSize();
152
0
    return stats;
153
0
}
Unexecuted instantiation: coinstats.cpp:std::optional<kernel::CCoinsStats> kernel::ComputeUTXOStats<HashWriter>(HashWriter, CCoinsView*, node::BlockManager&, std::function<void ()> const&)
Unexecuted instantiation: coinstats.cpp:std::optional<kernel::CCoinsStats> kernel::ComputeUTXOStats<MuHash3072>(MuHash3072, CCoinsView*, node::BlockManager&, std::function<void ()> const&)
Unexecuted instantiation: coinstats.cpp:std::optional<kernel::CCoinsStats> kernel::ComputeUTXOStats<std::nullptr_t>(std::nullptr_t, CCoinsView*, node::BlockManager&, std::function<void ()> const&)
154
155
std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
156
0
{
157
0
    return [&]() -> std::optional<CCoinsStats> {
158
0
        switch (hash_type) {
159
0
        case(CoinStatsHashType::HASH_SERIALIZED): {
160
0
            HashWriter ss{};
161
0
            return ComputeUTXOStats(ss, view, blockman, interruption_point);
162
0
        }
163
0
        case(CoinStatsHashType::MUHASH): {
164
0
            MuHash3072 muhash;
165
0
            return ComputeUTXOStats(muhash, view, blockman, interruption_point);
166
0
        }
167
0
        case(CoinStatsHashType::NONE): {
168
0
            return ComputeUTXOStats(nullptr, view, blockman, interruption_point);
169
0
        }
170
0
        } // no default case, so the compiler can warn about missing cases
171
0
        assert(false);
172
0
    }();
173
0
}
174
175
static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
176
0
{
177
0
    stats.hashSerialized = ss.GetHash();
178
0
}
179
static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
180
0
{
181
0
    uint256 out;
182
0
    muhash.Finalize(out);
183
0
    stats.hashSerialized = out;
184
0
}
185
0
static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
186
187
} // namespace kernel