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 <common/system.h>6#include <policy/policy.h>7#include <test/util/time.h>8#include <test/util/txmempool.h>9#include <txmempool.h>10#include <util/time.h>12#include <test/util/setup_common.h>14#include <boost/test/unit_test.hpp>15#include <vector>17BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)19static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::REPLACED;21class MemPoolTest final : public CTxMemPool22{23public:24using CTxMemPool::GetMinFee;25};27BOOST_AUTO_TEST_CASE(MempoolLookupTest)28{29auto& pool = static_cast<MemPoolTest&>(*Assert(m_node.mempool));30LOCK2(cs_main, pool.cs);31TestMemPoolEntryHelper entry;33CMutableTransaction tx = CMutableTransaction();34tx.vin.resize(1);35tx.vin[0].scriptSig = CScript() << OP_1;36tx.vout.resize(1);37tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;38tx.vout[0].nValue = 10 * COIN;40// Not in the mempool, so can't find it by txid or wtxid41BOOST_CHECK(!pool.get(tx.GetHash()));42BOOST_CHECK(!pool.get(CTransaction(tx).GetWitnessHash()));44TryAddToMempool(pool, entry.Fee(1000LL).FromTx(tx));46// Lookup by Txid47BOOST_CHECK(pool.get(tx.GetHash()));49// Lookup by Wtxid50BOOST_CHECK(pool.get(CTransaction(tx).GetWitnessHash()));51}53BOOST_AUTO_TEST_CASE(MempoolRemoveTest)54{55// Test CTxMemPool::remove functionality57TestMemPoolEntryHelper entry;58// Parent transaction with three children,59// and three grand-children:60CMutableTransaction txParent;61txParent.vin.resize(1);62txParent.vin[0].scriptSig = CScript() << OP_11;63txParent.vout.resize(3);64for (int i = 0; i < 3; i++)65{66txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;67txParent.vout[i].nValue = 33000LL;68}69CMutableTransaction txChild[3];70for (int i = 0; i < 3; i++)71{72txChild[i].vin.resize(1);73txChild[i].vin[0].scriptSig = CScript() << OP_11;74txChild[i].vin[0].prevout.hash = txParent.GetHash();75txChild[i].vin[0].prevout.n = i;76txChild[i].vout.resize(1);77txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;78txChild[i].vout[0].nValue = 11000LL;79}80CMutableTransaction txGrandChild[3];81for (int i = 0; i < 3; i++)82{83txGrandChild[i].vin.resize(1);84txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;85txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();86txGrandChild[i].vin[0].prevout.n = 0;87txGrandChild[i].vout.resize(1);88txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;89txGrandChild[i].vout[0].nValue = 11000LL;90}93CTxMemPool& testPool = *Assert(m_node.mempool);94LOCK2(::cs_main, testPool.cs);96// Nothing in pool, remove should do nothing:97unsigned int poolSize = testPool.size();98testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);99BOOST_CHECK_EQUAL(testPool.size(), poolSize);101// Just the parent:102TryAddToMempool(testPool, entry.FromTx(txParent));103poolSize = testPool.size();104testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);105BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);107// Parent, children, grandchildren:108TryAddToMempool(testPool, entry.FromTx(txParent));109for (int i = 0; i < 3; i++)110{111TryAddToMempool(testPool, entry.FromTx(txChild[i]));112TryAddToMempool(testPool, entry.FromTx(txGrandChild[i]));113}114// Remove Child[0], GrandChild[0] should be removed:115poolSize = testPool.size();116testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);117BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);118// ... make sure grandchild and child are gone:119poolSize = testPool.size();120testPool.removeRecursive(CTransaction(txGrandChild[0]), REMOVAL_REASON_DUMMY);121BOOST_CHECK_EQUAL(testPool.size(), poolSize);122poolSize = testPool.size();123testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);124BOOST_CHECK_EQUAL(testPool.size(), poolSize);125// Remove parent, all children/grandchildren should go:126poolSize = testPool.size();127testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);128BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);129BOOST_CHECK_EQUAL(testPool.size(), 0U);131// Add children and grandchildren, but NOT the parent (simulate the parent being in a block)132for (int i = 0; i < 3; i++)133{134TryAddToMempool(testPool, entry.FromTx(txChild[i]));135TryAddToMempool(testPool, entry.FromTx(txGrandChild[i]));136}137// Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be138// put into the mempool (maybe because it is non-standard):139poolSize = testPool.size();140testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);141BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);142BOOST_CHECK_EQUAL(testPool.size(), 0U);143}145BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)146{147auto& pool = static_cast<MemPoolTest&>(*Assert(m_node.mempool));148LOCK2(cs_main, pool.cs);149TestMemPoolEntryHelper entry;151CMutableTransaction tx1 = CMutableTransaction();152tx1.vin.resize(1);153tx1.vin[0].scriptSig = CScript() << OP_1;154tx1.vout.resize(1);155tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;156tx1.vout[0].nValue = 10 * COIN;157TryAddToMempool(pool, entry.Fee(1000LL).FromTx(tx1));159CMutableTransaction tx2 = CMutableTransaction();160tx2.vin.resize(1);161tx2.vin[0].scriptSig = CScript() << OP_2;162tx2.vout.resize(1);163tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;164tx2.vout[0].nValue = 10 * COIN;165TryAddToMempool(pool, entry.Fee(500LL).FromTx(tx2));167pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing168BOOST_CHECK(pool.exists(tx1.GetHash()));169BOOST_CHECK(pool.exists(tx2.GetHash()));171pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction172BOOST_CHECK(pool.exists(tx1.GetHash()));173BOOST_CHECK(!pool.exists(tx2.GetHash()));175TryAddToMempool(pool, entry.FromTx(tx2));176CMutableTransaction tx3 = CMutableTransaction();177tx3.vin.resize(1);178tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);179tx3.vin[0].scriptSig = CScript() << OP_2;180tx3.vout.resize(1);181tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;182tx3.vout[0].nValue = 10 * COIN;183TryAddToMempool(pool, entry.Fee(2000LL).FromTx(tx3));185pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)186BOOST_CHECK(!pool.exists(tx1.GetHash()));187BOOST_CHECK(pool.exists(tx2.GetHash()));188BOOST_CHECK(pool.exists(tx3.GetHash()));190pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits191BOOST_CHECK(!pool.exists(tx1.GetHash()));192BOOST_CHECK(!pool.exists(tx2.GetHash()));193BOOST_CHECK(!pool.exists(tx3.GetHash()));195CFeeRate maxFeeRateRemoved(2500, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));196BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);198CMutableTransaction tx4 = CMutableTransaction();199tx4.vin.resize(2);200tx4.vin[0].prevout.SetNull();201tx4.vin[0].scriptSig = CScript() << OP_4;202tx4.vin[1].prevout.SetNull();203tx4.vin[1].scriptSig = CScript() << OP_4;204tx4.vout.resize(2);205tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;206tx4.vout[0].nValue = 10 * COIN;207tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;208tx4.vout[1].nValue = 10 * COIN;210CMutableTransaction tx5 = CMutableTransaction();211tx5.vin.resize(2);212tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);213tx5.vin[0].scriptSig = CScript() << OP_4;214tx5.vin[1].prevout.SetNull();215tx5.vin[1].scriptSig = CScript() << OP_5;216tx5.vout.resize(2);217tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;218tx5.vout[0].nValue = 10 * COIN;219tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;220tx5.vout[1].nValue = 10 * COIN;222CMutableTransaction tx6 = CMutableTransaction();223tx6.vin.resize(2);224tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);225tx6.vin[0].scriptSig = CScript() << OP_4;226tx6.vin[1].prevout.SetNull();227tx6.vin[1].scriptSig = CScript() << OP_6;228tx6.vout.resize(2);229tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;230tx6.vout[0].nValue = 10 * COIN;231tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;232tx6.vout[1].nValue = 10 * COIN;234CMutableTransaction tx7 = CMutableTransaction();235tx7.vin.resize(2);236tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);237tx7.vin[0].scriptSig = CScript() << OP_5;238tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);239tx7.vin[1].scriptSig = CScript() << OP_6;240tx7.vout.resize(2);241tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;242tx7.vout[0].nValue = 10 * COIN;243tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;244tx7.vout[1].nValue = 10 * COIN;246TryAddToMempool(pool, entry.Fee(700LL).FromTx(tx4));247auto usage_with_tx4_only = pool.DynamicMemoryUsage();248TryAddToMempool(pool, entry.Fee(100LL).FromTx(tx5));249TryAddToMempool(pool, entry.Fee(110LL).FromTx(tx6));250TryAddToMempool(pool, entry.Fee(900LL).FromTx(tx7));
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.