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) 2011-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 <blockencodings.h>6#include <chainparams.h>7#include <consensus/merkle.h>8#include <pow.h>9#include <streams.h>10#include <test/util/random.h>11#include <test/util/txmempool.h>13#include <test/util/common.h>14#include <test/util/setup_common.h>16#include <boost/test/unit_test.hpp>18const std::vector<std::pair<Wtxid, CTransactionRef>> empty_extra_txn;20BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)22static CMutableTransaction BuildTransactionTestCase() {23CMutableTransaction tx;24tx.vin.resize(1);25tx.vin[0].scriptSig.resize(10);26tx.vout.resize(1);27tx.vout[0].nValue = 42;28return tx;29}31static CBlock BuildBlockTestCase(FastRandomContext& ctx) {32CBlock block;33CMutableTransaction tx = BuildTransactionTestCase();35block.vtx.resize(3);36block.vtx[0] = MakeTransactionRef(tx);37block.nVersion = 42;38block.hashPrevBlock = ctx.rand256();39block.nBits = 0x207fffff;41tx.vin[0].prevout.hash = Txid::FromUint256(ctx.rand256());42tx.vin[0].prevout.n = 0;43block.vtx[1] = MakeTransactionRef(tx);45tx.vin.resize(10);46for (size_t i = 0; i < tx.vin.size(); i++) {47tx.vin[i].prevout.hash = Txid::FromUint256(ctx.rand256());48tx.vin[i].prevout.n = 0;49}50block.vtx[2] = MakeTransactionRef(tx);52bool mutated;53block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);54assert(!mutated);55while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;56return block;57}59// Number of shared use_counts we expect for a tx we haven't touched60// (block + mempool entry + our copy from the GetSharedTx call)61constexpr long SHARED_TX_OFFSET{3};63BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)64{65CTxMemPool& pool = *Assert(m_node.mempool);66TestMemPoolEntryHelper entry;67auto rand_ctx(FastRandomContext(uint256{42}));68CBlock block(BuildBlockTestCase(rand_ctx));70LOCK2(cs_main, pool.cs);71TryAddToMempool(pool, entry.FromTx(block.vtx[2]));72BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);74// Do a simple ShortTxIDs RT75{76CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()};78DataStream stream{};79stream << shortIDs;81CBlockHeaderAndShortTxIDs shortIDs2;82stream >> shortIDs2;84PartiallyDownloadedBlock partialBlock(&pool);85BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);86BOOST_CHECK( partialBlock.IsTxAvailable(0));87BOOST_CHECK(!partialBlock.IsTxAvailable(1));88BOOST_CHECK( partialBlock.IsTxAvailable(2));90BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);92size_t poolSize = pool.size();93pool.removeRecursive(*block.vtx[2], MemPoolRemovalReason::REPLACED);94BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);96CBlock block2;97{98PartiallyDownloadedBlock tmp = partialBlock;99BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_INVALID); // No transactions100partialBlock = tmp;101}103// Wrong transaction104{105PartiallyDownloadedBlock tmp = partialBlock;106partialBlock.FillBlock(block2, {block.vtx[2]}, /*segwit_active=*/true); // Current implementation doesn't check txn here, but don't require that107partialBlock = tmp;108}109bool mutated;110BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));112CBlock block3;113BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}, /*segwit_active=*/true) == READ_STATUS_OK);114BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());115BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());116BOOST_CHECK(!mutated);117}118}120class TestHeaderAndShortIDs {121// Utility to encode custom CBlockHeaderAndShortTxIDs122public:123CBlockHeader header;124uint64_t nonce;125std::vector<uint64_t> shorttxids;126std::vector<PrefilledTransaction> prefilledtxn;128explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {129DataStream stream{};130stream << orig;131stream >> *this;132}133explicit TestHeaderAndShortIDs(const CBlock& block, FastRandomContext& ctx) :134TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block, ctx.rand64()}) {}136uint64_t GetShortID(const Wtxid& txhash) const {137DataStream stream{};138stream << *this;139CBlockHeaderAndShortTxIDs base;140stream >> base;141return base.GetShortID(txhash);142}144SERIALIZE_METHODS(TestHeaderAndShortIDs, obj) { READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<CBlockHeaderAndShortTxIDs::SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn); }145};147struct TestPartiallyDownloadedBlock : PartiallyDownloadedBlock {148using PartiallyDownloadedBlock::PartiallyDownloadedBlock;150size_t GetMempoolCount() const { return mempool_count; }151size_t GetExtraCount() const { return extra_count; }152};154BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)155{156CTxMemPool& pool = *Assert(m_node.mempool);157TestMemPoolEntryHelper entry;158auto rand_ctx(FastRandomContext(uint256{42}));159CBlock block(BuildBlockTestCase(rand_ctx));161LOCK2(cs_main, pool.cs);162TryAddToMempool(pool, entry.FromTx(block.vtx[2]));163BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);165Txid txhash;167// Test with pre-forwarding tx 1, but not coinbase168{169TestHeaderAndShortIDs shortIDs(block, rand_ctx);170shortIDs.prefilledtxn.resize(1);171shortIDs.prefilledtxn[0] = {1, block.vtx[1]};172shortIDs.shorttxids.resize(2);173shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetWitnessHash());174shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetWitnessHash());176DataStream stream{};177stream << shortIDs;179CBlockHeaderAndShortTxIDs shortIDs2;180stream >> shortIDs2;182PartiallyDownloadedBlock partialBlock(&pool);183BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);184BOOST_CHECK(!partialBlock.IsTxAvailable(0));185BOOST_CHECK( partialBlock.IsTxAvailable(1));186BOOST_CHECK( partialBlock.IsTxAvailable(2));188BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1); // +1 because of partialBlock190CBlock block2;191{192PartiallyDownloadedBlock tmp = partialBlock;193BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_INVALID); // No transactions194partialBlock = tmp;195}197// Wrong transaction198{199PartiallyDownloadedBlock tmp = partialBlock;200partialBlock.FillBlock(block2, {block.vtx[1]}, /*segwit_active=*/true); // Current implementation doesn't check txn here, but don't require that201partialBlock = tmp;202}203BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 2); // +2 because of partialBlock and block2204bool mutated;205BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));207CBlock block3;208PartiallyDownloadedBlock partialBlockCopy = partialBlock;209BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}, /*segwit_active=*/true) == READ_STATUS_OK);210BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());211BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());212BOOST_CHECK(!mutated);214BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 3); // +2 because of partialBlock and block2 and block3216txhash = block.vtx[2]->GetHash();217block.vtx.clear();218block2.vtx.clear();219block3.vtx.clear();220BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.221}222BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block223}225BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)226{227CTxMemPool& pool = *Assert(m_node.mempool);228TestMemPoolEntryHelper entry;229auto rand_ctx(FastRandomContext(uint256{42}));230CBlock block(BuildBlockTestCase(rand_ctx));232LOCK2(cs_main, pool.cs);233TryAddToMempool(pool, entry.FromTx(block.vtx[1]));234BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);236Txid txhash;238// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool239{240TestHeaderAndShortIDs shortIDs(block, rand_ctx);241shortIDs.prefilledtxn.resize(2);242shortIDs.prefilledtxn[0] = {0, block.vtx[0]};243shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1244shortIDs.shorttxids.resize(1);245shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetWitnessHash());247DataStream stream{};248stream << shortIDs;250CBlockHeaderAndShortTxIDs shortIDs2;
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.