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.
251Assert(!res.m_state.IsInvalid());252Assert(res.m_vsize);253Assert(res.m_base_fees);254Assert(res.m_effective_feerate);255Assert(res.m_wtxids_fee_calculations);256Assert(!res.m_other_wtxid);257break;258}259case MempoolAcceptResult::ResultType::INVALID:260{261// It may be already in the mempool since in ATMP cases we don't set MEMPOOL_ENTRY or DIFFERENT_WITNESS262Assert(!res.m_state.IsValid());263Assert(res.m_state.IsInvalid());265const bool is_reconsiderable{res.m_state.GetResult() == TxValidationResult::TX_RECONSIDERABLE};266Assert(!res.m_vsize);267Assert(!res.m_base_fees);268// Fee information is provided if the failure is TX_RECONSIDERABLE.269// In other cases, validation may be unable or unwilling to calculate the fees.270Assert(res.m_effective_feerate.has_value() == is_reconsiderable);271Assert(res.m_wtxids_fee_calculations.has_value() == is_reconsiderable);272Assert(!res.m_other_wtxid);273break;274}275case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:276{277// ATMP never sets this; only set in package settings278Assert(false);279break;280}281case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:282{283// ATMP never sets this; only set in package settings284Assert(false);285break;286}287}288}290FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)291{292SeedRandomStateForTest(SeedRand::ZEROS);293FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());294const auto& node = g_setup->m_node;295auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};297MockTime(fuzzed_data_provider, chainstate);299// All RBF-spendable outpoints300std::set<COutPoint> outpoints_rbf;301// All outpoints counting toward the total supply (subset of outpoints_rbf)302std::set<COutPoint> outpoints_supply;303for (const auto& outpoint : g_outpoints_coinbase_init_mature) {304Assert(outpoints_supply.insert(outpoint).second);305}306outpoints_rbf = outpoints_supply;308// The sum of the values of all spendable outpoints309constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};311SetMempoolConstraints(*node.args, fuzzed_data_provider);312auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};313MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());315chainstate.SetMempool(&tx_pool);317// Helper to query an amount318const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};319const auto GetAmount = [&](const COutPoint& outpoint) {320auto coin{amount_view.GetCoin(outpoint).value()};321return coin.out.nValue;322};324LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 100) {325{326// Total supply is the mempool fee + all outpoints327CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};328for (const auto& op : outpoints_supply) {329supply_now += GetAmount(op);330}331Assert(supply_now == SUPPLY_TOTAL);332}333Assert(!outpoints_supply.empty());335// Create transaction to add to the mempool336const CTransactionRef tx = [&] {337CMutableTransaction tx_mut;338tx_mut.version = fuzzed_data_provider.ConsumeBool() ? TRUC_VERSION : CTransaction::CURRENT_VERSION;339tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();340const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size());341const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2);343CAmount amount_in{0};344for (int i = 0; i < num_in; ++i) {345// Pop random outpoint346auto pop = outpoints_rbf.begin();347std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints_rbf.size() - 1));348const auto outpoint = *pop;349outpoints_rbf.erase(pop);350amount_in += GetAmount(outpoint);352// Create input353const auto sequence = ConsumeSequence(fuzzed_data_provider);354const auto script_sig = CScript{};355const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};356CTxIn in;357in.prevout = outpoint;358in.nSequence = sequence;359in.scriptSig = script_sig;360in.scriptWitness.stack = script_wit_stack;362tx_mut.vin.push_back(in);363}365// Check sigops in mempool + block template creation366bool add_sigops{fuzzed_data_provider.ConsumeBool()};368const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1000, amount_in);369const auto amount_out = (amount_in - amount_fee) / num_out;370for (int i = 0; i < num_out; ++i) {371if (i == 0 && add_sigops) {372tx_mut.vout.emplace_back(amount_out, CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG);373} else {374tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);375}376}378auto tx = MakeTransactionRef(tx_mut);379// Restore previously removed outpoints380for (const auto& in : tx->vin) {381Assert(outpoints_rbf.insert(in.prevout).second);382}383return tx;384}();386if (fuzzed_data_provider.ConsumeBool()) {387MockTime(fuzzed_data_provider, chainstate);388}389if (fuzzed_data_provider.ConsumeBool()) {390tx_pool.RollingFeeUpdate();391}392if (fuzzed_data_provider.ConsumeBool()) {393const auto& txid = fuzzed_data_provider.ConsumeBool() ?394tx->GetHash() :395PickValue(fuzzed_data_provider, outpoints_rbf).hash;396const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);397tx_pool.PrioritiseTransaction(txid, delta);398}400// Remember all removed and added transactions401std::set<CTransactionRef> removed;402std::set<CTransactionRef> added;403auto txr = std::make_shared<TransactionsDelta>(removed, added);404node.validation_signals->RegisterSharedValidationInterface(txr);406// Make sure ProcessNewPackage on one transaction works.407// The result is not guaranteed to be the same as what is returned by ATMP.408const auto result_package = WITH_LOCK(::cs_main,409return ProcessNewPackage(chainstate, tx_pool, {tx}, true, /*client_maxfeerate=*/{}));410// If something went wrong due to a package-specific policy, it might not return a411// validation result for the transaction.412if (result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {413auto it = result_package.m_tx_results.find(tx->GetWitnessHash());414Assert(it != result_package.m_tx_results.end());415Assert(it->second.m_result_type == MempoolAcceptResult::ResultType::VALID ||416it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);417}419const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), /*bypass_limits=*/false, /*test_accept=*/false));420const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;421node.validation_signals->SyncWithValidationInterfaceQueue();422node.validation_signals->UnregisterSharedValidationInterface(txr);424bool txid_in_mempool = tx_pool.exists(tx->GetHash());425bool wtxid_in_mempool = tx_pool.exists(tx->GetWitnessHash());426CheckATMPInvariants(res, txid_in_mempool, wtxid_in_mempool);428Assert(accepted != added.empty());429if (accepted) {430Assert(added.size() == 1); // For now, no package acceptance431Assert(tx == *added.begin());432CheckMempoolTRUCInvariants(tx_pool);433} else {434// Do not consider rejected transaction removed435removed.erase(tx);436}438// Helper to insert spent and created outpoints of a tx into collections439using Sets = std::vector<std::reference_wrapper<std::set<COutPoint>>>;440const auto insert_tx = [](Sets created_by_tx, Sets consumed_by_tx, const auto& tx) {441for (size_t i{0}; i < tx.vout.size(); ++i) {442for (auto& set : created_by_tx) {443Assert(set.get().emplace(tx.GetHash(), i).second);444}445}446for (const auto& in : tx.vin) {447for (auto& set : consumed_by_tx) {448Assert(set.get().insert(in.prevout).second);449}450}451};452// Add created outpoints, remove spent outpoints453{454// Outpoints that no longer exist at all455std::set<COutPoint> consumed_erased;456// Outpoints that no longer count toward the total supply457std::set<COutPoint> consumed_supply;458for (const auto& removed_tx : removed) {459insert_tx(/*created_by_tx=*/{consumed_erased}, /*consumed_by_tx=*/{outpoints_supply}, /*tx=*/*removed_tx);460}461for (const auto& added_tx : added) {462insert_tx(/*created_by_tx=*/{outpoints_supply, outpoints_rbf}, /*consumed_by_tx=*/{consumed_supply}, /*tx=*/*added_tx);463}464for (const auto& p : consumed_erased) {465Assert(outpoints_supply.erase(p) == 1);466Assert(outpoints_rbf.erase(p) == 1);467}468for (const auto& p : consumed_supply) {469Assert(outpoints_supply.erase(p) == 1);470}471}472}473Finish(fuzzed_data_provider, tx_pool, chainstate);474}476FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)477{478SeedRandomStateForTest(SeedRand::ZEROS);479FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());480const auto& node = g_setup->m_node;481auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};483MockTime(fuzzed_data_provider, chainstate);485std::vector<Txid> txids;486txids.reserve(g_outpoints_coinbase_init_mature.size());487for (const auto& outpoint : g_outpoints_coinbase_init_mature) {488txids.push_back(outpoint.hash);489}490for (int i{0}; i <= 3; ++i) {491// Add some immature and non-existent outpoints492txids.push_back(g_outpoints_coinbase_init_immature.at(i).hash);493txids.push_back(Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider)));494}496SetMempoolConstraints(*node.args, fuzzed_data_provider);497auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};498MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());500chainstate.SetMempool(&tx_pool);
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.