Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251options.coinbase_output_script = P2WSH_OP_TRUE;252MineBlock(g_setup->m_node, options);253Assert(g_setup->m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);255// Load the 201st block into g_blocks.256LOCK(::cs_main);257auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();258auto current_block = chainstate.m_chain.Tip();259LoadCurrentBlock(chainstate, current_block);260}262/**263* Read one transaction from the fuzzing input through the FuzzedDataProvider.264* It is intended to leave more space to craft complex transactions, especially265* with various script types (P2SH, P2WSH, TAPROOT, NOSCRIPT).266* It is exclusively used by ConsumeBlock to read transactions inside a block.267*/268CTransactionRef ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,269std::vector<CTxIn>& additional_txins,270bool coinbase = false,271int target_height = 0)272{273CMutableTransaction tx;274tx.version = fuzzed_data_provider.ConsumeBool() ?275CTransaction::CURRENT_VERSION :276fuzzed_data_provider.ConsumeIntegral<uint32_t>();277tx.nLockTime = fuzzed_data_provider.ConsumeBool() ?2780 :279fuzzed_data_provider.ConsumeIntegral<uint32_t>();281// Some harnesses want to explicitly read coinbase transactions from input.282if (coinbase) {283// vin size is hardcoded.284tx.vin.resize(1);285tx.vin[0].prevout.SetNull();286if (fuzzed_data_provider.ConsumeBool()) {287// 1/2 probability of a valid vin.288tx.vin[0].scriptSig = CScript() << target_height;289} else {290// Read arbitrary data from input as scriptSig.291auto script_sig = ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100);292tx.vin[0].scriptSig.assign(script_sig.begin(), script_sig.end());293}294} else {295// Read a normal transaction, with up to 10 inputs.296int num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);297tx.vin.resize(num_inputs);298for (int i = 0; i < num_inputs; i++) {299// Read an integer to choose a CTxIn or reuse one generated by the300// input. The content of the CTxIn is not read from the input per se.301uint32_t input_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, g_spend_candidate_txins.size() + additional_txins.size() - 1);302if (input_index < g_spend_candidate_txins.size()) {303// Pick it from the spend candidates.304tx.vin[i] = g_spend_candidate_txins[input_index];305} else {306// Pick it in the additional_txins set.307Assert((input_index - g_spend_candidate_txins.size()) < additional_txins.size());308tx.vin[i] = additional_txins[input_index - g_spend_candidate_txins.size()];309}311// Enable the fuzzer to mutate every CTxIn field after it is taken312// from the spend candidates.313if (fuzzed_data_provider.ConsumeBool()) {314tx.vin[i].nSequence = ConsumeSequence(fuzzed_data_provider);315}316if (fuzzed_data_provider.ConsumeBool()) {317tx.vin[i].prevout.n = fuzzed_data_provider.ConsumeIntegral<uint32_t>();318}319if (fuzzed_data_provider.ConsumeBool()) {320tx.vin[i].prevout.hash = Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider));321}322if (fuzzed_data_provider.ConsumeBool()) {323tx.vin[i].scriptSig = ConsumeScript(fuzzed_data_provider);324}325if (fuzzed_data_provider.ConsumeBool()) {326tx.vin[i].scriptWitness.stack.clear();327int num_wit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);328for (int j = 0; j < num_wit; j++) {329tx.vin[i].scriptWitness.stack.push_back(ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100));330}331}332}333}335// Read outputs.336int num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 10);337tx.vout.resize(num_outputs);338for (int i = 0; i < num_outputs; i++) {339// Read CAmount to spend.340tx.vout[i].nValue = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);342// Read scriptPubKey type into one of the valid types.343CallOneOf(344fuzzed_data_provider,345[&] {346// P2WSH347tx.vout[i].scriptPubKey = P2WSH_OP_TRUE;348},349[&] {350// P2SH351tx.vout[i].scriptPubKey = P2SH_OP_TRUE;352},353[&] {354// Taproot355tx.vout[i].scriptPubKey = TAPROOT_OP_TRUE;356},357[&] {358// Empty script359tx.vout[i].scriptPubKey = CScript();360},361[&] {362// Read arbitrary scriptPubKey.363tx.vout[i].scriptPubKey = ConsumeScript(fuzzed_data_provider);364});365}367// Create the shared pointer to the CTransaction object.368auto res = MakeTransactionRef(tx);370if (!coinbase) {371// Create spending scripts for CTxOuts so they can be spent in later372// transactions. Do it here as the transaction hash is definitive.373for (int i = 0; i < num_outputs; i++) {374MaybeAddSpendCandidate(additional_txins, *res, i);375}376}378return res;379}381/**382* Consume a block from the fuzzing input.383* It builds a block on top of the given prev_block.384*/385CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const CBlock& prev_block, int target_height,386std::vector<CTxIn>& additional_txins)387{388CBlock block;390// Initialize header fields.391block.nVersion = g_blocks.back()->nVersion;392block.hashPrevBlock = prev_block.GetHash();393block.nTime = g_blocks.back()->nTime + 2;394block.nBits = g_blocks.back()->nBits;396// Give the fuzzer input the ability to mutate block header fields.397if (fuzzed_data_provider.ConsumeBool()) {398block.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>();399}400if (fuzzed_data_provider.ConsumeBool()) {401block.hashPrevBlock = ConsumeUInt256(fuzzed_data_provider);402}404if (fuzzed_data_provider.ConsumeBool()) {405block.nTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();406}407if (fuzzed_data_provider.ConsumeBool()) {408block.nBits = fuzzed_data_provider.ConsumeIntegral<uint32_t>();409}411// Read the coinbase transaction from the input.412block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins, true, target_height));414// Read up to num_tx transactions from the input.415int num_tx = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5);416for (int i = 0; i < num_tx; i++) {417block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins));418}420// Commit witness.421if (fuzzed_data_provider.ConsumeBool()) {422g_setup->m_node.chainman->GenerateCoinbaseCommitment(block, nullptr);423}425// Set hashMerkleRoot to expected value.426block.hashMerkleRoot = BlockMerkleRoot(block);427// Let the fuzzer mutate hashMerkleRoot.428if (fuzzed_data_provider.ConsumeBool()) {429block.hashMerkleRoot = ConsumeUInt256(fuzzed_data_provider);430}432// Read the nonce from the input.433block.nNonce = fuzzed_data_provider.ConsumeIntegral<uint32_t>();435return block;436}439FUZZ_TARGET(connect_block, .init = initialize_connect_block)440{441SeedRandomStateForTest(SeedRand::ZEROS);442FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());443FakeNodeClock clock{g_blocks.back()->Time() + 2s};445LOCK(::cs_main);446g_setup->m_node.chainman->m_validation_cache.m_script_execution_cache.TestOnlyReset();447Chainstate& active_chainstate = g_setup->m_node.chainman->ActiveChainstate();448CBlockIndex* active_tip = active_chainstate.m_chain.Tip();449Assert(active_tip->GetBlockHash() == g_blocks.back()->GetHash());450CCoinsViewCache active_coins(&active_chainstate.CoinsTip());452// Read a new block from the data provider.453std::vector<CTxIn> additional_txins;454CBlock block = ConsumeBlock(fuzzed_data_provider, *g_blocks.back(), active_tip->nHeight + 1, additional_txins);456// Duplicate a transaction (not the coinbase) from the previous block457// to hit the BIP30 check.458if (fuzzed_data_provider.ConsumeBool()) {459const auto& duplicates = g_blocks.back()->vtx;460block.vtx.push_back(duplicates[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, duplicates.size() - 1)]);461}463// Compute new CBlockIndex object.464uint256 current_hash = block.GetHash();465CBlockIndex new_index(block);466new_index.pprev = active_tip;467new_index.nHeight = active_tip->nHeight + 1;468new_index.phashBlock = ¤t_hash;470// Try to connect the block.471BlockValidationState state;472bool connected = active_chainstate.ConnectBlock(block,473state,474&new_index,475active_coins,476/*fJustCheck=*/true);477Assert(connected == state.IsValid());478}480} // namespace
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.