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.
501size_t expected_num_orphans = orphanage->CountUniqueOrphans();503// Non-existent peer; nothing should be deleted504orphanage->EraseForPeer(/*peer=*/-1);505BOOST_CHECK_EQUAL(orphanage->CountUniqueOrphans(), expected_num_orphans);507// Each of first three peers stored508// two transactions each.509for (NodeId i = 0; i < 3; i++)510{511orphanage->EraseForPeer(i);512expected_num_orphans -= 2;513BOOST_CHECK_EQUAL(orphanage->CountUniqueOrphans(), expected_num_orphans);514}515}517BOOST_AUTO_TEST_CASE(same_txid_diff_witness)518{519FastRandomContext det_rand{true};520std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};521NodeId peer{0};523std::vector<COutPoint> empty_outpoints;524auto parent = MakeTransactionSpending(empty_outpoints, det_rand);526// Create children to go into orphanage.527auto child_normal = MakeTransactionSpending({{parent->GetHash(), 0}}, det_rand);528auto child_mutated = MakeMutation(child_normal);530const auto& normal_wtxid = child_normal->GetWitnessHash();531const auto& mutated_wtxid = child_mutated->GetWitnessHash();532BOOST_CHECK(normal_wtxid != mutated_wtxid);534BOOST_CHECK(orphanage->AddTx(child_normal, peer));535// EraseTx fails as transaction by this wtxid doesn't exist.536BOOST_CHECK_EQUAL(orphanage->EraseTx(mutated_wtxid), 0);537BOOST_CHECK(orphanage->HaveTx(normal_wtxid));538BOOST_CHECK(orphanage->GetTx(normal_wtxid) == child_normal);539BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));540BOOST_CHECK(orphanage->GetTx(mutated_wtxid) == nullptr);542// Must succeed. Both transactions should be present in orphanage.543BOOST_CHECK(orphanage->AddTx(child_mutated, peer));544BOOST_CHECK(orphanage->HaveTx(normal_wtxid));545BOOST_CHECK(orphanage->HaveTx(mutated_wtxid));547// Outpoints map should track all entries: check that both are returned as children of the parent.548std::set<CTransactionRef> expected_children{child_normal, child_mutated};549BOOST_CHECK(EqualTxns(expected_children, orphanage->GetChildrenFromSamePeer(parent, peer)));551// Erase by wtxid: mutated first552BOOST_CHECK_EQUAL(orphanage->EraseTx(mutated_wtxid), 1);553BOOST_CHECK(orphanage->HaveTx(normal_wtxid));554BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));556BOOST_CHECK_EQUAL(orphanage->EraseTx(normal_wtxid), 1);557BOOST_CHECK(!orphanage->HaveTx(normal_wtxid));558BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));559}562BOOST_AUTO_TEST_CASE(get_children)563{564FastRandomContext det_rand{true};565std::vector<COutPoint> empty_outpoints;567auto parent1 = MakeTransactionSpending(empty_outpoints, det_rand);568auto parent2 = MakeTransactionSpending(empty_outpoints, det_rand);570// Make sure these parents have different txids otherwise this test won't make sense.571while (parent1->GetHash() == parent2->GetHash()) {572parent2 = MakeTransactionSpending(empty_outpoints, det_rand);573}575// Create children to go into orphanage.576auto child_p1n0 = MakeTransactionSpending({{parent1->GetHash(), 0}}, det_rand);577auto child_p2n1 = MakeTransactionSpending({{parent2->GetHash(), 1}}, det_rand);578// Spends the same tx twice. Should not cause duplicates.579auto child_p1n0_p1n1 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent1->GetHash(), 1}}, det_rand);580// Spends the same outpoint as previous tx. Should still be returned; don't assume outpoints are unique.581auto child_p1n0_p2n0 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent2->GetHash(), 0}}, det_rand);583const NodeId node0{0};584const NodeId node1{1};585const NodeId node2{2};586const NodeId node3{3};588// All orphans provided by node1589{590auto orphanage{node::MakeTxOrphanage()};591BOOST_CHECK(orphanage->AddTx(child_p1n0, node1));592BOOST_CHECK(orphanage->AddTx(child_p2n1, node1));593BOOST_CHECK(orphanage->AddTx(child_p1n0_p1n1, node1));594BOOST_CHECK(orphanage->AddTx(child_p1n0_p2n0, node1));596// Also add some other announcers for the same transactions597BOOST_CHECK(!orphanage->AddTx(child_p1n0_p1n1, node0));598BOOST_CHECK(!orphanage->AddTx(child_p2n1, node0));599BOOST_CHECK(!orphanage->AddTx(child_p1n0, node3));602std::vector<CTransactionRef> expected_parent1_children{child_p1n0_p2n0, child_p1n0_p1n1, child_p1n0};603std::vector<CTransactionRef> expected_parent2_children{child_p1n0_p2n0, child_p2n1};605BOOST_CHECK(expected_parent1_children == orphanage->GetChildrenFromSamePeer(parent1, node1));606BOOST_CHECK(expected_parent2_children == orphanage->GetChildrenFromSamePeer(parent2, node1));608// The peer must match609BOOST_CHECK(orphanage->GetChildrenFromSamePeer(parent1, node2).empty());610BOOST_CHECK(orphanage->GetChildrenFromSamePeer(parent2, node2).empty());612// There shouldn't be any children of this tx in the orphanage613BOOST_CHECK(orphanage->GetChildrenFromSamePeer(child_p1n0_p2n0, node1).empty());614BOOST_CHECK(orphanage->GetChildrenFromSamePeer(child_p1n0_p2n0, node2).empty());615}617// Orphans provided by node1 and node2618{619std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};620BOOST_CHECK(orphanage->AddTx(child_p1n0, node1));621BOOST_CHECK(orphanage->AddTx(child_p2n1, node1));622BOOST_CHECK(orphanage->AddTx(child_p1n0_p1n1, node2));623BOOST_CHECK(orphanage->AddTx(child_p1n0_p2n0, node2));625// +----------------+---------------+----------------------------------+626// | | sender=node1 | sender=node2 |627// +----------------+---------------+----------------------------------+628// | spends parent1 | child_p1n0 | child_p1n0_p1n1, child_p1n0_p2n0 |629// | spends parent2 | child_p2n1 | child_p1n0_p2n0 |630// +----------------+---------------+----------------------------------+632// Children of parent1 from node1:633{634std::set<CTransactionRef> expected_parent1_node1{child_p1n0};636BOOST_CHECK_EQUAL(orphanage->GetChildrenFromSamePeer(parent1, node1).size(), 1);637BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0->GetWitnessHash(), node1));638BOOST_CHECK(EqualTxns(expected_parent1_node1, orphanage->GetChildrenFromSamePeer(parent1, node1)));639}641// Children of parent2 from node1:642{643std::set<CTransactionRef> expected_parent2_node1{child_p2n1};645BOOST_CHECK(EqualTxns(expected_parent2_node1, orphanage->GetChildrenFromSamePeer(parent2, node1)));646}648// Children of parent1 from node2: newest returned first.649{650std::vector<CTransactionRef> expected_parent1_node2{child_p1n0_p2n0, child_p1n0_p1n1};651BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p1n1->GetWitnessHash(), node2));652BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p2n0->GetWitnessHash(), node2));653BOOST_CHECK(expected_parent1_node2 == orphanage->GetChildrenFromSamePeer(parent1, node2));654}656// Children of parent2 from node2:657{658std::set<CTransactionRef> expected_parent2_node2{child_p1n0_p2n0};660BOOST_CHECK_EQUAL(1, orphanage->GetChildrenFromSamePeer(parent2, node2).size());661BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p2n0->GetWitnessHash(), node2));662BOOST_CHECK(EqualTxns(expected_parent2_node2, orphanage->GetChildrenFromSamePeer(parent2, node2)));663}664}665}667BOOST_AUTO_TEST_CASE(too_large_orphan_tx)668{669std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};670CMutableTransaction tx;671tx.vin.resize(1);673// check that txs larger than MAX_STANDARD_TX_WEIGHT are not added to the orphanage674BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT + 4);675BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT + 4);676BOOST_CHECK(!orphanage->AddTx(MakeTransactionRef(tx), 0));678tx.vout.clear();679BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT);680BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT);681BOOST_CHECK(orphanage->AddTx(MakeTransactionRef(tx), 0));682}684BOOST_AUTO_TEST_CASE(process_block)685{686FastRandomContext det_rand{true};687std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};689// Create outpoints that will be spent by transactions in the block690std::vector<COutPoint> outpoints;691const uint32_t num_outpoints{6};692outpoints.reserve(num_outpoints);693for (uint32_t i{0}; i < num_outpoints; ++i) {694// All the hashes should be different, but change the n just in case.695outpoints.emplace_back(Txid::FromUint256(det_rand.rand256()), i);696}698CBlock block;699const NodeId node{0};701auto control_tx = MakeTransactionSpending({}, det_rand);702BOOST_CHECK(orphanage->AddTx(control_tx, node));704auto bo_tx_same_txid = MakeTransactionSpending({outpoints.at(0)}, det_rand);705BOOST_CHECK(orphanage->AddTx(bo_tx_same_txid, node));706block.vtx.emplace_back(bo_tx_same_txid);708// 2 transactions with the same txid but different witness709auto b_tx_same_txid_diff_witness = MakeTransactionSpending({outpoints.at(1)}, det_rand);710block.vtx.emplace_back(b_tx_same_txid_diff_witness);712auto o_tx_same_txid_diff_witness = MakeMutation(b_tx_same_txid_diff_witness);713BOOST_CHECK(orphanage->AddTx(o_tx_same_txid_diff_witness, node));715// 2 different transactions that spend the same input.716auto b_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);717block.vtx.emplace_back(b_tx_conflict);719auto o_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);720BOOST_CHECK(orphanage->AddTx(o_tx_conflict, node));722// 2 different transactions that have 1 overlapping input.723auto b_tx_conflict_partial = MakeTransactionSpending({outpoints.at(3), outpoints.at(4)}, det_rand);724block.vtx.emplace_back(b_tx_conflict_partial);726auto o_tx_conflict_partial_2 = MakeTransactionSpending({outpoints.at(4), outpoints.at(5)}, det_rand);727BOOST_CHECK(orphanage->AddTx(o_tx_conflict_partial_2, node));729orphanage->EraseForBlock(block);730for (const auto& expected_removed : {bo_tx_same_txid, o_tx_same_txid_diff_witness, o_tx_conflict, o_tx_conflict_partial_2}) {731const auto& expected_removed_wtxid = expected_removed->GetWitnessHash();732BOOST_CHECK(!orphanage->HaveTx(expected_removed_wtxid));733}734// Only remaining tx is control_tx735BOOST_CHECK_EQUAL(orphanage->CountUniqueOrphans(), 1);736BOOST_CHECK(orphanage->HaveTx(control_tx->GetWitnessHash()));737}739BOOST_AUTO_TEST_CASE(multiple_announcers)740{741const NodeId node0{0};742const NodeId node1{1};743const NodeId node2{2};744size_t expected_total_count{0};745FastRandomContext det_rand{true};746std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};748// Check accounting per peer.749// Check that EraseForPeer works with multiple announcers.750{
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.