// Copyright (c) 2009-2022 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_KERNEL_MEMPOOL_ENTRY_H #define BITCOIN_KERNEL_MEMPOOL_ENTRY_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include class CBlockIndex; struct LockPoints { // Will be set to the blockchain height and median time past // values that would be necessary to satisfy all relative locktime // constraints (BIP68) of this tx given our view of block chain history int height{0}; int64_t time{0}; // As long as the current chain descends from the highest height block // containing one of the inputs used in the calculation, then the cached // values are still valid even after a reorg. CBlockIndex* maxInputBlock{nullptr}; }; struct CompareIteratorByHash { // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper // (e.g. a wrapped CTxMemPoolEntry&) template bool operator()(const std::reference_wrapper& a, const std::reference_wrapper& b) const { return a.get().GetTx().GetHash() < b.get().GetTx().GetHash(); } template bool operator()(const T& a, const T& b) const { return a->GetTx().GetHash() < b->GetTx().GetHash(); } }; /** \class CTxMemPoolEntry * * CTxMemPoolEntry stores data about the corresponding transaction, as well * as data about all in-mempool transactions that depend on the transaction * ("descendant" transactions). * * When a new entry is added to the mempool, we update the descendant state * (m_count_with_descendants, nSizeWithDescendants, and nModFeesWithDescendants) for * all ancestors of the newly added transaction. * */ class CTxMemPoolEntry { public: typedef std::reference_wrapper CTxMemPoolEntryRef; // two aliases, should the types ever diverge typedef std::set Parents; typedef std::set Children; private: CTxMemPoolEntry(const CTxMemPoolEntry&) = default; struct ExplicitCopyTag { explicit ExplicitCopyTag() = default; }; const CTransactionRef tx; mutable Parents m_parents; mutable Children m_children; const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups const int32_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) const size_t nUsageSize; //!< ... and total memory usage const int64_t nTime; //!< Local time when entering the mempool const uint64_t entry_sequence; //!< Sequence number used to determine whether this transaction is too recent for relay const unsigned int entryHeight; //!< Chain height when entering the mempool const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase const int64_t sigOpCost; //!< Total sigop cost CAmount m_modified_fee; //!< Used for determining the priority of the transaction for mining in a block mutable LockPoints lockPoints; //!< Track the height and time at which tx was final // Information about descendants of this transaction that are in the // mempool; if we remove this transaction we must remove all of these // descendants as well. int64_t m_count_with_descendants{1}; //!< number of descendant transactions // Using int64_t instead of int32_t to avoid signed integer overflow issues. int64_t nSizeWithDescendants; //!< ... and size CAmount nModFeesWithDescendants; //!< ... and total fees (all including us) // Analogous statistics for ancestor transactions int64_t m_count_with_ancestors{1}; // Using int64_t instead of int32_t to avoid signed integer overflow issues. int64_t nSizeWithAncestors; CAmount nModFeesWithAncestors; int64_t nSigOpCostWithAncestors; public: CTxMemPoolEntry(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) : tx{tx}, nFee{fee}, nTxWeight{GetTransactionWeight(*tx)}, nUsageSize{RecursiveDynamicUsage(tx)}, nTime{time}, entry_sequence{entry_sequence}, entryHeight{entry_height}, spendsCoinbase{spends_coinbase}, sigOpCost{sigops_cost}, m_modified_fee{nFee}, lockPoints{lp}, nSizeWithDescendants{GetTxSize()}, nModFeesWithDescendants{nFee}, nSizeWithAncestors{GetTxSize()}, nModFeesWithAncestors{nFee}, nSigOpCostWithAncestors{sigOpCost} {} CTxMemPoolEntry(ExplicitCopyTag, const CTxMemPoolEntry& entry) : CTxMemPoolEntry(entry) {} CTxMemPoolEntry& operator=(const CTxMemPoolEntry&) = delete; CTxMemPoolEntry(CTxMemPoolEntry&&) = delete; CTxMemPoolEntry& operator=(CTxMemPoolEntry&&) = delete; static constexpr ExplicitCopyTag ExplicitCopy{}; const CTransaction& GetTx() const { return *this->tx; } CTransactionRef GetSharedTx() const { return this->tx; } const CAmount& GetFee() const { return nFee; } int32_t GetTxSize() const { return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp); } int32_t GetTxWeight() const { return nTxWeight; } std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; } unsigned int GetHeight() const { return entryHeight; } uint64_t GetSequence() const { return entry_sequence; } int64_t GetSigOpCost() const { return sigOpCost; } CAmount GetModifiedFee() const { return m_modified_fee; } size_t DynamicMemoryUsage() const { return nUsageSize; } const LockPoints& GetLockPoints() const { return lockPoints; } // Adjusts the descendant state. void UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount); // Adjusts the ancestor state void UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps); // Updates the modified fees with descendants/ancestors. void UpdateModifiedFee(CAmount fee_diff) { nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff); nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff); m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff); } // Update the LockPoints after a reorg void UpdateLockPoints(const LockPoints& lp) const { lockPoints = lp; } uint64_t GetCountWithDescendants() const { return m_count_with_descendants; } int64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } bool GetSpendsCoinbase() const { return spendsCoinbase; } uint64_t GetCountWithAncestors() const { return m_count_with_ancestors; } int64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; } const Parents& GetMemPoolParentsConst() const { return m_parents; } const Children& GetMemPoolChildrenConst() const { return m_children; } Parents& GetMemPoolParents() const { return m_parents; } Children& GetMemPoolChildren() const { return m_children; } mutable size_t idx_randomized; //!< Index in mempool's txns_randomized mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms }; using CTxMemPoolEntryRef = CTxMemPoolEntry::CTxMemPoolEntryRef; struct TransactionInfo { const CTransactionRef m_tx; /* The fee the transaction paid */ const CAmount m_fee; /** * The virtual transaction size. * * This is a policy field which considers the sigop cost of the * transaction as well as its weight, and reinterprets it as bytes. * * It is the primary metric by which the mining algorithm selects * transactions. */ const int64_t m_virtual_transaction_size; /* The block height the transaction entered the mempool */ const unsigned int txHeight; TransactionInfo(const CTransactionRef& tx, const CAmount& fee, const int64_t vsize, const unsigned int height) : m_tx{tx}, m_fee{fee}, m_virtual_transaction_size{vsize}, txHeight{height} {} }; struct RemovedMempoolTransactionInfo { TransactionInfo info; explicit RemovedMempoolTransactionInfo(const CTxMemPoolEntry& entry) : info{entry.GetSharedTx(), entry.GetFee(), entry.GetTxSize(), entry.GetHeight()} {} }; struct NewMempoolTransactionInfo { TransactionInfo info; /* * This boolean indicates whether the transaction was added * without enforcing mempool fee limits. */ const bool m_from_disconnected_block; /* This boolean indicates whether the transaction is part of a package. */ const bool m_submitted_in_package; /* * This boolean indicates whether the blockchain is up to date when the * transaction is added to the mempool. */ const bool m_chainstate_is_current; /* Indicates whether the transaction has unconfirmed parents. */ const bool m_has_no_mempool_parents; explicit NewMempoolTransactionInfo(const CTransactionRef& tx, const CAmount& fee, const int64_t vsize, const unsigned int height, const bool from_disconnected_block, const bool submitted_in_package, const bool chainstate_is_current, const bool has_no_mempool_parents) : info{tx, fee, vsize, height}, m_from_disconnected_block{from_disconnected_block}, m_submitted_in_package{submitted_in_package}, m_chainstate_is_current{chainstate_is_current}, m_has_no_mempool_parents{has_no_mempool_parents} {} }; #endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H