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.
251stream >> shortIDs2;253PartiallyDownloadedBlock partialBlock(&pool);254BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);255BOOST_CHECK( partialBlock.IsTxAvailable(0));256BOOST_CHECK( partialBlock.IsTxAvailable(1));257BOOST_CHECK( partialBlock.IsTxAvailable(2));259BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);261CBlock block2;262PartiallyDownloadedBlock partialBlockCopy = partialBlock;263BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_OK);264BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());265bool mutated;266BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());267BOOST_CHECK(!mutated);269txhash = block.vtx[1]->GetHash();270block.vtx.clear();271block2.vtx.clear();272BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.273}274BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block275}277BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)278{279CTxMemPool& pool = *Assert(m_node.mempool);280CMutableTransaction coinbase = BuildTransactionTestCase();282CBlock block;283auto rand_ctx(FastRandomContext(uint256{42}));284block.vtx.resize(1);285block.vtx[0] = MakeTransactionRef(std::move(coinbase));286block.nVersion = 42;287block.hashPrevBlock = rand_ctx.rand256();288block.nBits = 0x207fffff;290bool mutated;291block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);292assert(!mutated);293while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;295// Test simple header round-trip with only coinbase296{297CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()};299DataStream stream{};300stream << shortIDs;302CBlockHeaderAndShortTxIDs shortIDs2;303stream >> shortIDs2;305PartiallyDownloadedBlock partialBlock(&pool);306BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);307BOOST_CHECK(partialBlock.IsTxAvailable(0));309CBlock block2;310std::vector<CTransactionRef> vtx_missing;311BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing, /*segwit_active=*/true) == READ_STATUS_OK);312BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());313BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());314BOOST_CHECK(!mutated);315}316}318BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {319CTxMemPool& pool = *Assert(m_node.mempool);320TestMemPoolEntryHelper entry;321auto rand_ctx(FastRandomContext(uint256{42}));323CMutableTransaction mtx = BuildTransactionTestCase();324mtx.vin[0].prevout.hash = Txid::FromUint256(rand_ctx.rand256());325mtx.vin[0].prevout.n = 0;326const CTransactionRef non_block_tx = MakeTransactionRef(std::move(mtx));328CBlock block(BuildBlockTestCase(rand_ctx));329// Leave one transaction missing so scanning doesn't stop before the collision.330mtx = BuildTransactionTestCase();331mtx.vin[0].prevout.hash = Txid::FromUint256(rand_ctx.rand256());332block.vtx.push_back(MakeTransactionRef(std::move(mtx)));333block.hashMerkleRoot = BlockMerkleRoot(block);334while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;336std::vector<std::pair<Wtxid, CTransactionRef>> extra_txn;337extra_txn.resize(10);339LOCK2(cs_main, pool.cs);340TryAddToMempool(pool, entry.FromTx(block.vtx[2]));341BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);342// Ensure the non_block_tx is actually not in the block343for (const auto &block_tx : block.vtx) {344BOOST_CHECK_NE(block_tx->GetHash(), non_block_tx->GetHash());345}346// Ensure block.vtx[1] is not in pool347BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()), nullptr);349{350const CBlockHeaderAndShortTxIDs cmpctblock{block, rand_ctx.rand64()};351PartiallyDownloadedBlock partial_block(&pool);352PartiallyDownloadedBlock partial_block_with_extra(&pool);354BOOST_CHECK(partial_block.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);355BOOST_CHECK( partial_block.IsTxAvailable(0));356BOOST_CHECK(!partial_block.IsTxAvailable(1));357BOOST_CHECK( partial_block.IsTxAvailable(2));359// Add an unrelated tx to extra_txn:360extra_txn[0] = {non_block_tx->GetWitnessHash(), non_block_tx};361// and a tx from the block that's not in the mempool:362extra_txn[1] = {block.vtx[1]->GetWitnessHash(), block.vtx[1]};364BOOST_CHECK(partial_block_with_extra.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);365BOOST_CHECK(partial_block_with_extra.IsTxAvailable(0));366// This transaction is now available via extra_txn:367BOOST_CHECK(partial_block_with_extra.IsTxAvailable(1));368BOOST_CHECK(partial_block_with_extra.IsTxAvailable(2));370// Simulate a mempool collision after finding an unrelated extra transaction.371extra_txn[2] = {block.vtx[2]->GetWitnessHash(), non_block_tx};372TestPartiallyDownloadedBlock partial_block_with_extra_collision{&pool};373BOOST_CHECK_EQUAL(partial_block_with_extra_collision.InitData(cmpctblock, extra_txn), READ_STATUS_OK);374BOOST_CHECK(partial_block_with_extra_collision.IsTxAvailable(1));375BOOST_CHECK(!partial_block_with_extra_collision.IsTxAvailable(2));376BOOST_CHECK_EQUAL(partial_block_with_extra_collision.GetMempoolCount(), 1U);377BOOST_CHECK_EQUAL(partial_block_with_extra_collision.GetExtraCount(), 1U);379// Now also collide the extra-sourced slot: both counters decrement exactly once.380extra_txn[3] = {block.vtx[1]->GetWitnessHash(), non_block_tx};381TestPartiallyDownloadedBlock partial_block_with_extra_source_collision{&pool};382BOOST_CHECK_EQUAL(partial_block_with_extra_source_collision.InitData(cmpctblock, extra_txn), READ_STATUS_OK);383BOOST_CHECK(!partial_block_with_extra_source_collision.IsTxAvailable(1));384BOOST_CHECK(!partial_block_with_extra_source_collision.IsTxAvailable(2));385BOOST_CHECK_EQUAL(partial_block_with_extra_source_collision.GetMempoolCount(), 0U);386BOOST_CHECK_EQUAL(partial_block_with_extra_source_collision.GetExtraCount(), 0U);388// Collided slots are terminal: not even the genuine transactions refill them.389extra_txn[4] = {block.vtx[2]->GetWitnessHash(), block.vtx[2]};390extra_txn[5] = {block.vtx[1]->GetWitnessHash(), block.vtx[1]};391TestPartiallyDownloadedBlock partial_block_no_refill{&pool};392BOOST_CHECK_EQUAL(partial_block_no_refill.InitData(cmpctblock, extra_txn), READ_STATUS_OK);393BOOST_CHECK(!partial_block_no_refill.IsTxAvailable(1));394BOOST_CHECK(!partial_block_no_refill.IsTxAvailable(2));395BOOST_CHECK_EQUAL(partial_block_no_refill.GetMempoolCount(), 0U);396BOOST_CHECK_EQUAL(partial_block_no_refill.GetExtraCount(), 0U);397}398}400BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {401BlockTransactionsRequest req1;402req1.blockhash = m_rng.rand256();403req1.indexes.resize(4);404req1.indexes[0] = 0;405req1.indexes[1] = 1;406req1.indexes[2] = 3;407req1.indexes[3] = 4;409DataStream stream{};410stream << req1;412BlockTransactionsRequest req2;413stream >> req2;415BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString());416BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size());417BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]);418BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]);419BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]);420BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);421}423BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {424// Check that the highest legal index is decoded correctly425BlockTransactionsRequest req0;426req0.blockhash = m_rng.rand256();427req0.indexes.resize(1);428req0.indexes[0] = 0xffff;429DataStream stream{};430stream << req0;432BlockTransactionsRequest req1;433stream >> req1;434BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size());435BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]);436}438BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {439// Any set of index deltas that starts with N values that sum to (0x10000 - N)440// causes the edge-case overflow that was originally not checked for. Such441// a request cannot be created by serializing a real BlockTransactionsRequest442// due to the overflow, so here we'll serialize from raw deltas.443BlockTransactionsRequest req0;444req0.blockhash = m_rng.rand256();445req0.indexes.resize(3);446req0.indexes[0] = 0x7000;447req0.indexes[1] = 0x10000 - 0x7000 - 2;448req0.indexes[2] = 0;449DataStream stream{};450stream << req0.blockhash;451WriteCompactSize(stream, req0.indexes.size());452WriteCompactSize(stream, req0.indexes[0]);453WriteCompactSize(stream, req0.indexes[1]);454WriteCompactSize(stream, req0.indexes[2]);456BlockTransactionsRequest req1;457BOOST_CHECK_EXCEPTION(stream >> req1, std::ios_base::failure, HasReason{"differential value overflow"});458}460BOOST_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.