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.
251auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());252BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");253}255// Check that mempool size hasn't changed.256BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);257}259BOOST_AUTO_TEST_CASE(noncontextual_package_tests)260{261// The signatures won't be verified so we can just use a placeholder262CKey placeholder_key = GenerateRandomKey();263CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));264CKey placeholder_key_2 = GenerateRandomKey();265CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));267// Parent and Child Package268{269auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,270CAmount(49 * COIN), /*submit=*/false);271CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);273auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,274CAmount(48 * COIN), /*submit=*/false);275CTransactionRef tx_child = MakeTransactionRef(mtx_child);277PackageValidationState state;278BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_child}, state));279BOOST_CHECK(!IsWellFormedPackage({tx_child, tx_parent}, state));280BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);281BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");282BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));283BOOST_CHECK(IsChildWithParentsTree({tx_parent, tx_child}));284BOOST_CHECK(GetPackageHash({tx_parent}) != GetPackageHash({tx_child}));285BOOST_CHECK(GetPackageHash({tx_child, tx_child}) != GetPackageHash({tx_child}));286BOOST_CHECK(GetPackageHash({tx_child, tx_parent}) != GetPackageHash({tx_child, tx_child}));287BOOST_CHECK(!IsChildWithParents({}));288BOOST_CHECK(!IsChildWithParentsTree({}));289}291// 24 Parents and 1 Child292{293Package package;294CMutableTransaction child;295for (int i{0}; i < 24; ++i) {296auto parent = MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],2970, 0, coinbaseKey, spk, CAmount(48 * COIN), false));298package.emplace_back(parent);299child.vin.emplace_back(COutPoint(parent->GetHash(), 0));300}301child.vout.emplace_back(47 * COIN, spk2);303// The child must be in the package.304BOOST_CHECK(!IsChildWithParents(package));306// The parents can be in any order.307FastRandomContext rng;308std::shuffle(package.begin(), package.end(), rng);309package.push_back(MakeTransactionRef(child));311PackageValidationState state;312BOOST_CHECK(IsWellFormedPackage(package, state));313BOOST_CHECK(IsChildWithParents(package));314BOOST_CHECK(IsChildWithParentsTree(package));316package.erase(package.begin());317BOOST_CHECK(IsChildWithParents(package));319// The package cannot have unrelated transactions.320package.insert(package.begin(), m_coinbase_txns[0]);321BOOST_CHECK(!IsChildWithParents(package));322}324// 2 Parents and 1 Child where one parent depends on the other.325{326CMutableTransaction mtx_parent;327mtx_parent.vin.emplace_back(COutPoint(m_coinbase_txns[0]->GetHash(), 0));328mtx_parent.vout.emplace_back(20 * COIN, spk);329mtx_parent.vout.emplace_back(20 * COIN, spk2);330CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);332CMutableTransaction mtx_parent_also_child;333mtx_parent_also_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 0));334mtx_parent_also_child.vout.emplace_back(20 * COIN, spk);335CTransactionRef tx_parent_also_child = MakeTransactionRef(mtx_parent_also_child);337CMutableTransaction mtx_child;338mtx_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 1));339mtx_child.vin.emplace_back(COutPoint(tx_parent_also_child->GetHash(), 0));340mtx_child.vout.emplace_back(39 * COIN, spk);341CTransactionRef tx_child = MakeTransactionRef(mtx_child);343PackageValidationState state;344BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));345BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));346BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));347BOOST_CHECK(!IsChildWithParentsTree({tx_parent, tx_parent_also_child, tx_child}));348// IsChildWithParents does not detect unsorted parents.349BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));350BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_parent_also_child, tx_child}, state));351BOOST_CHECK(!IsWellFormedPackage({tx_parent_also_child, tx_parent, tx_child}, state));352BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);353BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");354}355}357BOOST_AUTO_TEST_CASE(package_submission_tests)358{359// Mine blocks to mature coinbases.360mineBlocks(3);361MockMempoolMinFee(CFeeRate(5000), *m_node.mempool);362LOCK(cs_main);363unsigned int expected_pool_size = m_node.mempool->size();364CKey parent_key = GenerateRandomKey();365CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));367// Unrelated transactions are not allowed in package submission.368Package package_unrelated;369for (size_t i{0}; i < 10; ++i) {370auto mtx = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[i + 25], /*input_vout=*/0,371/*input_height=*/0, /*input_signing_key=*/coinbaseKey,372/*output_destination=*/parent_locking_script,373/*output_amount=*/CAmount(49 * COIN), /*submit=*/false);374package_unrelated.emplace_back(MakeTransactionRef(mtx));375}376auto result_unrelated_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,377package_unrelated, /*test_accept=*/false, /*client_maxfeerate=*/{});378// We don't expect m_tx_results for each transaction when basic sanity checks haven't passed.379BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());380BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);381BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");382BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);384// Parent and Child (and Grandchild) Package385Package package_parent_child;386Package package_3gen;387auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,388/*input_height=*/0, /*input_signing_key=*/coinbaseKey,389/*output_destination=*/parent_locking_script,390/*output_amount=*/CAmount(49 * COIN), /*submit=*/false);391CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);392package_parent_child.push_back(tx_parent);393package_3gen.push_back(tx_parent);395CKey child_key = GenerateRandomKey();396CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));397auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,398/*input_height=*/101, /*input_signing_key=*/parent_key,399/*output_destination=*/child_locking_script,400/*output_amount=*/CAmount(48 * COIN), /*submit=*/false);401CTransactionRef tx_child = MakeTransactionRef(mtx_child);402package_parent_child.push_back(tx_child);403package_3gen.push_back(tx_child);405CKey grandchild_key = GenerateRandomKey();406CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));407auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,408/*input_height=*/101, /*input_signing_key=*/child_key,409/*output_destination=*/grandchild_locking_script,410/*output_amount=*/CAmount(47 * COIN), /*submit=*/false);411CTransactionRef tx_grandchild = MakeTransactionRef(mtx_grandchild);412package_3gen.push_back(tx_grandchild);414// 3 Generations is not allowed.415{416auto result_3gen_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,417package_3gen, /*test_accept=*/false, /*client_maxfeerate=*/{});418BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());419BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);420BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");421BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);422}424// Parent and child package where transactions are invalid for reasons other than fee and425// missing inputs, so the package validation isn't expected to happen.426{427CScriptWitness bad_witness;428bad_witness.stack.emplace_back(1);429CMutableTransaction mtx_parent_invalid{mtx_parent};430mtx_parent_invalid.vin[0].scriptWitness = bad_witness;431CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);432Package package_invalid_parent{tx_parent_invalid, tx_child};433auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,434package_invalid_parent, /*test_accept=*/ false, /*client_maxfeerate=*/{});435if (auto err_parent_invalid{CheckPackageMempoolAcceptResult(package_invalid_parent, result_quit_early, /*expect_valid=*/false, m_node.mempool.get())}) {436BOOST_ERROR(err_parent_invalid.value());437} else {438auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());439auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());440BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);441BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");442BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);443BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");444}445BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);446}448// Submit package with parent + child.449{450const auto submit_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,451package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});452expected_pool_size += 2;453BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),454"Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());455BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());456auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());457auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());458BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());459BOOST_CHECK(it_parent->second.m_state.IsValid());460BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));461BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);462BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());463BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));464BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);465BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());467BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);468}470// Already-in-mempool transactions should be detected and de-duplicated.471{472const auto submit_deduped = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,473package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});474if (auto err_deduped{CheckPackageMempoolAcceptResult(package_parent_child, submit_deduped, /*expect_valid=*/true, m_node.mempool.get())}) {475BOOST_ERROR(err_deduped.value());476} else {477auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());478auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());479BOOST_CHECK(it_parent_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);480BOOST_CHECK(it_child_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);481}483BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);484}486// In-mempool parent and child with missing parent.487{488auto tx_parent_1 = MakeTransactionRef(CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,489/*input_height=*/0, /*input_signing_key=*/coinbaseKey,490/*output_destination=*/parent_locking_script,491/*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false));492auto tx_parent_2 = MakeTransactionRef(CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,493/*input_height=*/0, /*input_signing_key=*/coinbaseKey,494/*output_destination=*/parent_locking_script,495/*output_amount=*/CAmount(50 * COIN - 800), /*submit=*/false));497auto tx_child_missing_parent = MakeTransactionRef(CreateValidMempoolTransaction({tx_parent_1, tx_parent_2},498{{tx_parent_1->GetHash(), 0}, {tx_parent_2->GetHash(), 0}},499/*input_height=*/0, {parent_key},500{{49 * COIN, child_locking_script}}, /*submit=*/false));
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.