mempool_entry.h raw

   1  // Copyright (c) 2009-2022 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef LIMENKA_KERNEL_MEMPOOL_ENTRY_H
   6  #define LIMENKA_KERNEL_MEMPOOL_ENTRY_H
   7  
   8  #include <consensus/amount.h>
   9  #include <consensus/ct.h>
  10  #include <consensus/validation.h>
  11  #include <core_memusage.h>
  12  #include <policy/coin_age_priority.h>
  13  #include <policy/policy.h>
  14  #include <policy/settings.h>
  15  #include <primitives/transaction.h>
  16  #include <util/epochguard.h>
  17  #include <util/overflow.h>
  18  
  19  #include <cassert>
  20  #include <chrono>
  21  #include <functional>
  22  #include <memory>
  23  #include <set>
  24  #include <stddef.h>
  25  #include <stdint.h>
  26  
  27  class CBlockIndex;
  28  
  29  struct LockPoints {
  30      // Will be set to the blockchain height and median time past
  31      // values that would be necessary to satisfy all relative locktime
  32      // constraints (BIP68) of this tx given our view of block chain history
  33      int height{0};
  34      int64_t time{0};
  35      // As long as the current chain descends from the highest height block
  36      // containing one of the inputs used in the calculation, then the cached
  37      // values are still valid even after a reorg.
  38      CBlockIndex* maxInputBlock{nullptr};
  39  };
  40  
  41  enum MemPool_SPK_State {
  42      MSS_UNSEEN  = 0,
  43      MSS_SPENT   = 1,  // .second
  44      MSS_CREATED = 2,  // .first
  45      MSS_BOTH    = 3,
  46  };
  47  
  48  typedef std::map<uint160, enum MemPool_SPK_State> SPKStates_t;
  49  
  50  struct CompareIteratorByHash {
  51      // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper<T>
  52      // (e.g. a wrapped CTxMemPoolEntry&)
  53      template <typename T>
  54      bool operator()(const std::reference_wrapper<T>& a, const std::reference_wrapper<T>& b) const
  55      {
  56          return a.get().GetTx().GetHash() < b.get().GetTx().GetHash();
  57      }
  58      template <typename T>
  59      bool operator()(const T& a, const T& b) const
  60      {
  61          return a->GetTx().GetHash() < b->GetTx().GetHash();
  62      }
  63  };
  64  
  65  /** \class CTxMemPoolEntry
  66   *
  67   * CTxMemPoolEntry stores data about the corresponding transaction, as well
  68   * as data about all in-mempool transactions that depend on the transaction
  69   * ("descendant" transactions).
  70   *
  71   * When a new entry is added to the mempool, we update the descendant state
  72   * (m_count_with_descendants, nSizeWithDescendants, and nModFeesWithDescendants) for
  73   * all ancestors of the newly added transaction.
  74   *
  75   */
  76  
  77  class CTxMemPoolEntry
  78  {
  79  public:
  80      typedef std::reference_wrapper<const CTxMemPoolEntry> CTxMemPoolEntryRef;
  81      // two aliases, should the types ever diverge
  82      typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Parents;
  83      typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Children;
  84  
  85  private:
  86      CTxMemPoolEntry(const CTxMemPoolEntry&) = default;
  87      struct ExplicitCopyTag {
  88          explicit ExplicitCopyTag() = default;
  89      };
  90  
  91      const CTransactionRef tx;
  92      mutable Parents m_parents;
  93      mutable Children m_children;
  94      const CAmount nFee;             //!< Cached to avoid expensive parent-transaction lookups
  95      const int32_t nTxWeight;         //!< ... and avoid recomputing tx weight (also used for GetTxSize())
  96      const size_t nUsageSize;        //!< ... and total memory usage
  97      const int64_t nTime;            //!< Local time when entering the mempool
  98      const uint64_t entry_sequence;  //!< Sequence number used to determine whether this transaction is too recent for relay
  99      const int64_t sigOpCost;        //!< Total sigop cost
 100      const int32_t m_extra_weight;   //!< Policy-only additional transaction weight beyond nTxWeight
 101      const size_t nModSize;          //!< Cached modified size for priority
 102      const double entryPriority;     //!< Priority when entering the mempool
 103      const unsigned int entryHeight; //!< Chain height when entering the mempool
 104      double cachedPriority;          //!< Last calculated priority
 105      unsigned int cachedHeight;      //!< Height at which priority was last calculated
 106      CAmount inChainInputValue;      //!< Sum of all txin values that are already in blockchain
 107      const bool spendsCoinbase;      //!< keep track of transactions that spend a coinbase
 108      CAmount m_modified_fee;         //!< Used for determining the priority of the transaction for mining in a block
 109      mutable LockPoints lockPoints;  //!< Track the height and time at which tx was final
 110  
 111      // Information about descendants of this transaction that are in the
 112      // mempool; if we remove this transaction we must remove all of these
 113      // descendants as well.
 114      int64_t m_count_with_descendants{1}; //!< number of descendant transactions
 115      // Using int64_t instead of int32_t to avoid signed integer overflow issues.
 116      int64_t nSizeWithDescendants;      //!< ... and size
 117      CAmount nModFeesWithDescendants;   //!< ... and total fees (all including us)
 118  
 119      // Analogous statistics for ancestor transactions
 120      int64_t m_count_with_ancestors{1};
 121      // Using int64_t instead of int32_t to avoid signed integer overflow issues.
 122      int64_t nSizeWithAncestors;
 123      CAmount nModFeesWithAncestors;
 124      int64_t nSigOpCostWithAncestors;
 125  
 126  public:
 127      CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
 128                      int64_t time, unsigned int entry_height, uint64_t entry_sequence,
 129                      CoinAgeCache coin_age_cache,
 130                      bool spends_coinbase,
 131                      int32_t extra_weight,
 132                      int64_t sigops_cost, LockPoints lp)
 133          : tx{tx},
 134            nFee{fee},
 135            nTxWeight{GetTransactionWeight(*tx)},
 136            nUsageSize{RecursiveDynamicUsage(tx)},
 137            nTime{time},
 138            entry_sequence{entry_sequence},
 139            sigOpCost{sigops_cost},
 140            m_extra_weight{extra_weight},
 141            nModSize{CalculateModifiedSize(*tx, GetTxSize())},
 142            entryPriority{ComputePriority2(coin_age_cache.inputs_coin_age, nModSize)},
 143            entryHeight{entry_height},
 144            cachedPriority{entryPriority},
 145            // Since entries arrive *after* the tip's height, their entry priority is for the height+1
 146            cachedHeight{entry_height + 1},
 147            inChainInputValue{coin_age_cache.in_chain_input_value},
 148            spendsCoinbase{spends_coinbase},
 149            m_modified_fee{nFee},
 150            lockPoints{lp},
 151            nSizeWithDescendants{GetTxSize()},
 152            nModFeesWithDescendants{nFee},
 153            nSizeWithAncestors{GetTxSize()},
 154            nModFeesWithAncestors{nFee},
 155            nSigOpCostWithAncestors{sigOpCost} {
 156              // For confidential transactions the transparent-domain input
 157              // value beyond the fee legitimately crosses into the
 158              // confidential domain (mint); the kernel balance enforces
 159              // conservation there.
 160              if (GetCTKernelOutputIndex(*tx) == NO_CT_KERNEL_OUTPUT) {
 161                  CAmount nValueIn = tx->GetValueOut() + nFee;
 162                  assert(inChainInputValue <= nValueIn);
 163              }
 164          }
 165  
 166      CTxMemPoolEntry(ExplicitCopyTag, const CTxMemPoolEntry& entry) : CTxMemPoolEntry(entry) {}
 167      CTxMemPoolEntry& operator=(const CTxMemPoolEntry&) = delete;
 168      CTxMemPoolEntry(CTxMemPoolEntry&&) = delete;
 169      CTxMemPoolEntry& operator=(CTxMemPoolEntry&&) = delete;
 170  
 171      static constexpr ExplicitCopyTag ExplicitCopy{};
 172  
 173      const CTransaction& GetTx() const { return *this->tx; }
 174      CTransactionRef GetSharedTx() const { return this->tx; }
 175      double GetStartingPriority() const {return entryPriority; }
 176      CoinAgeCache GetInternalCoinAgeCache() const {
 177          return {
 178              .inputs_coin_age = static_cast<uint64_t>(ReversePriority2(cachedPriority, nModSize)),
 179              .in_chain_input_value = inChainInputValue,
 180          };
 181      }
 182      /**
 183       * Fast calculation of priority as update from cached value, but only valid if
 184       * currentHeight is greater than last height it was recalculated.
 185       */
 186      double GetPriority(unsigned int currentHeight) const;
 187      /**
 188       * Recalculate the cached priority as of currentHeight and adjust inChainInputValue by
 189       * valueInCurrentBlock which represents input that was just added to or removed from the blockchain.
 190       */
 191      void UpdateCachedPriority(unsigned int currentHeight, CAmount valueInCurrentBlock);
 192      const CAmount& GetFee() const { return nFee; }
 193      int32_t GetTxSize() const
 194      {
 195          return GetVirtualTransactionSize(nTxWeight + m_extra_weight, sigOpCost, ::nBytesPerSigOp);
 196      }
 197      int32_t GetTxWeight() const { return nTxWeight; }
 198      std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
 199      unsigned int GetHeight() const { return entryHeight; }
 200      uint64_t GetSequence() const { return entry_sequence; }
 201      int32_t GetExtraWeight() const { return m_extra_weight; }
 202      int64_t GetSigOpCost() const { return sigOpCost; }
 203      CAmount GetModifiedFee() const { return m_modified_fee; }
 204      size_t DynamicMemoryUsage() const { return nUsageSize; }
 205      const LockPoints& GetLockPoints() const { return lockPoints; }
 206  
 207      // Adjusts the descendant state.
 208      void UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount);
 209      // Adjusts the ancestor state
 210      void UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
 211      // Updates the modified fees with descendants/ancestors.
 212      void UpdateModifiedFee(CAmount fee_diff)
 213      {
 214          nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff);
 215          nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff);
 216          m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff);
 217      }
 218  
 219      // Update the LockPoints after a reorg
 220      void UpdateLockPoints(const LockPoints& lp) const
 221      {
 222          lockPoints = lp;
 223      }
 224  
 225      uint64_t GetCountWithDescendants() const { return m_count_with_descendants; }
 226      int64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
 227      CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
 228  
 229      bool GetSpendsCoinbase() const { return spendsCoinbase; }
 230  
 231      uint64_t GetCountWithAncestors() const { return m_count_with_ancestors; }
 232      int64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
 233      CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
 234      int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
 235  
 236      const Parents& GetMemPoolParentsConst() const { return m_parents; }
 237      const Children& GetMemPoolChildrenConst() const { return m_children; }
 238      Parents& GetMemPoolParents() const { return m_parents; }
 239      Children& GetMemPoolChildren() const { return m_children; }
 240  
 241      mutable size_t idx_randomized; //!< Index in mempool's txns_randomized
 242      mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
 243  
 244      SPKStates_t mapSPK;
 245  };
 246  
 247  using CTxMemPoolEntryRef = CTxMemPoolEntry::CTxMemPoolEntryRef;
 248  
 249  struct TransactionInfo {
 250      const CTransactionRef m_tx;
 251      /* The fee the transaction paid */
 252      const CAmount m_fee;
 253      /**
 254       * The virtual transaction size.
 255       *
 256       * This is a policy field which considers the sigop cost of the
 257       * transaction as well as its weight, and reinterprets it as bytes.
 258       *
 259       * It is the primary metric by which the mining algorithm selects
 260       * transactions.
 261       */
 262      const int64_t m_virtual_transaction_size;
 263      /* The block height the transaction entered the mempool */
 264      const unsigned int txHeight;
 265  
 266      TransactionInfo(const CTransactionRef& tx, const CAmount& fee, const int64_t vsize, const unsigned int height)
 267          : m_tx{tx},
 268            m_fee{fee},
 269            m_virtual_transaction_size{vsize},
 270            txHeight{height} {}
 271  };
 272  
 273  struct RemovedMempoolTransactionInfo {
 274      TransactionInfo info;
 275      explicit RemovedMempoolTransactionInfo(const CTxMemPoolEntry& entry)
 276          : info{entry.GetSharedTx(), entry.GetFee(), entry.GetTxSize(), entry.GetHeight()} {}
 277  };
 278  
 279  struct NewMempoolTransactionInfo {
 280      TransactionInfo info;
 281      /*
 282       * This boolean indicates whether the transaction was added
 283       * without enforcing mempool fee limits.
 284       */
 285      const ignore_rejects_type m_ignore_rejects;
 286      /* This boolean indicates whether the transaction is part of a package. */
 287      const bool m_submitted_in_package;
 288      /*
 289       * This boolean indicates whether the blockchain is up to date when the
 290       * transaction is added to the mempool.
 291       */
 292      const bool m_chainstate_is_current;
 293      /* Indicates whether the transaction has unconfirmed parents. */
 294      const bool m_has_no_mempool_parents;
 295  
 296      explicit NewMempoolTransactionInfo(const CTransactionRef& tx, const CAmount& fee,
 297                                         const int64_t vsize, const unsigned int height,
 298                                         const ignore_rejects_type& ignore_rejects, const bool submitted_in_package,
 299                                         const bool chainstate_is_current,
 300                                         const bool has_no_mempool_parents)
 301          : info{tx, fee, vsize, height},
 302            m_ignore_rejects{ignore_rejects},
 303            m_submitted_in_package{submitted_in_package},
 304            m_chainstate_is_current{chainstate_is_current},
 305            m_has_no_mempool_parents{has_no_mempool_parents} {}
 306  };
 307  
 308  #endif // LIMENKA_KERNEL_MEMPOOL_ENTRY_H
 309