Coverage Report

Created: 2026-07-30 14:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/connect_block.cpp
Line
Count
Source
1
// Copyright (c) 2026-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 <addresstype.h>
6
#include <chain.h>
7
#include <consensus/amount.h>
8
#include <consensus/merkle.h>
9
#include <node/kernel_notifications.h>
10
#include <node/mining_types.h>
11
#include <primitives/block.h>
12
#include <primitives/transaction.h>
13
#include <pubkey.h>
14
#include <script/interpreter.h>
15
#include <script/script.h>
16
#include <sync.h>
17
#include <test/fuzz/FuzzedDataProvider.h>
18
#include <test/fuzz/fuzz.h>
19
#include <test/fuzz/util.h>
20
#include <test/util/mining.h>
21
#include <test/util/script.h>
22
#include <test/util/setup_common.h>
23
#include <test/util/time.h>
24
#include <txmempool.h>
25
#include <uint256.h>
26
#include <validation.h>
27
#include <validationinterface.h>
28
29
#include <algorithm>
30
#include <cstdint>
31
#include <memory>
32
#include <set>
33
#include <utility>
34
#include <vector>
35
36
37
namespace {
38
39
TestingSetup* g_setup;
40
41
/** Vector of blocks to keep references to blocks (to enable fuzzing input to pick one to build upon) */
42
static std::vector<std::shared_ptr<CBlock>> g_blocks;
43
/** Set of block hashes in g_blocks */
44
static std::set<uint256> g_existing_block_hashes;
45
/** CTxIns for spending outputs (excluding OP_RETURN), which can be unspent, already spent, or an immature coinbase. */
46
static std::vector<CTxIn> g_spend_candidate_txins;
47
/** Static P2SH_OP_TRUE script */
48
static const CScript P2SH_OP_TRUE = CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScript() << OP_TRUE)) << OP_EQUAL;
49
/** Static P2SH_OP_TRUE unlock script */
50
static const CScript P2SH_OP_TRUE_UNLOCK = CScript() << MakeUCharSpan(CScript() << OP_TRUE);
51
/** Static TAPROOT_OP_TRUE script and its witness */
52
static CScript TAPROOT_OP_TRUE;
53
static std::vector<std::vector<uint8_t>> TAPROOT_OP_TRUE_WITNESS;
54
55
/**
56
 * Initialize TAPROOT_OP_TRUE and TAPROOT_OP_TRUE_WITNESS static variables.
57
 */
58
static void InitTaprootScript()
59
0
{
60
0
    uint256 merkle_tree_hash = ComputeTapleafHash(TAPROOT_LEAF_TAPSCRIPT, MakeUCharSpan(CScript() << OP_TRUE));
61
0
    uint256 internal_key{std::vector<uint8_t>(32, 1)};
62
0
    auto res = XOnlyPubKey(internal_key).CreateTapTweak(&merkle_tree_hash);
63
0
    Assert(res.has_value());
64
0
    auto control = ToByteVector(internal_key);
65
0
    control.insert(control.begin(), TAPROOT_LEAF_TAPSCRIPT | (res->second ? 1 : 0));
  Branch (65:63): [True: 0, False: 0]
66
67
0
    TAPROOT_OP_TRUE = CScript() << OP_1 << ToByteVector(res->first);
68
0
    TAPROOT_OP_TRUE_WITNESS.clear();
69
0
    TAPROOT_OP_TRUE_WITNESS.emplace_back(ToByteVector(CScript() << OP_TRUE));
70
0
    TAPROOT_OP_TRUE_WITNESS.emplace_back(std::move(control));
71
0
}
72
73
/**
74
 * Given a transaction and an output index, create a CTxIn that can be used to
75
 * spend it (if possible).
76
 */
77
static CTxIn GetSpendingScript(const CTransaction& tx, uint32_t vout_index)
78
14.1k
{
79
14.1k
    Assert(vout_index < tx.vout.size());
80
14.1k
    const CTxOut& output = tx.vout[vout_index];
81
82
14.1k
    CTxIn res{COutPoint(tx.GetHash(), vout_index)};
83
14.1k
    if (output.scriptPubKey.size() >= 1 && output.scriptPubKey[0] == OP_RETURN)
  Branch (83:9): [True: 11.2k, False: 2.85k]
  Branch (83:44): [True: 57, False: 11.2k]
84
57
        return res;
85
86
14.0k
    if (output.scriptPubKey == P2WSH_OP_TRUE) {
  Branch (86:9): [True: 5.66k, False: 8.40k]
87
5.66k
        res.scriptSig = CScript();
88
5.66k
        res.scriptWitness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
89
8.40k
    } else if (output.scriptPubKey == P2SH_OP_TRUE) {
  Branch (89:16): [True: 1.80k, False: 6.60k]
90
1.80k
        res.scriptSig = P2SH_OP_TRUE_UNLOCK;
91
6.60k
    } else if (output.scriptPubKey == CScript()) {
  Branch (91:16): [True: 2.85k, False: 3.75k]
92
2.85k
        res.scriptSig = CScript() << OP_TRUE;
93
3.75k
    } else if (output.scriptPubKey == TAPROOT_OP_TRUE) {
  Branch (93:16): [True: 1.88k, False: 1.86k]
94
1.88k
        res.scriptSig = CScript();
95
1.88k
        res.scriptWitness.stack = TAPROOT_OP_TRUE_WITNESS;
96
1.88k
    }
97
98
14.0k
    return res;
99
14.1k
}
100
101
102
/**
103
 * Read the block from the BlockManager and add it to g_blocks and g_existing_block_hashes.
104
 */
105
static void LoadCurrentBlock(Chainstate& chainstate, CBlockIndex* current_block)
106
0
{
107
    // Read the block from the BlockManager.
108
0
    Assert(current_block->nHeight >= 0);
109
    // Resize g_blocks if needed.
110
0
    if (g_blocks.size() <= (size_t)current_block->nHeight) {
  Branch (110:9): [True: 0, False: 0]
111
0
        g_blocks.resize(current_block->nHeight + 1);
112
0
    }
113
114
0
    g_blocks[current_block->nHeight] = std::make_shared<CBlock>();
115
0
    Assert(chainstate.m_blockman.ReadBlock(*g_blocks[current_block->nHeight], *current_block));
116
    // Update hash set.
117
0
    g_existing_block_hashes.insert(g_blocks[current_block->nHeight]->GetHash());
118
119
    // Iterate all transaction outputs.
120
0
    for (const auto& tx : g_blocks[current_block->nHeight]->vtx) {
  Branch (120:25): [True: 0, False: 0]
121
0
        for (uint32_t vout_index{0}; vout_index < tx->vout.size(); ++vout_index) {
  Branch (121:38): [True: 0, False: 0]
122
0
            auto& vout = tx->vout[vout_index];
123
            // Do not keep OP_RETURN outputs as they are not spendable.
124
0
            if (vout.scriptPubKey.size() >= 1 && vout.scriptPubKey[0] == OP_RETURN) continue;
  Branch (124:17): [True: 0, False: 0]
  Branch (124:50): [True: 0, False: 0]
125
            // Create the CTxIn that can be used to spend this output.
126
0
            g_spend_candidate_txins.push_back(GetSpendingScript(*tx, vout_index));
127
0
        }
128
0
    }
129
0
}
130
131
/**
132
 * Read the ChainState object into g_blocks.
133
 * Then fill g_spend_candidate_txins with inputs that can be tried by the target.
134
 */
135
static void LoadCurrentChain()
136
0
{
137
    // Clear existing data.
138
0
    g_blocks.clear();
139
0
    g_existing_block_hashes.clear();
140
0
    g_spend_candidate_txins.clear();
141
142
0
    {
143
0
        LOCK(::cs_main);
144
        // Retrieve the current chainstate.
145
0
        auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
146
        // Make sure it contains a valid mempool.
147
0
        Assert(chainstate.GetMempool());
148
149
        // Traverse the chain from tip to genesis.
150
0
        auto current_block = chainstate.m_chain.Tip();
151
152
0
        while (current_block != nullptr) {
  Branch (152:16): [True: 0, False: 0]
153
0
            LoadCurrentBlock(chainstate, current_block);
154
            // Move to previous block.
155
0
            current_block = current_block->pprev;
156
0
        }
157
0
    }
158
159
    // Reverse the order of g_spend_candidate_txins to have them in ascending order of
160
    // block height.
161
0
    std::reverse(g_spend_candidate_txins.begin(), g_spend_candidate_txins.end());
162
0
}
163
164
165
/**
166
 * Reset the chainman in the testing setup object.
167
 * Mine 2*COINBASE_MATURITY blocks to have spendable UTXOs.
168
 * It is called once in the initialization function.
169
 */
170
void ResetChainman(TestingSetup& setup)
171
0
{
172
0
    SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());
173
0
    setup.m_node.chainman.reset();
174
0
    setup.m_node.notifications->m_shutdown_on_fatal_error = false;
175
0
    setup.m_make_chainman();
176
0
    setup.LoadVerifyActivateChainstate();
177
178
0
    for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
  Branch (178:21): [True: 0, False: 0]
179
0
        node::BlockCreateOptions options;
180
0
        options.coinbase_output_script = P2WSH_OP_TRUE;
181
0
        MineBlock(setup.m_node, options);
182
0
    }
183
0
    setup.m_node.validation_signals->SyncWithValidationInterfaceQueue();
184
0
}
185
186
/** Create additional transactions in the mempool that spend
187
 * coins from mature blocks. Otherwise the mined chain only contains
188
 * coinbase transactions.
189
 */
190
void AddExtraTxsToMempool(TestingSetup& setup)
191
0
{
192
0
    Assert(Assert(Assert(setup.m_node.chainman)->ActiveChainstate().GetMempool())->size() == 0);
193
0
    for (size_t i = 1; i <= 10; i++) {
  Branch (193:24): [True: 0, False: 0]
194
0
        CMutableTransaction ctx;
195
0
        ctx.version = CTransaction::CURRENT_VERSION;
196
0
        ctx.vin.resize(1);
197
        // CTxIn is spendable as g_spend_candidate_txins comes from early blocks whose
198
        // coinbases are mature.
199
0
        ctx.vin[0] = g_spend_candidate_txins[i];
200
0
        ctx.vout.resize(4);
201
        // Arbitrarily create various outputs of different kinds in the same tx.
202
        // P2WSH
203
0
        ctx.vout[0].nValue = CAmount(15 * COIN);
204
0
        ctx.vout[0].scriptPubKey = P2WSH_OP_TRUE;
205
        // P2SH
206
0
        ctx.vout[1].nValue = CAmount(15 * COIN);
207
0
        ctx.vout[1].scriptPubKey = P2SH_OP_TRUE;
208
        // Taproot
209
0
        ctx.vout[2].nValue = CAmount(10 * COIN);
210
0
        ctx.vout[2].scriptPubKey = TAPROOT_OP_TRUE;
211
        // Empty script
212
0
        ctx.vout[3].nValue = CAmount(10 * COIN);
213
0
        ctx.vout[3].scriptPubKey = CScript();
214
215
0
        LOCK(::cs_main);
216
        // Add transaction to the mempool.
217
0
        const MempoolAcceptResult ctx_result = setup.m_node.chainman->ProcessTransaction(MakeTransactionRef(ctx));
218
0
        Assert(ctx_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
219
220
0
        Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == i);
221
        // Force the mempool to select this transaction even though its fee is zero.
222
0
        setup.m_node.chainman->ActiveChainstate().GetMempool()->PrioritiseTransaction(ctx.GetHash(), COIN);
223
0
    }
224
0
}
225
226
/** Initialize the chain for this target. */
227
static void initialize_connect_block()
228
0
{
229
    // Instantiate REGTEST chain.
230
0
    static auto testing_setup = MakeNoLogFileContext<TestingSetup>(
231
0
        /*chain_type=*/ChainType::REGTEST, TestOpts{
232
0
                                               .extra_args = {
233
0
                                                   "-minrelaytxfee=0",
234
0
                                                   "-acceptnonstdtxn",
235
0
                                               },
236
0
                                           });
237
0
    g_setup = testing_setup.get();
238
239
    // Reset the chainman in the testing setup object.
240
0
    ResetChainman(*g_setup);
241
242
    // Initialize Taproot script declared as static variables.
243
0
    InitTaprootScript();
244
245
    // Load the chain mined in ResetChainman in global variables g_blocks and
246
    // g_spend_candidate_txins, to make them available to pick by the target.
247
0
    LoadCurrentChain();
248
249
    // Prepare multiple transactions for block 201. They spend coins
250
    // from various coinbases that are now mature enough.
251
0
    AddExtraTxsToMempool(*g_setup);
252
    // Mine block 201, which contains the transactions added to the mempool.
253
0
    node::BlockCreateOptions options;
254
0
    options.coinbase_output_script = P2WSH_OP_TRUE;
255
0
    MineBlock(g_setup->m_node, options);
256
0
    Assert(g_setup->m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);
257
258
    // Load the 201th block into g_blocks.
259
0
    LOCK(::cs_main);
260
0
    auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
261
0
    auto current_block = chainstate.m_chain.Tip();
262
0
    LoadCurrentBlock(chainstate, current_block);
263
0
}
264
265
/**
266
 * Read one transaction from the fuzzing input through the FuzzedDataProvider.
267
 * It is intended to leave more space to craft complex transactions, especially
268
 * with various script types (P2SH, P2WSH, TAPROOT, NOSCRIPT).
269
 * It is exclusively used by ConsumeBlock to read transactions inside a block.
270
 */
271
CTransactionRef ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,
272
                                   std::vector<CTxIn>& additional_txins,
273
                                   bool coinbase = false,
274
                                   int target_height = 0)
275
10.0k
{
276
10.0k
    CMutableTransaction tx;
277
10.0k
    tx.version = fuzzed_data_provider.ConsumeBool() ?
  Branch (277:18): [True: 6.61k, False: 3.41k]
278
6.61k
                     CTransaction::CURRENT_VERSION :
279
10.0k
                     fuzzed_data_provider.ConsumeIntegral<uint32_t>();
280
10.0k
    tx.nLockTime = fuzzed_data_provider.ConsumeBool() ?
  Branch (280:20): [True: 5.92k, False: 4.09k]
281
5.92k
                       0 :
282
10.0k
                       fuzzed_data_provider.ConsumeIntegral<uint32_t>();
283
284
    // Some harnesses want to explicitly read coinbase transactions from input.
285
10.0k
    if (coinbase) {
  Branch (285:9): [True: 3.86k, False: 6.15k]
286
        // vin size is hardcoded.
287
3.86k
        tx.vin.resize(1);
288
3.86k
        tx.vin[0].prevout.SetNull();
289
3.86k
        tx.vin[0].nSequence = CTxIn::MAX_SEQUENCE_NONFINAL;
290
3.86k
        if (fuzzed_data_provider.ConsumeBool()) {
  Branch (290:13): [True: 3.54k, False: 321]
291
            // 1/2 probability of a valid vin.
292
3.54k
            tx.vin[0].scriptSig = CScript() << target_height;
293
3.54k
        } else {
294
            // Read arbitrary data from input as scriptSig.
295
321
            auto script_sig = ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100);
296
321
            tx.vin[0].scriptSig.assign(script_sig.begin(), script_sig.end());
297
321
        }
298
6.15k
    } else {
299
        // Read a normal transaction, with up to 10 inputs.
300
6.15k
        int num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);
301
6.15k
        tx.vin.resize(num_inputs);
302
18.9k
        for (int i = 0; i < num_inputs; i++) {
  Branch (302:25): [True: 12.8k, False: 6.15k]
303
            // Read an integer to choose a CTxIn or reuse one generated by the
304
            // input. The content of the CTxIn is not read from the input per se.
305
12.8k
            uint32_t input_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, g_spend_candidate_txins.size() + additional_txins.size() - 1);
306
12.8k
            if (input_index < g_spend_candidate_txins.size()) {
  Branch (306:17): [True: 12.1k, False: 646]
307
                // Pick it from the spend candidates.
308
12.1k
                tx.vin[i] = g_spend_candidate_txins[input_index];
309
12.1k
            } else {
310
                // Pick it in the additional_txins set.
311
646
                Assert((input_index - g_spend_candidate_txins.size()) < additional_txins.size());
312
646
                tx.vin[i] = additional_txins[input_index - g_spend_candidate_txins.size()];
313
646
            }
314
315
            // Enable the fuzzer to mutate every CTxIn field after it is taken
316
            // from the spend candidates.
317
12.8k
            if (fuzzed_data_provider.ConsumeBool()) {
  Branch (317:17): [True: 3.94k, False: 8.88k]
318
3.94k
                tx.vin[i].nSequence = ConsumeSequence(fuzzed_data_provider);
319
3.94k
            }
320
12.8k
            if (fuzzed_data_provider.ConsumeBool()) {
  Branch (320:17): [True: 2.87k, False: 9.95k]
321
2.87k
                tx.vin[i].prevout.n = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
322
2.87k
            }
323
12.8k
            if (fuzzed_data_provider.ConsumeBool()) {
  Branch (323:17): [True: 2.28k, False: 10.5k]
324
2.28k
                tx.vin[i].prevout.hash = Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider));
325
2.28k
            }
326
12.8k
            if (fuzzed_data_provider.ConsumeBool()) {
  Branch (326:17): [True: 4.77k, False: 8.06k]
327
4.77k
                tx.vin[i].scriptSig = ConsumeScript(fuzzed_data_provider);
328
4.77k
            }
329
12.8k
            if (fuzzed_data_provider.ConsumeBool()) {
  Branch (329:17): [True: 1.64k, False: 11.1k]
330
1.64k
                tx.vin[i].scriptWitness.stack.clear();
331
1.64k
                int num_wit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);
332
7.20k
                for (int j = 0; j < num_wit; j++) {
  Branch (332:33): [True: 5.56k, False: 1.64k]
333
5.56k
                    tx.vin[i].scriptWitness.stack.push_back(ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100));
334
5.56k
                }
335
1.64k
            }
336
12.8k
        }
337
6.15k
    }
338
339
    // Read outputs.
340
10.0k
    int num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 10);
341
10.0k
    tx.vout.resize(num_outputs);
342
34.0k
    for (int i = 0; i < num_outputs; i++) {
  Branch (342:21): [True: 24.0k, False: 10.0k]
343
        // Read CAmount to spend.
344
24.0k
        tx.vout[i].nValue = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
345
346
        // Read scriptPubKey type into one of the valid types.
347
24.0k
        switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 4)) {
348
9.26k
        case 0:
  Branch (348:9): [True: 9.26k, False: 14.7k]
349
            // P2WSH
350
9.26k
            tx.vout[i].scriptPubKey = P2WSH_OP_TRUE;
351
9.26k
            break;
352
3.73k
        case 1:
  Branch (352:9): [True: 3.73k, False: 20.3k]
353
            // P2SH
354
3.73k
            tx.vout[i].scriptPubKey = P2SH_OP_TRUE;
355
3.73k
            break;
356
2.86k
        case 2:
  Branch (356:9): [True: 2.86k, False: 21.1k]
357
            // Taproot
358
2.86k
            tx.vout[i].scriptPubKey = TAPROOT_OP_TRUE;
359
2.86k
            break;
360
2.22k
        case 3:
  Branch (360:9): [True: 2.22k, False: 21.8k]
361
            // Empty script
362
2.22k
            tx.vout[i].scriptPubKey = CScript();
363
2.22k
            break;
364
5.96k
        default: {
  Branch (364:9): [True: 5.96k, False: 18.0k]
365
            // Read arbitrary scriptPubKey.
366
5.96k
            tx.vout[i].scriptPubKey = ConsumeScript(fuzzed_data_provider);
367
5.96k
            break;
368
0
        }
369
24.0k
        }
370
24.0k
    }
371
372
    // Create the shared pointer to the CTransaction object.
373
10.0k
    auto res = MakeTransactionRef(tx);
374
375
10.0k
    if (!coinbase) {
  Branch (375:9): [True: 6.15k, False: 3.86k]
376
        // Create spending scripts for all CTxOuts so they can be spent in later
377
        // transactions. Do it here as the transaction hash is definitive.
378
20.2k
        for (int i = 0; i < num_outputs; i++) {
  Branch (378:25): [True: 14.1k, False: 6.15k]
379
14.1k
            additional_txins.emplace_back(GetSpendingScript(*res, i));
380
14.1k
        }
381
6.15k
    }
382
383
10.0k
    return res;
384
10.0k
}
385
386
/**
387
 * Consume a block from the fuzzing input.
388
 * It builds a block on top of the given prev_block.
389
 */
390
CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const CBlock& prev_block, int target_height,
391
                    std::vector<CTxIn>& additional_txins)
392
3.86k
{
393
3.86k
    CBlock block;
394
395
    // Initialize header fields.
396
3.86k
    block.nVersion = g_blocks.back()->nVersion;
397
3.86k
    block.hashPrevBlock = prev_block.GetHash();
398
3.86k
    block.nTime = g_blocks.back()->nTime + 2;
399
3.86k
    block.nBits = g_blocks.back()->nBits;
400
401
    // Give the fuzzer input the ability to mutate block header fields.
402
3.86k
    if (fuzzed_data_provider.ConsumeBool()) {
  Branch (402:9): [True: 275, False: 3.59k]
403
275
        block.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>();
404
275
    }
405
3.86k
    if (fuzzed_data_provider.ConsumeBool()) {
  Branch (405:9): [True: 386, False: 3.48k]
406
386
        block.hashPrevBlock = ConsumeUInt256(fuzzed_data_provider);
407
386
    }
408
409
3.86k
    if (fuzzed_data_provider.ConsumeBool()) {
  Branch (409:9): [True: 311, False: 3.55k]
410
311
        block.nTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
411
311
    }
412
3.86k
    if (fuzzed_data_provider.ConsumeBool()) {
  Branch (412:9): [True: 433, False: 3.43k]
413
433
        block.nBits = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
414
433
    }
415
416
    // Read the coinbase transaction from the input.
417
3.86k
    block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins, true, target_height));
418
419
    // Read up to num_tx transactions from the input.
420
3.86k
    int num_tx = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5);
421
10.0k
    for (int i = 0; i < num_tx; i++) {
  Branch (421:21): [True: 6.15k, False: 3.86k]
422
6.15k
        block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins));
423
6.15k
    }
424
425
    // Commit witness.
426
3.86k
    if (num_tx > 0) {
  Branch (426:9): [True: 3.28k, False: 587]
427
3.28k
        g_setup->m_node.chainman->GenerateCoinbaseCommitment(block, nullptr);
428
3.28k
    }
429
430
    // Set hashMerkleRoot to expected value.
431
3.86k
    block.hashMerkleRoot = BlockMerkleRoot(block);
432
    // Let the fuzzer mutate hashMerkleRoot.
433
3.86k
    if (fuzzed_data_provider.ConsumeBool()) {
  Branch (433:9): [True: 841, False: 3.02k]
434
841
        block.hashMerkleRoot = ConsumeUInt256(fuzzed_data_provider);
435
841
    }
436
437
    // Read the nonce from the input and avoid reusing a setup block hash.
438
3.86k
    block.nNonce = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
439
3.86k
    while (g_existing_block_hashes.contains(block.GetHash())) {
  Branch (439:12): [True: 0, False: 3.86k]
440
0
        ++block.nNonce;
441
0
    }
442
443
3.86k
    return block;
444
3.86k
}
445
446
447
FUZZ_TARGET(connect_block, .init = initialize_connect_block)
448
3.86k
{
449
3.86k
    SeedRandomStateForTest(SeedRand::ZEROS);
450
3.86k
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
451
3.86k
    FakeNodeClock clock{g_blocks.back()->Time() + 2s};
452
453
3.86k
    LOCK(::cs_main);
454
3.86k
    Chainstate& active_chainstate = g_setup->m_node.chainman->ActiveChainstate();
455
3.86k
    CBlockIndex* active_tip = active_chainstate.m_chain.Tip();
456
3.86k
    Assert(active_tip->GetBlockHash() == g_blocks.back()->GetHash());
457
3.86k
    CCoinsViewCache active_coins(&active_chainstate.CoinsTip());
458
459
    // Read a new block from the data provider.
460
3.86k
    std::vector<CTxIn> additional_txins;
461
3.86k
    CBlock block = ConsumeBlock(fuzzed_data_provider, *g_blocks.back(), active_tip->nHeight + 1, additional_txins);
462
463
    // Compute new CBlockIndex object.
464
3.86k
    uint256 current_hash = block.GetHash();
465
3.86k
    CBlockIndex new_index(block);
466
3.86k
    new_index.pprev = active_tip;
467
3.86k
    new_index.nHeight = active_tip->nHeight + 1;
468
3.86k
    new_index.phashBlock = &current_hash;
469
470
    // Try to connect the block.
471
3.86k
    BlockValidationState state;
472
3.86k
    bool connected = active_chainstate.ConnectBlock(block,
473
3.86k
                                                    state,
474
3.86k
                                                    &new_index,
475
3.86k
                                                    active_coins,
476
3.86k
                                                    /*fJustCheck=*/true);
477
3.86k
    Assert(connected == state.IsValid());
478
3.86k
}
479
480
} // namespace