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.
1// Copyright (c) 2026-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.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>29#include <algorithm>30#include <cstdint>31#include <memory>32#include <utility>33#include <vector>36namespace {38TestingSetup* g_setup;40/** Vector of blocks to keep references to blocks (to enable fuzzing input to pick one to build upon) */41static std::vector<std::shared_ptr<CBlock>> g_blocks;42/** CTxIns for spending outputs, which can be unspent, already spent, or an immature coinbase. */43static std::vector<CTxIn> g_spend_candidate_txins;44/** Static P2SH_OP_TRUE script */45static const CScript P2SH_OP_TRUE = CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScript() << OP_TRUE)) << OP_EQUAL;46/** Static P2SH_OP_TRUE unlock script */47static const CScript P2SH_OP_TRUE_UNLOCK = CScript() << MakeUCharSpan(CScript() << OP_TRUE);48/** Static TAPROOT_OP_TRUE script and its witness */49static CScript TAPROOT_OP_TRUE;50static std::vector<std::vector<uint8_t>> TAPROOT_OP_TRUE_WITNESS;52/**53* Initialize TAPROOT_OP_TRUE and TAPROOT_OP_TRUE_WITNESS static variables.54*/55static void InitTaprootScript()56{57uint256 merkle_tree_hash = ComputeTapleafHash(TAPROOT_LEAF_TAPSCRIPT, MakeUCharSpan(CScript() << OP_TRUE));58uint256 internal_key{std::vector<uint8_t>(32, 1)};59auto res = XOnlyPubKey(internal_key).CreateTapTweak(&merkle_tree_hash);60Assert(res.has_value());61auto control = ToByteVector(internal_key);62control.insert(control.begin(), TAPROOT_LEAF_TAPSCRIPT | (res->second ? 1 : 0));64TAPROOT_OP_TRUE = CScript() << OP_1 << ToByteVector(res->first);65TAPROOT_OP_TRUE_WITNESS.clear();66TAPROOT_OP_TRUE_WITNESS.emplace_back(ToByteVector(CScript() << OP_TRUE));67TAPROOT_OP_TRUE_WITNESS.emplace_back(std::move(control));68}70/**71* Given a transaction and an output index, create a CTxIn that can be72* used to spend it.73*/74static CTxIn GetSpendingScript(const CTransaction& tx, uint32_t vout_index)75{76Assert(vout_index < tx.vout.size());77const CTxOut& output = tx.vout[vout_index];79CTxIn res{COutPoint(tx.GetHash(), vout_index)};80if (output.scriptPubKey == P2WSH_OP_TRUE) {81res.scriptSig = CScript();82res.scriptWitness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);83} else if (output.scriptPubKey == P2SH_OP_TRUE) {84res.scriptSig = P2SH_OP_TRUE_UNLOCK;85} else if (output.scriptPubKey == CScript()) {86res.scriptSig = CScript() << OP_TRUE;87} else if (output.scriptPubKey == TAPROOT_OP_TRUE) {88res.scriptSig = CScript();89res.scriptWitness.stack = TAPROOT_OP_TRUE_WITNESS;90}92return res;93}95/**96* Add a spend candidate CTxIn unless the output is unspendable.97*/98static void MaybeAddSpendCandidate(std::vector<CTxIn>& pool, const CTransaction& tx, uint32_t vout_index)99{100Assert(vout_index < tx.vout.size());101if (tx.vout[vout_index].scriptPubKey.IsUnspendable()) return;102pool.push_back(GetSpendingScript(tx, vout_index));103}106/**107* Read the block from the BlockManager and add it to g_blocks.108*/109static void LoadCurrentBlock(Chainstate& chainstate, CBlockIndex* current_block)110{111// Read the block from the BlockManager.112Assert(current_block->nHeight >= 0);113// Resize g_blocks if needed.114if (g_blocks.size() <= (size_t)current_block->nHeight) {115g_blocks.resize(current_block->nHeight + 1);116}118g_blocks[current_block->nHeight] = std::make_shared<CBlock>();119Assert(chainstate.m_blockman.ReadBlock(*g_blocks[current_block->nHeight], *current_block));121// Iterate all transaction outputs.122for (const auto& tx : g_blocks[current_block->nHeight]->vtx) {123for (uint32_t vout_index{0}; vout_index < tx->vout.size(); ++vout_index) {124MaybeAddSpendCandidate(g_spend_candidate_txins, *tx, vout_index);125}126}127}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*/133static void LoadCurrentChain()134{135// Clear existing data.136g_blocks.clear();137g_spend_candidate_txins.clear();139{140LOCK(::cs_main);141// Retrieve the current chainstate.142auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();143// Make sure it contains a valid mempool.144Assert(chainstate.GetMempool());146// Traverse the chain from tip to genesis.147auto current_block = chainstate.m_chain.Tip();149while (current_block != nullptr) {150LoadCurrentBlock(chainstate, current_block);151// Move to previous block.152current_block = current_block->pprev;153}154}156// Reverse the order of g_spend_candidate_txins to have them in ascending order of157// block height.158std::reverse(g_spend_candidate_txins.begin(), g_spend_candidate_txins.end());159}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*/167void ResetChainman(TestingSetup& setup)168{169SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());170setup.m_node.chainman.reset();171setup.m_node.notifications->m_shutdown_on_fatal_error = false;172setup.m_make_chainman();173setup.LoadVerifyActivateChainstate();175for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {176node::BlockCreateOptions options;177options.coinbase_output_script = P2WSH_OP_TRUE;178MineBlock(setup.m_node, options);179}180setup.m_node.validation_signals->SyncWithValidationInterfaceQueue();181}183/** Create additional transactions in the mempool that spend184* coins from mature blocks. Otherwise the mined chain only contains185* coinbase transactions.186*/187void AddExtraTxsToMempool(TestingSetup& setup)188{189Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);190for (size_t i = 1; i <= 10; i++) {191CMutableTransaction ctx;192ctx.version = CTransaction::CURRENT_VERSION;193ctx.vin.resize(1);194// CTxIn is spendable as g_spend_candidate_txins comes from early blocks whose195// coinbases are mature.196ctx.vin[0] = g_spend_candidate_txins[i];197ctx.vout.resize(4);198// Arbitrarily create various outputs of different kinds in the same tx.199// P2WSH200ctx.vout[0].nValue = CAmount(15 * COIN);201ctx.vout[0].scriptPubKey = P2WSH_OP_TRUE;202// P2SH203ctx.vout[1].nValue = CAmount(15 * COIN);204ctx.vout[1].scriptPubKey = P2SH_OP_TRUE;205// Taproot206ctx.vout[2].nValue = CAmount(10 * COIN);207ctx.vout[2].scriptPubKey = TAPROOT_OP_TRUE;208// Empty script209ctx.vout[3].nValue = CAmount(10 * COIN);210ctx.vout[3].scriptPubKey = CScript();212LOCK(::cs_main);213// Add transaction to the mempool.214const MempoolAcceptResult ctx_result = setup.m_node.chainman->ProcessTransaction(MakeTransactionRef(ctx));215Assert(ctx_result.m_result_type == MempoolAcceptResult::ResultType::VALID);217Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == i);218// Force the mempool to select this transaction even though its fee is zero.219setup.m_node.chainman->ActiveChainstate().GetMempool()->PrioritiseTransaction(ctx.GetHash(), COIN);220}221}223/** Initialize the chain for this target. */224static void initialize_connect_block()225{226// Instantiate REGTEST chain.227static auto testing_setup = MakeNoLogFileContext<TestingSetup>(228/*chain_type=*/ChainType::REGTEST, TestOpts{229.extra_args = {230"-minrelaytxfee=0",231"-acceptnonstdtxn",232},233});234g_setup = testing_setup.get();236// Reset the chainman in the testing setup object.237ResetChainman(*g_setup);239// Initialize Taproot script declared as static variables.240InitTaprootScript();242// Load the chain mined in ResetChainman in global variables g_blocks and243// g_spend_candidate_txins, to make them available to pick by the target.244LoadCurrentChain();246// Prepare multiple transactions for block 201. They spend coins247// from various coinbases that are now mature enough.248AddExtraTxsToMempool(*g_setup);249// Mine block 201, which contains the transactions added to the mempool.250node::BlockCreateOptions options;
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.