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.
1501[](const auto& ws) { return ws.m_ptx->GetWitnessHash(); });1502TxValidationState placeholder_state;1503if (args.m_package_feerates &&1504!CheckFeeRate(m_subpackage.m_total_vsize, m_subpackage.m_total_modified_fees, placeholder_state)) {1505package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");1506return PackageMempoolAcceptResult(package_state, {{workspaces.back().m_ptx->GetWitnessHash(),1507MempoolAcceptResult::FeeFailure(placeholder_state, CFeeRate(m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize), all_package_wtxids)}});1508}1510// Apply package mempool RBF checks.1511if (m_subpackage.m_rbf && !PackageRBFChecks(txns, workspaces, package_state)) {1512return PackageMempoolAcceptResult(package_state, std::move(results));1513}1515// Check if the transactions would exceed the cluster size limit.1516if (!m_subpackage.m_changeset->CheckMemPoolPolicyLimits()) {1517package_state.Invalid(PackageValidationResult::PCKG_POLICY, "too-large-cluster", "");1518return PackageMempoolAcceptResult(package_state, std::move(results));1519}1521// Now that we've bounded the resulting possible ancestry count, check package for dust spends1522if (m_pool.m_opts.require_standard) {1523TxValidationState child_state;1524Wtxid child_wtxid;1525if (!CheckEphemeralSpends(txns, m_pool.m_opts.dust_relay_feerate, m_pool, child_state, child_wtxid)) {1526package_state.Invalid(PackageValidationResult::PCKG_TX, "unspent-dust");1527results.emplace(child_wtxid, MempoolAcceptResult::Failure(child_state));1528return PackageMempoolAcceptResult(package_state, std::move(results));1529}1530}1532for (Workspace& ws : workspaces) {1533ws.m_package_feerate = package_feerate;1534if (!PolicyScriptChecks(ws)) {1535// Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.1536package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");1537results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));1538return PackageMempoolAcceptResult(package_state, std::move(results));1539}1540if (args.m_test_accept) {1541const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :1542CFeeRate{ws.m_modified_fees, static_cast<int32_t>(ws.m_vsize)};1543const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :1544std::vector<Wtxid>{ws.m_ptx->GetWitnessHash()};1545results.emplace(ws.m_ptx->GetWitnessHash(),1546MempoolAcceptResult::Success(std::move(m_subpackage.m_replaced_transactions),1547ws.m_vsize, ws.m_base_fees, effective_feerate,1548effective_feerate_wtxids));1549}1550}1552if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, std::move(results));1554if (!SubmitPackage(args, workspaces, package_state, results)) {1555// PackageValidationState filled in by SubmitPackage().1556return PackageMempoolAcceptResult(package_state, std::move(results));1557}1559return PackageMempoolAcceptResult(package_state, std::move(results));1560}1562void MemPoolAccept::CleanupTemporaryCoins()1563{1564// There are 3 kinds of coins in m_view:1565// (1) Temporary coins from the transactions in subpackage, constructed by m_viewmempool.1566// (2) Mempool coins from transactions in the mempool, constructed by m_viewmempool.1567// (3) Confirmed coins fetched from our current UTXO set.1568//1569// (1) Temporary coins need to be removed, regardless of whether the transaction was submitted.1570// If the transaction was submitted to the mempool, m_viewmempool will be able to fetch them from1571// there. If it wasn't submitted to mempool, it is incorrect to keep them - future calls may try1572// to spend those coins that don't actually exist.1573// (2) Mempool coins also need to be removed. If the mempool contents have changed as a result1574// of submitting or replacing transactions, coins previously fetched from mempool may now be1575// spent or nonexistent. Those coins need to be deleted from m_view.1576// (3) Confirmed coins don't need to be removed. The chainstate has not changed (we are1577// holding cs_main and no blocks have been processed) so the confirmed tx cannot disappear like1578// a mempool tx can. The coin may now be spent after we submitted a tx to mempool, but1579// we have already checked that the package does not have 2 transactions spending the same coin1580// and we check whether a mempool transaction spends conflicting coins (CTxMemPool::GetConflictTx).1581// Keeping them in m_view is an optimization to not re-fetch confirmed coins if we later look up1582// inputs for this transaction again.1583for (const auto& outpoint : m_viewmempool.GetNonBaseCoins()) {1584// In addition to resetting m_viewmempool, we also need to manually delete these coins from1585// m_view because it caches copies of the coins it fetched from m_viewmempool previously.1586m_view.Uncache(outpoint);1587}1588// This deletes the temporary and mempool coins.1589m_viewmempool.Reset();1590}1592PackageMempoolAcceptResult MemPoolAccept::AcceptSubPackage(const std::vector<CTransactionRef>& subpackage, ATMPArgs& args)1593{1594AssertLockHeld(::cs_main);1595AssertLockHeld(m_pool.cs);1596auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs) {1597if (subpackage.size() > 1) {1598return AcceptMultipleTransactionsInternal(subpackage, args);1599}1600const auto& tx = subpackage.front();1601ATMPArgs single_args = ATMPArgs::SingleInPackageAccept(args);1602const auto single_res = AcceptSingleTransactionInternal(tx, single_args);1603PackageValidationState package_state_wrapped;1604if (single_res.m_result_type != MempoolAcceptResult::ResultType::VALID) {1605package_state_wrapped.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");1606}1607return PackageMempoolAcceptResult(package_state_wrapped, {{tx->GetWitnessHash(), single_res}});1608}();1610// Clean up m_view and m_viewmempool so that other subpackage evaluations don't have access to1611// coins they shouldn't. Keep some coins in order to minimize re-fetching coins from the UTXO set.1612// Clean up package feerate and rbf calculations1613ClearSubPackageState();1615return result;1616}1618PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, ATMPArgs& args)1619{1620Assert(!package.empty());1621AssertLockHeld(cs_main);1622// Used if returning a PackageMempoolAcceptResult directly from this function.1623PackageValidationState package_state_quit_early;1625// There are two topologies we are able to handle through this function:1626// (1) A single transaction1627// (2) A child-with-parents package.1628// Check that the package is well-formed. If it isn't, we won't try to validate any of the1629// transactions and thus won't return any MempoolAcceptResults, just a package-wide error.1631// Context-free package checks.1632if (!IsWellFormedPackage(package, package_state_quit_early)) {1633return PackageMempoolAcceptResult(package_state_quit_early, {});1634}1636if (package.size() > 1 && !IsChildWithParents(package)) {1637// All transactions in the package must be a parent of the last transaction. This is just an1638// opportunity for us to fail fast on a context-free check without taking the mempool lock.1639package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents");1640return PackageMempoolAcceptResult(package_state_quit_early, {});1641}1643LOCK(m_pool.cs);1644// Stores results from which we will create the returned PackageMempoolAcceptResult.1645// A result may be changed if a mempool transaction is evicted later due to LimitMempoolSize().1646std::map<Wtxid, MempoolAcceptResult> results_final;1647// Results from individual validation which will be returned if no other result is available for1648// this transaction. "Nonfinal" because if a transaction fails by itself but succeeds later1649// (i.e. when evaluated with a fee-bumping child), the result in this map may be discarded.1650std::map<Wtxid, MempoolAcceptResult> individual_results_nonfinal;1651// Tracks whether we think package submission could result in successful entry to the mempool1652bool quit_early{false};1653std::vector<CTransactionRef> txns_package_eval;1654for (const auto& tx : package) {1655const auto& wtxid = tx->GetWitnessHash();1656const auto& txid = tx->GetHash();1657// There are 3 possibilities: already in mempool, same-txid-diff-wtxid already in mempool,1658// or not in mempool. An already confirmed tx is treated as one not in mempool, because all1659// we know is that the inputs aren't available.1660if (m_pool.exists(wtxid)) {1661// Exact transaction already exists in the mempool.1662// Node operators are free to set their mempool policies however they please, nodes may receive1663// transactions in different orders, and malicious counterparties may try to take advantage of1664// policy differences to pin or delay propagation of transactions. As such, it's possible for1665// some package transaction(s) to already be in the mempool, and we don't want to reject the1666// entire package in that case (as that could be a censorship vector). De-duplicate the1667// transactions that are already in the mempool, and only call AcceptMultipleTransactions() with1668// the new transactions. This ensures we don't double-count transaction counts and sizes when1669// checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.1670const auto& entry{*Assert(m_pool.GetEntry(txid))};1671results_final.emplace(wtxid, MempoolAcceptResult::MempoolTx(entry.GetTxSize(), entry.GetFee()));1672} else if (m_pool.exists(txid)) {1673// Transaction with the same non-witness data but different witness (same txid,1674// different wtxid) already exists in the mempool.1675//1676// We don't allow replacement transactions right now, so just swap the package1677// transaction for the mempool one. Note that we are ignoring the validity of the1678// package transaction passed in.1679// TODO: allow witness replacement in packages.1680const auto& entry{*Assert(m_pool.GetEntry(txid))};1681// Provide the wtxid of the mempool tx so that the caller can look it up in the mempool.1682results_final.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(entry.GetTx().GetWitnessHash()));1683} else {1684// Transaction does not already exist in the mempool.1685// Try submitting the transaction on its own.1686const auto single_package_res = AcceptSubPackage({tx}, args);1687const auto& single_res = single_package_res.m_tx_results.at(wtxid);1688if (single_res.m_result_type == MempoolAcceptResult::ResultType::VALID) {1689// The transaction succeeded on its own and is now in the mempool. Don't include it1690// in package validation, because its fees should only be "used" once.1691assert(m_pool.exists(wtxid));1692results_final.emplace(wtxid, single_res);1693} else if (package.size() == 1 || // If there is only one transaction, no need to retry it "as a package"1694(single_res.m_state.GetResult() != TxValidationResult::TX_RECONSIDERABLE &&1695single_res.m_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS)) {1696// Package validation policy only differs from individual policy in its evaluation1697// of feerate. For example, if a transaction fails here due to violation of a1698// consensus rule, the result will not change when it is submitted as part of a1699// package. To minimize the amount of repeated work, unless the transaction fails1700// due to feerate or missing inputs (its parent is a previous transaction in the1701// package that failed due to feerate), don't run package validation. Note that this1702// decision might not make sense if different types of packages are allowed in the1703// future. Continue individually validating the rest of the transactions, because1704// some of them may still be valid.1705quit_early = true;1706package_state_quit_early.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");1707individual_results_nonfinal.emplace(wtxid, single_res);1708} else {1709individual_results_nonfinal.emplace(wtxid, single_res);1710txns_package_eval.push_back(tx);1711}1712}1713}1715auto multi_submission_result = quit_early || txns_package_eval.empty() ? PackageMempoolAcceptResult(package_state_quit_early, {}) :1716AcceptSubPackage(txns_package_eval, args);1717PackageValidationState& package_state_final = multi_submission_result.m_state;1719// This is invoked by AcceptSubPackage() already, so this is just here for1720// clarity (since it's not permitted to invoke LimitMempoolSize() while a1721// changeset is outstanding).1722ClearSubPackageState();1724// Make sure we haven't exceeded max mempool size.1725// Package transactions that were submitted to mempool or already in mempool may be evicted.1726// If mempool contents change, then the m_view cache is dirty. It has already been cleared above.1727LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());1729for (const auto& tx : package) {1730const auto& wtxid = tx->GetWitnessHash();1731if (multi_submission_result.m_tx_results.contains(wtxid)) {1732// We shouldn't have re-submitted if the tx result was already in results_final.1733Assume(!results_final.contains(wtxid));1734// If it was submitted, check to see if the tx is still in the mempool. It could have1735// been evicted due to LimitMempoolSize() above.1736const auto& txresult = multi_submission_result.m_tx_results.at(wtxid);1737if (txresult.m_result_type == MempoolAcceptResult::ResultType::VALID && !m_pool.exists(wtxid)) {1738package_state_final.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");1739TxValidationState mempool_full_state;1740mempool_full_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");1741results_final.emplace(wtxid, MempoolAcceptResult::Failure(mempool_full_state));1742} else {1743results_final.emplace(wtxid, txresult);1744}1745} else if (const auto it{results_final.find(wtxid)}; it != results_final.end()) {1746// Already-in-mempool transaction. Check to see if it's still there, as it could have1747// been evicted when LimitMempoolSize() was called.1748Assume(it->second.m_result_type != MempoolAcceptResult::ResultType::INVALID);1749Assume(!individual_results_nonfinal.contains(wtxid));1750// Query by txid to include the same-txid-different-witness ones.