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) 2014-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 <chainparams.h>6#include <consensus/amount.h>7#include <consensus/merkle.h>8#include <core_io.h>9#include <hash.h>10#include <net.h>11#include <signet.h>12#include <uint256.h>13#include <util/chaintype.h>14#include <validation.h>16#include <string>18#include <test/util/setup_common.h>20#include <boost/test/unit_test.hpp>22BOOST_FIXTURE_TEST_SUITE(validation_tests, BasicTestingSetup)24static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)25{26int maxHalvings = 64;27CAmount nInitialSubsidy = 50 * COIN;29CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 030BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);31for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {32int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;33CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);34BOOST_CHECK(nSubsidy <= nInitialSubsidy);35BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);36nPreviousSubsidy = nSubsidy;37}38BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);39}41static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)42{43Consensus::Params consensusParams;44consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;45TestBlockSubsidyHalvings(consensusParams);46}48BOOST_AUTO_TEST_CASE(block_subsidy_test)49{50const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);51TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in main52TestBlockSubsidyHalvings(150); // As in regtest53TestBlockSubsidyHalvings(1000); // Just another interval54}56BOOST_AUTO_TEST_CASE(subsidy_limit_test)57{58const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);59CAmount nSum = 0;60for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {61CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus());62BOOST_CHECK(nSubsidy <= 50 * COIN);63nSum += nSubsidy * 1000;64BOOST_CHECK(MoneyRange(nSum));65}66BOOST_CHECK_EQUAL(nSum, CAmount{2099999997690000});67}69BOOST_AUTO_TEST_CASE(signet_parse_tests)70{71ArgsManager signet_argsman;72signet_argsman.ForceSetArg("-signetchallenge", "51"); // set challenge to OP_TRUE73const auto signet_params = CreateChainParams(signet_argsman, ChainType::SIGNET);74CBlock block;75BOOST_CHECK(signet_params->GetConsensus().signet_challenge == std::vector<uint8_t>{OP_TRUE});76CScript challenge{OP_TRUE};78// empty block is invalid79BOOST_CHECK(!SignetTxs::Create(block, challenge));80BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));82// no witness commitment83CMutableTransaction cb;84cb.vout.emplace_back(0, CScript{});85block.vtx.push_back(MakeTransactionRef(cb));86block.vtx.push_back(MakeTransactionRef(cb)); // Add dummy tx to exercise merkle root code87BOOST_CHECK(!SignetTxs::Create(block, challenge));88BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));90// no header is treated valid91std::vector<uint8_t> witness_commitment_section_141{0xaa, 0x21, 0xa9, 0xed};92for (int i = 0; i < 32; ++i) {93witness_commitment_section_141.push_back(0xff);94}95cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141;96block.vtx.at(0) = MakeTransactionRef(cb);97BOOST_CHECK(SignetTxs::Create(block, challenge));98BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));100// no data after header, valid101std::vector<uint8_t> witness_commitment_section_325{0xec, 0xc7, 0xda, 0xa2};102cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;103block.vtx.at(0) = MakeTransactionRef(cb);104BOOST_CHECK(SignetTxs::Create(block, challenge));105BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));107// Premature end of data, invalid108witness_commitment_section_325.push_back(0x01);109witness_commitment_section_325.push_back(0x51);110cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;111block.vtx.at(0) = MakeTransactionRef(cb);112BOOST_CHECK(!SignetTxs::Create(block, challenge));113BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));115// has data, valid116witness_commitment_section_325.push_back(0x00);117cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;118block.vtx.at(0) = MakeTransactionRef(cb);119BOOST_CHECK(SignetTxs::Create(block, challenge));120BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));122// Extraneous data, invalid123witness_commitment_section_325.push_back(0x00);124cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;125block.vtx.at(0) = MakeTransactionRef(cb);126BOOST_CHECK(!SignetTxs::Create(block, challenge));127BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));128}130//! Test retrieval of valid assumeutxo values.131BOOST_AUTO_TEST_CASE(test_assumeutxo)132{133const auto params = CreateChainParams(*m_node.args, ChainType::REGTEST);135// These heights don't have assumeutxo configurations associated, per the contents136// of kernel/chainparams.cpp.137std::vector<int> bad_heights{0, 100, 111, 115, 209, 211};139for (auto empty : bad_heights) {140const auto out = params->AssumeutxoForHeight(empty);141BOOST_CHECK(!out);142}144const auto out110 = *params->AssumeutxoForHeight(110);145BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "86e9a1205b418b16dde3a18a78c730e30137e28466bda5dbf6b33ab8fc05447c");146BOOST_CHECK_EQUAL(out110.m_chain_tx_count, 111U);148const auto out110_2 = *params->AssumeutxoForBlockhash(uint256{"135eec25a6fb277884e5824e7aa7d052c4868161c99a5122170b5266f86c273d"});149BOOST_CHECK_EQUAL(out110_2.hash_serialized.ToString(), "86e9a1205b418b16dde3a18a78c730e30137e28466bda5dbf6b33ab8fc05447c");150BOOST_CHECK_EQUAL(out110_2.m_chain_tx_count, 111U);151}153BOOST_AUTO_TEST_CASE(block_malleation)154{155// Test utilities that calls `IsBlockMutated` and then clears the validity156// cache flags on `CBlock`.157auto is_mutated = [](CBlock& block, bool check_witness_root) {158bool mutated{IsBlockMutated(block, check_witness_root)};159block.fChecked = false;160block.m_checked_witness_commitment = false;161block.m_checked_merkle_root = false;162return mutated;163};164auto is_not_mutated = [&is_mutated](CBlock& block, bool check_witness_root) {165return !is_mutated(block, check_witness_root);166};168// Test utilities to create coinbase transactions and insert witness169// commitments.170//171// Note: this will not include the witness stack by default to avoid172// triggering the "no witnesses allowed for blocks that don't commit to173// witnesses" rule when testing other malleation vectors.174auto create_coinbase_tx = [](bool include_witness = false) {175CMutableTransaction coinbase;176coinbase.vin.resize(1);177if (include_witness) {178coinbase.vin[0].scriptWitness.stack.resize(1);179coinbase.vin[0].scriptWitness.stack[0] = std::vector<unsigned char>(32, 0x00);180}182coinbase.vout.resize(1);183coinbase.vout[0].scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT);184coinbase.vout[0].scriptPubKey[0] = OP_RETURN;185coinbase.vout[0].scriptPubKey[1] = 0x24;186coinbase.vout[0].scriptPubKey[2] = 0xaa;187coinbase.vout[0].scriptPubKey[3] = 0x21;188coinbase.vout[0].scriptPubKey[4] = 0xa9;189coinbase.vout[0].scriptPubKey[5] = 0xed;191auto tx = MakeTransactionRef(coinbase);192assert(tx->IsCoinBase());193return tx;194};195auto insert_witness_commitment = [](CBlock& block, uint256 commitment) {196assert(!block.vtx.empty() && block.vtx[0]->IsCoinBase() && !block.vtx[0]->vout.empty());198CMutableTransaction mtx{*block.vtx[0]};199CHash256().Write(commitment).Write(std::vector<unsigned char>(32, 0x00)).Finalize(commitment);200memcpy(&mtx.vout[0].scriptPubKey[6], commitment.begin(), 32);201block.vtx[0] = MakeTransactionRef(mtx);202};204{205CBlock block;207// Empty block is expected to have merkle root of 0x0.208BOOST_CHECK(block.vtx.empty());209block.hashMerkleRoot = uint256{1};210BOOST_CHECK(is_mutated(block, /*check_witness_root=*/false));211block.hashMerkleRoot = uint256{};212BOOST_CHECK(is_not_mutated(block, /*check_witness_root=*/false));214// Block with a single coinbase tx is mutated if the merkle root is not215// equal to the coinbase tx's hash.216block.vtx.push_back(create_coinbase_tx());217BOOST_CHECK(block.vtx[0]->GetHash().ToUint256() != block.hashMerkleRoot);218BOOST_CHECK(is_mutated(block, /*check_witness_root=*/false));219block.hashMerkleRoot = block.vtx[0]->GetHash().ToUint256();220BOOST_CHECK(is_not_mutated(block, /*check_witness_root=*/false));222// Block with two transactions is mutated if the merkle root does not223// match the double sha256 of the concatenation of the two transaction224// hashes.225block.vtx.push_back(MakeTransactionRef(CMutableTransaction{}));226BOOST_CHECK(is_mutated(block, /*check_witness_root=*/false));227HashWriter hasher;228hasher.write(block.vtx[0]->GetHash());229hasher.write(block.vtx[1]->GetHash());230block.hashMerkleRoot = hasher.GetHash();231BOOST_CHECK(is_not_mutated(block, /*check_witness_root=*/false));233// Block with two transactions is mutated if any node is duplicate.234{235block.vtx[1] = block.vtx[0];236HashWriter hasher;237hasher.write(block.vtx[0]->GetHash());238hasher.write(block.vtx[1]->GetHash());239block.hashMerkleRoot = hasher.GetHash();240BOOST_CHECK(is_mutated(block, /*check_witness_root=*/false));241}243// Blocks with 64-byte coinbase transactions are not considered mutated244block.vtx.clear();245{246CMutableTransaction mtx;247mtx.vin.resize(1);248mtx.vout.resize(1);249mtx.vout[0].scriptPubKey.resize(4);250block.vtx.push_back(MakeTransactionRef(mtx));
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.