LCOV - code coverage report
Current view: top level - src/test/fuzz - connect_block.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 49.8 % 221 110
Test Date: 2026-08-29 05:53:03 Functions: 52.9 % 17 9
Branches: 30.9 % 272 84

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

Generated by: LCOV version 2.5.0-full