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