// 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: 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 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} {} 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) { 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 vTxHashesIdx; //!< Index in mempool's vTxHashes mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms }; using CTxMemPoolEntryRef = CTxMemPoolEntry::CTxMemPoolEntryRef; #endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H