Coverage Report

Created: 2026-09-01 13:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/cmpctblock.cpp
Line
Count
Source
1
// Copyright (c) 2026 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 <addrman.h>
6
#include <blockencodings.h>
7
#include <chain.h>
8
#include <chainparams.h>
9
#include <coins.h>
10
#include <consensus/amount.h>
11
#include <consensus/consensus.h>
12
#include <consensus/merkle.h>
13
#include <net.h>
14
#include <net_processing.h>
15
#include <netmessagemaker.h>
16
#include <node/blockstorage.h>
17
#include <policy/truc_policy.h>
18
#include <primitives/block.h>
19
#include <primitives/transaction.h>
20
#include <protocol.h>
21
#include <script/script.h>
22
#include <serialize.h>
23
#include <sync.h>
24
#include <test/fuzz/FuzzedDataProvider.h>
25
#include <test/fuzz/fuzz.h>
26
#include <test/fuzz/util.h>
27
#include <test/fuzz/util/net.h>
28
#include <test/util/net.h>
29
#include <test/util/random.h>
30
#include <test/util/script.h>
31
#include <test/util/setup_common.h>
32
#include <test/util/time.h>
33
#include <test/util/validation.h>
34
#include <txmempool.h>
35
#include <uint256.h>
36
#include <util/check.h>
37
#include <util/time.h>
38
#include <validation.h>
39
#include <validationinterface.h>
40
41
#include <boost/multi_index/detail/hash_index_iterator.hpp>
42
43
#include <cstddef>
44
#include <cstdint>
45
#include <functional>
46
#include <iterator>
47
#include <memory>
48
#include <optional>
49
#include <string>
50
#include <utility>
51
#include <vector>
52
53
namespace {
54
55
TestingSetup* g_setup;
56
57
//! Fee each created tx will pay.
58
const CAmount AMOUNT_FEE{1000};
59
//! Cached coinbases that each iteration can copy and use.
60
std::vector<std::pair<COutPoint, CAmount>> g_mature_coinbase;
61
//! Constant value used to create valid headers.
62
uint32_t g_nBits;
63
//! One for each block the fuzzer generates.
64
struct BlockInfo {
65
    std::shared_ptr<CBlock> block;
66
    uint256 hash;
67
    uint32_t height;
68
};
69
//! Used to access prefilledtxn and shorttxids.
70
class FuzzedCBlockHeaderAndShortTxIDs : public CBlockHeaderAndShortTxIDs
71
{
72
    using CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs;
73
74
public:
75
    void AddPrefilledTx(PrefilledTransaction&& prefilledtx)
76
2.93k
    {
77
2.93k
        prefilledtxn.push_back(std::move(prefilledtx));
78
2.93k
    }
79
80
    void RemoveCoinbasePrefill()
81
870
    {
82
870
        prefilledtxn.erase(prefilledtxn.begin());
83
870
    }
84
85
    void InsertCoinbaseShortTxID(uint64_t shorttxid)
86
870
    {
87
870
        shorttxids.insert(shorttxids.begin(), shorttxid);
88
870
    }
89
90
    void EraseShortTxIDs(size_t index)
91
2.93k
    {
92
2.93k
        shorttxids.erase(shorttxids.begin() + index);
93
2.93k
    }
94
95
1.62k
    size_t PrefilledTxCount() {
96
1.62k
        return prefilledtxn.size();
97
1.62k
    }
98
99
1.62k
    size_t ShortTxIDCount() {
100
1.62k
        return shorttxids.size();
101
1.62k
    }
102
};
103
104
105
} // namespace
106
107
extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
108
109
void initialize_cmpctblock()
110
0
{
111
0
    FakeNodeClock init_clock{}; // Uses the existing mock time
112
0
    static const auto testing_setup = MakeNoLogFileContext<TestingSetup>();
113
0
    g_setup = testing_setup.get();
114
0
    g_nBits = Params().GenesisBlock().nBits;
115
    // Replace validation_signals before creating chainman and mempool so they use it.
116
0
    testing_setup->m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<ImmediateBackgroundTaskRunner>());
117
0
    g_mature_coinbase = ResetChainmanAndMempool(*g_setup, init_clock);
118
0
}
119
120
FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock)
121
1.66k
{
122
1.66k
    SeedRandomStateForTest(SeedRand::ZEROS);
123
1.66k
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
124
125
1.66k
    FakeNodeClock node_clock{1610000000s}; // 2021-01-07, arbitrary
126
1.66k
    FakeSteadyClock steady_clock;
127
128
1.66k
    auto setup = g_setup;
129
1.66k
    auto& mempool = *setup->m_node.mempool;
130
1.66k
    auto& chainman = static_cast<TestChainstateManager&>(*setup->m_node.chainman);
131
1.66k
    chainman.ResetIbd();
132
1.66k
    chainman.DisableNextWrite();
133
1.66k
    const size_t initial_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
134
135
1.66k
    AddrMan addrman{*setup->m_node.netgroupman, /*deterministic=*/true, /*consistency_check_ratio=*/0};
136
1.66k
    auto& connman = *static_cast<ConnmanTestMsg*>(setup->m_node.connman.get());
137
1.66k
    auto peerman = PeerManager::make(connman, addrman,
138
1.66k
                                     /*banman=*/nullptr, chainman,
139
1.66k
                                     mempool, *setup->m_node.warnings,
140
1.66k
                                     PeerManager::Options{
141
1.66k
                                         .deterministic_rng = true,
142
1.66k
                                     });
143
1.66k
    connman.SetMsgProc(peerman.get());
144
145
1.66k
    setup->m_node.validation_signals->RegisterValidationInterface(peerman.get());
146
1.66k
    setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
147
148
1.66k
    LOCK(NetEventsInterface::g_msgproc_mutex);
149
150
1.66k
    std::vector<CNode*> peers;
151
8.31k
    for (int i = 0; i < 4; ++i) {
  Branch (151:21): [True: 6.64k, False: 1.66k]
152
6.64k
        peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, i).release());
153
6.64k
        CNode& p2p_node = *peers.back();
154
6.64k
        FillNode(fuzzed_data_provider, connman, p2p_node);
155
6.64k
        connman.AddTestNode(p2p_node);
156
6.64k
    }
157
158
    // Stores blocks generated this iteration.
159
1.66k
    std::vector<BlockInfo> info;
160
161
    // Coinbase UTXOs for this iteration.
162
1.66k
    std::vector<std::pair<COutPoint, CAmount>> mature_coinbase = g_mature_coinbase;
163
164
1.66k
    const uint64_t initial_sequence{WITH_LOCK(mempool.cs, return mempool.GetSequence())};
165
166
312k
    auto create_tx = [&]() -> CTransactionRef {
167
312k
        CMutableTransaction tx_mut;
168
312k
        tx_mut.version = fuzzed_data_provider.ConsumeBool() ? CTransaction::CURRENT_VERSION : TRUC_VERSION;
  Branch (168:26): [True: 306k, False: 5.71k]
169
312k
        tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
  Branch (169:28): [True: 306k, False: 5.91k]
170
171
        // Choose an outpoint from the mempool, created blocks, or coinbases.
172
312k
        CAmount amount_in;
173
312k
        COutPoint outpoint;
174
312k
        unsigned long mempool_size = mempool.size();
175
312k
        if (mempool_size != 0 && fuzzed_data_provider.ConsumeBool()) {
  Branch (175:13): [True: 192k, False: 119k]
  Branch (175:34): [True: 187k, False: 4.69k]
176
187k
            size_t random_idx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mempool_size - 1);
177
187k
            CTransactionRef tx = WITH_LOCK(mempool.cs, return mempool.txns_randomized[random_idx].second->GetSharedTx(););
178
187k
            outpoint = COutPoint(tx->GetHash(), 0);
179
187k
            amount_in = tx->vout[0].nValue;
180
187k
        } else if (info.size() != 0 && fuzzed_data_provider.ConsumeBool()) {
  Branch (180:20): [True: 121k, False: 3.40k]
  Branch (180:40): [True: 113k, False: 7.70k]
181
            // These blocks (and txs) may be invalid, use a spent output, or not be in the main chain.
182
113k
            auto info_it = info.begin();
183
113k
            std::advance(info_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1));
184
113k
            auto tx_it = info_it->block->vtx.begin();
185
113k
            std::advance(tx_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info_it->block->vtx.size() - 1));
186
113k
            outpoint = COutPoint(tx_it->get()->GetHash(), 0);
187
113k
            amount_in = tx_it->get()->vout[0].nValue;
188
113k
        } else {
189
11.1k
            auto coinbase_it = mature_coinbase.begin();
190
11.1k
            std::advance(coinbase_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mature_coinbase.size() - 1));
191
11.1k
            outpoint = coinbase_it->first;
192
11.1k
            amount_in = coinbase_it->second;
193
11.1k
        }
194
195
312k
        const auto sequence = ConsumeSequence(fuzzed_data_provider);
196
312k
        const auto script_sig = CScript{};
197
312k
        const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
198
199
312k
        CTxIn in;
200
312k
        in.prevout = outpoint;
201
312k
        in.nSequence = sequence;
202
312k
        in.scriptSig = script_sig;
203
312k
        in.scriptWitness.stack = script_wit_stack;
204
312k
        tx_mut.vin.push_back(in);
205
206
312k
        const CAmount amount_out = amount_in - AMOUNT_FEE;
207
312k
        tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
208
209
312k
        auto tx = MakeTransactionRef(tx_mut);
210
312k
        return tx;
211
312k
    };
212
213
33.3k
    auto create_block = [&]() {
214
33.3k
        uint256 prev;
215
33.3k
        uint32_t height;
216
217
33.3k
        if (info.size() == 0 || fuzzed_data_provider.ConsumeBool()) {
  Branch (217:13): [True: 1.22k, False: 32.1k]
  Branch (217:33): [True: 30.5k, False: 1.57k]
218
31.7k
            LOCK(cs_main);
219
31.7k
            prev = chainman.ActiveChain().Tip()->GetBlockHash();
220
31.7k
            height = chainman.ActiveChain().Height() + 1;
221
31.7k
        } else {
222
1.57k
            size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1);
223
1.57k
            prev = info[index].hash;
224
1.57k
            height = info[index].height + 1;
225
1.57k
        }
226
227
33.3k
        const auto new_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->GetMedianTimePast() + 1);
228
229
33.3k
        CBlockHeader header;
230
33.3k
        header.nNonce = 0;
231
33.3k
        header.hashPrevBlock = prev;
232
33.3k
        header.nBits = g_nBits;
233
33.3k
        header.nTime = new_time;
234
33.3k
        header.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>();
235
236
33.3k
        std::shared_ptr<CBlock> block = std::make_shared<CBlock>();
237
33.3k
        *block = header;
238
239
33.3k
        CMutableTransaction coinbase_tx;
240
33.3k
        coinbase_tx.vin.resize(1);
241
33.3k
        coinbase_tx.vin[0].prevout.SetNull();
242
33.3k
        coinbase_tx.vin[0].scriptSig = CScript() << height << OP_0;
243
33.3k
        coinbase_tx.vout.resize(1);
244
33.3k
        coinbase_tx.vout[0].scriptPubKey = CScript() << OP_TRUE;
245
33.3k
        coinbase_tx.vout[0].nValue = COIN;
246
33.3k
        block->vtx.push_back(MakeTransactionRef(coinbase_tx));
247
248
33.3k
        const auto mempool_size = mempool.size();
249
33.3k
        if (fuzzed_data_provider.ConsumeBool() && mempool_size != 0) {
  Branch (249:13): [True: 31.2k, False: 2.06k]
  Branch (249:51): [True: 13.7k, False: 17.5k]
250
            // Add txns from the mempool. Since we do not include parents, it may be an invalid block.
251
13.7k
            size_t num_txns = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, mempool_size);
252
13.7k
            size_t random_idx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mempool_size - 1);
253
254
13.7k
            LOCK(mempool.cs);
255
104k
            for (size_t i = random_idx; i < random_idx + num_txns; ++i) {
  Branch (255:41): [True: 90.9k, False: 13.7k]
256
90.9k
                CTransactionRef mempool_tx = mempool.txns_randomized[i % mempool_size].second->GetSharedTx();
257
90.9k
                block->vtx.push_back(mempool_tx);
258
90.9k
            }
259
13.7k
        }
260
261
        // Create and add (possibly invalid) txns that are not in the mempool.
262
33.3k
        if (fuzzed_data_provider.ConsumeBool()) {
  Branch (262:13): [True: 30.8k, False: 2.51k]
263
30.8k
            size_t new_txns = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 10);
264
196k
            for (size_t i = 0; i < new_txns; ++i) {
  Branch (264:32): [True: 166k, False: 30.8k]
265
166k
                CTransactionRef non_mempool_tx = create_tx();
266
166k
                block->vtx.push_back(non_mempool_tx);
267
166k
            }
268
30.8k
        }
269
270
33.3k
        CBlockIndex* pindexPrev{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(prev))};
271
33.3k
        chainman.GenerateCoinbaseCommitment(*block, pindexPrev);
272
273
33.3k
        bool mutated;
274
33.3k
        block->hashMerkleRoot = BlockMerkleRoot(*block, &mutated);
275
33.3k
        FinalizeHeader(*block, chainman);
276
277
33.3k
        BlockInfo block_info;
278
33.3k
        block_info.block = block;
279
33.3k
        block_info.hash = block->GetHash();
280
33.3k
        block_info.height = height;
281
282
33.3k
        return block_info;
283
33.3k
    };
284
285
383k
    LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 1000) {
286
383k
        CSerializedNetMsg net_msg;
287
383k
        bool sent_net_msg = true;
288
383k
        bool requested_hb = false;
289
383k
        bool sent_sendcmpct = false;
290
383k
        bool valid_sendcmpct = false;
291
292
383k
        CallOneOf(
293
383k
            fuzzed_data_provider,
294
383k
            [&]() {
295
                // Send a compact block.
296
69.5k
                std::shared_ptr<CBlock> cblock;
297
298
                // Pick an existing block or create a new block.
299
69.5k
                if (fuzzed_data_provider.ConsumeBool() && info.size() != 0) {
  Branch (299:21): [True: 66.9k, False: 2.59k]
  Branch (299:59): [True: 66.4k, False: 536]
300
66.4k
                    size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1);
301
66.4k
                    cblock = info[index].block;
302
66.4k
                } else {
303
3.13k
                    BlockInfo block_info = create_block();
304
3.13k
                    cblock = block_info.block;
305
3.13k
                    info.push_back(block_info);
306
3.13k
                }
307
308
69.5k
                uint64_t nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
309
69.5k
                FuzzedCBlockHeaderAndShortTxIDs cmpctblock(*cblock, nonce);
310
311
69.5k
                if (fuzzed_data_provider.ConsumeBool()) {
  Branch (311:21): [True: 67.9k, False: 1.62k]
312
67.9k
                    CBlockHeaderAndShortTxIDs base_cmpctblock = cmpctblock;
313
67.9k
                    net_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, base_cmpctblock);
314
67.9k
                    return;
315
67.9k
                }
316
317
1.62k
                int prev_idx = 0;
318
1.62k
                size_t num_erased = 1;
319
1.62k
                size_t num_txs = cblock->vtx.size();
320
321
9.76k
                for (size_t i = 0; i < num_txs; ++i) {
  Branch (321:36): [True: 8.13k, False: 1.62k]
322
8.13k
                    if (i == 0) {
  Branch (322:25): [True: 1.62k, False: 6.51k]
323
                        // Handle the coinbase specially. We either keep it prefilled or remove it.
324
1.62k
                        if (fuzzed_data_provider.ConsumeBool()) continue;
  Branch (324:29): [True: 752, False: 870]
325
326
                        // Remove the prefilled coinbase.
327
870
                        num_erased = 0;
328
870
                        uint64_t coinbase_shortid = cmpctblock.GetShortID(cblock->vtx[0]->GetWitnessHash());
329
870
                        cmpctblock.RemoveCoinbasePrefill();
330
870
                        cmpctblock.InsertCoinbaseShortTxID(coinbase_shortid);
331
870
                        continue;
332
1.62k
                    }
333
334
6.51k
                    if (fuzzed_data_provider.ConsumeBool()) continue;
  Branch (334:25): [True: 3.57k, False: 2.93k]
335
336
2.93k
                    uint16_t prefill_idx = num_erased == 0 ? i : i - prev_idx - 1;
  Branch (336:44): [True: 448, False: 2.48k]
337
2.93k
                    prev_idx = i;
338
2.93k
                    CTransactionRef txref = cblock->vtx[i];
339
2.93k
                    PrefilledTransaction prefilledtx = {/*index=*/prefill_idx, txref};
340
2.93k
                    cmpctblock.AddPrefilledTx(std::move(prefilledtx));
341
342
                    // Remove from shorttxids since we've prefilled. Subtract however many txs have been prefilled.
343
2.93k
                    cmpctblock.EraseShortTxIDs(i - num_erased);
344
2.93k
                    ++num_erased;
345
2.93k
                }
346
347
1.62k
                assert(cmpctblock.PrefilledTxCount() + cmpctblock.ShortTxIDCount() == num_txs);
  Branch (347:17): [True: 1.62k, False: 0]
348
349
1.62k
                CBlockHeaderAndShortTxIDs base_cmpctblock = cmpctblock;
350
1.62k
                net_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, base_cmpctblock);
351
1.62k
            },
352
383k
            [&]() {
353
                // Send a blocktxn message for an existing block (if one exists).
354
6.35k
                size_t num_blocks = info.size();
355
6.35k
                if (num_blocks == 0) {
  Branch (355:21): [True: 648, False: 5.70k]
356
648
                    sent_net_msg = false;
357
648
                    return;
358
648
                }
359
360
                // Fetch an existing block and randomly choose transactions to send over.
361
5.70k
                size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, num_blocks - 1);
362
5.70k
                const BlockInfo& block_info = info[index];
363
5.70k
                BlockTransactions block_txn;
364
5.70k
                block_txn.blockhash = block_info.hash;
365
5.70k
                std::shared_ptr<CBlock> cblock = block_info.block;
366
367
31.6k
                for (size_t i = 0; i < cblock->vtx.size(); i++) {
  Branch (367:36): [True: 25.9k, False: 5.70k]
368
25.9k
                    if (fuzzed_data_provider.ConsumeBool()) continue;
  Branch (368:25): [True: 23.7k, False: 2.23k]
369
370
2.23k
                    block_txn.txn.push_back(cblock->vtx[i]);
371
2.23k
                }
372
373
5.70k
                net_msg = NetMsg::Make(NetMsgType::BLOCKTXN, block_txn);
374
5.70k
            },
375
383k
            [&]() {
376
                // Send a headers message for an existing block (if one exists).
377
88.7k
                size_t num_blocks = info.size();
378
88.7k
                if (num_blocks == 0) {
  Branch (378:21): [True: 9.62k, False: 79.0k]
379
9.62k
                    sent_net_msg = false;
380
9.62k
                    return;
381
9.62k
                }
382
383
                // Choose an existing block and send a HEADERS message for it.
384
79.0k
                size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, num_blocks - 1);
385
79.0k
                CBlock block = *info[index].block;
386
79.0k
                block.vtx.clear(); // No tx in HEADERS.
387
79.0k
                std::vector<CBlock> headers;
388
79.0k
                headers.emplace_back(block);
389
390
79.0k
                net_msg = NetMsg::Make(NetMsgType::HEADERS, TX_WITH_WITNESS(headers));
391
79.0k
            },
392
383k
            [&]() {
393
                // Send a sendcmpct message, optionally setting hb mode.
394
23.0k
                bool hb = fuzzed_data_provider.ConsumeBool();
395
23.0k
                uint64_t version{fuzzed_data_provider.ConsumeBool() ? CMPCTBLOCKS_VERSION : fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
  Branch (395:34): [True: 22.3k, False: 707]
396
23.0k
                net_msg = NetMsg::Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/hb, /*version=*/version);
397
23.0k
                requested_hb = hb;
398
23.0k
                sent_sendcmpct = true;
399
23.0k
                valid_sendcmpct = version == CMPCTBLOCKS_VERSION;
400
23.0k
            },
401
383k
            [&]() {
402
                // Mine a block, but don't send it.
403
30.1k
                BlockInfo block_info = create_block();
404
30.1k
                info.push_back(block_info);
405
30.1k
                sent_net_msg = false;
406
30.1k
            },
407
383k
            [&]() {
408
                // Send a transaction.
409
146k
                CTransactionRef tx = create_tx();
410
146k
                net_msg = NetMsg::Make(NetMsgType::TX, TX_WITH_WITNESS(*tx));
411
146k
            },
412
383k
            [&]() {
413
                // Set mock time randomly or to tip's time.
414
19.7k
                if (fuzzed_data_provider.ConsumeBool()) {
  Branch (414:21): [True: 17.4k, False: 2.24k]
415
17.4k
                    node_clock.set(ConsumeTime(fuzzed_data_provider));
416
17.4k
                } else {
417
2.24k
                    const NodeSeconds tip_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->Time());
418
2.24k
                    node_clock.set(tip_time);
419
2.24k
                }
420
421
19.7k
                sent_net_msg = false;
422
19.7k
            });
423
424
383k
        if (!sent_net_msg) {
  Branch (424:13): [True: 60.1k, False: 323k]
425
60.1k
            continue;
426
60.1k
        }
427
428
323k
        CNode& random_node = *PickValue(fuzzed_data_provider, peers);
429
323k
        connman.FlushSendBuffer(random_node);
430
323k
        (void)connman.ReceiveMsgFrom(random_node, std::move(net_msg));
431
432
323k
        bool more_work{true};
433
647k
        while (more_work) {
  Branch (433:16): [True: 324k, False: 323k]
434
324k
            random_node.fPauseSend = false;
435
436
324k
            more_work = connman.ProcessMessagesOnce(random_node);
437
324k
            peerman->SendMessages(random_node);
438
324k
        }
439
440
323k
        std::vector<CNodeStats> stats;
441
323k
        connman.GetNodeStats(stats);
442
443
        // We should have at maximum 3 HB peers.
444
323k
        int num_hb = 0;
445
1.29M
        for (const CNodeStats& stat : stats) {
  Branch (445:37): [True: 1.29M, False: 323k]
446
1.29M
            if (stat.m_bip152_highbandwidth_to) {
  Branch (446:17): [True: 3.26k, False: 1.29M]
447
                // HB peers cannot be feelers or other "special" connections (besides addr-fetch).
448
3.26k
                CNode* hb_peer = peers[stat.nodeid];
449
3.26k
                if (!hb_peer->fDisconnect) num_hb += 1;
  Branch (449:21): [True: 3.16k, False: 105]
450
3.26k
                assert(hb_peer->IsInboundConn() || hb_peer->IsOutboundOrBlockRelayConn() || hb_peer->IsManualConn() || hb_peer->IsAddrFetchConn());
  Branch (450:17): [True: 689, False: 2.57k]
  Branch (450:17): [True: 1.14k, False: 1.43k]
  Branch (450:17): [True: 1.34k, False: 85]
  Branch (450:17): [True: 85, False: 0]
  Branch (450:17): [True: 3.26k, False: 0]
451
3.26k
            }
452
1.29M
        }
453
323k
        assert(num_hb <= 3);
  Branch (453:9): [True: 323k, False: 0]
454
455
323k
        if (sent_sendcmpct && !random_node.fDisconnect) {
  Branch (455:13): [True: 23.0k, False: 300k]
  Branch (455:31): [True: 21.0k, False: 2.05k]
456
            // If the fuzzer sent SENDCMPCT with proper version, check the node's state matches what it sent.
457
21.0k
            const CNodeStats& random_node_stats = stats[random_node.GetId()];
458
21.0k
            if (valid_sendcmpct) assert(random_node_stats.m_bip152_highbandwidth_from == requested_hb);
  Branch (458:17): [True: 20.4k, False: 628]
  Branch (458:34): [True: 20.4k, False: 0]
459
21.0k
        }
460
323k
    }
461
462
1.66k
    setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
463
1.66k
    setup->m_node.validation_signals->UnregisterAllValidationInterfaces();
464
1.66k
    connman.StopNodes();
465
466
1.66k
    const size_t end_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
467
1.66k
    const uint64_t end_sequence{WITH_LOCK(mempool.cs, return mempool.GetSequence())};
468
469
1.66k
    if (initial_index_size != end_index_size || initial_sequence != end_sequence) {
  Branch (469:9): [True: 944, False: 718]
  Branch (469:49): [True: 0, False: 718]
470
944
        MakeRandDeterministicDANGEROUS(uint256::ZERO);
471
944
        g_mature_coinbase = ResetChainmanAndMempool(*g_setup, node_clock);
472
944
    }
473
1.66k
}