/root/bitcoin/src/txmempool.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-2022 The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #include <txmempool.h> |
7 | | |
8 | | #include <chain.h> |
9 | | #include <coins.h> |
10 | | #include <common/system.h> |
11 | | #include <consensus/consensus.h> |
12 | | #include <consensus/tx_verify.h> |
13 | | #include <consensus/validation.h> |
14 | | #include <logging.h> |
15 | | #include <policy/policy.h> |
16 | | #include <policy/settings.h> |
17 | | #include <random.h> |
18 | | #include <tinyformat.h> |
19 | | #include <util/check.h> |
20 | | #include <util/feefrac.h> |
21 | | #include <util/moneystr.h> |
22 | | #include <util/overflow.h> |
23 | | #include <util/result.h> |
24 | | #include <util/time.h> |
25 | | #include <util/trace.h> |
26 | | #include <util/translation.h> |
27 | | #include <validationinterface.h> |
28 | | |
29 | | #include <algorithm> |
30 | | #include <cmath> |
31 | | #include <numeric> |
32 | | #include <optional> |
33 | | #include <ranges> |
34 | | #include <string_view> |
35 | | #include <utility> |
36 | | |
37 | | TRACEPOINT_SEMAPHORE(mempool, added); |
38 | | TRACEPOINT_SEMAPHORE(mempool, removed); |
39 | | |
40 | | bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) |
41 | 0 | { |
42 | 0 | AssertLockHeld(cs_main); |
43 | | // If there are relative lock times then the maxInputBlock will be set |
44 | | // If there are no relative lock times, the LockPoints don't depend on the chain |
45 | 0 | if (lp.maxInputBlock) { |
46 | | // Check whether active_chain is an extension of the block at which the LockPoints |
47 | | // calculation was valid. If not LockPoints are no longer valid |
48 | 0 | if (!active_chain.Contains(lp.maxInputBlock)) { |
49 | 0 | return false; |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | // LockPoints still valid |
54 | 0 | return true; |
55 | 0 | } |
56 | | |
57 | | void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, |
58 | | const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove) |
59 | 0 | { |
60 | 0 | CTxMemPoolEntry::Children stageEntries, descendants; |
61 | 0 | stageEntries = updateIt->GetMemPoolChildrenConst(); |
62 | |
|
63 | 0 | while (!stageEntries.empty()) { |
64 | 0 | const CTxMemPoolEntry& descendant = *stageEntries.begin(); |
65 | 0 | descendants.insert(descendant); |
66 | 0 | stageEntries.erase(descendant); |
67 | 0 | const CTxMemPoolEntry::Children& children = descendant.GetMemPoolChildrenConst(); |
68 | 0 | for (const CTxMemPoolEntry& childEntry : children) { |
69 | 0 | cacheMap::iterator cacheIt = cachedDescendants.find(mapTx.iterator_to(childEntry)); |
70 | 0 | if (cacheIt != cachedDescendants.end()) { |
71 | | // We've already calculated this one, just add the entries for this set |
72 | | // but don't traverse again. |
73 | 0 | for (txiter cacheEntry : cacheIt->second) { |
74 | 0 | descendants.insert(*cacheEntry); |
75 | 0 | } |
76 | 0 | } else if (!descendants.count(childEntry)) { |
77 | | // Schedule for later processing |
78 | 0 | stageEntries.insert(childEntry); |
79 | 0 | } |
80 | 0 | } |
81 | 0 | } |
82 | | // descendants now contains all in-mempool descendants of updateIt. |
83 | | // Update and add to cached descendant map |
84 | 0 | int32_t modifySize = 0; |
85 | 0 | CAmount modifyFee = 0; |
86 | 0 | int64_t modifyCount = 0; |
87 | 0 | for (const CTxMemPoolEntry& descendant : descendants) { |
88 | 0 | if (!setExclude.count(descendant.GetTx().GetHash())) { |
89 | 0 | modifySize += descendant.GetTxSize(); |
90 | 0 | modifyFee += descendant.GetModifiedFee(); |
91 | 0 | modifyCount++; |
92 | 0 | cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant)); |
93 | | // Update ancestor state for each descendant |
94 | 0 | mapTx.modify(mapTx.iterator_to(descendant), [=](CTxMemPoolEntry& e) { |
95 | 0 | e.UpdateAncestorState(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()); |
96 | 0 | }); |
97 | | // Don't directly remove the transaction here -- doing so would |
98 | | // invalidate iterators in cachedDescendants. Mark it for removal |
99 | | // by inserting into descendants_to_remove. |
100 | 0 | if (descendant.GetCountWithAncestors() > uint64_t(m_opts.limits.ancestor_count) || descendant.GetSizeWithAncestors() > m_opts.limits.ancestor_size_vbytes) { |
101 | 0 | descendants_to_remove.insert(descendant.GetTx().GetHash()); |
102 | 0 | } |
103 | 0 | } |
104 | 0 | } |
105 | 0 | mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }); |
106 | 0 | } |
107 | | |
108 | | void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) |
109 | 0 | { |
110 | 0 | AssertLockHeld(cs); |
111 | | // For each entry in vHashesToUpdate, store the set of in-mempool, but not |
112 | | // in-vHashesToUpdate transactions, so that we don't have to recalculate |
113 | | // descendants when we come across a previously seen entry. |
114 | 0 | cacheMap mapMemPoolDescendantsToUpdate; |
115 | | |
116 | | // Use a set for lookups into vHashesToUpdate (these entries are already |
117 | | // accounted for in the state of their ancestors) |
118 | 0 | std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); |
119 | |
|
120 | 0 | std::set<uint256> descendants_to_remove; |
121 | | |
122 | | // Iterate in reverse, so that whenever we are looking at a transaction |
123 | | // we are sure that all in-mempool descendants have already been processed. |
124 | | // This maximizes the benefit of the descendant cache and guarantees that |
125 | | // CTxMemPoolEntry::m_children will be updated, an assumption made in |
126 | | // UpdateForDescendants. |
127 | 0 | for (const uint256& hash : vHashesToUpdate | std::views::reverse) { |
128 | | // calculate children from mapNextTx |
129 | 0 | txiter it = mapTx.find(hash); |
130 | 0 | if (it == mapTx.end()) { |
131 | 0 | continue; |
132 | 0 | } |
133 | 0 | auto iter = mapNextTx.lower_bound(COutPoint(Txid::FromUint256(hash), 0)); |
134 | | // First calculate the children, and update CTxMemPoolEntry::m_children to |
135 | | // include them, and update their CTxMemPoolEntry::m_parents to include this tx. |
136 | | // we cache the in-mempool children to avoid duplicate updates |
137 | 0 | { |
138 | 0 | WITH_FRESH_EPOCH(m_epoch); |
139 | 0 | for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { |
140 | 0 | const uint256 &childHash = iter->second->GetHash(); |
141 | 0 | txiter childIter = mapTx.find(childHash); |
142 | 0 | assert(childIter != mapTx.end()); |
143 | | // We can skip updating entries we've encountered before or that |
144 | | // are in the block (which are already accounted for). |
145 | 0 | if (!visited(childIter) && !setAlreadyIncluded.count(childHash)) { |
146 | 0 | UpdateChild(it, childIter, true); |
147 | 0 | UpdateParent(childIter, it, true); |
148 | 0 | } |
149 | 0 | } |
150 | 0 | } // release epoch guard for UpdateForDescendants |
151 | 0 | UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded, descendants_to_remove); |
152 | 0 | } |
153 | | |
154 | 0 | for (const auto& txid : descendants_to_remove) { |
155 | | // This txid may have been removed already in a prior call to removeRecursive. |
156 | | // Therefore we ensure it is not yet removed already. |
157 | 0 | if (const std::optional<txiter> txiter = GetIter(txid)) { |
158 | 0 | removeRecursive((*txiter)->GetTx(), MemPoolRemovalReason::SIZELIMIT); |
159 | 0 | } |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateAncestorsAndCheckLimits( |
164 | | int64_t entry_size, |
165 | | size_t entry_count, |
166 | | CTxMemPoolEntry::Parents& staged_ancestors, |
167 | | const Limits& limits) const |
168 | 3.66M | { |
169 | 3.66M | int64_t totalSizeWithAncestors = entry_size; |
170 | 3.66M | setEntries ancestors; |
171 | | |
172 | 26.9M | while (!staged_ancestors.empty()) { |
173 | 23.2M | const CTxMemPoolEntry& stage = staged_ancestors.begin()->get(); |
174 | 23.2M | txiter stageit = mapTx.iterator_to(stage); |
175 | | |
176 | 23.2M | ancestors.insert(stageit); |
177 | 23.2M | staged_ancestors.erase(stage); |
178 | 23.2M | totalSizeWithAncestors += stageit->GetTxSize(); |
179 | | |
180 | 23.2M | if (stageit->GetSizeWithDescendants() + entry_size > limits.descendant_size_vbytes) { |
181 | 11.4k | return util::Error{Untranslated(strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes))}; |
182 | 23.2M | } else if (stageit->GetCountWithDescendants() + entry_count > static_cast<uint64_t>(limits.descendant_count)) { |
183 | 5.77k | return util::Error{Untranslated(strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count))}; |
184 | 23.2M | } else if (totalSizeWithAncestors > limits.ancestor_size_vbytes) { |
185 | 6.24k | return util::Error{Untranslated(strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes))}; |
186 | 6.24k | } |
187 | | |
188 | 23.2M | const CTxMemPoolEntry::Parents& parents = stageit->GetMemPoolParentsConst(); |
189 | 32.2M | for (const CTxMemPoolEntry& parent : parents) { |
190 | 32.2M | txiter parent_it = mapTx.iterator_to(parent); |
191 | | |
192 | | // If this is a new ancestor, add it. |
193 | 32.2M | if (ancestors.count(parent_it) == 0) { |
194 | 24.8M | staged_ancestors.insert(parent); |
195 | 24.8M | } |
196 | 32.2M | if (staged_ancestors.size() + ancestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) { |
197 | 3.43k | return util::Error{Untranslated(strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count))}; |
198 | 3.43k | } |
199 | 32.2M | } |
200 | 23.2M | } |
201 | | |
202 | 3.63M | return ancestors; |
203 | 3.66M | } |
204 | | |
205 | | util::Result<void> CTxMemPool::CheckPackageLimits(const Package& package, |
206 | | const int64_t total_vsize) const |
207 | 69.8k | { |
208 | 69.8k | size_t pack_count = package.size(); |
209 | | |
210 | | // Package itself is busting mempool limits; should be rejected even if no staged_ancestors exist |
211 | 69.8k | if (pack_count > static_cast<uint64_t>(m_opts.limits.ancestor_count)) { |
212 | 120 | return util::Error{Untranslated(strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_count, m_opts.limits.ancestor_count))}; |
213 | 69.7k | } else if (pack_count > static_cast<uint64_t>(m_opts.limits.descendant_count)) { |
214 | 94 | return util::Error{Untranslated(strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_count, m_opts.limits.descendant_count))}; |
215 | 69.6k | } else if (total_vsize > m_opts.limits.ancestor_size_vbytes) { |
216 | 160 | return util::Error{Untranslated(strprintf("package size %u exceeds ancestor size limit [limit: %u]", total_vsize, m_opts.limits.ancestor_size_vbytes))}; |
217 | 69.5k | } else if (total_vsize > m_opts.limits.descendant_size_vbytes) { |
218 | 45 | return util::Error{Untranslated(strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_opts.limits.descendant_size_vbytes))}; |
219 | 45 | } |
220 | | |
221 | 69.4k | CTxMemPoolEntry::Parents staged_ancestors; |
222 | 102k | for (const auto& tx : package) { |
223 | 336k | for (const auto& input : tx->vin) { |
224 | 336k | std::optional<txiter> piter = GetIter(input.prevout.hash); |
225 | 336k | if (piter) { |
226 | 20.8k | staged_ancestors.insert(**piter); |
227 | 20.8k | if (staged_ancestors.size() + package.size() > static_cast<uint64_t>(m_opts.limits.ancestor_count)) { |
228 | 35 | return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", m_opts.limits.ancestor_count))}; |
229 | 35 | } |
230 | 20.8k | } |
231 | 336k | } |
232 | 102k | } |
233 | | // When multiple transactions are passed in, the ancestors and descendants of all transactions |
234 | | // considered together must be within limits even if they are not interdependent. This may be |
235 | | // stricter than the limits for each individual transaction. |
236 | 69.4k | const auto ancestors{CalculateAncestorsAndCheckLimits(total_vsize, package.size(), |
237 | 69.4k | staged_ancestors, m_opts.limits)}; |
238 | | // It's possible to overestimate the ancestor/descendant totals. |
239 | 69.4k | if (!ancestors.has_value()) return util::Error{Untranslated("possibly " + util::ErrorString(ancestors).original)}; |
240 | 69.2k | return {}; |
241 | 69.4k | } |
242 | | |
243 | | util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateMemPoolAncestors( |
244 | | const CTxMemPoolEntry &entry, |
245 | | const Limits& limits, |
246 | | bool fSearchForParents /* = true */) const |
247 | 3.62M | { |
248 | 3.62M | CTxMemPoolEntry::Parents staged_ancestors; |
249 | 3.62M | const CTransaction &tx = entry.GetTx(); |
250 | | |
251 | 3.62M | if (fSearchForParents) { |
252 | | // Get parents of this transaction that are in the mempool |
253 | | // GetMemPoolParents() is only valid for entries in the mempool, so we |
254 | | // iterate mapTx to find parents. |
255 | 11.2M | for (unsigned int i = 0; i < tx.vin.size(); i++) { |
256 | 8.56M | std::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash); |
257 | 8.56M | if (piter) { |
258 | 4.62M | staged_ancestors.insert(**piter); |
259 | 4.62M | if (staged_ancestors.size() + 1 > static_cast<uint64_t>(limits.ancestor_count)) { |
260 | 31.0k | return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count))}; |
261 | 31.0k | } |
262 | 4.62M | } |
263 | 8.56M | } |
264 | 2.70M | } else { |
265 | | // If we're not searching for parents, we require this to already be an |
266 | | // entry in the mempool and use the entry's cached parents. |
267 | 921k | txiter it = mapTx.iterator_to(entry); |
268 | 921k | staged_ancestors = it->GetMemPoolParentsConst(); |
269 | 921k | } |
270 | | |
271 | 3.59M | return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, staged_ancestors, |
272 | 3.59M | limits); |
273 | 3.62M | } |
274 | | |
275 | | CTxMemPool::setEntries CTxMemPool::AssumeCalculateMemPoolAncestors( |
276 | | std::string_view calling_fn_name, |
277 | | const CTxMemPoolEntry &entry, |
278 | | const Limits& limits, |
279 | | bool fSearchForParents /* = true */) const |
280 | 1.05M | { |
281 | 1.05M | auto result{CalculateMemPoolAncestors(entry, limits, fSearchForParents)}; |
282 | 1.05M | if (!Assume(result)) { |
283 | 0 | LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Error, "%s: CalculateMemPoolAncestors failed unexpectedly, continuing with empty ancestor set (%s)\n", |
284 | 0 | calling_fn_name, util::ErrorString(result).original); |
285 | 0 | } |
286 | 1.05M | return std::move(result).value_or(CTxMemPool::setEntries{}); |
287 | 1.05M | } |
288 | | |
289 | | void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) |
290 | 2.25M | { |
291 | 2.25M | const CTxMemPoolEntry::Parents& parents = it->GetMemPoolParentsConst(); |
292 | | // add or remove this tx as a child of each parent |
293 | 2.25M | for (const CTxMemPoolEntry& parent : parents) { |
294 | 1.14M | UpdateChild(mapTx.iterator_to(parent), it, add); |
295 | 1.14M | } |
296 | 2.25M | const int32_t updateCount = (add ? 1 : -1); |
297 | 2.25M | const int32_t updateSize{updateCount * it->GetTxSize()}; |
298 | 2.25M | const CAmount updateFee = updateCount * it->GetModifiedFee(); |
299 | 21.9M | for (txiter ancestorIt : setAncestors) { |
300 | 21.9M | mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(updateSize, updateFee, updateCount); }); |
301 | 21.9M | } |
302 | 2.25M | } |
303 | | |
304 | | void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) |
305 | 2.14M | { |
306 | 2.14M | int64_t updateCount = setAncestors.size(); |
307 | 2.14M | int64_t updateSize = 0; |
308 | 2.14M | CAmount updateFee = 0; |
309 | 2.14M | int64_t updateSigOpsCost = 0; |
310 | 21.8M | for (txiter ancestorIt : setAncestors) { |
311 | 21.8M | updateSize += ancestorIt->GetTxSize(); |
312 | 21.8M | updateFee += ancestorIt->GetModifiedFee(); |
313 | 21.8M | updateSigOpsCost += ancestorIt->GetSigOpCost(); |
314 | 21.8M | } |
315 | 2.14M | mapTx.modify(it, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(updateSize, updateFee, updateCount, updateSigOpsCost); }); |
316 | 2.14M | } |
317 | | |
318 | | void CTxMemPool::UpdateChildrenForRemoval(txiter it) |
319 | 106k | { |
320 | 106k | const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst(); |
321 | 106k | for (const CTxMemPoolEntry& updateIt : children) { |
322 | 0 | UpdateParent(mapTx.iterator_to(updateIt), it, false); |
323 | 0 | } |
324 | 106k | } |
325 | | |
326 | | void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) |
327 | 2.39M | { |
328 | | // For each entry, walk back all ancestors and decrement size associated with this |
329 | | // transaction |
330 | 2.39M | if (updateDescendants) { |
331 | | // updateDescendants should be true whenever we're not recursively |
332 | | // removing a tx and all its descendants, eg when a transaction is |
333 | | // confirmed in a block. |
334 | | // Here we only update statistics and not data in CTxMemPool::Parents |
335 | | // and CTxMemPoolEntry::Children (which we need to preserve until we're |
336 | | // finished with all operations that need to traverse the mempool). |
337 | 0 | for (txiter removeIt : entriesToRemove) { |
338 | 0 | setEntries setDescendants; |
339 | 0 | CalculateDescendants(removeIt, setDescendants); |
340 | 0 | setDescendants.erase(removeIt); // don't update state for self |
341 | 0 | int32_t modifySize = -removeIt->GetTxSize(); |
342 | 0 | CAmount modifyFee = -removeIt->GetModifiedFee(); |
343 | 0 | int modifySigOps = -removeIt->GetSigOpCost(); |
344 | 0 | for (txiter dit : setDescendants) { |
345 | 0 | mapTx.modify(dit, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(modifySize, modifyFee, -1, modifySigOps); }); |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | 2.39M | for (txiter removeIt : entriesToRemove) { |
350 | 106k | const CTxMemPoolEntry &entry = *removeIt; |
351 | | // Since this is a tx that is already in the mempool, we can call CMPA |
352 | | // with fSearchForParents = false. If the mempool is in a consistent |
353 | | // state, then using true or false should both be correct, though false |
354 | | // should be a bit faster. |
355 | | // However, if we happen to be in the middle of processing a reorg, then |
356 | | // the mempool can be in an inconsistent state. In this case, the set |
357 | | // of ancestors reachable via GetMemPoolParents()/GetMemPoolChildren() |
358 | | // will be the same as the set of ancestors whose packages include this |
359 | | // transaction, because when we add a new transaction to the mempool in |
360 | | // addNewTransaction(), we assume it has no children, and in the case of a |
361 | | // reorg where that assumption is false, the in-mempool children aren't |
362 | | // linked to the in-block tx's until UpdateTransactionsFromBlock() is |
363 | | // called. |
364 | | // So if we're being called during a reorg, ie before |
365 | | // UpdateTransactionsFromBlock() has been called, then |
366 | | // GetMemPoolParents()/GetMemPoolChildren() will differ from the set of |
367 | | // mempool parents we'd calculate by searching, and it's important that |
368 | | // we use the cached notion of ancestor transactions as the set of |
369 | | // things to update for removal. |
370 | 106k | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits(), /*fSearchForParents=*/false)}; |
371 | | // Note that UpdateAncestorsOf severs the child links that point to |
372 | | // removeIt in the entries for the parents of removeIt. |
373 | 106k | UpdateAncestorsOf(false, removeIt, ancestors); |
374 | 106k | } |
375 | | // After updating all the ancestor sizes, we can now sever the link between each |
376 | | // transaction being removed and any mempool children (ie, update CTxMemPoolEntry::m_parents |
377 | | // for each direct child of a transaction being removed). |
378 | 2.39M | for (txiter removeIt : entriesToRemove) { |
379 | 106k | UpdateChildrenForRemoval(removeIt); |
380 | 106k | } |
381 | 2.39M | } |
382 | | |
383 | | void CTxMemPoolEntry::UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount) |
384 | 22.7M | { |
385 | 22.7M | nSizeWithDescendants += modifySize; |
386 | 22.7M | assert(nSizeWithDescendants > 0); |
387 | 22.7M | nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, modifyFee); |
388 | 22.7M | m_count_with_descendants += modifyCount; |
389 | 22.7M | assert(m_count_with_descendants > 0); |
390 | 22.7M | } |
391 | | |
392 | | void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps) |
393 | 2.22M | { |
394 | 2.22M | nSizeWithAncestors += modifySize; |
395 | 2.22M | assert(nSizeWithAncestors > 0); |
396 | 2.22M | nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, modifyFee); |
397 | 2.22M | m_count_with_ancestors += modifyCount; |
398 | 2.22M | assert(m_count_with_ancestors > 0); |
399 | 2.22M | nSigOpCostWithAncestors += modifySigOps; |
400 | 2.22M | assert(int(nSigOpCostWithAncestors) >= 0); |
401 | 2.22M | } |
402 | | |
403 | | //! Clamp option values and populate the error if options are not valid. |
404 | | static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error) |
405 | 27.4k | { |
406 | 27.4k | opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000); |
407 | 27.4k | int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40; |
408 | 27.4k | if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) { |
409 | 1.60k | error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0)); |
410 | 1.60k | } |
411 | 27.4k | return std::move(opts); |
412 | 27.4k | } |
413 | | |
414 | | CTxMemPool::CTxMemPool(Options opts, bilingual_str& error) |
415 | 27.4k | : m_opts{Flatten(std::move(opts), error)} |
416 | 27.4k | { |
417 | 27.4k | } |
418 | | |
419 | | bool CTxMemPool::isSpent(const COutPoint& outpoint) const |
420 | 12 | { |
421 | 12 | LOCK(cs); |
422 | 12 | return mapNextTx.count(outpoint); |
423 | 12 | } |
424 | | |
425 | | unsigned int CTxMemPool::GetTransactionsUpdated() const |
426 | 0 | { |
427 | 0 | return nTransactionsUpdated; |
428 | 0 | } |
429 | | |
430 | | void CTxMemPool::AddTransactionsUpdated(unsigned int n) |
431 | 145k | { |
432 | 145k | nTransactionsUpdated += n; |
433 | 145k | } |
434 | | |
435 | | void CTxMemPool::Apply(ChangeSet* changeset) |
436 | 2.14M | { |
437 | 2.14M | AssertLockHeld(cs); |
438 | 2.14M | RemoveStaged(changeset->m_to_remove, false, MemPoolRemovalReason::REPLACED); |
439 | | |
440 | 4.29M | for (size_t i=0; i<changeset->m_entry_vec.size(); ++i) { |
441 | 2.14M | auto tx_entry = changeset->m_entry_vec[i]; |
442 | 2.14M | std::optional<CTxMemPool::setEntries> ancestors; |
443 | 2.14M | if (i == 0) { |
444 | | // Note: ChangeSet::CalculateMemPoolAncestors() will return a |
445 | | // cached value if mempool ancestors for this transaction were |
446 | | // previously calculated. |
447 | | // We can only use a cached ancestor calculation for the first |
448 | | // transaction in a package, because in-package parents won't be |
449 | | // present in the cached ancestor sets of in-package children. |
450 | | // We pass in Limits::NoLimits() to ensure that this function won't fail |
451 | | // (we're going to be applying this set of transactions whether or |
452 | | // not the mempool policy limits are being respected). |
453 | 2.14M | ancestors = *Assume(changeset->CalculateMemPoolAncestors(tx_entry, Limits::NoLimits())); |
454 | 2.14M | } |
455 | | // First splice this entry into mapTx. |
456 | 2.14M | auto node_handle = changeset->m_to_add.extract(tx_entry); |
457 | 2.14M | auto result = mapTx.insert(std::move(node_handle)); |
458 | | |
459 | 2.14M | Assume(result.inserted); |
460 | 2.14M | txiter it = result.position; |
461 | | |
462 | | // Now update the entry for ancestors/descendants. |
463 | 2.14M | if (ancestors.has_value()) { |
464 | 2.14M | addNewTransaction(it, *ancestors); |
465 | 2.14M | } else { |
466 | 1.43k | addNewTransaction(it); |
467 | 1.43k | } |
468 | 2.14M | } |
469 | 2.14M | } |
470 | | |
471 | | void CTxMemPool::addNewTransaction(CTxMemPool::txiter it) |
472 | 1.43k | { |
473 | 1.43k | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())}; |
474 | 1.43k | return addNewTransaction(it, ancestors); |
475 | 1.43k | } |
476 | | |
477 | | void CTxMemPool::addNewTransaction(CTxMemPool::txiter newit, CTxMemPool::setEntries& setAncestors) |
478 | 2.14M | { |
479 | 2.14M | const CTxMemPoolEntry& entry = *newit; |
480 | | |
481 | | // Update cachedInnerUsage to include contained transaction's usage. |
482 | | // (When we update the entry for in-mempool parents, memory usage will be |
483 | | // further updated.) |
484 | 2.14M | cachedInnerUsage += entry.DynamicMemoryUsage(); |
485 | | |
486 | 2.14M | const CTransaction& tx = newit->GetTx(); |
487 | 2.14M | std::set<Txid> setParentTransactions; |
488 | 6.61M | for (unsigned int i = 0; i < tx.vin.size(); i++) { |
489 | 4.46M | mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); |
490 | 4.46M | setParentTransactions.insert(tx.vin[i].prevout.hash); |
491 | 4.46M | } |
492 | | // Don't bother worrying about child transactions of this one. |
493 | | // Normal case of a new transaction arriving is that there can't be any |
494 | | // children, because such children would be orphans. |
495 | | // An exception to that is if a transaction enters that used to be in a block. |
496 | | // In that case, our disconnect block logic will call UpdateTransactionsFromBlock |
497 | | // to clean up the mess we're leaving here. |
498 | | |
499 | | // Update ancestors with information about this tx |
500 | 2.14M | for (const auto& pit : GetIterSet(setParentTransactions)) { |
501 | 1.11M | UpdateParent(newit, pit, true); |
502 | 1.11M | } |
503 | 2.14M | UpdateAncestorsOf(true, newit, setAncestors); |
504 | 2.14M | UpdateEntryForAncestors(newit, setAncestors); |
505 | | |
506 | 2.14M | nTransactionsUpdated++; |
507 | 2.14M | totalTxSize += entry.GetTxSize(); |
508 | 2.14M | m_total_fee += entry.GetFee(); |
509 | | |
510 | 2.14M | txns_randomized.emplace_back(newit->GetSharedTx()); |
511 | 2.14M | newit->idx_randomized = txns_randomized.size() - 1; |
512 | | |
513 | 2.14M | TRACEPOINT(mempool, added, |
514 | 2.14M | entry.GetTx().GetHash().data(), |
515 | 2.14M | entry.GetTxSize(), |
516 | 2.14M | entry.GetFee() |
517 | 2.14M | ); |
518 | 2.14M | } |
519 | | |
520 | | void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) |
521 | 106k | { |
522 | | // We increment mempool sequence value no matter removal reason |
523 | | // even if not directly reported below. |
524 | 106k | uint64_t mempool_sequence = GetAndIncrementSequence(); |
525 | | |
526 | 106k | if (reason != MemPoolRemovalReason::BLOCK && m_opts.signals) { |
527 | | // Notify clients that a transaction has been removed from the mempool |
528 | | // for any reason except being included in a block. Clients interested |
529 | | // in transactions included in blocks can subscribe to the BlockConnected |
530 | | // notification. |
531 | 100k | m_opts.signals->TransactionRemovedFromMempool(it->GetSharedTx(), reason, mempool_sequence); |
532 | 100k | } |
533 | 106k | TRACEPOINT(mempool, removed, |
534 | 106k | it->GetTx().GetHash().data(), |
535 | 106k | RemovalReasonToString(reason).c_str(), |
536 | 106k | it->GetTxSize(), |
537 | 106k | it->GetFee(), |
538 | 106k | std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count() |
539 | 106k | ); |
540 | | |
541 | 106k | for (const CTxIn& txin : it->GetTx().vin) |
542 | 178k | mapNextTx.erase(txin.prevout); |
543 | | |
544 | 106k | RemoveUnbroadcastTx(it->GetTx().GetHash(), true /* add logging because unchecked */); |
545 | | |
546 | 106k | if (txns_randomized.size() > 1) { |
547 | | // Update idx_randomized of the to-be-moved entry. |
548 | 94.1k | Assert(GetEntry(txns_randomized.back()->GetHash()))->idx_randomized = it->idx_randomized; |
549 | | // Remove entry from txns_randomized by replacing it with the back and deleting the back. |
550 | 94.1k | txns_randomized[it->idx_randomized] = std::move(txns_randomized.back()); |
551 | 94.1k | txns_randomized.pop_back(); |
552 | 94.1k | if (txns_randomized.size() * 2 < txns_randomized.capacity()) |
553 | 13.8k | txns_randomized.shrink_to_fit(); |
554 | 94.1k | } else |
555 | 12.7k | txns_randomized.clear(); |
556 | | |
557 | 106k | totalTxSize -= it->GetTxSize(); |
558 | 106k | m_total_fee -= it->GetFee(); |
559 | 106k | cachedInnerUsage -= it->DynamicMemoryUsage(); |
560 | 106k | cachedInnerUsage -= memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst()); |
561 | 106k | mapTx.erase(it); |
562 | 106k | nTransactionsUpdated++; |
563 | 106k | } |
564 | | |
565 | | // Calculates descendants of entry that are not already in setDescendants, and adds to |
566 | | // setDescendants. Assumes entryit is already a tx in the mempool and CTxMemPoolEntry::m_children |
567 | | // is correct for tx and all descendants. |
568 | | // Also assumes that if an entry is in setDescendants already, then all |
569 | | // in-mempool descendants of it are already in setDescendants as well, so that we |
570 | | // can save time by not iterating over those entries. |
571 | | void CTxMemPool::CalculateDescendants(txiter entryit, setEntries& setDescendants) const |
572 | 2.49M | { |
573 | 2.49M | setEntries stage; |
574 | 2.49M | if (setDescendants.count(entryit) == 0) { |
575 | 2.24M | stage.insert(entryit); |
576 | 2.24M | } |
577 | | // Traverse down the children of entry, only adding children that are not |
578 | | // accounted for in setDescendants already (because those children have either |
579 | | // already been walked, or will be walked in this iteration). |
580 | 50.8M | while (!stage.empty()) { |
581 | 48.3M | txiter it = *stage.begin(); |
582 | 48.3M | setDescendants.insert(it); |
583 | 48.3M | stage.erase(it); |
584 | | |
585 | 48.3M | const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst(); |
586 | 69.4M | for (const CTxMemPoolEntry& child : children) { |
587 | 69.4M | txiter childiter = mapTx.iterator_to(child); |
588 | 69.4M | if (!setDescendants.count(childiter)) { |
589 | 54.0M | stage.insert(childiter); |
590 | 54.0M | } |
591 | 69.4M | } |
592 | 48.3M | } |
593 | 2.49M | } |
594 | | |
595 | | void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason) |
596 | 4.48k | { |
597 | | // Remove transaction from memory pool |
598 | 4.48k | AssertLockHeld(cs); |
599 | 4.48k | Assume(!m_have_changeset); |
600 | 4.48k | setEntries txToRemove; |
601 | 4.48k | txiter origit = mapTx.find(origTx.GetHash()); |
602 | 4.48k | if (origit != mapTx.end()) { |
603 | 4.48k | txToRemove.insert(origit); |
604 | 4.48k | } else { |
605 | | // When recursively removing but origTx isn't in the mempool |
606 | | // be sure to remove any children that are in the pool. This can |
607 | | // happen during chain re-orgs if origTx isn't re-accepted into |
608 | | // the mempool for any reason. |
609 | 0 | for (unsigned int i = 0; i < origTx.vout.size(); i++) { |
610 | 0 | auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); |
611 | 0 | if (it == mapNextTx.end()) |
612 | 0 | continue; |
613 | 0 | txiter nextit = mapTx.find(it->second->GetHash()); |
614 | 0 | assert(nextit != mapTx.end()); |
615 | 0 | txToRemove.insert(nextit); |
616 | 0 | } |
617 | 0 | } |
618 | 4.48k | setEntries setAllRemoves; |
619 | 4.48k | for (txiter it : txToRemove) { |
620 | 4.48k | CalculateDescendants(it, setAllRemoves); |
621 | 4.48k | } |
622 | | |
623 | 4.48k | RemoveStaged(setAllRemoves, false, reason); |
624 | 4.48k | } |
625 | | |
626 | | void CTxMemPool::removeForReorg(CChain& chain, std::function<bool(txiter)> check_final_and_mature) |
627 | 0 | { |
628 | | // Remove transactions spending a coinbase which are now immature and no-longer-final transactions |
629 | 0 | AssertLockHeld(cs); |
630 | 0 | AssertLockHeld(::cs_main); |
631 | 0 | Assume(!m_have_changeset); |
632 | |
|
633 | 0 | setEntries txToRemove; |
634 | 0 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { |
635 | 0 | if (check_final_and_mature(it)) txToRemove.insert(it); |
636 | 0 | } |
637 | 0 | setEntries setAllRemoves; |
638 | 0 | for (txiter it : txToRemove) { |
639 | 0 | CalculateDescendants(it, setAllRemoves); |
640 | 0 | } |
641 | 0 | RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG); |
642 | 0 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { |
643 | 0 | assert(TestLockPointValidity(chain, it->GetLockPoints())); |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | | void CTxMemPool::removeConflicts(const CTransaction &tx) |
648 | 145k | { |
649 | | // Remove transactions which depend on inputs of tx, recursively |
650 | 145k | AssertLockHeld(cs); |
651 | 145k | for (const CTxIn &txin : tx.vin) { |
652 | 145k | auto it = mapNextTx.find(txin.prevout); |
653 | 145k | if (it != mapNextTx.end()) { |
654 | 0 | const CTransaction &txConflict = *it->second; |
655 | 0 | if (txConflict != tx) |
656 | 0 | { |
657 | 0 | ClearPrioritisation(txConflict.GetHash()); |
658 | 0 | removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); |
659 | 0 | } |
660 | 0 | } |
661 | 145k | } |
662 | 145k | } |
663 | | |
664 | | /** |
665 | | * Called when a block is connected. Removes from mempool. |
666 | | */ |
667 | | void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) |
668 | 145k | { |
669 | 145k | AssertLockHeld(cs); |
670 | 145k | Assume(!m_have_changeset); |
671 | 145k | std::vector<RemovedMempoolTransactionInfo> txs_removed_for_block; |
672 | 145k | txs_removed_for_block.reserve(vtx.size()); |
673 | 145k | for (const auto& tx : vtx) |
674 | 145k | { |
675 | 145k | txiter it = mapTx.find(tx->GetHash()); |
676 | 145k | if (it != mapTx.end()) { |
677 | 0 | setEntries stage; |
678 | 0 | stage.insert(it); |
679 | 0 | txs_removed_for_block.emplace_back(*it); |
680 | 0 | RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); |
681 | 0 | } |
682 | 145k | removeConflicts(*tx); |
683 | 145k | ClearPrioritisation(tx->GetHash()); |
684 | 145k | } |
685 | 145k | if (m_opts.signals) { |
686 | 144k | m_opts.signals->MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight); |
687 | 144k | } |
688 | 145k | lastRollingFeeUpdate = GetTime(); |
689 | 145k | blockSinceLastRollingFeeBump = true; |
690 | 145k | } |
691 | | |
692 | | void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const |
693 | 187k | { |
694 | 187k | if (m_opts.check_ratio == 0) return; |
695 | | |
696 | 187k | if (FastRandomContext().randrange(m_opts.check_ratio) >= 1) return; |
697 | | |
698 | 187k | AssertLockHeld(::cs_main); |
699 | 187k | LOCK(cs); |
700 | 187k | LogDebug(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); |
701 | | |
702 | 187k | uint64_t checkTotal = 0; |
703 | 187k | CAmount check_total_fee{0}; |
704 | 187k | uint64_t innerUsage = 0; |
705 | 187k | uint64_t prev_ancestor_count{0}; |
706 | | |
707 | 187k | CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip)); |
708 | | |
709 | 187k | for (const auto& it : GetSortedDepthAndScore()) { |
710 | 129k | checkTotal += it->GetTxSize(); |
711 | 129k | check_total_fee += it->GetFee(); |
712 | 129k | innerUsage += it->DynamicMemoryUsage(); |
713 | 129k | const CTransaction& tx = it->GetTx(); |
714 | 129k | innerUsage += memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst()); |
715 | 129k | CTxMemPoolEntry::Parents setParentCheck; |
716 | 204k | for (const CTxIn &txin : tx.vin) { |
717 | | // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. |
718 | 204k | indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); |
719 | 204k | if (it2 != mapTx.end()) { |
720 | 58.8k | const CTransaction& tx2 = it2->GetTx(); |
721 | 58.8k | assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); |
722 | 58.8k | setParentCheck.insert(*it2); |
723 | 58.8k | } |
724 | | // We are iterating through the mempool entries sorted in order by ancestor count. |
725 | | // All parents must have been checked before their children and their coins added to |
726 | | // the mempoolDuplicate coins cache. |
727 | 204k | assert(mempoolDuplicate.HaveCoin(txin.prevout)); |
728 | | // Check whether its inputs are marked in mapNextTx. |
729 | 204k | auto it3 = mapNextTx.find(txin.prevout); |
730 | 204k | assert(it3 != mapNextTx.end()); |
731 | 204k | assert(it3->first == &txin.prevout); |
732 | 204k | assert(it3->second == &tx); |
733 | 204k | } |
734 | 129k | auto comp = [](const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) -> bool { |
735 | 84.6k | return a.GetTx().GetHash() == b.GetTx().GetHash(); |
736 | 84.6k | }; |
737 | 129k | assert(setParentCheck.size() == it->GetMemPoolParentsConst().size()); |
738 | 129k | assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp)); |
739 | | // Verify ancestor state is correct. |
740 | 129k | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())}; |
741 | 129k | uint64_t nCountCheck = ancestors.size() + 1; |
742 | 129k | int32_t nSizeCheck = it->GetTxSize(); |
743 | 129k | CAmount nFeesCheck = it->GetModifiedFee(); |
744 | 129k | int64_t nSigOpCheck = it->GetSigOpCost(); |
745 | | |
746 | 129k | for (txiter ancestorIt : ancestors) { |
747 | 76.8k | nSizeCheck += ancestorIt->GetTxSize(); |
748 | 76.8k | nFeesCheck += ancestorIt->GetModifiedFee(); |
749 | 76.8k | nSigOpCheck += ancestorIt->GetSigOpCost(); |
750 | 76.8k | } |
751 | | |
752 | 129k | assert(it->GetCountWithAncestors() == nCountCheck); |
753 | 129k | assert(it->GetSizeWithAncestors() == nSizeCheck); |
754 | 129k | assert(it->GetSigOpCostWithAncestors() == nSigOpCheck); |
755 | 129k | assert(it->GetModFeesWithAncestors() == nFeesCheck); |
756 | | // Sanity check: we are walking in ascending ancestor count order. |
757 | 129k | assert(prev_ancestor_count <= it->GetCountWithAncestors()); |
758 | 129k | prev_ancestor_count = it->GetCountWithAncestors(); |
759 | | |
760 | | // Check children against mapNextTx |
761 | 129k | CTxMemPoolEntry::Children setChildrenCheck; |
762 | 129k | auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); |
763 | 129k | int32_t child_sizes{0}; |
764 | 188k | for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) { |
765 | 58.8k | txiter childit = mapTx.find(iter->second->GetHash()); |
766 | 58.8k | assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions |
767 | 58.8k | if (setChildrenCheck.insert(*childit).second) { |
768 | 42.3k | child_sizes += childit->GetTxSize(); |
769 | 42.3k | } |
770 | 58.8k | } |
771 | 129k | assert(setChildrenCheck.size() == it->GetMemPoolChildrenConst().size()); |
772 | 129k | assert(std::equal(setChildrenCheck.begin(), setChildrenCheck.end(), it->GetMemPoolChildrenConst().begin(), comp)); |
773 | | // Also check to make sure size is greater than sum with immediate children. |
774 | | // just a sanity check, not definitive that this calc is correct... |
775 | 129k | assert(it->GetSizeWithDescendants() >= child_sizes + it->GetTxSize()); |
776 | | |
777 | 129k | TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass |
778 | 129k | CAmount txfee = 0; |
779 | 129k | assert(!tx.IsCoinBase()); |
780 | 129k | assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee)); |
781 | 204k | for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout); |
782 | 129k | AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max()); |
783 | 129k | } |
784 | 392k | for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { |
785 | 204k | uint256 hash = it->second->GetHash(); |
786 | 204k | indexed_transaction_set::const_iterator it2 = mapTx.find(hash); |
787 | 204k | const CTransaction& tx = it2->GetTx(); |
788 | 204k | assert(it2 != mapTx.end()); |
789 | 204k | assert(&tx == it->second); |
790 | 204k | } |
791 | | |
792 | 187k | assert(totalTxSize == checkTotal); |
793 | 187k | assert(m_total_fee == check_total_fee); |
794 | 187k | assert(innerUsage == cachedInnerUsage); |
795 | 187k | } |
796 | | |
797 | | bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid) |
798 | 0 | { |
799 | | /* Return `true` if hasha should be considered sooner than hashb. Namely when: |
800 | | * a is not in the mempool, but b is |
801 | | * both are in the mempool and a has fewer ancestors than b |
802 | | * both are in the mempool and a has a higher score than b |
803 | | */ |
804 | 0 | LOCK(cs); |
805 | 0 | indexed_transaction_set::const_iterator j = wtxid ? get_iter_from_wtxid(hashb) : mapTx.find(hashb); |
806 | 0 | if (j == mapTx.end()) return false; |
807 | 0 | indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha); |
808 | 0 | if (i == mapTx.end()) return true; |
809 | 0 | uint64_t counta = i->GetCountWithAncestors(); |
810 | 0 | uint64_t countb = j->GetCountWithAncestors(); |
811 | 0 | if (counta == countb) { |
812 | 0 | return CompareTxMemPoolEntryByScore()(*i, *j); |
813 | 0 | } |
814 | 0 | return counta < countb; |
815 | 0 | } |
816 | | |
817 | | namespace { |
818 | | class DepthAndScoreComparator |
819 | | { |
820 | | public: |
821 | | bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b) |
822 | 52.6M | { |
823 | 52.6M | uint64_t counta = a->GetCountWithAncestors(); |
824 | 52.6M | uint64_t countb = b->GetCountWithAncestors(); |
825 | 52.6M | if (counta == countb) { |
826 | 36.8M | return CompareTxMemPoolEntryByScore()(*a, *b); |
827 | 36.8M | } |
828 | 15.7M | return counta < countb; |
829 | 52.6M | } |
830 | | }; |
831 | | } // namespace |
832 | | |
833 | | std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const |
834 | 865k | { |
835 | 865k | std::vector<indexed_transaction_set::const_iterator> iters; |
836 | 865k | AssertLockHeld(cs); |
837 | | |
838 | 865k | iters.reserve(mapTx.size()); |
839 | | |
840 | 9.94M | for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) { |
841 | 9.07M | iters.push_back(mi); |
842 | 9.07M | } |
843 | 865k | std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); |
844 | 865k | return iters; |
845 | 865k | } |
846 | | |
847 | 8.96M | static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { |
848 | 8.96M | return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), it->GetFee(), it->GetTxSize(), it->GetModifiedFee() - it->GetFee()}; |
849 | 8.96M | } |
850 | | |
851 | | std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const |
852 | 19 | { |
853 | 19 | AssertLockHeld(cs); |
854 | | |
855 | 19 | std::vector<CTxMemPoolEntryRef> ret; |
856 | 19 | ret.reserve(mapTx.size()); |
857 | 19 | for (const auto& it : GetSortedDepthAndScore()) { |
858 | 0 | ret.emplace_back(*it); |
859 | 0 | } |
860 | 19 | return ret; |
861 | 19 | } |
862 | | |
863 | | std::vector<TxMempoolInfo> CTxMemPool::infoAll() const |
864 | 678k | { |
865 | 678k | LOCK(cs); |
866 | 678k | auto iters = GetSortedDepthAndScore(); |
867 | | |
868 | 678k | std::vector<TxMempoolInfo> ret; |
869 | 678k | ret.reserve(mapTx.size()); |
870 | 8.94M | for (auto it : iters) { |
871 | 8.94M | ret.push_back(GetInfo(it)); |
872 | 8.94M | } |
873 | | |
874 | 678k | return ret; |
875 | 678k | } |
876 | | |
877 | | const CTxMemPoolEntry* CTxMemPool::GetEntry(const Txid& txid) const |
878 | 8.95M | { |
879 | 8.95M | AssertLockHeld(cs); |
880 | 8.95M | const auto i = mapTx.find(txid); |
881 | 8.95M | return i == mapTx.end() ? nullptr : &(*i); |
882 | 8.95M | } |
883 | | |
884 | | CTransactionRef CTxMemPool::get(const uint256& hash) const |
885 | 46.2M | { |
886 | 46.2M | LOCK(cs); |
887 | 46.2M | indexed_transaction_set::const_iterator i = mapTx.find(hash); |
888 | 46.2M | if (i == mapTx.end()) |
889 | 21.9M | return nullptr; |
890 | 24.2M | return i->GetSharedTx(); |
891 | 46.2M | } |
892 | | |
893 | | TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const |
894 | 13.0k | { |
895 | 13.0k | LOCK(cs); |
896 | 13.0k | indexed_transaction_set::const_iterator i = (gtxid.IsWtxid() ? get_iter_from_wtxid(gtxid.GetHash()) : mapTx.find(gtxid.GetHash())); |
897 | 13.0k | if (i == mapTx.end()) |
898 | 0 | return TxMempoolInfo(); |
899 | 13.0k | return GetInfo(i); |
900 | 13.0k | } |
901 | | |
902 | | TxMempoolInfo CTxMemPool::info_for_relay(const GenTxid& gtxid, uint64_t last_sequence) const |
903 | 92.3k | { |
904 | 92.3k | LOCK(cs); |
905 | 92.3k | indexed_transaction_set::const_iterator i = (gtxid.IsWtxid() ? get_iter_from_wtxid(gtxid.GetHash()) : mapTx.find(gtxid.GetHash())); |
906 | 92.3k | if (i != mapTx.end() && i->GetSequence() < last_sequence) { |
907 | 0 | return GetInfo(i); |
908 | 92.3k | } else { |
909 | 92.3k | return TxMempoolInfo(); |
910 | 92.3k | } |
911 | 92.3k | } |
912 | | |
913 | | void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta) |
914 | 2.25M | { |
915 | 2.25M | { |
916 | 2.25M | LOCK(cs); |
917 | 2.25M | CAmount &delta = mapDeltas[hash]; |
918 | 2.25M | delta = SaturatingAdd(delta, nFeeDelta); |
919 | 2.25M | txiter it = mapTx.find(hash); |
920 | 2.25M | if (it != mapTx.end()) { |
921 | 778k | mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); }); |
922 | | // Now update all ancestors' modified fees with descendants |
923 | 778k | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)}; |
924 | 785k | for (txiter ancestorIt : ancestors) { |
925 | 785k | mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);}); |
926 | 785k | } |
927 | | // Now update all descendants' modified fees with ancestors |
928 | 778k | setEntries setDescendants; |
929 | 778k | CalculateDescendants(it, setDescendants); |
930 | 778k | setDescendants.erase(it); |
931 | 778k | for (txiter descendantIt : setDescendants) { |
932 | 80.6k | mapTx.modify(descendantIt, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(0, nFeeDelta, 0, 0); }); |
933 | 80.6k | } |
934 | 778k | ++nTransactionsUpdated; |
935 | 778k | } |
936 | 2.25M | if (delta == 0) { |
937 | 11.2k | mapDeltas.erase(hash); |
938 | 11.2k | LogPrintf("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : ""); |
939 | 2.24M | } else { |
940 | 2.24M | LogPrintf("PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n", |
941 | 2.24M | hash.ToString(), |
942 | 2.24M | it == mapTx.end() ? "not " : "", |
943 | 2.24M | FormatMoney(nFeeDelta), |
944 | 2.24M | FormatMoney(delta)); |
945 | 2.24M | } |
946 | 2.25M | } |
947 | 2.25M | } |
948 | | |
949 | | void CTxMemPool::ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const |
950 | 2.73M | { |
951 | 2.73M | AssertLockHeld(cs); |
952 | 2.73M | std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash); |
953 | 2.73M | if (pos == mapDeltas.end()) |
954 | 2.51M | return; |
955 | 213k | const CAmount &delta = pos->second; |
956 | 213k | nFeeDelta += delta; |
957 | 213k | } |
958 | | |
959 | | void CTxMemPool::ClearPrioritisation(const uint256& hash) |
960 | 145k | { |
961 | 145k | AssertLockHeld(cs); |
962 | 145k | mapDeltas.erase(hash); |
963 | 145k | } |
964 | | |
965 | | std::vector<CTxMemPool::delta_info> CTxMemPool::GetPrioritisedTransactions() const |
966 | 23 | { |
967 | 23 | AssertLockNotHeld(cs); |
968 | 23 | LOCK(cs); |
969 | 23 | std::vector<delta_info> result; |
970 | 23 | result.reserve(mapDeltas.size()); |
971 | 241 | for (const auto& [txid, delta] : mapDeltas) { |
972 | 241 | const auto iter{mapTx.find(txid)}; |
973 | 241 | const bool in_mempool{iter != mapTx.end()}; |
974 | 241 | std::optional<CAmount> modified_fee; |
975 | 241 | if (in_mempool) modified_fee = iter->GetModifiedFee(); |
976 | 241 | result.emplace_back(delta_info{in_mempool, delta, modified_fee, txid}); |
977 | 241 | } |
978 | 23 | return result; |
979 | 23 | } |
980 | | |
981 | | const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const |
982 | 10.5M | { |
983 | 10.5M | const auto it = mapNextTx.find(prevout); |
984 | 10.5M | return it == mapNextTx.end() ? nullptr : it->second; |
985 | 10.5M | } |
986 | | |
987 | | std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const uint256& txid) const |
988 | 15.4M | { |
989 | 15.4M | auto it = mapTx.find(txid); |
990 | 15.4M | if (it != mapTx.end()) return it; |
991 | 7.44M | return std::nullopt; |
992 | 15.4M | } |
993 | | |
994 | | CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<Txid>& hashes) const |
995 | 2.73M | { |
996 | 2.73M | CTxMemPool::setEntries ret; |
997 | 3.06M | for (const auto& h : hashes) { |
998 | 3.06M | const auto mi = GetIter(h); |
999 | 3.06M | if (mi) ret.insert(*mi); |
1000 | 3.06M | } |
1001 | 2.73M | return ret; |
1002 | 2.73M | } |
1003 | | |
1004 | | std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<uint256>& txids) const |
1005 | 4.26k | { |
1006 | 4.26k | AssertLockHeld(cs); |
1007 | 4.26k | std::vector<txiter> ret; |
1008 | 4.26k | ret.reserve(txids.size()); |
1009 | 252k | for (const auto& txid : txids) { |
1010 | 252k | const auto it{GetIter(txid)}; |
1011 | 252k | if (!it) return {}; |
1012 | 252k | ret.push_back(*it); |
1013 | 252k | } |
1014 | 4.26k | return ret; |
1015 | 4.26k | } |
1016 | | |
1017 | | bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const |
1018 | 176k | { |
1019 | 361k | for (unsigned int i = 0; i < tx.vin.size(); i++) |
1020 | 240k | if (exists(GenTxid::Txid(tx.vin[i].prevout.hash))) |
1021 | 55.5k | return false; |
1022 | 121k | return true; |
1023 | 176k | } |
1024 | | |
1025 | 2.22M | CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } |
1026 | | |
1027 | | std::optional<Coin> CCoinsViewMemPool::GetCoin(const COutPoint& outpoint) const |
1028 | 45.5M | { |
1029 | | // Check to see if the inputs are made available by another tx in the package. |
1030 | | // These Coins would not be available in the underlying CoinsView. |
1031 | 45.5M | if (auto it = m_temp_added.find(outpoint); it != m_temp_added.end()) { |
1032 | 113k | return it->second; |
1033 | 113k | } |
1034 | | |
1035 | | // If an entry in the mempool exists, always return that one, as it's guaranteed to never |
1036 | | // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) |
1037 | | // transactions. First checking the underlying cache risks returning a pruned entry instead. |
1038 | 45.4M | CTransactionRef ptx = mempool.get(outpoint.hash); |
1039 | 45.4M | if (ptx) { |
1040 | 24.0M | if (outpoint.n < ptx->vout.size()) { |
1041 | 24.0M | Coin coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false); |
1042 | 24.0M | m_non_base_coins.emplace(outpoint); |
1043 | 24.0M | return coin; |
1044 | 24.0M | } |
1045 | 1.96k | return std::nullopt; |
1046 | 24.0M | } |
1047 | 21.3M | return base->GetCoin(outpoint); |
1048 | 45.4M | } |
1049 | | |
1050 | | void CCoinsViewMemPool::PackageAddTransaction(const CTransactionRef& tx) |
1051 | 112k | { |
1052 | 1.29M | for (unsigned int n = 0; n < tx->vout.size(); ++n) { |
1053 | 1.17M | m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false)); |
1054 | 1.17M | m_non_base_coins.emplace(tx->GetHash(), n); |
1055 | 1.17M | } |
1056 | 112k | } |
1057 | | void CCoinsViewMemPool::Reset() |
1058 | 523k | { |
1059 | 523k | m_temp_added.clear(); |
1060 | 523k | m_non_base_coins.clear(); |
1061 | 523k | } |
1062 | | |
1063 | 2.95M | size_t CTxMemPool::DynamicMemoryUsage() const { |
1064 | 2.95M | LOCK(cs); |
1065 | | // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. |
1066 | 2.95M | return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage; |
1067 | 2.95M | } |
1068 | | |
1069 | 106k | void CTxMemPool::RemoveUnbroadcastTx(const uint256& txid, const bool unchecked) { |
1070 | 106k | LOCK(cs); |
1071 | | |
1072 | 106k | if (m_unbroadcast_txids.erase(txid)) |
1073 | 0 | { |
1074 | 0 | LogDebug(BCLog::MEMPOOL, "Removed %i from set of unbroadcast txns%s\n", txid.GetHex(), (unchecked ? " before confirmation that txn was sent out" : "")); |
1075 | 0 | } |
1076 | 106k | } |
1077 | | |
1078 | 2.39M | void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { |
1079 | 2.39M | AssertLockHeld(cs); |
1080 | 2.39M | UpdateForRemoveFromMempool(stage, updateDescendants); |
1081 | 2.39M | for (txiter it : stage) { |
1082 | 106k | removeUnchecked(it, reason); |
1083 | 106k | } |
1084 | 2.39M | } |
1085 | | |
1086 | | int CTxMemPool::Expire(std::chrono::seconds time) |
1087 | 223k | { |
1088 | 223k | AssertLockHeld(cs); |
1089 | 223k | Assume(!m_have_changeset); |
1090 | 223k | indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin(); |
1091 | 223k | setEntries toremove; |
1092 | 267k | while (it != mapTx.get<entry_time>().end() && it->GetTime() < time) { |
1093 | 43.9k | toremove.insert(mapTx.project<0>(it)); |
1094 | 43.9k | it++; |
1095 | 43.9k | } |
1096 | 223k | setEntries stage; |
1097 | 223k | for (txiter removeit : toremove) { |
1098 | 43.9k | CalculateDescendants(removeit, stage); |
1099 | 43.9k | } |
1100 | 223k | RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY); |
1101 | 223k | return stage.size(); |
1102 | 223k | } |
1103 | | |
1104 | | void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) |
1105 | 1.14M | { |
1106 | 1.14M | AssertLockHeld(cs); |
1107 | 1.14M | CTxMemPoolEntry::Children s; |
1108 | 1.14M | if (add && entry->GetMemPoolChildren().insert(*child).second) { |
1109 | 1.11M | cachedInnerUsage += memusage::IncrementalDynamicUsage(s); |
1110 | 1.11M | } else if (!add && entry->GetMemPoolChildren().erase(*child)) { |
1111 | 36.0k | cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); |
1112 | 36.0k | } |
1113 | 1.14M | } |
1114 | | |
1115 | | void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add) |
1116 | 1.11M | { |
1117 | 1.11M | AssertLockHeld(cs); |
1118 | 1.11M | CTxMemPoolEntry::Parents s; |
1119 | 1.11M | if (add && entry->GetMemPoolParents().insert(*parent).second) { |
1120 | 1.11M | cachedInnerUsage += memusage::IncrementalDynamicUsage(s); |
1121 | 1.11M | } else if (!add && entry->GetMemPoolParents().erase(*parent)) { |
1122 | 0 | cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); |
1123 | 0 | } |
1124 | 1.11M | } |
1125 | | |
1126 | 1.95M | CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { |
1127 | 1.95M | LOCK(cs); |
1128 | 1.95M | if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0) |
1129 | 1.92M | return CFeeRate(llround(rollingMinimumFeeRate)); |
1130 | | |
1131 | 28.7k | int64_t time = GetTime(); |
1132 | 28.7k | if (time > lastRollingFeeUpdate + 10) { |
1133 | 3.27k | double halflife = ROLLING_FEE_HALFLIFE; |
1134 | 3.27k | if (DynamicMemoryUsage() < sizelimit / 4) |
1135 | 0 | halflife /= 4; |
1136 | 3.27k | else if (DynamicMemoryUsage() < sizelimit / 2) |
1137 | 0 | halflife /= 2; |
1138 | | |
1139 | 3.27k | rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); |
1140 | 3.27k | lastRollingFeeUpdate = time; |
1141 | | |
1142 | 3.27k | if (rollingMinimumFeeRate < (double)m_opts.incremental_relay_feerate.GetFeePerK() / 2) { |
1143 | 2.54k | rollingMinimumFeeRate = 0; |
1144 | 2.54k | return CFeeRate(0); |
1145 | 2.54k | } |
1146 | 3.27k | } |
1147 | 26.2k | return std::max(CFeeRate(llround(rollingMinimumFeeRate)), m_opts.incremental_relay_feerate); |
1148 | 28.7k | } |
1149 | | |
1150 | 24.1k | void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { |
1151 | 24.1k | AssertLockHeld(cs); |
1152 | 24.1k | if (rate.GetFeePerK() > rollingMinimumFeeRate) { |
1153 | 11.6k | rollingMinimumFeeRate = rate.GetFeePerK(); |
1154 | 11.6k | blockSinceLastRollingFeeBump = false; |
1155 | 11.6k | } |
1156 | 24.1k | } |
1157 | | |
1158 | 223k | void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) { |
1159 | 223k | AssertLockHeld(cs); |
1160 | 223k | Assume(!m_have_changeset); |
1161 | | |
1162 | 223k | unsigned nTxnRemoved = 0; |
1163 | 223k | CFeeRate maxFeeRateRemoved(0); |
1164 | 247k | while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) { |
1165 | 24.1k | indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin(); |
1166 | | |
1167 | | // We set the new mempool min fee to the feerate of the removed set, plus the |
1168 | | // "minimum reasonable fee rate" (ie some value under which we consider txn |
1169 | | // to have 0 fee). This way, we don't allow txn to enter mempool with feerate |
1170 | | // equal to txn which were removed with no block in between. |
1171 | 24.1k | CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); |
1172 | 24.1k | removed += m_opts.incremental_relay_feerate; |
1173 | 24.1k | trackPackageRemoved(removed); |
1174 | 24.1k | maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); |
1175 | | |
1176 | 24.1k | setEntries stage; |
1177 | 24.1k | CalculateDescendants(mapTx.project<0>(it), stage); |
1178 | 24.1k | nTxnRemoved += stage.size(); |
1179 | | |
1180 | 24.1k | std::vector<CTransaction> txn; |
1181 | 24.1k | if (pvNoSpendsRemaining) { |
1182 | 24.1k | txn.reserve(stage.size()); |
1183 | 24.1k | for (txiter iter : stage) |
1184 | 25.2k | txn.push_back(iter->GetTx()); |
1185 | 24.1k | } |
1186 | 24.1k | RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); |
1187 | 24.1k | if (pvNoSpendsRemaining) { |
1188 | 25.2k | for (const CTransaction& tx : txn) { |
1189 | 39.4k | for (const CTxIn& txin : tx.vin) { |
1190 | 39.4k | if (exists(GenTxid::Txid(txin.prevout.hash))) continue; |
1191 | 36.5k | pvNoSpendsRemaining->push_back(txin.prevout); |
1192 | 36.5k | } |
1193 | 25.2k | } |
1194 | 24.1k | } |
1195 | 24.1k | } |
1196 | | |
1197 | 223k | if (maxFeeRateRemoved > CFeeRate(0)) { |
1198 | 8.54k | LogDebug(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); |
1199 | 8.54k | } |
1200 | 223k | } |
1201 | | |
1202 | 0 | uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const { |
1203 | | // find parent with highest descendant count |
1204 | 0 | std::vector<txiter> candidates; |
1205 | 0 | setEntries counted; |
1206 | 0 | candidates.push_back(entry); |
1207 | 0 | uint64_t maximum = 0; |
1208 | 0 | while (candidates.size()) { |
1209 | 0 | txiter candidate = candidates.back(); |
1210 | 0 | candidates.pop_back(); |
1211 | 0 | if (!counted.insert(candidate).second) continue; |
1212 | 0 | const CTxMemPoolEntry::Parents& parents = candidate->GetMemPoolParentsConst(); |
1213 | 0 | if (parents.size() == 0) { |
1214 | 0 | maximum = std::max(maximum, candidate->GetCountWithDescendants()); |
1215 | 0 | } else { |
1216 | 0 | for (const CTxMemPoolEntry& i : parents) { |
1217 | 0 | candidates.push_back(mapTx.iterator_to(i)); |
1218 | 0 | } |
1219 | 0 | } |
1220 | 0 | } |
1221 | 0 | return maximum; |
1222 | 0 | } |
1223 | | |
1224 | 3.07M | void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const { |
1225 | 3.07M | LOCK(cs); |
1226 | 3.07M | auto it = mapTx.find(txid); |
1227 | 3.07M | ancestors = descendants = 0; |
1228 | 3.07M | if (it != mapTx.end()) { |
1229 | 0 | ancestors = it->GetCountWithAncestors(); |
1230 | 0 | if (ancestorsize) *ancestorsize = it->GetSizeWithAncestors(); |
1231 | 0 | if (ancestorfees) *ancestorfees = it->GetModFeesWithAncestors(); |
1232 | 0 | descendants = CalculateDescendantMaximum(it); |
1233 | 0 | } |
1234 | 3.07M | } |
1235 | | |
1236 | | bool CTxMemPool::GetLoadTried() const |
1237 | 1 | { |
1238 | 1 | LOCK(cs); |
1239 | 1 | return m_load_tried; |
1240 | 1 | } |
1241 | | |
1242 | | void CTxMemPool::SetLoadTried(bool load_tried) |
1243 | 2.37k | { |
1244 | 2.37k | LOCK(cs); |
1245 | 2.37k | m_load_tried = load_tried; |
1246 | 2.37k | } |
1247 | | |
1248 | | std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<uint256>& txids) const |
1249 | 4.26k | { |
1250 | 4.26k | AssertLockHeld(cs); |
1251 | 4.26k | std::vector<txiter> clustered_txs{GetIterVec(txids)}; |
1252 | | // Use epoch: visiting an entry means we have added it to the clustered_txs vector. It does not |
1253 | | // necessarily mean the entry has been processed. |
1254 | 4.26k | WITH_FRESH_EPOCH(m_epoch); |
1255 | 252k | for (const auto& it : clustered_txs) { |
1256 | 252k | visited(it); |
1257 | 252k | } |
1258 | | // i = index of where the list of entries to process starts |
1259 | 390k | for (size_t i{0}; i < clustered_txs.size(); ++i) { |
1260 | | // DoS protection: if there are 500 or more entries to process, just quit. |
1261 | 386k | if (clustered_txs.size() > 500) return {}; |
1262 | 386k | const txiter& tx_iter = clustered_txs.at(i); |
1263 | 772k | for (const auto& entries : {tx_iter->GetMemPoolParentsConst(), tx_iter->GetMemPoolChildrenConst()}) { |
1264 | 999k | for (const CTxMemPoolEntry& entry : entries) { |
1265 | 999k | const auto entry_it = mapTx.iterator_to(entry); |
1266 | 999k | if (!visited(entry_it)) { |
1267 | 134k | clustered_txs.push_back(entry_it); |
1268 | 134k | } |
1269 | 999k | } |
1270 | 772k | } |
1271 | 386k | } |
1272 | 4.26k | return clustered_txs; |
1273 | 4.26k | } |
1274 | | |
1275 | | std::optional<std::string> CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts) |
1276 | 10.0k | { |
1277 | 2.21M | for (const auto& direct_conflict : direct_conflicts) { |
1278 | | // Ancestor and descendant counts are inclusive of the tx itself. |
1279 | 2.21M | const auto ancestor_count{direct_conflict->GetCountWithAncestors()}; |
1280 | 2.21M | const auto descendant_count{direct_conflict->GetCountWithDescendants()}; |
1281 | 2.21M | const bool has_ancestor{ancestor_count > 1}; |
1282 | 2.21M | const bool has_descendant{descendant_count > 1}; |
1283 | 2.21M | const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()}; |
1284 | | // The only allowed configurations are: |
1285 | | // 1 ancestor and 0 descendant |
1286 | | // 0 ancestor and 1 descendant |
1287 | | // 0 ancestor and 0 descendant |
1288 | 2.21M | if (ancestor_count > 2) { |
1289 | 470 | return strprintf("%s has %u ancestors, max 1 allowed", txid_string, ancestor_count - 1); |
1290 | 2.21M | } else if (descendant_count > 2) { |
1291 | 499 | return strprintf("%s has %u descendants, max 1 allowed", txid_string, descendant_count - 1); |
1292 | 2.21M | } else if (has_ancestor && has_descendant) { |
1293 | 304 | return strprintf("%s has both ancestor and descendant, exceeding cluster limit of 2", txid_string); |
1294 | 304 | } |
1295 | | // Additionally enforce that: |
1296 | | // If we have a child, we are its only parent. |
1297 | | // If we have a parent, we are its only child. |
1298 | 2.21M | if (has_descendant) { |
1299 | 1.05M | const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin(); |
1300 | 1.05M | if (our_child->get().GetCountWithAncestors() > 2) { |
1301 | 253 | return strprintf("%s is not the only parent of child %s", |
1302 | 253 | txid_string, our_child->get().GetSharedTx()->GetHash().ToString()); |
1303 | 253 | } |
1304 | 1.16M | } else if (has_ancestor) { |
1305 | 1.14M | const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin(); |
1306 | 1.14M | if (our_parent->get().GetCountWithDescendants() > 2) { |
1307 | 208 | return strprintf("%s is not the only child of parent %s", |
1308 | 208 | txid_string, our_parent->get().GetSharedTx()->GetHash().ToString()); |
1309 | 208 | } |
1310 | 1.14M | } |
1311 | 2.21M | } |
1312 | 8.30k | return std::nullopt; |
1313 | 10.0k | } |
1314 | | |
1315 | | util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CTxMemPool::ChangeSet::CalculateChunksForRBF() |
1316 | 10.0k | { |
1317 | 10.0k | LOCK(m_pool->cs); |
1318 | 10.0k | FeeFrac replacement_feerate{0, 0}; |
1319 | 17.9k | for (auto it : m_entry_vec) { |
1320 | 17.9k | replacement_feerate += {it->GetModifiedFee(), it->GetTxSize()}; |
1321 | 17.9k | } |
1322 | | |
1323 | 10.0k | auto err_string{m_pool->CheckConflictTopology(m_to_remove)}; |
1324 | 10.0k | if (err_string.has_value()) { |
1325 | | // Unsupported topology for calculating a feerate diagram |
1326 | 1.73k | return util::Error{Untranslated(err_string.value())}; |
1327 | 1.73k | } |
1328 | | |
1329 | | // new diagram will have chunks that consist of each ancestor of |
1330 | | // direct_conflicts that is at its own fee/size, along with the replacement |
1331 | | // tx/package at its own fee/size |
1332 | | |
1333 | | // old diagram will consist of the ancestors and descendants of each element of |
1334 | | // all_conflicts. every such transaction will either be at its own feerate (followed |
1335 | | // by any descendant at its own feerate), or as a single chunk at the descendant's |
1336 | | // ancestor feerate. |
1337 | | |
1338 | 8.30k | std::vector<FeeFrac> old_chunks; |
1339 | | // Step 1: build the old diagram. |
1340 | | |
1341 | | // The above clusters are all trivially linearized; |
1342 | | // they have a strict topology of 1 or two connected transactions. |
1343 | | |
1344 | | // OLD: Compute existing chunks from all affected clusters |
1345 | 2.21M | for (auto txiter : m_to_remove) { |
1346 | | // Does this transaction have descendants? |
1347 | 2.21M | if (txiter->GetCountWithDescendants() > 1) { |
1348 | | // Consider this tx when we consider the descendant. |
1349 | 1.05M | continue; |
1350 | 1.05M | } |
1351 | | // Does this transaction have ancestors? |
1352 | 1.16M | FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()}; |
1353 | 1.16M | if (txiter->GetCountWithAncestors() > 1) { |
1354 | | // We'll add chunks for either the ancestor by itself and this tx |
1355 | | // by itself, or for a combined package. |
1356 | 1.14M | FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast<int32_t>(txiter->GetSizeWithAncestors())}; |
1357 | 1.14M | if (individual >> package) { |
1358 | | // The individual feerate is higher than the package, and |
1359 | | // therefore higher than the parent's fee. Chunk these |
1360 | | // together. |
1361 | 674k | old_chunks.emplace_back(package); |
1362 | 674k | } else { |
1363 | | // Add two points, one for the parent and one for this child. |
1364 | 469k | old_chunks.emplace_back(package - individual); |
1365 | 469k | old_chunks.emplace_back(individual); |
1366 | 469k | } |
1367 | 1.14M | } else { |
1368 | 22.9k | old_chunks.emplace_back(individual); |
1369 | 22.9k | } |
1370 | 1.16M | } |
1371 | | |
1372 | | // No topology restrictions post-chunking; sort |
1373 | 8.30k | std::sort(old_chunks.begin(), old_chunks.end(), std::greater()); |
1374 | | |
1375 | 8.30k | std::vector<FeeFrac> new_chunks; |
1376 | | |
1377 | | /* Step 2: build the NEW diagram |
1378 | | * CON = Conflicts of proposed chunk |
1379 | | * CNK = Proposed chunk |
1380 | | * NEW = OLD - CON + CNK: New diagram includes all chunks in OLD, minus |
1381 | | * the conflicts, plus the proposed chunk |
1382 | | */ |
1383 | | |
1384 | | // OLD - CON: Add any parents of direct conflicts that are not conflicted themselves |
1385 | 2.21M | for (auto direct_conflict : m_to_remove) { |
1386 | | // If a direct conflict has an ancestor that is not in all_conflicts, |
1387 | | // it can be affected by the replacement of the child. |
1388 | 2.21M | if (direct_conflict->GetMemPoolParentsConst().size() > 0) { |
1389 | | // Grab the parent. |
1390 | 1.14M | const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get(); |
1391 | 1.14M | if (!m_to_remove.contains(m_pool->mapTx.iterator_to(parent))) { |
1392 | | // This transaction would be left over, so add to the NEW |
1393 | | // diagram. |
1394 | 92.8k | new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize()); |
1395 | 92.8k | } |
1396 | 1.14M | } |
1397 | 2.21M | } |
1398 | | // + CNK: Add the proposed chunk itself |
1399 | 8.30k | new_chunks.emplace_back(replacement_feerate); |
1400 | | |
1401 | | // No topology restrictions post-chunking; sort |
1402 | 8.30k | std::sort(new_chunks.begin(), new_chunks.end(), std::greater()); |
1403 | 8.30k | return std::make_pair(old_chunks, new_chunks); |
1404 | 10.0k | } |
1405 | | |
1406 | | CTxMemPool::ChangeSet::TxHandle CTxMemPool::ChangeSet::StageAddition(const CTransactionRef& tx, const CAmount fee, int64_t time, unsigned int entry_height, uint64_t entry_sequence, bool spends_coinbase, int64_t sigops_cost, LockPoints lp) |
1407 | 2.73M | { |
1408 | 2.73M | LOCK(m_pool->cs); |
1409 | 2.73M | Assume(m_to_add.find(tx->GetHash()) == m_to_add.end()); |
1410 | 2.73M | auto newit = m_to_add.emplace(tx, fee, time, entry_height, entry_sequence, spends_coinbase, sigops_cost, lp).first; |
1411 | 2.73M | CAmount delta{0}; |
1412 | 2.73M | m_pool->ApplyDelta(tx->GetHash(), delta); |
1413 | 2.73M | if (delta) m_to_add.modify(newit, [&delta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(delta); }); |
1414 | | |
1415 | 2.73M | m_entry_vec.push_back(newit); |
1416 | 2.73M | return newit; |
1417 | 2.73M | } |
1418 | | |
1419 | | void CTxMemPool::ChangeSet::Apply() |
1420 | 2.14M | { |
1421 | 2.14M | LOCK(m_pool->cs); |
1422 | 2.14M | m_pool->Apply(this); |
1423 | 2.14M | m_to_add.clear(); |
1424 | 2.14M | m_to_remove.clear(); |
1425 | 2.14M | m_entry_vec.clear(); |
1426 | 2.14M | m_ancestors.clear(); |
1427 | 2.14M | } |