Inside Bitcoin
Opening the selected file…
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) 2016-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 <policy/rbf.h>7#include <consensus/amount.h>8#include <kernel/mempool_entry.h>9#include <policy/feerate.h>10#include <primitives/transaction.h>11#include <sync.h>12#include <tinyformat.h>13#include <txmempool.h>14#include <uint256.h>15#include <util/check.h>16#include <util/moneystr.h>17#include <util/rbf.h>19#include <limits>20#include <vector>22#include <compare>24RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)25{26AssertLockHeld(pool.cs);28// First check the transaction itself.29if (SignalsOptInRBF(tx)) {30return RBFTransactionState::REPLACEABLE_BIP125;31}33// If this transaction is not in our mempool, then we can't be sure34// we will know about all its inputs.35if (!pool.exists(tx.GetHash())) {36return RBFTransactionState::UNKNOWN;37}39// If all the inputs have nSequence >= maxint-1, it still might be40// signaled for RBF if any unconfirmed parents have signaled.41const auto& entry{*Assert(pool.GetEntry(tx.GetHash()))};42auto ancestors{pool.CalculateMemPoolAncestors(entry)};44for (CTxMemPool::txiter it : ancestors) {45if (SignalsOptInRBF(it->GetTx())) {46return RBFTransactionState::REPLACEABLE_BIP125;47}48}49return RBFTransactionState::FINAL;50}52RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)53{54// If we don't have a local mempool we can only check the transaction itself.55return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;56}58std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,59CTxMemPool& pool,60const CTxMemPool::setEntries& iters_conflicting,61CTxMemPool::setEntries& all_conflicts)62{63AssertLockHeld(pool.cs);64// Rule #5: don't consider replacements that conflict directly with more65// than MAX_REPLACEMENT_CANDIDATES distinct clusters. This implies a bound66// on how many mempool clusters might need to be re-sorted in order to67// process the replacement (though the actual number of clusters we68// relinearize may be greater than this number, due to cluster splitting).69auto num_clusters = pool.GetUniqueClusterCount(iters_conflicting);70if (num_clusters > MAX_REPLACEMENT_CANDIDATES) {71return strprintf("rejecting replacement %s; too many conflicting clusters (%u > %d)",72tx.GetHash().ToString(),73num_clusters,74MAX_REPLACEMENT_CANDIDATES);75}76// Calculate the set of all transactions that would have to be evicted.77for (CTxMemPool::txiter it : iters_conflicting) {78// The cluster count limit ensures that we won't do too much work on a79// single invocation of this function.80pool.CalculateDescendants(it, all_conflicts);81}82return std::nullopt;83}85std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,86const std::set<Txid>& direct_conflicts,87const Txid& txid)88{89for (CTxMemPool::txiter ancestorIt : ancestors) {90const Txid& hashAncestor = ancestorIt->GetTx().GetHash();91if (direct_conflicts.contains(hashAncestor)) {92return strprintf("%s spends conflicting transaction %s",93txid.ToString(),94hashAncestor.ToString());95}96}97return std::nullopt;98}100std::optional<std::string> PaysForRBF(CAmount original_fees,101CAmount replacement_fees,102size_t replacement_vsize,103CFeeRate relay_fee,104const Txid& txid)105{106// Rule #3: The replacement fees must be greater than or equal to fees of the107// transactions it replaces, otherwise the bandwidth used by those conflicting transactions108// would not be paid for.109if (replacement_fees < original_fees) {110return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",111txid.ToString(), FormatMoney(replacement_fees), FormatMoney(original_fees));112}114// Rule #4: The new transaction must pay for its own bandwidth. Otherwise, we have a DoS115// vector where attackers can cause a transaction to be replaced (and relayed) repeatedly by116// increasing the fee by tiny amounts.117CAmount additional_fees = replacement_fees - original_fees;118if (additional_fees < relay_fee.GetFee(replacement_vsize)) {119return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",120txid.ToString(),121FormatMoney(additional_fees),122FormatMoney(relay_fee.GetFee(replacement_vsize)));123}124return std::nullopt;125}127std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool::ChangeSet& changeset)128{129// Require that the replacement strictly improves the mempool's feerate diagram.130const auto chunk_results{changeset.CalculateChunksForRBF()};132if (!chunk_results.has_value()) {133return std::make_pair(DiagramCheckError::UNCALCULABLE, util::ErrorString(chunk_results).original);134}136if (!std::is_gt(CompareChunks(chunk_results.value().second, chunk_results.value().first))) {137return std::make_pair(DiagramCheckError::FAILURE, "insufficient feerate: does not improve feerate diagram");138}139return std::nullopt;140}