Branch data Line data Source code
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 : 148169 : struct BlockInfo {
[ - + + -
- - + - -
- - - ]
65 : : std::shared_ptr<CBlock> block;
66 : : uint256 hash;
67 : : uint32_t height;
68 : : };
69 : : //! Used to access prefilledtxn and shorttxids.
70 : 0 : class FuzzedCBlockHeaderAndShortTxIDs : public CBlockHeaderAndShortTxIDs
71 : : {
72 [ + - ]: 94742 : using CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs;
73 : :
74 : : public:
75 : 4068 : void AddPrefilledTx(PrefilledTransaction&& prefilledtx)
76 : : {
77 : 8136 : prefilledtxn.push_back(std::move(prefilledtx));
78 : 4068 : }
79 : :
80 : 1257 : void RemoveCoinbasePrefill()
81 : : {
82 : 1257 : prefilledtxn.erase(prefilledtxn.begin());
83 : 1257 : }
84 : :
85 : 1257 : void InsertCoinbaseShortTxID(uint64_t shorttxid)
86 : : {
87 : 1257 : shorttxids.insert(shorttxids.begin(), shorttxid);
88 : 1257 : }
89 : :
90 : 4068 : void EraseShortTxIDs(size_t index)
91 : : {
92 : 4068 : shorttxids.erase(shorttxids.begin() + index);
93 : 4068 : }
94 : :
95 : 2486 : size_t PrefilledTxCount() {
96 : 4972 : return prefilledtxn.size();
97 : : }
98 : :
99 : 2486 : size_t ShortTxIDCount() {
100 : 4972 : return shorttxids.size();
101 : : }
102 : : };
103 : :
104 : :
105 : : } // namespace
106 : :
107 : : extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
108 : :
109 : 1 : void initialize_cmpctblock()
110 : : {
111 : 1 : FakeNodeClock init_clock{}; // Uses the existing mock time
112 [ + - + - : 1 : static const auto testing_setup = MakeNoLogFileContext<TestingSetup>();
+ - ]
113 [ + - ]: 1 : g_setup = testing_setup.get();
114 [ + - ]: 1 : g_nBits = Params().GenesisBlock().nBits;
115 : : // Replace validation_signals before creating chainman and mempool so they use it.
116 [ + - + - ]: 1 : testing_setup->m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<ImmediateBackgroundTaskRunner>());
117 [ + - ]: 2 : g_mature_coinbase = ResetChainmanAndMempool(*g_setup, init_clock);
118 : 1 : }
119 : :
120 [ + - ]: 3995 : FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock)
121 : : {
122 : 3519 : SeedRandomStateForTest(SeedRand::ZEROS);
123 : 3519 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
124 : :
125 : 3519 : FakeNodeClock node_clock{1610000000s}; // 2021-01-07, arbitrary
126 [ + - ]: 3519 : FakeSteadyClock steady_clock;
127 : :
128 : 3519 : auto setup = g_setup;
129 [ + - ]: 3519 : auto& mempool = *setup->m_node.mempool;
130 : 3519 : auto& chainman = static_cast<TestChainstateManager&>(*setup->m_node.chainman);
131 [ + - ]: 3519 : chainman.ResetIbd();
132 [ + - ]: 3519 : chainman.DisableNextWrite();
133 [ + - ][ + - ]: 7038 : const size_t initial_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
134 : :
135 [ + - ]: 3519 : AddrMan addrman{*setup->m_node.netgroupman, /*deterministic=*/true, /*consistency_check_ratio=*/0};
136 [ + - ]: 3519 : auto& connman = *static_cast<ConnmanTestMsg*>(setup->m_node.connman.get());
137 : 3519 : auto peerman = PeerManager::make(connman, addrman,
138 : : /*banman=*/nullptr, chainman,
139 : 3519 : mempool, *setup->m_node.warnings,
140 : : PeerManager::Options{
141 : : .deterministic_rng = true,
142 [ + - ]: 3519 : });
143 [ + - ]: 3519 : connman.SetMsgProc(peerman.get());
144 : :
145 [ + - ]: 3519 : setup->m_node.validation_signals->RegisterValidationInterface(peerman.get());
146 [ + - ]: 3519 : setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
147 : :
148 [ + - ]: 3519 : LOCK(NetEventsInterface::g_msgproc_mutex);
149 : :
150 : 3519 : std::vector<CNode*> peers;
151 [ + + ]: 17595 : for (int i = 0; i < 4; ++i) {
152 [ + - ]: 14076 : peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, i).release());
153 : 14076 : CNode& p2p_node = *peers.back();
154 : 14076 : FillNode(fuzzed_data_provider, connman, p2p_node);
155 [ + - ]: 14076 : connman.AddTestNode(p2p_node);
156 : : }
157 : :
158 : : // Stores blocks generated this iteration.
159 : 3519 : std::vector<BlockInfo> info;
160 : :
161 : : // Coinbase UTXOs for this iteration.
162 [ + - ]: 3519 : std::vector<std::pair<COutPoint, CAmount>> mature_coinbase = g_mature_coinbase;
163 : :
164 [ + - ][ + - ]: 7038 : const uint64_t initial_sequence{WITH_LOCK(mempool.cs, return mempool.GetSequence())};
165 : :
166 : 376752 : auto create_tx = [&]() -> CTransactionRef {
167 : 373233 : CMutableTransaction tx_mut;
168 [ + + ]: 373233 : tx_mut.version = fuzzed_data_provider.ConsumeBool() ? CTransaction::CURRENT_VERSION : TRUC_VERSION;
169 [ + + ]: 373233 : tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
170 : :
171 : : // Choose an outpoint from the mempool, created blocks, or coinbases.
172 : 373233 : CAmount amount_in;
173 [ + - ]: 373233 : COutPoint outpoint;
174 [ + - ]: 373233 : unsigned long mempool_size = mempool.size();
175 [ + + + + ]: 373233 : if (mempool_size != 0 && fuzzed_data_provider.ConsumeBool()) {
176 : 197596 : size_t random_idx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mempool_size - 1);
177 [ + - + - : 592788 : CTransactionRef tx = WITH_LOCK(mempool.cs, return mempool.txns_randomized[random_idx].second->GetSharedTx(););
+ - ]
178 [ + - ]: 197596 : outpoint = COutPoint(tx->GetHash(), 0);
179 [ + - ]: 197596 : amount_in = tx->vout[0].nValue;
180 [ - + + + : 373233 : } else if (info.size() != 0 && fuzzed_data_provider.ConsumeBool()) {
+ + ]
181 : : // These blocks (and txs) may be invalid, use a spent output, or not be in the main chain.
182 [ - + ]: 156285 : auto info_it = info.begin();
183 [ - + ]: 156285 : std::advance(info_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1));
184 [ - + ]: 156285 : auto tx_it = info_it->block->vtx.begin();
185 [ - + ]: 156285 : std::advance(tx_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info_it->block->vtx.size() - 1));
186 : 156285 : outpoint = COutPoint(tx_it->get()->GetHash(), 0);
187 : 156285 : amount_in = tx_it->get()->vout[0].nValue;
188 : : } else {
189 [ - + ]: 19352 : auto coinbase_it = mature_coinbase.begin();
190 [ - + ]: 19352 : std::advance(coinbase_it, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mature_coinbase.size() - 1));
191 : 19352 : outpoint = coinbase_it->first;
192 : 19352 : amount_in = coinbase_it->second;
193 : : }
194 : :
195 : 373233 : const auto sequence = ConsumeSequence(fuzzed_data_provider);
196 : 373233 : const auto script_sig = CScript{};
197 [ - + + + : 746466 : const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
- - ]
198 : :
199 : 373233 : CTxIn in;
200 : 373233 : in.prevout = outpoint;
201 : 373233 : in.nSequence = sequence;
202 : 373233 : in.scriptSig = script_sig;
203 [ + - ]: 373233 : in.scriptWitness.stack = script_wit_stack;
204 [ + - ]: 373233 : tx_mut.vin.push_back(in);
205 : :
206 : 373233 : const CAmount amount_out = amount_in - AMOUNT_FEE;
207 [ + - ]: 373233 : tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
208 : :
209 [ + - ]: 373233 : auto tx = MakeTransactionRef(tx_mut);
210 : 373233 : return tx;
211 [ + - ]: 1123218 : };
212 : :
213 : 46379 : auto create_block = [&]() {
214 : 42860 : uint256 prev;
215 : 42860 : uint32_t height;
216 : :
217 [ - + + + : 42860 : if (info.size() == 0 || fuzzed_data_provider.ConsumeBool()) {
+ + ]
218 : 40483 : LOCK(cs_main);
219 [ + - - + ]: 80966 : prev = chainman.ActiveChain().Tip()->GetBlockHash();
220 [ + - - + : 40483 : height = chainman.ActiveChain().Height() + 1;
+ - ]
221 : 40483 : } else {
222 [ - + ]: 2377 : size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1);
223 : 2377 : prev = info[index].hash;
224 : 2377 : height = info[index].height + 1;
225 : : }
226 : :
227 [ + - - + : 171440 : const auto new_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->GetMedianTimePast() + 1);
+ - ]
228 : :
229 : 42860 : CBlockHeader header;
230 : 42860 : header.nNonce = 0;
231 : 42860 : header.hashPrevBlock = prev;
232 : 42860 : header.nBits = g_nBits;
233 : 42860 : header.nTime = new_time;
234 : 42860 : header.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>();
235 : :
236 : 42860 : std::shared_ptr<CBlock> block = std::make_shared<CBlock>();
237 : 42860 : *block = header;
238 : :
239 [ + - ]: 42860 : CMutableTransaction coinbase_tx;
240 [ + - ]: 42860 : coinbase_tx.vin.resize(1);
241 : 42860 : coinbase_tx.vin[0].prevout.SetNull();
242 [ + - + - ]: 42860 : coinbase_tx.vin[0].scriptSig = CScript() << height << OP_0;
243 [ + - ]: 42860 : coinbase_tx.vout.resize(1);
244 [ + - ]: 42860 : coinbase_tx.vout[0].scriptPubKey = CScript() << OP_TRUE;
245 [ + - ]: 42860 : coinbase_tx.vout[0].nValue = COIN;
246 [ + - + - : 85720 : block->vtx.push_back(MakeTransactionRef(coinbase_tx));
- + ]
247 : :
248 [ + - ]: 42860 : const auto mempool_size = mempool.size();
249 [ + + + + ]: 42860 : if (fuzzed_data_provider.ConsumeBool() && mempool_size != 0) {
250 : : // Add txns from the mempool. Since we do not include parents, it may be an invalid block.
251 : 14915 : size_t num_txns = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, mempool_size);
252 : 14915 : size_t random_idx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, mempool_size - 1);
253 : :
254 [ + - ]: 14915 : LOCK(mempool.cs);
255 [ + + ]: 112044 : for (size_t i = random_idx; i < random_idx + num_txns; ++i) {
256 [ + - ]: 97129 : CTransactionRef mempool_tx = mempool.txns_randomized[i % mempool_size].second->GetSharedTx();
257 [ + - ]: 97129 : block->vtx.push_back(mempool_tx);
258 : 97129 : }
259 : 14915 : }
260 : :
261 : : // Create and add (possibly invalid) txns that are not in the mempool.
262 [ + + ]: 42860 : if (fuzzed_data_provider.ConsumeBool()) {
263 : 38590 : size_t new_txns = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 10);
264 [ + + ]: 248372 : for (size_t i = 0; i < new_txns; ++i) {
265 [ + - ]: 209782 : CTransactionRef non_mempool_tx = create_tx();
266 [ + - ]: 209782 : block->vtx.push_back(non_mempool_tx);
267 : 209782 : }
268 : : }
269 : :
270 [ + - + - : 128580 : CBlockIndex* pindexPrev{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(prev))};
+ - ]
271 [ + - ]: 42860 : chainman.GenerateCoinbaseCommitment(*block, pindexPrev);
272 : :
273 : 42860 : bool mutated;
274 [ + - ]: 42860 : block->hashMerkleRoot = BlockMerkleRoot(*block, &mutated);
275 [ + - ]: 42860 : FinalizeHeader(*block, chainman);
276 : :
277 : 42860 : BlockInfo block_info;
278 : 42860 : block_info.block = block;
279 [ + - ]: 42860 : block_info.hash = block->GetHash();
280 : 42860 : block_info.height = height;
281 : :
282 : 42860 : return block_info;
283 [ + - ]: 89239 : };
284 : :
285 [ + + + + ]: 499826 : LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 1000) {
286 [ + - ]: 496307 : CSerializedNetMsg net_msg;
287 : 496307 : bool sent_net_msg = true;
288 : 496307 : bool requested_hb = false;
289 : 496307 : bool sent_sendcmpct = false;
290 : 496307 : bool valid_sendcmpct = false;
291 : :
292 [ + - ]: 496307 : CallOneOf(
293 : : fuzzed_data_provider,
294 : 94742 : [&]() {
295 : : // Send a compact block.
296 : 94742 : std::shared_ptr<CBlock> cblock;
297 : :
298 : : // Pick an existing block or create a new block.
299 [ + + - + : 94742 : if (fuzzed_data_provider.ConsumeBool() && info.size() != 0) {
+ + ]
300 : 89654 : size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, info.size() - 1);
301 : 89654 : cblock = info[index].block;
302 : : } else {
303 [ + - ]: 5088 : BlockInfo block_info = create_block();
304 : 5088 : cblock = block_info.block;
305 [ + - ]: 5088 : info.push_back(block_info);
306 : 5088 : }
307 : :
308 : 94742 : uint64_t nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
309 [ + - ]: 94742 : FuzzedCBlockHeaderAndShortTxIDs cmpctblock(*cblock, nonce);
310 : :
311 [ + + ]: 94742 : if (fuzzed_data_provider.ConsumeBool()) {
312 [ + - ]: 92256 : CBlockHeaderAndShortTxIDs base_cmpctblock = cmpctblock;
313 [ + - + - ]: 184512 : net_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, base_cmpctblock);
314 : 92256 : return;
315 : 92256 : }
316 : :
317 : 2486 : int prev_idx = 0;
318 : 2486 : size_t num_erased = 1;
319 [ - + ]: 2486 : size_t num_txs = cblock->vtx.size();
320 : :
321 [ + + ]: 14075 : for (size_t i = 0; i < num_txs; ++i) {
322 [ + + ]: 11589 : if (i == 0) {
323 : : // Handle the coinbase specially. We either keep it prefilled or remove it.
324 [ + + ]: 2486 : if (fuzzed_data_provider.ConsumeBool()) continue;
325 : :
326 : : // Remove the prefilled coinbase.
327 : 1257 : num_erased = 0;
328 [ + - ]: 1257 : uint64_t coinbase_shortid = cmpctblock.GetShortID(cblock->vtx[0]->GetWitnessHash());
329 : 1257 : cmpctblock.RemoveCoinbasePrefill();
330 [ + - ]: 1257 : cmpctblock.InsertCoinbaseShortTxID(coinbase_shortid);
331 : 1257 : continue;
332 : 1257 : }
333 : :
334 [ + + ]: 9103 : if (fuzzed_data_provider.ConsumeBool()) continue;
335 : :
336 [ + + ]: 4068 : uint16_t prefill_idx = num_erased == 0 ? i : i - prev_idx - 1;
337 : 4068 : prev_idx = i;
338 [ + - ]: 4068 : CTransactionRef txref = cblock->vtx[i];
339 [ + - ]: 4068 : PrefilledTransaction prefilledtx = {/*index=*/prefill_idx, txref};
340 [ + - ]: 4068 : cmpctblock.AddPrefilledTx(std::move(prefilledtx));
341 : :
342 : : // Remove from shorttxids since we've prefilled. Subtract however many txs have been prefilled.
343 : 4068 : cmpctblock.EraseShortTxIDs(i - num_erased);
344 [ - + ]: 4068 : ++num_erased;
345 [ + - ]: 8136 : }
346 : :
347 [ - + - + : 2486 : assert(cmpctblock.PrefilledTxCount() + cmpctblock.ShortTxIDCount() == num_txs);
- + ]
348 : :
349 [ + - ]: 2486 : CBlockHeaderAndShortTxIDs base_cmpctblock = cmpctblock;
350 [ + - + - ]: 4972 : net_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, base_cmpctblock);
351 [ + - + - ]: 191970 : },
352 : 10677 : [&]() {
353 : : // Send a blocktxn message for an existing block (if one exists).
354 [ - + ]: 10677 : size_t num_blocks = info.size();
355 [ + + ]: 10677 : if (num_blocks == 0) {
356 : 1407 : sent_net_msg = false;
357 : 1407 : return;
358 : : }
359 : :
360 : : // Fetch an existing block and randomly choose transactions to send over.
361 : 9270 : size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, num_blocks - 1);
362 [ + - ]: 9270 : const BlockInfo& block_info = info[index];
363 : 9270 : BlockTransactions block_txn;
364 : 9270 : block_txn.blockhash = block_info.hash;
365 [ + - ]: 9270 : std::shared_ptr<CBlock> cblock = block_info.block;
366 : :
367 [ - + + + ]: 63812 : for (size_t i = 0; i < cblock->vtx.size(); i++) {
368 [ + + ]: 54542 : if (fuzzed_data_provider.ConsumeBool()) continue;
369 : :
370 [ + - ]: 3067 : block_txn.txn.push_back(cblock->vtx[i]);
371 : : }
372 : :
373 [ + - + - : 18540 : net_msg = NetMsg::Make(NetMsgType::BLOCKTXN, block_txn);
+ - ]
374 : 9270 : },
375 : 131641 : [&]() {
376 : : // Send a headers message for an existing block (if one exists).
377 [ - + ]: 131641 : size_t num_blocks = info.size();
378 [ + + ]: 131641 : if (num_blocks == 0) {
379 : 19658 : sent_net_msg = false;
380 : 19658 : return;
381 : : }
382 : :
383 : : // Choose an existing block and send a HEADERS message for it.
384 : 111983 : size_t index = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, num_blocks - 1);
385 : 111983 : CBlock block = *info[index].block;
386 : 111983 : block.vtx.clear(); // No tx in HEADERS.
387 : 111983 : std::vector<CBlock> headers;
388 [ + - ]: 111983 : headers.emplace_back(block);
389 : :
390 [ + - + - ]: 223966 : net_msg = NetMsg::Make(NetMsgType::HEADERS, TX_WITH_WITNESS(headers));
391 : 111983 : },
392 : 33824 : [&]() {
393 : : // Send a sendcmpct message, optionally setting hb mode.
394 : 33824 : bool hb = fuzzed_data_provider.ConsumeBool();
395 [ + + ]: 33824 : uint64_t version{fuzzed_data_provider.ConsumeBool() ? CMPCTBLOCKS_VERSION : fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
396 [ + - ]: 67648 : net_msg = NetMsg::Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/hb, /*version=*/version);
397 : 33824 : requested_hb = hb;
398 : 33824 : sent_sendcmpct = true;
399 : 33824 : valid_sendcmpct = version == CMPCTBLOCKS_VERSION;
400 : 33824 : },
401 : 37772 : [&]() {
402 : : // Mine a block, but don't send it.
403 : 37772 : BlockInfo block_info = create_block();
404 [ + - ]: 37772 : info.push_back(block_info);
405 [ + - ]: 37772 : sent_net_msg = false;
406 : 37772 : },
407 : 163451 : [&]() {
408 : : // Send a transaction.
409 : 163451 : CTransactionRef tx = create_tx();
410 [ + - + - : 326902 : net_msg = NetMsg::Make(NetMsgType::TX, TX_WITH_WITNESS(*tx));
+ - ]
411 : 163451 : },
412 : 24200 : [&]() {
413 : : // Set mock time randomly or to tip's time.
414 [ + + ]: 24200 : if (fuzzed_data_provider.ConsumeBool()) {
415 : 20771 : node_clock.set(ConsumeTime(fuzzed_data_provider));
416 : : } else {
417 [ + - - + : 13716 : const NodeSeconds tip_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->Time());
+ - ]
418 : 3429 : node_clock.set(tip_time);
419 : : }
420 : :
421 : 24200 : sent_net_msg = false;
422 : 24200 : });
423 : :
424 [ + + ]: 496307 : if (!sent_net_msg) {
425 : 83037 : continue;
426 : : }
427 : :
428 : 413270 : CNode& random_node = *PickValue(fuzzed_data_provider, peers);
429 [ + - ]: 413270 : connman.FlushSendBuffer(random_node);
430 [ + - ]: 413270 : (void)connman.ReceiveMsgFrom(random_node, std::move(net_msg));
431 : :
432 : : bool more_work{true};
433 [ + + ]: 827042 : while (more_work) {
434 [ + - ]: 413772 : random_node.fPauseSend = false;
435 : :
436 [ + - ]: 413772 : more_work = connman.ProcessMessagesOnce(random_node);
437 [ + - ]: 413772 : peerman->SendMessages(random_node);
438 : : }
439 : :
440 : 413270 : std::vector<CNodeStats> stats;
441 [ + - ]: 413270 : connman.GetNodeStats(stats);
442 : :
443 : : // We should have at maximum 3 HB peers.
444 : 413270 : int num_hb = 0;
445 [ + + ]: 2066350 : for (const CNodeStats& stat : stats) {
446 [ + + ]: 1653080 : if (stat.m_bip152_highbandwidth_to) {
447 : : // HB peers cannot be feelers or other "special" connections (besides addr-fetch).
448 [ + + ]: 3873 : CNode* hb_peer = peers[stat.nodeid];
449 [ + + ]: 3873 : if (!hb_peer->fDisconnect) num_hb += 1;
450 [ + + + + : 3873 : assert(hb_peer->IsInboundConn() || hb_peer->IsOutboundOrBlockRelayConn() || hb_peer->IsManualConn() || hb_peer->IsAddrFetchConn());
+ + - + ]
451 : : }
452 : : }
453 [ - + ]: 413270 : assert(num_hb <= 3);
454 : :
455 [ + + + + ]: 413270 : if (sent_sendcmpct && !random_node.fDisconnect) {
456 : : // If the fuzzer sent SENDCMPCT with proper version, check the node's state matches what it sent.
457 [ + + ]: 28456 : const CNodeStats& random_node_stats = stats[random_node.GetId()];
458 [ + + - + ]: 28456 : if (valid_sendcmpct) assert(random_node_stats.m_bip152_highbandwidth_from == requested_hb);
459 : : }
460 : 909577 : }
461 : :
462 [ + - ]: 3519 : setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
463 [ + - ]: 3519 : setup->m_node.validation_signals->UnregisterAllValidationInterfaces();
464 [ + - ]: 3519 : connman.StopNodes();
465 : :
466 [ + - ][ + - ]: 7038 : const size_t end_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
467 [ + - ][ + - ]: 7038 : const uint64_t end_sequence{WITH_LOCK(mempool.cs, return mempool.GetSequence())};
468 : :
469 [ + + ]: 3519 : if (initial_index_size != end_index_size || initial_sequence != end_sequence) {
470 : 1494 : MakeRandDeterministicDANGEROUS(uint256::ZERO);
471 [ + - ]: 2988 : g_mature_coinbase = ResetChainmanAndMempool(*g_setup, node_clock);
472 : : }
473 [ + - ]: 7038 : }
|