Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

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