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.
751CMutableTransaction tx;752tx.vin.resize(1);753tx.vin[0].prevout.hash = txFirst[0]->GetHash();754tx.vin[0].prevout.n = 0;755tx.vin[0].scriptSig = CScript() << OP_1;756tx.vout.resize(1);757tx.vout[0].nValue = 5000000000LL; // 0 fee758Txid hashFreePrioritisedTx = tx.GetHash();759TryAddToMempool(tx_mempool, entry.Fee(0).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));760tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);762tx.vin[0].prevout.hash = txFirst[1]->GetHash();763tx.vin[0].prevout.n = 0;764tx.vout[0].nValue = 5000000000LL - 1000;765// This tx has a low fee: 1000 satoshis766Txid hashParentTx = tx.GetHash(); // save this txid for later use767TryAddToMempool(tx_mempool, entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));769// This tx has a medium fee: 10000 satoshis770tx.vin[0].prevout.hash = txFirst[2]->GetHash();771tx.vout[0].nValue = 5000000000LL - 10000;772Txid hashMediumFeeTx = tx.GetHash();773TryAddToMempool(tx_mempool, entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));774tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);776// This tx also has a low fee, but is prioritised777tx.vin[0].prevout.hash = hashParentTx;778tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee779Txid hashPrioritsedChild = tx.GetHash();780TryAddToMempool(tx_mempool, entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));781tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);783// Test that transaction selection properly updates ancestor fee calculations as prioritised784// parents get included in a block. Create a transaction with two prioritised ancestors, each785// included by itself: FreeParent <- FreeChild <- FreeGrandchild.786// When FreeParent is added, a modified entry will be created for FreeChild + FreeGrandchild787// FreeParent's prioritisation should not be included in that entry.788// When FreeChild is included, FreeChild's prioritisation should also not be included.789tx.vin[0].prevout.hash = txFirst[3]->GetHash();790tx.vout[0].nValue = 5000000000LL; // 0 fee791Txid hashFreeParent = tx.GetHash();792TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(tx));793tx_mempool.PrioritiseTransaction(hashFreeParent, 10 * COIN);795tx.vin[0].prevout.hash = hashFreeParent;796tx.vout[0].nValue = 5000000000LL; // 0 fee797Txid hashFreeChild = tx.GetHash();798TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));799tx_mempool.PrioritiseTransaction(hashFreeChild, 1 * COIN);801tx.vin[0].prevout.hash = hashFreeChild;802tx.vout[0].nValue = 5000000000LL; // 0 fee803Txid hashFreeGrandchild = tx.GetHash();804TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));806auto block_template = mining->createNewBlock(options, /*cooldown=*/false);807BOOST_REQUIRE(block_template);808CBlock block{block_template->getBlock()};809BOOST_REQUIRE_EQUAL(block.vtx.size(), 6U);810BOOST_CHECK(block.vtx[1]->GetHash() == hashFreeParent);811BOOST_CHECK(block.vtx[2]->GetHash() == hashFreePrioritisedTx);812BOOST_CHECK(block.vtx[3]->GetHash() == hashParentTx);813BOOST_CHECK(block.vtx[4]->GetHash() == hashPrioritsedChild);814BOOST_CHECK(block.vtx[5]->GetHash() == hashFreeChild);815for (size_t i=0; i<block.vtx.size(); ++i) {816// The FreeParent and FreeChild's prioritisations should not impact the child.817BOOST_CHECK(block.vtx[i]->GetHash() != hashFreeGrandchild);818// De-prioritised transaction should not be included.819BOOST_CHECK(block.vtx[i]->GetHash() != hashMediumFeeTx);820}821}823// NOTE: These tests rely on CreateNewBlock doing its own self-validation!824BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)825{826auto mining{MakeMining()};827BOOST_REQUIRE(mining);829// Note that by default, these tests run with size accounting enabled.830CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;831BlockCreateOptions options{832.coinbase_output_script = scriptPubKey,833};835// Create and check a simple template836std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options, /*cooldown=*/false);837BOOST_REQUIRE(block_template);839BlockCreateOptions invalid_options{options};840invalid_options.block_max_weight = DEFAULT_BLOCK_RESERVED_WEIGHT - 1;841BOOST_CHECK_EXCEPTION(mining->createNewBlock(invalid_options, /*cooldown=*/false),842std::runtime_error,843HasReason("block_reserved_weight (8000) exceeds block_max_weight (7999)"));845{846CBlock block{block_template->getBlock()};847{848std::string reason;849std::string debug;850BOOST_REQUIRE(!mining->checkBlock(block, {.check_pow = false}, reason, debug));851BOOST_REQUIRE_EQUAL(reason, "bad-txnmrklroot");852BOOST_REQUIRE_EQUAL(debug, "hashMerkleRoot mismatch");853}855block.hashMerkleRoot = BlockMerkleRoot(block);857{858std::string reason;859std::string debug;860BOOST_REQUIRE(mining->checkBlock(block, {.check_pow = false}, reason, debug));861BOOST_REQUIRE_EQUAL(reason, "");862BOOST_REQUIRE_EQUAL(debug, "");863}865{866// A block template does not have proof-of-work, but it might pass867// verification by coincidence. Grind the nonce if needed:868while (CheckProofOfWork(block.GetHash(), block.nBits, Assert(m_node.chainman)->GetParams().GetConsensus())) {869block.nNonce++;870}872std::string reason;873std::string debug;874BOOST_REQUIRE(!mining->checkBlock(block, {.check_pow = true}, reason, debug));875BOOST_REQUIRE_EQUAL(reason, "high-hash");876BOOST_REQUIRE_EQUAL(debug, "proof of work failed");877}878}880// We can't make transactions until we have inputs881// Therefore, load 110 blocks :)882static_assert(std::size(BLOCKINFO) == 110, "Should have 110 blocks to import");883int baseheight = 0;884std::vector<CTransactionRef> txFirst;885for (const auto& bi : BLOCKINFO) {886const int current_height{mining->getTip()->height};888/**889* Simple block creation, nothing special yet.890* If current_height is odd, block_template will have already been891* set at the end of the previous loop.892*/893if (current_height % 2 == 0) {894block_template = mining->createNewBlock(options, /*cooldown=*/false);895BOOST_REQUIRE(block_template);896}898CBlock block{block_template->getBlock()};899CMutableTransaction txCoinbase(*block.vtx[0]);900{901LOCK(cs_main);902block.nVersion = VERSIONBITS_TOP_BITS;903block.nTime = Assert(m_node.chainman)->ActiveChain().Tip()->GetMedianTimePast()+1;904txCoinbase.version = 1;905txCoinbase.vin[0].scriptSig = CScript{} << (current_height + 1) << bi.extranonce;906txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)907txCoinbase.vout[0].scriptPubKey = CScript();908block.vtx[0] = MakeTransactionRef(txCoinbase);909if (txFirst.size() == 0)910baseheight = current_height;911if (txFirst.size() < 4)912txFirst.push_back(block.vtx[0]);913block.hashMerkleRoot = BlockMerkleRoot(block);914block.nNonce = bi.nonce;915}916// Alternate calls between submitBlock and submitSolution via the917// Mining interface.918std::string reason{"stale reason"};919std::string debug{"stale debug"};920if (current_height % 2 == 0) {921BOOST_REQUIRE(mining->submitBlock(block, reason, debug));922BOOST_REQUIRE_EQUAL(reason, "");923BOOST_REQUIRE_EQUAL(debug, "");925reason = "stale reason";926debug = "stale debug";927BOOST_REQUIRE(!mining->submitBlock(block, reason, debug));928BOOST_REQUIRE_EQUAL(reason, "duplicate");929BOOST_REQUIRE_EQUAL(debug, "");930} else {931reason = "stale reason";932debug = "stale debug";933BOOST_REQUIRE(block_template->submitSolution(block.nVersion, block.nTime, block.nNonce, MakeTransactionRef(txCoinbase), reason, debug));934BOOST_REQUIRE_EQUAL(reason, "");935BOOST_REQUIRE_EQUAL(debug, "");936BOOST_CHECK_THROW(block_template->submitSolutionOld7(block.nVersion, block.nTime, block.nNonce,937MakeTransactionRef(txCoinbase)),938std::runtime_error);939}940{941LOCK(cs_main);942// The above calls don't guarantee the tip is actually updated, so943// we explicitly check this.944auto maybe_new_tip{Assert(m_node.chainman)->ActiveChain().Tip()};945BOOST_REQUIRE_EQUAL(maybe_new_tip->GetBlockHash(), block.GetHash());946}947if (current_height % 2 == 0) {948block_template = block_template->waitNext();949BOOST_REQUIRE(block_template);950} else {951// This just adds coverage952mining->waitTipChanged(block.hashPrevBlock);953}954}956LOCK(cs_main);958TestBasicMining(scriptPubKey, txFirst, baseheight);960m_node.chainman->ActiveChain().Tip()->nHeight--;962TestPackageSelection(scriptPubKey, txFirst);964m_node.chainman->ActiveChain().Tip()->nHeight--;966TestPrioritisedMining(scriptPubKey, txFirst);968TestSigOpsAdjustedWeightChunkLimit(scriptPubKey, txFirst);969}971BOOST_AUTO_TEST_SUITE_END()
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.