/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 | } |