fuzz coverage

Coverage Report

Created: 2025-06-01 19:34

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