mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-31 10:41:08 +00:00
This is likely slightly slower, but this was the last place we were using epochs instead of sets to deduplicate, and this is only used by the RPC code and in tests, and should not be CPU-performance critical. Eliminating this allows us to save 8 bytes in CTxMemPoolEntry. Co-Authored-By: Pieter Wuille <bitcoin-dev@wuille.net>
783 lines
33 KiB
C++
783 lines
33 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-present The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_TXMEMPOOL_H
|
|
#define BITCOIN_TXMEMPOOL_H
|
|
|
|
#include <coins.h>
|
|
#include <consensus/amount.h>
|
|
#include <indirectmap.h>
|
|
#include <kernel/cs_main.h>
|
|
#include <kernel/mempool_entry.h> // IWYU pragma: export
|
|
#include <kernel/mempool_limits.h> // IWYU pragma: export
|
|
#include <kernel/mempool_options.h> // IWYU pragma: export
|
|
#include <kernel/mempool_removal_reason.h> // IWYU pragma: export
|
|
#include <policy/feerate.h>
|
|
#include <policy/packages.h>
|
|
#include <primitives/transaction.h>
|
|
#include <primitives/transaction_identifier.h>
|
|
#include <sync.h>
|
|
#include <txgraph.h>
|
|
#include <util/feefrac.h>
|
|
#include <util/hasher.h>
|
|
#include <util/result.h>
|
|
|
|
#include <boost/multi_index/hashed_index.hpp>
|
|
#include <boost/multi_index/identity.hpp>
|
|
#include <boost/multi_index/indexed_by.hpp>
|
|
#include <boost/multi_index/ordered_index.hpp>
|
|
#include <boost/multi_index/sequenced_index.hpp>
|
|
#include <boost/multi_index/tag.hpp>
|
|
#include <boost/multi_index_container.hpp>
|
|
|
|
#include <atomic>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <set>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
class CChain;
|
|
class ValidationSignals;
|
|
|
|
struct bilingual_str;
|
|
|
|
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
|
|
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
|
|
|
|
/** How many linearization iterations required for TxGraph clusters to have
|
|
* "acceptable" quality, if they cannot be optimally linearized with fewer
|
|
* iterations. */
|
|
static constexpr uint64_t ACCEPTABLE_ITERS = 1'700;
|
|
|
|
/** How much work we ask TxGraph to do after a mempool change occurs (either
|
|
* due to a changeset being applied, a new block being found, or a reorg). */
|
|
static constexpr uint64_t POST_CHANGE_WORK = 5 * ACCEPTABLE_ITERS;
|
|
|
|
/**
|
|
* Test whether the LockPoints height and time are still valid on the current chain
|
|
*/
|
|
bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
|
|
// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
|
|
struct mempoolentry_txid
|
|
{
|
|
typedef Txid result_type;
|
|
result_type operator() (const CTxMemPoolEntry &entry) const
|
|
{
|
|
return entry.GetTx().GetHash();
|
|
}
|
|
|
|
result_type operator() (const CTransactionRef& tx) const
|
|
{
|
|
return tx->GetHash();
|
|
}
|
|
};
|
|
|
|
// extracts a transaction witness-hash from CTxMemPoolEntry or CTransactionRef
|
|
struct mempoolentry_wtxid
|
|
{
|
|
typedef Wtxid result_type;
|
|
result_type operator() (const CTxMemPoolEntry &entry) const
|
|
{
|
|
return entry.GetTx().GetWitnessHash();
|
|
}
|
|
|
|
result_type operator() (const CTransactionRef& tx) const
|
|
{
|
|
return tx->GetWitnessHash();
|
|
}
|
|
};
|
|
|
|
class CompareTxMemPoolEntryByEntryTime
|
|
{
|
|
public:
|
|
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
|
|
{
|
|
return a.GetTime() < b.GetTime();
|
|
}
|
|
};
|
|
|
|
// Multi_index tag names
|
|
struct entry_time {};
|
|
struct index_by_wtxid {};
|
|
|
|
/**
|
|
* Information about a mempool transaction.
|
|
*/
|
|
struct TxMempoolInfo
|
|
{
|
|
/** The transaction itself */
|
|
CTransactionRef tx;
|
|
|
|
/** Time the transaction entered the mempool. */
|
|
std::chrono::seconds m_time;
|
|
|
|
/** Fee of the transaction. */
|
|
CAmount fee;
|
|
|
|
/** Virtual size of the transaction. */
|
|
int32_t vsize;
|
|
|
|
/** The fee delta. */
|
|
int64_t nFeeDelta;
|
|
};
|
|
|
|
/**
|
|
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
|
|
* that may be included in the next block.
|
|
*
|
|
* Transactions are added when they are seen on the network (or created by the
|
|
* local node), but not all transactions seen are added to the pool. For
|
|
* example, the following new transactions will not be added to the mempool:
|
|
* - a transaction which doesn't meet the minimum fee requirements.
|
|
* - a new transaction that double-spends an input of a transaction already in
|
|
* the pool where the new transaction does not meet the Replace-By-Fee
|
|
* requirements as defined in doc/policy/mempool-replacements.md.
|
|
* - a non-standard transaction.
|
|
*
|
|
* TxGraph (CTxMemPool::m_txgraph) provides an abstraction layer for separating
|
|
* the transaction graph parts of the mempool from the rest of the
|
|
* Bitcoin-specific logic. Specifically, TxGraph handles (for each transaction)
|
|
* managing the in-mempool parents and children, and has knowledge of the fee
|
|
* and size of every transaction. It uses this to partition the mempool into
|
|
* connected clusters, and it implements (among other things):
|
|
* - limits on the size of a cluster (in both number of transactions
|
|
* and total weight)
|
|
* - sorting the mempool optimally for block inclusion, taking into account
|
|
* dependencies
|
|
* - selecting transactions for removal due to cluster size limit violations
|
|
* after a reorg.
|
|
* See txgraph.h and txgraph.cpp for more details.
|
|
*
|
|
* CTxMemPool itself handles the Bitcoin-specific parts of mempool
|
|
* transactions; it stores the full transaction inside CTxMemPoolEntry, along
|
|
* with other consensus-specific fields (such as whether a transaction spends a
|
|
* coinbase, or the LockPoints for transaction finality). And it provides
|
|
* interfaces to the rest of the codebase, such as:
|
|
* - to validation for replace-by-fee calculations and cluster size limits
|
|
* when evaluating unconfirmed transactions
|
|
* - to validation for evicting transactions due to expiry or the mempool size
|
|
* limit being hit
|
|
* - to validation for updating the mempool to be consistent with the best
|
|
* chain after a new block is connected or after a reorg.
|
|
* - to net_processing for ordering transactions that are to-be-announced to
|
|
* other peers
|
|
* - to RPC code for inspecting the mempool
|
|
*
|
|
* (Many of these interfaces are just wrappers around corresponding TxGraph
|
|
* functions.)
|
|
*
|
|
* Within CTxMemPool, the mempool entries are stored in a boost::multi_index
|
|
* mapTx, which sorts the mempool on 3 criteria:
|
|
* - transaction hash (txid)
|
|
* - witness-transaction hash (wtxid)
|
|
* - time in mempool
|
|
*
|
|
* We also maintain a map from COutPoint to the (in-mempool) transaction that
|
|
* spends it (mapNextTx). This allows us to recover from a reorg and find
|
|
* transactions in the mempool that conflict with transactions that are
|
|
* confirmed in a block.
|
|
*
|
|
*/
|
|
class CTxMemPool
|
|
{
|
|
protected:
|
|
std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
|
|
|
|
uint64_t totalTxSize GUARDED_BY(cs){0}; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
|
|
CAmount m_total_fee GUARDED_BY(cs){0}; //!< sum of all mempool tx's fees (NOT modified fee)
|
|
uint64_t cachedInnerUsage GUARDED_BY(cs){0}; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
|
|
|
|
mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs){GetTime()};
|
|
mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs){false};
|
|
mutable double rollingMinimumFeeRate GUARDED_BY(cs){0}; //!< minimum fee to get into the pool, decreases exponentially
|
|
|
|
// In-memory counter for external mempool tracking purposes.
|
|
// This number is incremented once every time a transaction
|
|
// is added or removed from the mempool for any reason.
|
|
mutable uint64_t m_sequence_number GUARDED_BY(cs){1};
|
|
|
|
void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
bool m_load_tried GUARDED_BY(cs){false};
|
|
|
|
CFeeRate GetMinFee(size_t sizelimit) const;
|
|
|
|
public:
|
|
|
|
static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing
|
|
|
|
struct CTxMemPoolEntry_Indices final : boost::multi_index::indexed_by<
|
|
// sorted by txid
|
|
boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,
|
|
// sorted by wtxid
|
|
boost::multi_index::hashed_unique<
|
|
boost::multi_index::tag<index_by_wtxid>,
|
|
mempoolentry_wtxid,
|
|
SaltedWtxidHasher
|
|
>,
|
|
// sorted by entry time
|
|
boost::multi_index::ordered_non_unique<
|
|
boost::multi_index::tag<entry_time>,
|
|
boost::multi_index::identity<CTxMemPoolEntry>,
|
|
CompareTxMemPoolEntryByEntryTime
|
|
>
|
|
>
|
|
{};
|
|
typedef boost::multi_index_container<
|
|
CTxMemPoolEntry,
|
|
CTxMemPoolEntry_Indices
|
|
> indexed_transaction_set;
|
|
|
|
/**
|
|
* This mutex needs to be locked when accessing `mapTx` or other members
|
|
* that are guarded by it.
|
|
*
|
|
* @par Consistency guarantees
|
|
* By design, it is guaranteed that:
|
|
* 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
|
|
* that is consistent with current chain tip (`ActiveChain()` and
|
|
* `CoinsTip()`) and is fully populated. Fully populated means that if the
|
|
* current active chain is missing transactions that were present in a
|
|
* previously active chain, all the missing transactions will have been
|
|
* re-added to the mempool and should be present if they meet size and
|
|
* consistency constraints.
|
|
* 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool
|
|
* consistent with some chain that was active since `cs_main` was last
|
|
* locked, and that is fully populated as described above. It is ok for
|
|
* code that only needs to query or remove transactions from the mempool
|
|
* to lock just `mempool.cs` without `cs_main`.
|
|
*
|
|
* To provide these guarantees, it is necessary to lock both `cs_main` and
|
|
* `mempool.cs` whenever adding transactions to the mempool and whenever
|
|
* changing the chain tip. It's necessary to keep both mutexes locked until
|
|
* the mempool is consistent with the new chain tip and fully populated.
|
|
*/
|
|
mutable RecursiveMutex cs;
|
|
std::unique_ptr<TxGraph> m_txgraph GUARDED_BY(cs);
|
|
mutable std::unique_ptr<TxGraph::BlockBuilder> m_builder GUARDED_BY(cs);
|
|
indexed_transaction_set mapTx GUARDED_BY(cs);
|
|
|
|
using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator;
|
|
std::vector<std::pair<Wtxid, txiter>> txns_randomized GUARDED_BY(cs); //!< All transactions in mapTx with their wtxids, in arbitrary order
|
|
|
|
typedef std::set<txiter, CompareIteratorByHash> setEntries;
|
|
|
|
using Limits = kernel::MemPoolLimits;
|
|
|
|
std::tuple<size_t, size_t, CAmount> CalculateAncestorData(const CTxMemPoolEntry& entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
std::tuple<size_t, size_t, CAmount> CalculateDescendantData(const CTxMemPoolEntry& entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
int64_t GetDescendantCount(txiter it) const { LOCK(cs); return m_txgraph->GetDescendants(*it, TxGraph::Level::MAIN).size(); }
|
|
int64_t GetDescendantCount(const CTxMemPoolEntry &e) const { LOCK(cs); return m_txgraph->GetDescendants(e, TxGraph::Level::MAIN).size(); }
|
|
int64_t GetAncestorCount(const CTxMemPoolEntry &e) const { LOCK(cs); return m_txgraph->GetAncestors(e, TxGraph::Level::MAIN).size(); }
|
|
std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> GetChildren(const CTxMemPoolEntry &entry) const;
|
|
std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> GetParents(const CTxMemPoolEntry &entry) const;
|
|
|
|
private:
|
|
std::vector<indexed_transaction_set::const_iterator> GetSortedScoreWithTopology() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/**
|
|
* Track locally submitted transactions to periodically retry initial broadcast.
|
|
*/
|
|
std::set<Txid> m_unbroadcast_txids GUARDED_BY(cs);
|
|
|
|
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it)
|
|
{
|
|
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()};
|
|
}
|
|
|
|
// Helper to remove all transactions that conflict with a given
|
|
// transaction (used for transactions appearing in a block).
|
|
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
public:
|
|
indirectmap<COutPoint, txiter> mapNextTx GUARDED_BY(cs);
|
|
std::map<Txid, CAmount> mapDeltas GUARDED_BY(cs);
|
|
|
|
using Options = kernel::MemPoolOptions;
|
|
|
|
const Options m_opts;
|
|
|
|
/** Create a new CTxMemPool.
|
|
* Sanity checks will be off by default for performance, because otherwise
|
|
* accepting transactions becomes O(N^2) where N is the number of transactions
|
|
* in the pool.
|
|
*/
|
|
explicit CTxMemPool(Options opts, bilingual_str& error);
|
|
|
|
/**
|
|
* If sanity-checking is turned on, check makes sure the pool is
|
|
* consistent (does not contain two transactions that spend the same inputs,
|
|
* all inputs are in the mapNextTx array). If sanity-checking is turned off,
|
|
* check does nothing.
|
|
*/
|
|
void check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
|
|
/**
|
|
* Remove a transaction from the mempool along with any descendants.
|
|
* If the transaction is not already in the mempool, find any descendants
|
|
* and remove them.
|
|
*/
|
|
void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
/** After reorg, filter the entries that would no longer be valid in the next block, and update
|
|
* the entries' cached LockPoints if needed. The mempool does not have any knowledge of
|
|
* consensus rules. It just applies the callable function and removes the ones for which it
|
|
* returns true.
|
|
* @param[in] filter_final_and_mature Predicate that checks the relevant validation rules
|
|
* and updates an entry's LockPoints.
|
|
* */
|
|
void removeForReorg(CChain& chain, std::function<bool(txiter)> filter_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
|
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
bool CompareMiningScoreWithTopology(const Wtxid& hasha, const Wtxid& hashb) const;
|
|
bool isSpent(const COutPoint& outpoint) const;
|
|
unsigned int GetTransactionsUpdated() const;
|
|
void AddTransactionsUpdated(unsigned int n);
|
|
/**
|
|
* Check that none of this transactions inputs are in the mempool, and thus
|
|
* the tx is not dependent on other mempool transactions to be included in a block.
|
|
*/
|
|
bool HasNoInputsOf(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Affect CreateNewBlock prioritisation of transactions */
|
|
void PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta);
|
|
void ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
void ClearPrioritisation(const Txid& hash) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
struct delta_info {
|
|
/** Whether this transaction is in the mempool. */
|
|
const bool in_mempool;
|
|
/** The fee delta added using PrioritiseTransaction(). */
|
|
const CAmount delta;
|
|
/** The modified fee (base fee + delta) of this entry. Only present if in_mempool=true. */
|
|
std::optional<CAmount> modified_fee;
|
|
/** The prioritised transaction's txid. */
|
|
const Txid txid;
|
|
};
|
|
/** Return a vector of all entries in mapDeltas with their corresponding delta_info. */
|
|
std::vector<delta_info> GetPrioritisedTransactions() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
|
|
|
/** Get the transaction in the pool that spends the same prevout */
|
|
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Returns an iterator to the given hash, if found */
|
|
std::optional<txiter> GetIter(const Txid& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
std::optional<txiter> GetIter(const Wtxid& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups.
|
|
* Does not require that all of the hashes correspond to actual transactions in the mempool,
|
|
* only returns the ones that exist. */
|
|
setEntries GetIterSet(const std::set<Txid>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Translate a list of hashes into a list of mempool iterators to avoid repeated lookups.
|
|
* The nth element in txids becomes the nth element in the returned vector. If any of the txids
|
|
* don't actually exist in the mempool, returns an empty vector. */
|
|
std::vector<txiter> GetIterVec(const std::vector<Txid>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** UpdateTransactionsFromBlock is called when adding transactions from a
|
|
* disconnected block back to the mempool, new mempool entries may have
|
|
* children in the mempool (which is generally not the case when otherwise
|
|
* adding transactions).
|
|
* @post updated descendant state for descendants of each transaction in
|
|
* vHashesToUpdate (excluding any child transactions present in
|
|
* vHashesToUpdate, which are already accounted for). Updated state
|
|
* includes add fee/size information for such descendants to the
|
|
* parent and updated ancestor state to include the parent.
|
|
*
|
|
* @param[in] vHashesToUpdate The set of txids from the
|
|
* disconnected block that have been accepted back into the mempool.
|
|
*/
|
|
void UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
|
|
|
std::vector<FeePerWeight> GetFeerateDiagram() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
FeePerWeight GetMainChunkFeerate(const CTxMemPoolEntry& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
return m_txgraph->GetMainChunkFeerate(tx);
|
|
}
|
|
std::vector<const CTxMemPoolEntry*> GetCluster(Txid txid) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
auto tx = GetIter(txid);
|
|
if (!tx) return {};
|
|
auto cluster = m_txgraph->GetCluster(**tx, TxGraph::Level::MAIN);
|
|
std::vector<const CTxMemPoolEntry*> ret;
|
|
ret.reserve(cluster.size());
|
|
for (const auto& tx : cluster) {
|
|
ret.emplace_back(static_cast<const CTxMemPoolEntry*>(tx));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
size_t GetUniqueClusterCount(const setEntries& iters_conflicting) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
std::vector<const TxGraph::Ref *> entries;
|
|
entries.reserve(iters_conflicting.size());
|
|
for (auto it : iters_conflicting) {
|
|
entries.emplace_back(&*it);
|
|
}
|
|
Assume(!m_txgraph->IsOversized(TxGraph::Level::MAIN));
|
|
return m_txgraph->CountDistinctClusters(entries, TxGraph::Level::MAIN);
|
|
}
|
|
|
|
/**
|
|
* Calculate all in-mempool ancestors of entry (not including the tx itself)
|
|
*
|
|
* @param[in] entry CTxMemPoolEntry of which all in-mempool ancestors are calculated
|
|
*
|
|
* @return all in-mempool ancestors
|
|
*/
|
|
setEntries CalculateMemPoolAncestors(const CTxMemPoolEntry& entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
bool HasDescendants(const Txid& txid) const;
|
|
|
|
/** Collect the entire cluster of connected transactions for each transaction in txids.
|
|
* All txids must correspond to transaction entries in the mempool, otherwise this returns an
|
|
* empty vector. This call will also exit early and return an empty vector if it collects 500 or
|
|
* more transactions as a DoS protection. */
|
|
std::vector<txiter> GatherClusters(const std::vector<Txid>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Populate setDescendants with all in-mempool descendants of given transaction.
|
|
* Assumes that setDescendants includes all in-mempool descendants of anything
|
|
* already in it. */
|
|
void CalculateDescendants(txiter it, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
CTxMemPool::txiter CalculateDescendants(const CTxMemPoolEntry& entry, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** The minimum fee to get into the mempool, which may itself not be enough
|
|
* for larger-sized transactions.
|
|
* The m_incremental_relay_feerate policy variable is used to bound the time it
|
|
* takes the fee rate to go back down all the way to 0. When the feerate
|
|
* would otherwise be half of this, it is set to 0 instead.
|
|
*/
|
|
CFeeRate GetMinFee() const {
|
|
return GetMinFee(m_opts.max_size_bytes);
|
|
}
|
|
|
|
/** Remove transactions from the mempool until its dynamic size is <= sizelimit.
|
|
* pvNoSpendsRemaining, if set, will be populated with the list of outpoints
|
|
* which are not in mempool which no longer have any spends in this mempool.
|
|
*/
|
|
void TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
|
|
int Expire(std::chrono::seconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/**
|
|
* Calculate the ancestor and cluster count for the given transaction.
|
|
* The counts include the transaction itself.
|
|
* When ancestors is non-zero (ie, the transaction itself is in the mempool),
|
|
* ancestorsize and ancestorfees will also be set to the appropriate values.
|
|
*/
|
|
void GetTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& cluster_count, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const;
|
|
|
|
/**
|
|
* @returns true if an initial attempt to load the persisted mempool was made, regardless of
|
|
* whether the attempt was successful or not
|
|
*/
|
|
bool GetLoadTried() const;
|
|
|
|
/**
|
|
* Set whether or not an initial attempt to load the persisted mempool was made (regardless
|
|
* of whether the attempt was successful or not)
|
|
*/
|
|
void SetLoadTried(bool load_tried);
|
|
|
|
unsigned long size() const
|
|
{
|
|
LOCK(cs);
|
|
return mapTx.size();
|
|
}
|
|
|
|
uint64_t GetTotalTxSize() const EXCLUSIVE_LOCKS_REQUIRED(cs)
|
|
{
|
|
AssertLockHeld(cs);
|
|
return totalTxSize;
|
|
}
|
|
|
|
CAmount GetTotalFee() const EXCLUSIVE_LOCKS_REQUIRED(cs)
|
|
{
|
|
AssertLockHeld(cs);
|
|
return m_total_fee;
|
|
}
|
|
|
|
bool exists(const Txid& txid) const
|
|
{
|
|
LOCK(cs);
|
|
return (mapTx.count(txid) != 0);
|
|
}
|
|
|
|
bool exists(const Wtxid& wtxid) const
|
|
{
|
|
LOCK(cs);
|
|
return (mapTx.get<index_by_wtxid>().count(wtxid) != 0);
|
|
}
|
|
|
|
const CTxMemPoolEntry* GetEntry(const Txid& txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
CTransactionRef get(const Txid& hash) const;
|
|
|
|
template <TxidOrWtxid T>
|
|
TxMempoolInfo info(const T& id) const
|
|
{
|
|
LOCK(cs);
|
|
auto i{GetIter(id)};
|
|
return i.has_value() ? GetInfo(*i) : TxMempoolInfo{};
|
|
}
|
|
|
|
/** Returns info for a transaction if its entry_sequence < last_sequence */
|
|
template <TxidOrWtxid T>
|
|
TxMempoolInfo info_for_relay(const T& id, uint64_t last_sequence) const
|
|
{
|
|
LOCK(cs);
|
|
auto i{GetIter(id)};
|
|
return (i.has_value() && i.value()->GetSequence() < last_sequence) ? GetInfo(*i) : TxMempoolInfo{};
|
|
}
|
|
|
|
std::vector<CTxMemPoolEntryRef> entryAll() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
std::vector<TxMempoolInfo> infoAll() const;
|
|
|
|
size_t DynamicMemoryUsage() const;
|
|
|
|
/** Adds a transaction to the unbroadcast set */
|
|
void AddUnbroadcastTx(const Txid& txid)
|
|
{
|
|
LOCK(cs);
|
|
// Sanity check the transaction is in the mempool & insert into
|
|
// unbroadcast set.
|
|
if (exists(txid)) m_unbroadcast_txids.insert(txid);
|
|
};
|
|
|
|
bool CheckPolicyLimits(const CTransactionRef& tx);
|
|
|
|
/** Removes a transaction from the unbroadcast set */
|
|
void RemoveUnbroadcastTx(const Txid& txid, bool unchecked = false);
|
|
|
|
/** Returns transactions in unbroadcast set */
|
|
std::set<Txid> GetUnbroadcastTxs() const
|
|
{
|
|
LOCK(cs);
|
|
return m_unbroadcast_txids;
|
|
}
|
|
|
|
/** Returns whether a txid is in the unbroadcast set */
|
|
bool IsUnbroadcastTx(const Txid& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
|
|
{
|
|
AssertLockHeld(cs);
|
|
return m_unbroadcast_txids.contains(txid);
|
|
}
|
|
|
|
/** Guards this internal counter for external reporting */
|
|
uint64_t GetAndIncrementSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
return m_sequence_number++;
|
|
}
|
|
|
|
uint64_t GetSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
return m_sequence_number;
|
|
}
|
|
|
|
private:
|
|
/** Remove a set of transactions from the mempool.
|
|
* If a transaction is in this set, then all in-mempool descendants must
|
|
* also be in the set, unless this transaction is being removed for being
|
|
* in a block.
|
|
*/
|
|
void RemoveStaged(setEntries& stage, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/* Helper for the public removeRecursive() */
|
|
void removeRecursive(txiter to_remove, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
/* Removal from the mempool also triggers removal of the entry's Ref from txgraph. */
|
|
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
public:
|
|
/*
|
|
* CTxMemPool::ChangeSet:
|
|
*
|
|
* This class is used for all mempool additions and associated removals (eg
|
|
* due to rbf). Removals that don't need to be evaluated for acceptance,
|
|
* such as removing transactions that appear in a block, or due to reorg,
|
|
* or removals related to mempool limiting or expiry do not need to use
|
|
* this.
|
|
*
|
|
* Callers can interleave calls to StageAddition()/StageRemoval(), and
|
|
* removals may be invoked in any order, but additions must be done in a
|
|
* topological order in the case of transaction packages (ie, parents must
|
|
* be added before children).
|
|
*
|
|
* CalculateChunksForRBF() can be used to calculate the feerate diagram of
|
|
* the proposed set of new transactions and compare with the existing
|
|
* mempool.
|
|
*
|
|
* CalculateMemPoolAncestors() calculates the in-mempool (not including
|
|
* what is in the change set itself) ancestors of a given transaction.
|
|
*
|
|
* Apply() will apply the removals and additions that are staged into the
|
|
* mempool.
|
|
*
|
|
* Only one changeset may exist at a time. While a changeset is
|
|
* outstanding, no removals or additions may be made directly to the
|
|
* mempool.
|
|
*/
|
|
class ChangeSet {
|
|
public:
|
|
explicit ChangeSet(CTxMemPool* pool) : m_pool(pool) { m_pool->m_txgraph->StartStaging(); }
|
|
~ChangeSet() EXCLUSIVE_LOCKS_REQUIRED(m_pool->cs) {
|
|
AssertLockHeld(m_pool->cs);
|
|
if (m_pool->m_txgraph->HaveStaging()) {
|
|
m_pool->m_txgraph->AbortStaging();
|
|
}
|
|
m_pool->m_have_changeset = false;
|
|
}
|
|
|
|
ChangeSet(const ChangeSet&) = delete;
|
|
ChangeSet& operator=(const ChangeSet&) = delete;
|
|
|
|
using TxHandle = CTxMemPool::txiter;
|
|
|
|
TxHandle StageAddition(const CTransactionRef& tx, CAmount fee, int64_t time, unsigned int entry_height, uint64_t entry_sequence, bool spends_coinbase, int64_t sigops_cost, LockPoints lp);
|
|
|
|
void StageRemoval(CTxMemPool::txiter it);
|
|
|
|
const CTxMemPool::setEntries& GetRemovals() const { return m_to_remove; }
|
|
|
|
/** Check if any cluster limits are exceeded. Returns true if pass, false if fail. */
|
|
bool CheckMemPoolPolicyLimits();
|
|
|
|
CTxMemPool::setEntries CalculateMemPoolAncestors(TxHandle tx)
|
|
{
|
|
// Look up transaction in our cache first
|
|
auto it = m_ancestors.find(tx);
|
|
if (it != m_ancestors.end()) return it->second;
|
|
|
|
// If not found, try to have the mempool calculate it, and cache
|
|
// for later.
|
|
LOCK(m_pool->cs);
|
|
auto ret = m_pool->CalculateMemPoolAncestors(*tx);
|
|
m_ancestors.try_emplace(tx, ret);
|
|
return ret;
|
|
}
|
|
|
|
std::vector<CTransactionRef> GetAddedTxns() const {
|
|
std::vector<CTransactionRef> ret;
|
|
ret.reserve(m_entry_vec.size());
|
|
for (const auto& entry : m_entry_vec) {
|
|
ret.emplace_back(entry->GetSharedTx());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Calculate the sorted chunks for the old and new mempool relating to the
|
|
* clusters that would be affected by a potential replacement transaction.
|
|
*
|
|
* @return old and new diagram pair respectively, or an error string if the conflicts don't match a calculable topology
|
|
*/
|
|
util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CalculateChunksForRBF();
|
|
|
|
size_t GetTxCount() const { return m_entry_vec.size(); }
|
|
const CTransaction& GetAddedTxn(size_t index) const { return m_entry_vec.at(index)->GetTx(); }
|
|
|
|
void Apply() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
|
|
private:
|
|
void ProcessDependencies();
|
|
|
|
CTxMemPool* m_pool;
|
|
CTxMemPool::indexed_transaction_set m_to_add;
|
|
std::vector<CTxMemPool::txiter> m_entry_vec; // track the added transactions' insertion order
|
|
// map from the m_to_add index to the ancestors for the transaction
|
|
std::map<CTxMemPool::txiter, CTxMemPool::setEntries, CompareIteratorByHash> m_ancestors;
|
|
CTxMemPool::setEntries m_to_remove;
|
|
bool m_dependencies_processed{false};
|
|
|
|
friend class CTxMemPool;
|
|
};
|
|
|
|
std::unique_ptr<ChangeSet> GetChangeSet() EXCLUSIVE_LOCKS_REQUIRED(cs) {
|
|
Assume(!m_have_changeset);
|
|
m_have_changeset = true;
|
|
return std::make_unique<ChangeSet>(this);
|
|
}
|
|
|
|
bool m_have_changeset GUARDED_BY(cs){false};
|
|
|
|
friend class CTxMemPool::ChangeSet;
|
|
|
|
private:
|
|
// Apply the given changeset to the mempool, by removing transactions in
|
|
// the to_remove set and adding transactions in the to_add set.
|
|
void Apply(CTxMemPool::ChangeSet* changeset) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
// addNewTransaction must update state for all ancestors of a given transaction,
|
|
// to track size/count of descendant transactions. First version of
|
|
// addNewTransaction can be used to have it call CalculateMemPoolAncestors(), and
|
|
// then invoke the second version.
|
|
// Note that addNewTransaction is ONLY called (via Apply()) from ATMP
|
|
// outside of tests and any other callers may break wallet's in-mempool
|
|
// tracking (due to lack of CValidationInterface::TransactionAddedToMempool
|
|
// callbacks).
|
|
void addNewTransaction(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
public:
|
|
void StartBlockBuilding() const EXCLUSIVE_LOCKS_REQUIRED(cs) { assert(!m_builder); m_builder = m_txgraph->GetBlockBuilder(); }
|
|
FeePerWeight GetBlockBuilderChunk(std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef>& entries) const EXCLUSIVE_LOCKS_REQUIRED(cs)
|
|
{
|
|
if (!m_builder) { return {}; }
|
|
|
|
auto res = m_builder->GetCurrentChunk();
|
|
if (!res) { return {}; }
|
|
|
|
auto [chunk_entries, chunk_feerate] = *res;
|
|
for (TxGraph::Ref* ref : chunk_entries) {
|
|
entries.emplace_back(static_cast<const CTxMemPoolEntry&>(*ref));
|
|
}
|
|
return chunk_feerate;
|
|
}
|
|
void IncludeBuilderChunk() const EXCLUSIVE_LOCKS_REQUIRED(cs) { m_builder->Include(); }
|
|
void SkipBuilderChunk() const EXCLUSIVE_LOCKS_REQUIRED(cs) { m_builder->Skip(); }
|
|
void StopBlockBuilding() const EXCLUSIVE_LOCKS_REQUIRED(cs) { m_builder.reset(); }
|
|
};
|
|
|
|
/**
|
|
* CCoinsView that brings transactions from a mempool into view.
|
|
* It does not check for spendings by memory pool transactions.
|
|
* Instead, it provides access to all Coins which are either unspent in the
|
|
* base CCoinsView, are outputs from any mempool transaction, or are
|
|
* tracked temporarily to allow transaction dependencies in package validation.
|
|
* This allows transaction replacement to work as expected, as you want to
|
|
* have all inputs "available" to check signatures, and any cycles in the
|
|
* dependency graph are checked directly in AcceptToMemoryPool.
|
|
* It also allows you to sign a double-spend directly in
|
|
* signrawtransactionwithkey and signrawtransactionwithwallet,
|
|
* as long as the conflicting transaction is not yet confirmed.
|
|
*/
|
|
class CCoinsViewMemPool : public CCoinsViewBacked
|
|
{
|
|
/**
|
|
* Coins made available by transactions being validated. Tracking these allows for package
|
|
* validation, since we can access transaction outputs without submitting them to mempool.
|
|
*/
|
|
std::unordered_map<COutPoint, Coin, SaltedOutpointHasher> m_temp_added;
|
|
|
|
/**
|
|
* Set of all coins that have been fetched from mempool or created using PackageAddTransaction
|
|
* (not base). Used to track the origin of a coin, see GetNonBaseCoins().
|
|
*/
|
|
mutable std::unordered_set<COutPoint, SaltedOutpointHasher> m_non_base_coins;
|
|
protected:
|
|
const CTxMemPool& mempool;
|
|
|
|
public:
|
|
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
|
|
/** GetCoin, returning whether it exists and is not spent. Also updates m_non_base_coins if the
|
|
* coin is not fetched from base. */
|
|
std::optional<Coin> GetCoin(const COutPoint& outpoint) const override;
|
|
/** Add the coins created by this transaction. These coins are only temporarily stored in
|
|
* m_temp_added and cannot be flushed to the back end. Only used for package validation. */
|
|
void PackageAddTransaction(const CTransactionRef& tx);
|
|
/** Get all coins in m_non_base_coins. */
|
|
const std::unordered_set<COutPoint, SaltedOutpointHasher>& GetNonBaseCoins() const { return m_non_base_coins; }
|
|
/** Clear m_temp_added and m_non_base_coins. */
|
|
void Reset();
|
|
};
|
|
#endif // BITCOIN_TXMEMPOOL_H
|