/Users/eugenesiegel/btc/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 | 21.4k | { |
42 | 21.4k | AssertLockHeld(cs_main); Line | Count | Source | 137 | 21.4k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
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 | 21.4k | 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 | 21.4k | if (!active_chain.Contains(lp.maxInputBlock)) { |
49 | 0 | return false; |
50 | 0 | } |
51 | 21.4k | } |
52 | | |
53 | | // LockPoints still valid |
54 | 21.4k | return true; |
55 | 21.4k | } |
56 | | |
57 | | void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, |
58 | | const std::set<Txid>& setExclude, std::set<Txid>& descendants_to_remove) |
59 | 3.01k | { |
60 | 3.01k | CTxMemPoolEntry::Children stageEntries, descendants; |
61 | 3.01k | stageEntries = updateIt->GetMemPoolChildrenConst(); |
62 | | |
63 | 11.0k | while (!stageEntries.empty()) { |
64 | 8.04k | const CTxMemPoolEntry& descendant = *stageEntries.begin(); |
65 | 8.04k | descendants.insert(descendant); |
66 | 8.04k | stageEntries.erase(descendant); |
67 | 8.04k | const CTxMemPoolEntry::Children& children = descendant.GetMemPoolChildrenConst(); |
68 | 8.04k | for (const CTxMemPoolEntry& childEntry : children) { |
69 | 6.18k | cacheMap::iterator cacheIt = cachedDescendants.find(mapTx.iterator_to(childEntry)); |
70 | 6.18k | 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 | 6.18k | } else if (!descendants.count(childEntry)) { |
77 | | // Schedule for later processing |
78 | 6.18k | stageEntries.insert(childEntry); |
79 | 6.18k | } |
80 | 6.18k | } |
81 | 8.04k | } |
82 | | // descendants now contains all in-mempool descendants of updateIt. |
83 | | // Update and add to cached descendant map |
84 | 3.01k | int32_t modifySize = 0; |
85 | 3.01k | CAmount modifyFee = 0; |
86 | 3.01k | int64_t modifyCount = 0; |
87 | 8.04k | for (const CTxMemPoolEntry& descendant : descendants) { |
88 | 8.04k | if (!setExclude.count(descendant.GetTx().GetHash())) { |
89 | 7.17k | modifySize += descendant.GetTxSize(); |
90 | 7.17k | modifyFee += descendant.GetModifiedFee(); |
91 | 7.17k | modifyCount++; |
92 | 7.17k | cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant)); |
93 | | // Update ancestor state for each descendant |
94 | 7.17k | mapTx.modify(mapTx.iterator_to(descendant), [=](CTxMemPoolEntry& e) { |
95 | 7.17k | e.UpdateAncestorState(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()); |
96 | 7.17k | }); |
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 | 7.17k | 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 | 7.17k | } |
104 | 8.04k | } |
105 | 3.01k | mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }); |
106 | 3.01k | } |
107 | | |
108 | | void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate) |
109 | 4.77k | { |
110 | 4.77k | AssertLockHeld(cs); Line | Count | Source | 137 | 4.77k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &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 | 4.77k | 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 | 4.77k | std::set<Txid> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); |
119 | | |
120 | 4.77k | std::set<Txid> 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 | 4.77k | for (const Txid& hash : vHashesToUpdate | std::views::reverse) { |
128 | | // calculate children from mapNextTx |
129 | 3.01k | txiter it = mapTx.find(hash); |
130 | 3.01k | if (it == mapTx.end()) { |
131 | 0 | continue; |
132 | 0 | } |
133 | 3.01k | auto iter = mapNextTx.lower_bound(COutPoint(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 | 3.01k | { |
138 | 3.01k | WITH_FRESH_EPOCH(m_epoch); Line | Count | Source | 100 | 3.01k | #define WITH_FRESH_EPOCH(epoch) const Epoch::Guard UNIQUE_NAME(epoch_guard_)(epoch) Line | Count | Source | 11 | 3.01k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 3.01k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 3.01k | #define PASTE(x, y) x ## y |
|
|
|
|
139 | 4.87k | for (; iter != mapNextTx.end() && iter->first->hash == hash3.87k ; ++iter1.85k ) { |
140 | 1.85k | const Txid &childHash = iter->second->GetHash(); |
141 | 1.85k | txiter childIter = mapTx.find(childHash); |
142 | 1.85k | 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 | 1.85k | if (!visited(childIter) && !setAlreadyIncluded.count(childHash)) { |
146 | 989 | UpdateChild(it, childIter, true); |
147 | 989 | UpdateParent(childIter, it, true); |
148 | 989 | } |
149 | 1.85k | } |
150 | 3.01k | } // release epoch guard for UpdateForDescendants |
151 | 3.01k | UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded, descendants_to_remove); |
152 | 3.01k | } |
153 | | |
154 | 4.77k | 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 | 4.77k | } |
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.34M | { |
169 | 3.34M | int64_t totalSizeWithAncestors = entry_size; |
170 | 3.34M | setEntries ancestors; |
171 | | |
172 | 11.6M | while (!staged_ancestors.empty()) { |
173 | 8.33M | const CTxMemPoolEntry& stage = staged_ancestors.begin()->get(); |
174 | 8.33M | txiter stageit = mapTx.iterator_to(stage); |
175 | | |
176 | 8.33M | ancestors.insert(stageit); |
177 | 8.33M | staged_ancestors.erase(stage); |
178 | 8.33M | totalSizeWithAncestors += stageit->GetTxSize(); |
179 | | |
180 | 8.33M | if (stageit->GetSizeWithDescendants() + entry_size > limits.descendant_size_vbytes) { |
181 | 0 | return util::Error{Untranslated(strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
182 | 8.33M | } else if (stageit->GetCountWithDescendants() + entry_count > static_cast<uint64_t>(limits.descendant_count)) { |
183 | 0 | return util::Error{Untranslated(strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
184 | 8.33M | } else if (totalSizeWithAncestors > limits.ancestor_size_vbytes) { |
185 | 0 | return util::Error{Untranslated(strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
186 | 0 | } |
187 | | |
188 | 8.33M | const CTxMemPoolEntry::Parents& parents = stageit->GetMemPoolParentsConst(); |
189 | 8.33M | for (const CTxMemPoolEntry& parent : parents) { |
190 | 5.70M | txiter parent_it = mapTx.iterator_to(parent); |
191 | | |
192 | | // If this is a new ancestor, add it. |
193 | 5.70M | if (ancestors.count(parent_it) == 0) { |
194 | 5.70M | staged_ancestors.insert(parent); |
195 | 5.70M | } |
196 | 5.70M | if (staged_ancestors.size() + ancestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) { |
197 | 0 | return util::Error{Untranslated(strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
198 | 0 | } |
199 | 5.70M | } |
200 | 8.33M | } |
201 | | |
202 | 3.34M | return ancestors; |
203 | 3.34M | } |
204 | | |
205 | | util::Result<void> CTxMemPool::CheckPackageLimits(const Package& package, |
206 | | const int64_t total_vsize) const |
207 | 0 | { |
208 | 0 | size_t pack_count = package.size(); |
209 | | |
210 | | // Package itself is busting mempool limits; should be rejected even if no staged_ancestors exist |
211 | 0 | if (pack_count > static_cast<uint64_t>(m_opts.limits.ancestor_count)) { |
212 | 0 | return util::Error{Untranslated(strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_count, m_opts.limits.ancestor_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
213 | 0 | } else if (pack_count > static_cast<uint64_t>(m_opts.limits.descendant_count)) { |
214 | 0 | return util::Error{Untranslated(strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_count, m_opts.limits.descendant_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
215 | 0 | } else if (total_vsize > m_opts.limits.ancestor_size_vbytes) { |
216 | 0 | return util::Error{Untranslated(strprintf("package size %u exceeds ancestor size limit [limit: %u]", total_vsize, m_opts.limits.ancestor_size_vbytes))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
217 | 0 | } else if (total_vsize > m_opts.limits.descendant_size_vbytes) { |
218 | 0 | return util::Error{Untranslated(strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_opts.limits.descendant_size_vbytes))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
219 | 0 | } |
220 | | |
221 | 0 | CTxMemPoolEntry::Parents staged_ancestors; |
222 | 0 | for (const auto& tx : package) { |
223 | 0 | for (const auto& input : tx->vin) { |
224 | 0 | std::optional<txiter> piter = GetIter(input.prevout.hash); |
225 | 0 | if (piter) { |
226 | 0 | staged_ancestors.insert(**piter); |
227 | 0 | if (staged_ancestors.size() + package.size() > static_cast<uint64_t>(m_opts.limits.ancestor_count)) { |
228 | 0 | return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", m_opts.limits.ancestor_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
229 | 0 | } |
230 | 0 | } |
231 | 0 | } |
232 | 0 | } |
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 | 0 | const auto ancestors{CalculateAncestorsAndCheckLimits(total_vsize, package.size(), |
237 | 0 | staged_ancestors, m_opts.limits)}; |
238 | | // It's possible to overestimate the ancestor/descendant totals. |
239 | 0 | if (!ancestors.has_value()) return util::Error{Untranslated("possibly " + util::ErrorString(ancestors).original)}; |
240 | 0 | return {}; |
241 | 0 | } |
242 | | |
243 | | util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateMemPoolAncestors( |
244 | | const CTxMemPoolEntry &entry, |
245 | | const Limits& limits, |
246 | | bool fSearchForParents /* = true */) const |
247 | 3.34M | { |
248 | 3.34M | CTxMemPoolEntry::Parents staged_ancestors; |
249 | 3.34M | const CTransaction &tx = entry.GetTx(); |
250 | | |
251 | 3.34M | 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 | 6.24M | for (unsigned int i = 0; i < tx.vin.size(); i++3.12M ) { |
256 | 3.12M | std::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash); |
257 | 3.12M | if (piter) { |
258 | 2.45M | staged_ancestors.insert(**piter); |
259 | 2.45M | if (staged_ancestors.size() + 1 > static_cast<uint64_t>(limits.ancestor_count)) { |
260 | 0 | return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count))}; Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
261 | 0 | } |
262 | 2.45M | } |
263 | 3.12M | } |
264 | 3.12M | } 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 | 220k | txiter it = mapTx.iterator_to(entry); |
268 | 220k | staged_ancestors = it->GetMemPoolParentsConst(); |
269 | 220k | } |
270 | | |
271 | 3.34M | return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, staged_ancestors, |
272 | 3.34M | limits); |
273 | 3.34M | } |
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 | 2.95M | { |
281 | 2.95M | auto result{CalculateMemPoolAncestors(entry, limits, fSearchForParents)}; |
282 | 2.95M | if (!Assume(result)) { Line | Count | Source | 118 | 2.95M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
283 | 0 | LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Error, "%s: CalculateMemPoolAncestors failed unexpectedly, continuing with empty ancestor set (%s)\n", Line | Count | Source | 373 | 0 | do { \ | 374 | 0 | if (LogAcceptCategory((category), (level))) { \ | 375 | 0 | bool rate_limit{level >= BCLog::Level::Info}; \ | 376 | 0 | LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
| 377 | 0 | } \ | 378 | 0 | } while (0) |
|
284 | 0 | calling_fn_name, util::ErrorString(result).original); |
285 | 0 | } |
286 | 2.95M | return std::move(result).value_or(CTxMemPool::setEntries{}); |
287 | 2.95M | } |
288 | | |
289 | | void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) |
290 | 521k | { |
291 | 521k | const CTxMemPoolEntry::Parents& parents = it->GetMemPoolParentsConst(); |
292 | | // add or remove this tx as a child of each parent |
293 | 521k | for (const CTxMemPoolEntry& parent : parents) { |
294 | 416k | UpdateChild(mapTx.iterator_to(parent), it, add); |
295 | 416k | } |
296 | 521k | const int32_t updateCount = (add ? 1301k : -1220k ); |
297 | 521k | const int32_t updateSize{updateCount * it->GetTxSize()}; |
298 | 521k | const CAmount updateFee = updateCount * it->GetModifiedFee(); |
299 | 1.48M | for (txiter ancestorIt : setAncestors) { |
300 | 1.48M | mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(updateSize, updateFee, updateCount); }); |
301 | 1.48M | } |
302 | 521k | } |
303 | | |
304 | | void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) |
305 | 301k | { |
306 | 301k | int64_t updateCount = setAncestors.size(); |
307 | 301k | int64_t updateSize = 0; |
308 | 301k | CAmount updateFee = 0; |
309 | 301k | int64_t updateSigOpsCost = 0; |
310 | 841k | for (txiter ancestorIt : setAncestors) { |
311 | 841k | updateSize += ancestorIt->GetTxSize(); |
312 | 841k | updateFee += ancestorIt->GetModifiedFee(); |
313 | 841k | updateSigOpsCost += ancestorIt->GetSigOpCost(); |
314 | 841k | } |
315 | 301k | mapTx.modify(it, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(updateSize, updateFee, updateCount, updateSigOpsCost); }); |
316 | 301k | } |
317 | | |
318 | | void CTxMemPool::UpdateChildrenForRemoval(txiter it) |
319 | 220k | { |
320 | 220k | const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst(); |
321 | 220k | for (const CTxMemPoolEntry& updateIt : children) { |
322 | 13.3k | UpdateParent(mapTx.iterator_to(updateIt), it, false); |
323 | 13.3k | } |
324 | 220k | } |
325 | | |
326 | | void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) |
327 | 630k | { |
328 | | // For each entry, walk back all ancestors and decrement size associated with this |
329 | | // transaction |
330 | 630k | 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 | 14.5k | for (txiter removeIt : entriesToRemove) { |
338 | 14.5k | setEntries setDescendants; |
339 | 14.5k | CalculateDescendants(removeIt, setDescendants); |
340 | 14.5k | setDescendants.erase(removeIt); // don't update state for self |
341 | 14.5k | int32_t modifySize = -removeIt->GetTxSize(); |
342 | 14.5k | CAmount modifyFee = -removeIt->GetModifiedFee(); |
343 | 14.5k | int modifySigOps = -removeIt->GetSigOpCost(); |
344 | 33.2k | for (txiter dit : setDescendants) { |
345 | 33.2k | mapTx.modify(dit, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(modifySize, modifyFee, -1, modifySigOps); }); |
346 | 33.2k | } |
347 | 14.5k | } |
348 | 14.5k | } |
349 | 630k | for (txiter removeIt : entriesToRemove) { |
350 | 220k | 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 | 220k | 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 | 220k | UpdateAncestorsOf(false, removeIt, ancestors); |
374 | 220k | } |
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 | 630k | for (txiter removeIt : entriesToRemove) { |
379 | 220k | UpdateChildrenForRemoval(removeIt); |
380 | 220k | } |
381 | 630k | } |
382 | | |
383 | | void CTxMemPoolEntry::UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount) |
384 | 1.48M | { |
385 | 1.48M | nSizeWithDescendants += modifySize; |
386 | 1.48M | assert(nSizeWithDescendants > 0); |
387 | 1.48M | nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, modifyFee); |
388 | 1.48M | m_count_with_descendants += modifyCount; |
389 | 1.48M | assert(m_count_with_descendants > 0); |
390 | 1.48M | } |
391 | | |
392 | | void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps) |
393 | 341k | { |
394 | 341k | nSizeWithAncestors += modifySize; |
395 | 341k | assert(nSizeWithAncestors > 0); |
396 | 341k | nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, modifyFee); |
397 | 341k | m_count_with_ancestors += modifyCount; |
398 | 341k | assert(m_count_with_ancestors > 0); |
399 | 341k | nSigOpCostWithAncestors += modifySigOps; |
400 | 341k | assert(int(nSigOpCostWithAncestors) >= 0); |
401 | 341k | } |
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 | 38.8k | { |
406 | 38.8k | opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000); |
407 | 38.8k | int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40; |
408 | 38.8k | if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) { |
409 | 0 | error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0)); Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
410 | 0 | } |
411 | 38.8k | return std::move(opts); |
412 | 38.8k | } |
413 | | |
414 | | CTxMemPool::CTxMemPool(Options opts, bilingual_str& error) |
415 | 38.8k | : m_opts{Flatten(std::move(opts), error)} |
416 | 38.8k | { |
417 | 38.8k | } |
418 | | |
419 | | bool CTxMemPool::isSpent(const COutPoint& outpoint) const |
420 | 0 | { |
421 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
422 | 0 | return mapNextTx.count(outpoint); |
423 | 0 | } |
424 | | |
425 | | unsigned int CTxMemPool::GetTransactionsUpdated() const |
426 | 0 | { |
427 | 0 | return nTransactionsUpdated; |
428 | 0 | } |
429 | | |
430 | | void CTxMemPool::AddTransactionsUpdated(unsigned int n) |
431 | 36.2k | { |
432 | 36.2k | nTransactionsUpdated += n; |
433 | 36.2k | } |
434 | | |
435 | | void CTxMemPool::Apply(ChangeSet* changeset) |
436 | 301k | { |
437 | 301k | AssertLockHeld(cs); Line | Count | Source | 137 | 301k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
438 | 301k | RemoveStaged(changeset->m_to_remove, false, MemPoolRemovalReason::REPLACED); |
439 | | |
440 | 602k | for (size_t i=0; i<changeset->m_entry_vec.size(); ++i301k ) { |
441 | 301k | auto tx_entry = changeset->m_entry_vec[i]; |
442 | 301k | std::optional<CTxMemPool::setEntries> ancestors; |
443 | 301k | 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 | 301k | ancestors = *Assume(changeset->CalculateMemPoolAncestors(tx_entry, Limits::NoLimits())); Line | Count | Source | 118 | 301k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
454 | 301k | } |
455 | | // First splice this entry into mapTx. |
456 | 301k | auto node_handle = changeset->m_to_add.extract(tx_entry); |
457 | 301k | auto result = mapTx.insert(std::move(node_handle)); |
458 | | |
459 | 301k | Assume(result.inserted); Line | Count | Source | 118 | 301k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
460 | 301k | txiter it = result.position; |
461 | | |
462 | | // Now update the entry for ancestors/descendants. |
463 | 301k | if (ancestors.has_value()) { |
464 | 301k | addNewTransaction(it, *ancestors); |
465 | 301k | } else { |
466 | 0 | addNewTransaction(it); |
467 | 0 | } |
468 | 301k | } |
469 | 301k | } |
470 | | |
471 | | void CTxMemPool::addNewTransaction(CTxMemPool::txiter it) |
472 | 0 | { |
473 | 0 | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())}; |
474 | 0 | return addNewTransaction(it, ancestors); |
475 | 0 | } |
476 | | |
477 | | void CTxMemPool::addNewTransaction(CTxMemPool::txiter newit, CTxMemPool::setEntries& setAncestors) |
478 | 301k | { |
479 | 301k | 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 | 301k | cachedInnerUsage += entry.DynamicMemoryUsage(); |
485 | | |
486 | 301k | const CTransaction& tx = newit->GetTx(); |
487 | 301k | std::set<Txid> setParentTransactions; |
488 | 602k | for (unsigned int i = 0; i < tx.vin.size(); i++301k ) { |
489 | 301k | mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); |
490 | 301k | setParentTransactions.insert(tx.vin[i].prevout.hash); |
491 | 301k | } |
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 | 301k | for (const auto& pit : GetIterSet(setParentTransactions)) { |
501 | 244k | UpdateParent(newit, pit, true); |
502 | 244k | } |
503 | 301k | UpdateAncestorsOf(true, newit, setAncestors); |
504 | 301k | UpdateEntryForAncestors(newit, setAncestors); |
505 | | |
506 | 301k | nTransactionsUpdated++; |
507 | 301k | totalTxSize += entry.GetTxSize(); |
508 | 301k | m_total_fee += entry.GetFee(); |
509 | | |
510 | 301k | txns_randomized.emplace_back(tx.GetWitnessHash(), newit); |
511 | 301k | newit->idx_randomized = txns_randomized.size() - 1; |
512 | | |
513 | 301k | TRACEPOINT(mempool, added, |
514 | 301k | entry.GetTx().GetHash().data(), |
515 | 301k | entry.GetTxSize(), |
516 | 301k | entry.GetFee() |
517 | 301k | ); |
518 | 301k | } |
519 | | |
520 | | void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) |
521 | 220k | { |
522 | | // We increment mempool sequence value no matter removal reason |
523 | | // even if not directly reported below. |
524 | 220k | uint64_t mempool_sequence = GetAndIncrementSequence(); |
525 | | |
526 | 220k | if (reason != MemPoolRemovalReason::BLOCK && m_opts.signals205k ) { |
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 | 205k | m_opts.signals->TransactionRemovedFromMempool(it->GetSharedTx(), reason, mempool_sequence); |
532 | 205k | } |
533 | 220k | TRACEPOINT(mempool, removed, |
534 | 220k | it->GetTx().GetHash().data(), |
535 | 220k | RemovalReasonToString(reason).c_str(), |
536 | 220k | it->GetTxSize(), |
537 | 220k | it->GetFee(), |
538 | 220k | std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count() |
539 | 220k | ); |
540 | | |
541 | 220k | for (const CTxIn& txin : it->GetTx().vin) |
542 | 220k | mapNextTx.erase(txin.prevout); |
543 | | |
544 | 220k | RemoveUnbroadcastTx(it->GetTx().GetHash(), true /* add logging because unchecked */); |
545 | | |
546 | 220k | if (txns_randomized.size() > 1) { |
547 | | // Remove entry from txns_randomized by replacing it with the back and deleting the back. |
548 | 186k | txns_randomized[it->idx_randomized] = std::move(txns_randomized.back()); |
549 | 186k | txns_randomized[it->idx_randomized].second->idx_randomized = it->idx_randomized; |
550 | 186k | txns_randomized.pop_back(); |
551 | 186k | if (txns_randomized.size() * 2 < txns_randomized.capacity()) { |
552 | 68.2k | txns_randomized.shrink_to_fit(); |
553 | 68.2k | } |
554 | 186k | } else { |
555 | 33.6k | txns_randomized.clear(); |
556 | 33.6k | } |
557 | | |
558 | 220k | totalTxSize -= it->GetTxSize(); |
559 | 220k | m_total_fee -= it->GetFee(); |
560 | 220k | cachedInnerUsage -= it->DynamicMemoryUsage(); |
561 | 220k | cachedInnerUsage -= memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst()); |
562 | 220k | mapTx.erase(it); |
563 | 220k | nTransactionsUpdated++; |
564 | 220k | } |
565 | | |
566 | | // Calculates descendants of entry that are not already in setDescendants, and adds to |
567 | | // setDescendants. Assumes entryit is already a tx in the mempool and CTxMemPoolEntry::m_children |
568 | | // is correct for tx and all descendants. |
569 | | // Also assumes that if an entry is in setDescendants already, then all |
570 | | // in-mempool descendants of it are already in setDescendants as well, so that we |
571 | | // can save time by not iterating over those entries. |
572 | | void CTxMemPool::CalculateDescendants(txiter entryit, setEntries& setDescendants) const |
573 | 177k | { |
574 | 177k | setEntries stage; |
575 | 177k | if (setDescendants.count(entryit) == 0) { |
576 | 91.3k | stage.insert(entryit); |
577 | 91.3k | } |
578 | | // Traverse down the children of entry, only adding children that are not |
579 | | // accounted for in setDescendants already (because those children have either |
580 | | // already been walked, or will be walked in this iteration). |
581 | 430k | while (!stage.empty()) { |
582 | 253k | txiter it = *stage.begin(); |
583 | 253k | setDescendants.insert(it); |
584 | 253k | stage.erase(it); |
585 | | |
586 | 253k | const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst(); |
587 | 253k | for (const CTxMemPoolEntry& child : children) { |
588 | 198k | txiter childiter = mapTx.iterator_to(child); |
589 | 198k | if (!setDescendants.count(childiter)) { |
590 | 161k | stage.insert(childiter); |
591 | 161k | } |
592 | 198k | } |
593 | 253k | } |
594 | 177k | } |
595 | | |
596 | | void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason) |
597 | 6.77k | { |
598 | | // Remove transaction from memory pool |
599 | 6.77k | AssertLockHeld(cs); Line | Count | Source | 137 | 6.77k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
600 | 6.77k | Assume(!m_have_changeset); Line | Count | Source | 118 | 6.77k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
601 | 6.77k | setEntries txToRemove; |
602 | 6.77k | txiter origit = mapTx.find(origTx.GetHash()); |
603 | 6.77k | if (origit != mapTx.end()) { |
604 | 692 | txToRemove.insert(origit); |
605 | 6.08k | } else { |
606 | | // When recursively removing but origTx isn't in the mempool |
607 | | // be sure to remove any children that are in the pool. This can |
608 | | // happen during chain re-orgs if origTx isn't re-accepted into |
609 | | // the mempool for any reason. |
610 | 16.9k | for (unsigned int i = 0; i < origTx.vout.size(); i++10.8k ) { |
611 | 10.8k | auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); |
612 | 10.8k | if (it == mapNextTx.end()) |
613 | 10.5k | continue; |
614 | 367 | txiter nextit = mapTx.find(it->second->GetHash()); |
615 | 367 | assert(nextit != mapTx.end()); |
616 | 367 | txToRemove.insert(nextit); |
617 | 367 | } |
618 | 6.08k | } |
619 | 6.77k | setEntries setAllRemoves; |
620 | 6.77k | for (txiter it : txToRemove) { |
621 | 1.05k | CalculateDescendants(it, setAllRemoves); |
622 | 1.05k | } |
623 | | |
624 | 6.77k | RemoveStaged(setAllRemoves, false, reason); |
625 | 6.77k | } |
626 | | |
627 | | void CTxMemPool::removeForReorg(CChain& chain, std::function<bool(txiter)> check_final_and_mature) |
628 | 4.77k | { |
629 | | // Remove transactions spending a coinbase which are now immature and no-longer-final transactions |
630 | 4.77k | AssertLockHeld(cs); Line | Count | Source | 137 | 4.77k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
631 | 4.77k | AssertLockHeld(::cs_main); Line | Count | Source | 137 | 4.77k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
632 | 4.77k | Assume(!m_have_changeset); Line | Count | Source | 118 | 4.77k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
633 | | |
634 | 4.77k | setEntries txToRemove; |
635 | 15.9k | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++11.1k ) { |
636 | 11.1k | if (check_final_and_mature(it)) txToRemove.insert(it)230 ; |
637 | 11.1k | } |
638 | 4.77k | setEntries setAllRemoves; |
639 | 4.77k | for (txiter it : txToRemove) { |
640 | 230 | CalculateDescendants(it, setAllRemoves); |
641 | 230 | } |
642 | 4.77k | RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG); |
643 | 15.0k | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++10.2k ) { |
644 | 10.2k | assert(TestLockPointValidity(chain, it->GetLockPoints())); |
645 | 10.2k | } |
646 | 4.77k | } |
647 | | |
648 | | void CTxMemPool::removeConflicts(const CTransaction &tx) |
649 | 45.1k | { |
650 | | // Remove transactions which depend on inputs of tx, recursively |
651 | 45.1k | AssertLockHeld(cs); Line | Count | Source | 137 | 45.1k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
652 | 45.1k | for (const CTxIn &txin : tx.vin) { |
653 | 45.1k | auto it = mapNextTx.find(txin.prevout); |
654 | 45.1k | if (it != mapNextTx.end()) { |
655 | 692 | const CTransaction &txConflict = *it->second; |
656 | 692 | if (Assume(txConflict.GetHash() != tx.GetHash())) Line | Count | Source | 118 | 692 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
657 | 692 | { |
658 | 692 | ClearPrioritisation(txConflict.GetHash()); |
659 | 692 | removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); |
660 | 692 | } |
661 | 692 | } |
662 | 45.1k | } |
663 | 45.1k | } |
664 | | |
665 | | void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) |
666 | 31.4k | { |
667 | | // Remove confirmed txs and conflicts when a new block is connected, updating the fee logic |
668 | 31.4k | AssertLockHeld(cs); Line | Count | Source | 137 | 31.4k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
669 | 31.4k | Assume(!m_have_changeset); Line | Count | Source | 118 | 31.4k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
670 | 31.4k | std::vector<RemovedMempoolTransactionInfo> txs_removed_for_block; |
671 | 31.4k | if (mapTx.size() || mapNextTx.size()4.44k || mapDeltas.size()4.44k ) { |
672 | 26.9k | txs_removed_for_block.reserve(vtx.size()); |
673 | 45.1k | for (const auto& tx : vtx) { |
674 | 45.1k | txiter it = mapTx.find(tx->GetHash()); |
675 | 45.1k | if (it != mapTx.end()) { |
676 | 14.5k | setEntries stage; |
677 | 14.5k | stage.insert(it); |
678 | 14.5k | txs_removed_for_block.emplace_back(*it); |
679 | 14.5k | RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); |
680 | 14.5k | } |
681 | 45.1k | removeConflicts(*tx); |
682 | 45.1k | ClearPrioritisation(tx->GetHash()); |
683 | 45.1k | } |
684 | 26.9k | } |
685 | 31.4k | if (m_opts.signals) { |
686 | 31.4k | m_opts.signals->MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight); |
687 | 31.4k | } |
688 | 31.4k | lastRollingFeeUpdate = GetTime(); |
689 | 31.4k | blockSinceLastRollingFeeBump = true; |
690 | 31.4k | } |
691 | | |
692 | | void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const |
693 | 646k | { |
694 | 646k | if (m_opts.check_ratio == 0) return0 ; |
695 | | |
696 | 646k | if (FastRandomContext().randrange(m_opts.check_ratio) >= 1) return0 ; |
697 | | |
698 | 646k | AssertLockHeld(::cs_main); Line | Count | Source | 137 | 646k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
699 | 646k | LOCK(cs); Line | Count | Source | 259 | 646k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 646k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 646k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 646k | #define PASTE(x, y) x ## y |
|
|
|
|
700 | 646k | LogDebug(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); Line | Count | Source | 381 | 646k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) Line | Count | Source | 373 | 646k | do { \ | 374 | 646k | if (LogAcceptCategory((category), (level))) { \ | 375 | 0 | bool rate_limit{level >= BCLog::Level::Info}; \ | 376 | 0 | LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
| 377 | 0 | } \ | 378 | 646k | } while (0) |
|
|
701 | | |
702 | 646k | uint64_t checkTotal = 0; |
703 | 646k | CAmount check_total_fee{0}; |
704 | 646k | uint64_t innerUsage = 0; |
705 | 646k | uint64_t prev_ancestor_count{0}; |
706 | | |
707 | 646k | CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip)); |
708 | | |
709 | 2.73M | for (const auto& it : GetSortedDepthAndScore()) { |
710 | 2.73M | checkTotal += it->GetTxSize(); |
711 | 2.73M | check_total_fee += it->GetFee(); |
712 | 2.73M | innerUsage += it->DynamicMemoryUsage(); |
713 | 2.73M | const CTransaction& tx = it->GetTx(); |
714 | 2.73M | innerUsage += memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst()); |
715 | 2.73M | CTxMemPoolEntry::Parents setParentCheck; |
716 | 2.73M | for (const CTxIn &txin : tx.vin) { |
717 | | // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. |
718 | 2.73M | indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); |
719 | 2.73M | if (it2 != mapTx.end()) { |
720 | 2.11M | const CTransaction& tx2 = it2->GetTx(); |
721 | 2.11M | assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); |
722 | 2.11M | setParentCheck.insert(*it2); |
723 | 2.11M | } |
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 | 2.73M | assert(mempoolDuplicate.HaveCoin(txin.prevout)); |
728 | | // Check whether its inputs are marked in mapNextTx. |
729 | 2.73M | auto it3 = mapNextTx.find(txin.prevout); |
730 | 2.73M | assert(it3 != mapNextTx.end()); |
731 | 2.73M | assert(it3->first == &txin.prevout); |
732 | 2.73M | assert(it3->second == &tx); |
733 | 2.73M | } |
734 | 4.23M | auto comp = [](const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) -> bool 2.73M { |
735 | 4.23M | return a.GetTx().GetHash() == b.GetTx().GetHash(); |
736 | 4.23M | }; |
737 | 2.73M | assert(setParentCheck.size() == it->GetMemPoolParentsConst().size()); |
738 | 2.73M | assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp)); |
739 | | // Verify ancestor state is correct. |
740 | 2.73M | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())}; |
741 | 2.73M | uint64_t nCountCheck = ancestors.size() + 1; |
742 | 2.73M | int32_t nSizeCheck = it->GetTxSize(); |
743 | 2.73M | CAmount nFeesCheck = it->GetModifiedFee(); |
744 | 2.73M | int64_t nSigOpCheck = it->GetSigOpCost(); |
745 | | |
746 | 6.55M | for (txiter ancestorIt : ancestors) { |
747 | 6.55M | nSizeCheck += ancestorIt->GetTxSize(); |
748 | 6.55M | nFeesCheck += ancestorIt->GetModifiedFee(); |
749 | 6.55M | nSigOpCheck += ancestorIt->GetSigOpCost(); |
750 | 6.55M | } |
751 | | |
752 | 2.73M | assert(it->GetCountWithAncestors() == nCountCheck); |
753 | 2.73M | assert(it->GetSizeWithAncestors() == nSizeCheck); |
754 | 2.73M | assert(it->GetSigOpCostWithAncestors() == nSigOpCheck); |
755 | 2.73M | assert(it->GetModFeesWithAncestors() == nFeesCheck); |
756 | | // Sanity check: we are walking in ascending ancestor count order. |
757 | 2.73M | assert(prev_ancestor_count <= it->GetCountWithAncestors()); |
758 | 2.73M | prev_ancestor_count = it->GetCountWithAncestors(); |
759 | | |
760 | | // Check children against mapNextTx |
761 | 2.73M | CTxMemPoolEntry::Children setChildrenCheck; |
762 | 2.73M | auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); |
763 | 2.73M | int32_t child_sizes{0}; |
764 | 4.85M | for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash()4.09M ; ++iter2.11M ) { |
765 | 2.11M | txiter childit = mapTx.find(iter->second->GetHash()); |
766 | 2.11M | assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions |
767 | 2.11M | if (setChildrenCheck.insert(*childit).second) { |
768 | 2.11M | child_sizes += childit->GetTxSize(); |
769 | 2.11M | } |
770 | 2.11M | } |
771 | 2.73M | assert(setChildrenCheck.size() == it->GetMemPoolChildrenConst().size()); |
772 | 2.73M | 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 | 2.73M | assert(it->GetSizeWithDescendants() >= child_sizes + it->GetTxSize()); |
776 | | |
777 | 2.73M | TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass |
778 | 2.73M | CAmount txfee = 0; |
779 | 2.73M | assert(!tx.IsCoinBase()); |
780 | 2.73M | assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee)); |
781 | 2.73M | for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout); |
782 | 2.73M | AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max()); |
783 | 2.73M | } |
784 | 2.73M | for (const auto& [_, next_tx] : mapNextTx)646k { |
785 | 2.73M | auto it = mapTx.find(next_tx->GetHash()); |
786 | 2.73M | const CTransaction& tx = it->GetTx(); |
787 | 2.73M | assert(it != mapTx.end()); |
788 | 2.73M | assert(&tx == next_tx); |
789 | 2.73M | } |
790 | | |
791 | 646k | assert(totalTxSize == checkTotal); |
792 | 646k | assert(m_total_fee == check_total_fee); |
793 | 646k | assert(innerUsage == cachedInnerUsage); |
794 | 646k | } |
795 | | |
796 | | bool CTxMemPool::CompareDepthAndScore(const Wtxid& hasha, const Wtxid& hashb) const |
797 | 682k | { |
798 | | /* Return `true` if hasha should be considered sooner than hashb. Namely when: |
799 | | * a is not in the mempool, but b is |
800 | | * both are in the mempool and a has fewer ancestors than b |
801 | | * both are in the mempool and a has a higher score than b |
802 | | */ |
803 | 682k | LOCK(cs); Line | Count | Source | 259 | 682k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 682k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 682k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 682k | #define PASTE(x, y) x ## y |
|
|
|
|
804 | 682k | auto j{GetIter(hashb)}; |
805 | 682k | if (!j.has_value()) return false407k ; |
806 | 274k | auto i{GetIter(hasha)}; |
807 | 274k | if (!i.has_value()) return true88.5k ; |
808 | 186k | uint64_t counta = i.value()->GetCountWithAncestors(); |
809 | 186k | uint64_t countb = j.value()->GetCountWithAncestors(); |
810 | 186k | if (counta == countb) { |
811 | 126 | return CompareTxMemPoolEntryByScore()(*i.value(), *j.value()); |
812 | 126 | } |
813 | 186k | return counta < countb; |
814 | 186k | } |
815 | | |
816 | | namespace { |
817 | | class DepthAndScoreComparator |
818 | | { |
819 | | public: |
820 | | bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b) |
821 | 2.31M | { |
822 | 2.31M | uint64_t counta = a->GetCountWithAncestors(); |
823 | 2.31M | uint64_t countb = b->GetCountWithAncestors(); |
824 | 2.31M | if (counta == countb) { |
825 | 20.1k | return CompareTxMemPoolEntryByScore()(*a, *b); |
826 | 20.1k | } |
827 | 2.29M | return counta < countb; |
828 | 2.31M | } |
829 | | }; |
830 | | } // namespace |
831 | | |
832 | | std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const |
833 | 646k | { |
834 | 646k | std::vector<indexed_transaction_set::const_iterator> iters; |
835 | 646k | AssertLockHeld(cs); Line | Count | Source | 137 | 646k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
836 | | |
837 | 646k | iters.reserve(mapTx.size()); |
838 | | |
839 | 3.37M | for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi2.73M ) { |
840 | 2.73M | iters.push_back(mi); |
841 | 2.73M | } |
842 | 646k | std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); |
843 | 646k | return iters; |
844 | 646k | } |
845 | | |
846 | | std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const |
847 | 0 | { |
848 | 0 | AssertLockHeld(cs); Line | Count | Source | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
849 | |
|
850 | 0 | std::vector<CTxMemPoolEntryRef> ret; |
851 | 0 | ret.reserve(mapTx.size()); |
852 | 0 | for (const auto& it : GetSortedDepthAndScore()) { |
853 | 0 | ret.emplace_back(*it); |
854 | 0 | } |
855 | 0 | return ret; |
856 | 0 | } |
857 | | |
858 | | std::vector<TxMempoolInfo> CTxMemPool::infoAll() const |
859 | 0 | { |
860 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
861 | 0 | auto iters = GetSortedDepthAndScore(); |
862 | |
|
863 | 0 | std::vector<TxMempoolInfo> ret; |
864 | 0 | ret.reserve(mapTx.size()); |
865 | 0 | for (auto it : iters) { |
866 | 0 | ret.push_back(GetInfo(it)); |
867 | 0 | } |
868 | |
|
869 | 0 | return ret; |
870 | 0 | } |
871 | | |
872 | | const CTxMemPoolEntry* CTxMemPool::GetEntry(const Txid& txid) const |
873 | 0 | { |
874 | 0 | AssertLockHeld(cs); Line | Count | Source | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
875 | 0 | const auto i = mapTx.find(txid); |
876 | 0 | return i == mapTx.end() ? nullptr : &(*i); |
877 | 0 | } |
878 | | |
879 | | CTransactionRef CTxMemPool::get(const Txid& hash) const |
880 | 3.83M | { |
881 | 3.83M | LOCK(cs); Line | Count | Source | 259 | 3.83M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 3.83M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 3.83M | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 3.83M | #define PASTE(x, y) x ## y |
|
|
|
|
882 | 3.83M | indexed_transaction_set::const_iterator i = mapTx.find(hash); |
883 | 3.83M | if (i == mapTx.end()) |
884 | 484k | return nullptr; |
885 | 3.34M | return i->GetSharedTx(); |
886 | 3.83M | } |
887 | | |
888 | | void CTxMemPool::PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta) |
889 | 0 | { |
890 | 0 | { |
891 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
892 | 0 | CAmount &delta = mapDeltas[hash]; |
893 | 0 | delta = SaturatingAdd(delta, nFeeDelta); |
894 | 0 | txiter it = mapTx.find(hash); |
895 | 0 | if (it != mapTx.end()) { |
896 | 0 | mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); }); |
897 | | // Now update all ancestors' modified fees with descendants |
898 | 0 | auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)}; |
899 | 0 | for (txiter ancestorIt : ancestors) { |
900 | 0 | mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);}); |
901 | 0 | } |
902 | | // Now update all descendants' modified fees with ancestors |
903 | 0 | setEntries setDescendants; |
904 | 0 | CalculateDescendants(it, setDescendants); |
905 | 0 | setDescendants.erase(it); |
906 | 0 | for (txiter descendantIt : setDescendants) { |
907 | 0 | mapTx.modify(descendantIt, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(0, nFeeDelta, 0, 0); }); |
908 | 0 | } |
909 | 0 | ++nTransactionsUpdated; |
910 | 0 | } |
911 | 0 | if (delta == 0) { |
912 | 0 | mapDeltas.erase(hash); |
913 | 0 | LogPrintf("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : ""); Line | Count | Source | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) Line | Count | Source | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
|
|
|
914 | 0 | } else { |
915 | 0 | LogPrintf("PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n", Line | Count | Source | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) Line | Count | Source | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
|
|
|
916 | 0 | hash.ToString(), |
917 | 0 | it == mapTx.end() ? "not " : "", |
918 | 0 | FormatMoney(nFeeDelta), |
919 | 0 | FormatMoney(delta)); |
920 | 0 | } |
921 | 0 | } |
922 | 0 | } |
923 | | |
924 | | void CTxMemPool::ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const |
925 | 389k | { |
926 | 389k | AssertLockHeld(cs); Line | Count | Source | 137 | 389k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
927 | 389k | std::map<Txid, CAmount>::const_iterator pos = mapDeltas.find(hash); |
928 | 389k | if (pos == mapDeltas.end()) |
929 | 389k | return; |
930 | 0 | const CAmount &delta = pos->second; |
931 | 0 | nFeeDelta += delta; |
932 | 0 | } |
933 | | |
934 | | void CTxMemPool::ClearPrioritisation(const Txid& hash) |
935 | 45.8k | { |
936 | 45.8k | AssertLockHeld(cs); Line | Count | Source | 137 | 45.8k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
937 | 45.8k | mapDeltas.erase(hash); |
938 | 45.8k | } |
939 | | |
940 | | std::vector<CTxMemPool::delta_info> CTxMemPool::GetPrioritisedTransactions() const |
941 | 0 | { |
942 | 0 | AssertLockNotHeld(cs); Line | Count | Source | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) |
|
943 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
944 | 0 | std::vector<delta_info> result; |
945 | 0 | result.reserve(mapDeltas.size()); |
946 | 0 | for (const auto& [txid, delta] : mapDeltas) { |
947 | 0 | const auto iter{mapTx.find(txid)}; |
948 | 0 | const bool in_mempool{iter != mapTx.end()}; |
949 | 0 | std::optional<CAmount> modified_fee; |
950 | 0 | if (in_mempool) modified_fee = iter->GetModifiedFee(); |
951 | 0 | result.emplace_back(delta_info{in_mempool, delta, modified_fee, txid}); |
952 | 0 | } |
953 | 0 | return result; |
954 | 0 | } |
955 | | |
956 | | const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const |
957 | 437k | { |
958 | 437k | const auto it = mapNextTx.find(prevout); |
959 | 437k | return it == mapNextTx.end() ? nullptr317k : it->second120k ; |
960 | 437k | } |
961 | | |
962 | | std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Txid& txid) const |
963 | 3.77M | { |
964 | 3.77M | AssertLockHeld(cs); Line | Count | Source | 137 | 3.77M | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
965 | 3.77M | auto it = mapTx.find(txid); |
966 | 3.77M | return it != mapTx.end() ? std::make_optional(it)3.04M : std::nullopt728k ; |
967 | 3.77M | } |
968 | | |
969 | | std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Wtxid& wtxid) const |
970 | 1.14M | { |
971 | 1.14M | AssertLockHeld(cs); Line | Count | Source | 137 | 1.14M | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
972 | 1.14M | auto it{mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid))}; |
973 | 1.14M | return it != mapTx.end() ? std::make_optional(it)555k : std::nullopt588k ; |
974 | 1.14M | } |
975 | | |
976 | | CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<Txid>& hashes) const |
977 | 690k | { |
978 | 690k | CTxMemPool::setEntries ret; |
979 | 690k | for (const auto& h : hashes) { |
980 | 389k | const auto mi = GetIter(h); |
981 | 389k | if (mi) ret.insert(*mi)332k ; |
982 | 389k | } |
983 | 690k | return ret; |
984 | 690k | } |
985 | | |
986 | | std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<Txid>& txids) const |
987 | 0 | { |
988 | 0 | AssertLockHeld(cs); Line | Count | Source | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
989 | 0 | std::vector<txiter> ret; |
990 | 0 | ret.reserve(txids.size()); |
991 | 0 | for (const auto& txid : txids) { |
992 | 0 | const auto it{GetIter(txid)}; |
993 | 0 | if (!it) return {}; |
994 | 0 | ret.push_back(*it); |
995 | 0 | } |
996 | 0 | return ret; |
997 | 0 | } |
998 | | |
999 | | bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const |
1000 | 261k | { |
1001 | 318k | for (unsigned int i = 0; i < tx.vin.size(); i++57.0k ) |
1002 | 261k | if (exists(tx.vin[i].prevout.hash)) |
1003 | 204k | return false; |
1004 | 57.0k | return true; |
1005 | 261k | } |
1006 | | |
1007 | 497k | CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } |
1008 | | |
1009 | | std::optional<Coin> CCoinsViewMemPool::GetCoin(const COutPoint& outpoint) const |
1010 | 3.14M | { |
1011 | | // Check to see if the inputs are made available by another tx in the package. |
1012 | | // These Coins would not be available in the underlying CoinsView. |
1013 | 3.14M | if (auto it = m_temp_added.find(outpoint); it != m_temp_added.end()) { |
1014 | 0 | return it->second; |
1015 | 0 | } |
1016 | | |
1017 | | // If an entry in the mempool exists, always return that one, as it's guaranteed to never |
1018 | | // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) |
1019 | | // transactions. First checking the underlying cache risks returning a pruned entry instead. |
1020 | 3.14M | CTransactionRef ptx = mempool.get(outpoint.hash); |
1021 | 3.14M | if (ptx) { |
1022 | 2.77M | if (outpoint.n < ptx->vout.size()) { |
1023 | 2.77M | Coin coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false); |
1024 | 2.77M | m_non_base_coins.emplace(outpoint); |
1025 | 2.77M | return coin; |
1026 | 2.77M | } |
1027 | 0 | return std::nullopt; |
1028 | 2.77M | } |
1029 | 370k | return base->GetCoin(outpoint); |
1030 | 3.14M | } |
1031 | | |
1032 | | void CCoinsViewMemPool::PackageAddTransaction(const CTransactionRef& tx) |
1033 | 0 | { |
1034 | 0 | for (unsigned int n = 0; n < tx->vout.size(); ++n) { |
1035 | 0 | m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false)); |
1036 | 0 | m_non_base_coins.emplace(tx->GetHash(), n); |
1037 | 0 | } |
1038 | 0 | } |
1039 | | void CCoinsViewMemPool::Reset() |
1040 | 298k | { |
1041 | 298k | m_temp_added.clear(); |
1042 | 298k | m_non_base_coins.clear(); |
1043 | 298k | } |
1044 | | |
1045 | 994k | size_t CTxMemPool::DynamicMemoryUsage() const { |
1046 | 994k | LOCK(cs); Line | Count | Source | 259 | 994k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 994k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 994k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 994k | #define PASTE(x, y) x ## y |
|
|
|
|
1047 | | // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. |
1048 | 994k | return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage; |
1049 | 994k | } |
1050 | | |
1051 | 220k | void CTxMemPool::RemoveUnbroadcastTx(const Txid& txid, const bool unchecked) { |
1052 | 220k | LOCK(cs); Line | Count | Source | 259 | 220k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 220k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 220k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 220k | #define PASTE(x, y) x ## y |
|
|
|
|
1053 | | |
1054 | 220k | if (m_unbroadcast_txids.erase(txid)) |
1055 | 0 | { |
1056 | 0 | LogDebug(BCLog::MEMPOOL, "Removed %i from set of unbroadcast txns%s\n", txid.GetHex(), (unchecked ? " before confirmation that txn was sent out" : "")); Line | Count | Source | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) Line | Count | Source | 373 | 0 | do { \ | 374 | 0 | if (LogAcceptCategory((category), (level))) { \ | 375 | 0 | bool rate_limit{level >= BCLog::Level::Info}; \ | 376 | 0 | LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
| 377 | 0 | } \ | 378 | 0 | } while (0) |
|
|
1057 | 0 | } |
1058 | 220k | } |
1059 | | |
1060 | 630k | void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { |
1061 | 630k | AssertLockHeld(cs); Line | Count | Source | 137 | 630k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1062 | 630k | UpdateForRemoveFromMempool(stage, updateDescendants); |
1063 | 630k | for (txiter it : stage) { |
1064 | 220k | removeUnchecked(it, reason); |
1065 | 220k | } |
1066 | 630k | } |
1067 | | |
1068 | | int CTxMemPool::Expire(std::chrono::seconds time) |
1069 | 302k | { |
1070 | 302k | AssertLockHeld(cs); Line | Count | Source | 137 | 302k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1071 | 302k | Assume(!m_have_changeset); Line | Count | Source | 118 | 302k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
1072 | 302k | indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin(); |
1073 | 302k | setEntries toremove; |
1074 | 464k | while (it != mapTx.get<entry_time>().end() && it->GetTime() < time463k ) { |
1075 | 161k | toremove.insert(mapTx.project<0>(it)); |
1076 | 161k | it++; |
1077 | 161k | } |
1078 | 302k | setEntries stage; |
1079 | 302k | for (txiter removeit : toremove) { |
1080 | 161k | CalculateDescendants(removeit, stage); |
1081 | 161k | } |
1082 | 302k | RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY); |
1083 | 302k | return stage.size(); |
1084 | 302k | } |
1085 | | |
1086 | | void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) |
1087 | 417k | { |
1088 | 417k | AssertLockHeld(cs); Line | Count | Source | 137 | 417k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1089 | 417k | CTxMemPoolEntry::Children s; |
1090 | 417k | if (add && entry->GetMemPoolChildren().insert(*child).second245k ) { |
1091 | 245k | cachedInnerUsage += memusage::IncrementalDynamicUsage(s); |
1092 | 245k | } else if (172k !add172k && entry->GetMemPoolChildren().erase(*child)172k ) { |
1093 | 172k | cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); |
1094 | 172k | } |
1095 | 417k | } |
1096 | | |
1097 | | void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add) |
1098 | 258k | { |
1099 | 258k | AssertLockHeld(cs); Line | Count | Source | 137 | 258k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1100 | 258k | CTxMemPoolEntry::Parents s; |
1101 | 258k | if (add && entry->GetMemPoolParents().insert(*parent).second245k ) { |
1102 | 245k | cachedInnerUsage += memusage::IncrementalDynamicUsage(s); |
1103 | 245k | } else if (13.3k !add13.3k && entry->GetMemPoolParents().erase(*parent)13.3k ) { |
1104 | 13.3k | cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); |
1105 | 13.3k | } |
1106 | 258k | } |
1107 | | |
1108 | 1.49M | CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { |
1109 | 1.49M | LOCK(cs); Line | Count | Source | 259 | 1.49M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 1.49M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 1.49M | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 1.49M | #define PASTE(x, y) x ## y |
|
|
|
|
1110 | 1.49M | if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0217k ) |
1111 | 1.49M | return CFeeRate(llround(rollingMinimumFeeRate)); |
1112 | | |
1113 | 0 | int64_t time = GetTime(); |
1114 | 0 | if (time > lastRollingFeeUpdate + 10) { |
1115 | 0 | double halflife = ROLLING_FEE_HALFLIFE; |
1116 | 0 | if (DynamicMemoryUsage() < sizelimit / 4) |
1117 | 0 | halflife /= 4; |
1118 | 0 | else if (DynamicMemoryUsage() < sizelimit / 2) |
1119 | 0 | halflife /= 2; |
1120 | |
|
1121 | 0 | rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); |
1122 | 0 | lastRollingFeeUpdate = time; |
1123 | |
|
1124 | 0 | if (rollingMinimumFeeRate < (double)m_opts.incremental_relay_feerate.GetFeePerK() / 2) { |
1125 | 0 | rollingMinimumFeeRate = 0; |
1126 | 0 | return CFeeRate(0); |
1127 | 0 | } |
1128 | 0 | } |
1129 | 0 | return std::max(CFeeRate(llround(rollingMinimumFeeRate)), m_opts.incremental_relay_feerate); |
1130 | 0 | } |
1131 | | |
1132 | 0 | void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { |
1133 | 0 | AssertLockHeld(cs); Line | Count | Source | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1134 | 0 | if (rate.GetFeePerK() > rollingMinimumFeeRate) { |
1135 | 0 | rollingMinimumFeeRate = rate.GetFeePerK(); |
1136 | 0 | blockSinceLastRollingFeeBump = false; |
1137 | 0 | } |
1138 | 0 | } |
1139 | | |
1140 | 302k | void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) { |
1141 | 302k | AssertLockHeld(cs); Line | Count | Source | 137 | 302k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1142 | 302k | Assume(!m_have_changeset); Line | Count | Source | 118 | 302k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
1143 | | |
1144 | 302k | unsigned nTxnRemoved = 0; |
1145 | 302k | CFeeRate maxFeeRateRemoved(0); |
1146 | 302k | while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit270k ) { |
1147 | 0 | indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin(); |
1148 | | |
1149 | | // We set the new mempool min fee to the feerate of the removed set, plus the |
1150 | | // "minimum reasonable fee rate" (ie some value under which we consider txn |
1151 | | // to have 0 fee). This way, we don't allow txn to enter mempool with feerate |
1152 | | // equal to txn which were removed with no block in between. |
1153 | 0 | CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); |
1154 | 0 | removed += m_opts.incremental_relay_feerate; |
1155 | 0 | trackPackageRemoved(removed); |
1156 | 0 | maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); |
1157 | |
|
1158 | 0 | setEntries stage; |
1159 | 0 | CalculateDescendants(mapTx.project<0>(it), stage); |
1160 | 0 | nTxnRemoved += stage.size(); |
1161 | |
|
1162 | 0 | std::vector<CTransaction> txn; |
1163 | 0 | if (pvNoSpendsRemaining) { |
1164 | 0 | txn.reserve(stage.size()); |
1165 | 0 | for (txiter iter : stage) |
1166 | 0 | txn.push_back(iter->GetTx()); |
1167 | 0 | } |
1168 | 0 | RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); |
1169 | 0 | if (pvNoSpendsRemaining) { |
1170 | 0 | for (const CTransaction& tx : txn) { |
1171 | 0 | for (const CTxIn& txin : tx.vin) { |
1172 | 0 | if (exists(txin.prevout.hash)) continue; |
1173 | 0 | pvNoSpendsRemaining->push_back(txin.prevout); |
1174 | 0 | } |
1175 | 0 | } |
1176 | 0 | } |
1177 | 0 | } |
1178 | | |
1179 | 302k | if (maxFeeRateRemoved > CFeeRate(0)) { |
1180 | 0 | LogDebug(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); Line | Count | Source | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) Line | Count | Source | 373 | 0 | do { \ | 374 | 0 | if (LogAcceptCategory((category), (level))) { \ | 375 | 0 | bool rate_limit{level >= BCLog::Level::Info}; \ | 376 | 0 | LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ Line | Count | Source | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) |
| 377 | 0 | } \ | 378 | 0 | } while (0) |
|
|
1181 | 0 | } |
1182 | 302k | } |
1183 | | |
1184 | 0 | uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const { |
1185 | | // find parent with highest descendant count |
1186 | 0 | std::vector<txiter> candidates; |
1187 | 0 | setEntries counted; |
1188 | 0 | candidates.push_back(entry); |
1189 | 0 | uint64_t maximum = 0; |
1190 | 0 | while (candidates.size()) { |
1191 | 0 | txiter candidate = candidates.back(); |
1192 | 0 | candidates.pop_back(); |
1193 | 0 | if (!counted.insert(candidate).second) continue; |
1194 | 0 | const CTxMemPoolEntry::Parents& parents = candidate->GetMemPoolParentsConst(); |
1195 | 0 | if (parents.size() == 0) { |
1196 | 0 | maximum = std::max(maximum, candidate->GetCountWithDescendants()); |
1197 | 0 | } else { |
1198 | 0 | for (const CTxMemPoolEntry& i : parents) { |
1199 | 0 | candidates.push_back(mapTx.iterator_to(i)); |
1200 | 0 | } |
1201 | 0 | } |
1202 | 0 | } |
1203 | 0 | return maximum; |
1204 | 0 | } |
1205 | | |
1206 | 0 | void CTxMemPool::GetTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const { |
1207 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
1208 | 0 | auto it = mapTx.find(txid); |
1209 | 0 | ancestors = descendants = 0; |
1210 | 0 | if (it != mapTx.end()) { |
1211 | 0 | ancestors = it->GetCountWithAncestors(); |
1212 | 0 | if (ancestorsize) *ancestorsize = it->GetSizeWithAncestors(); |
1213 | 0 | if (ancestorfees) *ancestorfees = it->GetModFeesWithAncestors(); |
1214 | 0 | descendants = CalculateDescendantMaximum(it); |
1215 | 0 | } |
1216 | 0 | } |
1217 | | |
1218 | | bool CTxMemPool::GetLoadTried() const |
1219 | 0 | { |
1220 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
1221 | 0 | return m_load_tried; |
1222 | 0 | } |
1223 | | |
1224 | | void CTxMemPool::SetLoadTried(bool load_tried) |
1225 | 0 | { |
1226 | 0 | LOCK(cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
1227 | 0 | m_load_tried = load_tried; |
1228 | 0 | } |
1229 | | |
1230 | | std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<Txid>& txids) const |
1231 | 0 | { |
1232 | 0 | AssertLockHeld(cs); Line | Count | Source | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
|
1233 | 0 | std::vector<txiter> clustered_txs{GetIterVec(txids)}; |
1234 | | // Use epoch: visiting an entry means we have added it to the clustered_txs vector. It does not |
1235 | | // necessarily mean the entry has been processed. |
1236 | 0 | WITH_FRESH_EPOCH(m_epoch); Line | Count | Source | 100 | 0 | #define WITH_FRESH_EPOCH(epoch) const Epoch::Guard UNIQUE_NAME(epoch_guard_)(epoch) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
1237 | 0 | for (const auto& it : clustered_txs) { |
1238 | 0 | visited(it); |
1239 | 0 | } |
1240 | | // i = index of where the list of entries to process starts |
1241 | 0 | for (size_t i{0}; i < clustered_txs.size(); ++i) { |
1242 | | // DoS protection: if there are 500 or more entries to process, just quit. |
1243 | 0 | if (clustered_txs.size() > 500) return {}; |
1244 | 0 | const txiter& tx_iter = clustered_txs.at(i); |
1245 | 0 | for (const auto& entries : {tx_iter->GetMemPoolParentsConst(), tx_iter->GetMemPoolChildrenConst()}) { |
1246 | 0 | for (const CTxMemPoolEntry& entry : entries) { |
1247 | 0 | const auto entry_it = mapTx.iterator_to(entry); |
1248 | 0 | if (!visited(entry_it)) { |
1249 | 0 | clustered_txs.push_back(entry_it); |
1250 | 0 | } |
1251 | 0 | } |
1252 | 0 | } |
1253 | 0 | } |
1254 | 0 | return clustered_txs; |
1255 | 0 | } |
1256 | | |
1257 | | std::optional<std::string> CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts) |
1258 | 0 | { |
1259 | 0 | for (const auto& direct_conflict : direct_conflicts) { |
1260 | | // Ancestor and descendant counts are inclusive of the tx itself. |
1261 | 0 | const auto ancestor_count{direct_conflict->GetCountWithAncestors()}; |
1262 | 0 | const auto descendant_count{direct_conflict->GetCountWithDescendants()}; |
1263 | 0 | const bool has_ancestor{ancestor_count > 1}; |
1264 | 0 | const bool has_descendant{descendant_count > 1}; |
1265 | 0 | const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()}; |
1266 | | // The only allowed configurations are: |
1267 | | // 1 ancestor and 0 descendant |
1268 | | // 0 ancestor and 1 descendant |
1269 | | // 0 ancestor and 0 descendant |
1270 | 0 | if (ancestor_count > 2) { |
1271 | 0 | return strprintf("%s has %u ancestors, max 1 allowed", txid_string, ancestor_count - 1); Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
1272 | 0 | } else if (descendant_count > 2) { |
1273 | 0 | return strprintf("%s has %u descendants, max 1 allowed", txid_string, descendant_count - 1); Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
1274 | 0 | } else if (has_ancestor && has_descendant) { |
1275 | 0 | return strprintf("%s has both ancestor and descendant, exceeding cluster limit of 2", txid_string); Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
1276 | 0 | } |
1277 | | // Additionally enforce that: |
1278 | | // If we have a child, we are its only parent. |
1279 | | // If we have a parent, we are its only child. |
1280 | 0 | if (has_descendant) { |
1281 | 0 | const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin(); |
1282 | 0 | if (our_child->get().GetCountWithAncestors() > 2) { |
1283 | 0 | return strprintf("%s is not the only parent of child %s", Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
1284 | 0 | txid_string, our_child->get().GetSharedTx()->GetHash().ToString()); |
1285 | 0 | } |
1286 | 0 | } else if (has_ancestor) { |
1287 | 0 | const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin(); |
1288 | 0 | if (our_parent->get().GetCountWithDescendants() > 2) { |
1289 | 0 | return strprintf("%s is not the only child of parent %s", Line | Count | Source | 1172 | 0 | #define strprintf tfm::format |
|
1290 | 0 | txid_string, our_parent->get().GetSharedTx()->GetHash().ToString()); |
1291 | 0 | } |
1292 | 0 | } |
1293 | 0 | } |
1294 | 0 | return std::nullopt; |
1295 | 0 | } |
1296 | | |
1297 | | util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CTxMemPool::ChangeSet::CalculateChunksForRBF() |
1298 | 0 | { |
1299 | 0 | LOCK(m_pool->cs); Line | Count | Source | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 0 | #define PASTE(x, y) x ## y |
|
|
|
|
1300 | 0 | FeeFrac replacement_feerate{0, 0}; |
1301 | 0 | for (auto it : m_entry_vec) { |
1302 | 0 | replacement_feerate += {it->GetModifiedFee(), it->GetTxSize()}; |
1303 | 0 | } |
1304 | |
|
1305 | 0 | auto err_string{m_pool->CheckConflictTopology(m_to_remove)}; |
1306 | 0 | if (err_string.has_value()) { |
1307 | | // Unsupported topology for calculating a feerate diagram |
1308 | 0 | return util::Error{Untranslated(err_string.value())}; |
1309 | 0 | } |
1310 | | |
1311 | | // new diagram will have chunks that consist of each ancestor of |
1312 | | // direct_conflicts that is at its own fee/size, along with the replacement |
1313 | | // tx/package at its own fee/size |
1314 | | |
1315 | | // old diagram will consist of the ancestors and descendants of each element of |
1316 | | // all_conflicts. every such transaction will either be at its own feerate (followed |
1317 | | // by any descendant at its own feerate), or as a single chunk at the descendant's |
1318 | | // ancestor feerate. |
1319 | | |
1320 | 0 | std::vector<FeeFrac> old_chunks; |
1321 | | // Step 1: build the old diagram. |
1322 | | |
1323 | | // The above clusters are all trivially linearized; |
1324 | | // they have a strict topology of 1 or two connected transactions. |
1325 | | |
1326 | | // OLD: Compute existing chunks from all affected clusters |
1327 | 0 | for (auto txiter : m_to_remove) { |
1328 | | // Does this transaction have descendants? |
1329 | 0 | if (txiter->GetCountWithDescendants() > 1) { |
1330 | | // Consider this tx when we consider the descendant. |
1331 | 0 | continue; |
1332 | 0 | } |
1333 | | // Does this transaction have ancestors? |
1334 | 0 | FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()}; |
1335 | 0 | if (txiter->GetCountWithAncestors() > 1) { |
1336 | | // We'll add chunks for either the ancestor by itself and this tx |
1337 | | // by itself, or for a combined package. |
1338 | 0 | FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast<int32_t>(txiter->GetSizeWithAncestors())}; |
1339 | 0 | if (individual >> package) { |
1340 | | // The individual feerate is higher than the package, and |
1341 | | // therefore higher than the parent's fee. Chunk these |
1342 | | // together. |
1343 | 0 | old_chunks.emplace_back(package); |
1344 | 0 | } else { |
1345 | | // Add two points, one for the parent and one for this child. |
1346 | 0 | old_chunks.emplace_back(package - individual); |
1347 | 0 | old_chunks.emplace_back(individual); |
1348 | 0 | } |
1349 | 0 | } else { |
1350 | 0 | old_chunks.emplace_back(individual); |
1351 | 0 | } |
1352 | 0 | } |
1353 | | |
1354 | | // No topology restrictions post-chunking; sort |
1355 | 0 | std::sort(old_chunks.begin(), old_chunks.end(), std::greater()); |
1356 | |
|
1357 | 0 | std::vector<FeeFrac> new_chunks; |
1358 | | |
1359 | | /* Step 2: build the NEW diagram |
1360 | | * CON = Conflicts of proposed chunk |
1361 | | * CNK = Proposed chunk |
1362 | | * NEW = OLD - CON + CNK: New diagram includes all chunks in OLD, minus |
1363 | | * the conflicts, plus the proposed chunk |
1364 | | */ |
1365 | | |
1366 | | // OLD - CON: Add any parents of direct conflicts that are not conflicted themselves |
1367 | 0 | for (auto direct_conflict : m_to_remove) { |
1368 | | // If a direct conflict has an ancestor that is not in all_conflicts, |
1369 | | // it can be affected by the replacement of the child. |
1370 | 0 | if (direct_conflict->GetMemPoolParentsConst().size() > 0) { |
1371 | | // Grab the parent. |
1372 | 0 | const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get(); |
1373 | 0 | if (!m_to_remove.contains(m_pool->mapTx.iterator_to(parent))) { |
1374 | | // This transaction would be left over, so add to the NEW |
1375 | | // diagram. |
1376 | 0 | new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize()); |
1377 | 0 | } |
1378 | 0 | } |
1379 | 0 | } |
1380 | | // + CNK: Add the proposed chunk itself |
1381 | 0 | new_chunks.emplace_back(replacement_feerate); |
1382 | | |
1383 | | // No topology restrictions post-chunking; sort |
1384 | 0 | std::sort(new_chunks.begin(), new_chunks.end(), std::greater()); |
1385 | 0 | return std::make_pair(old_chunks, new_chunks); |
1386 | 0 | } |
1387 | | |
1388 | | 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) |
1389 | 389k | { |
1390 | 389k | LOCK(m_pool->cs); Line | Count | Source | 259 | 389k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 389k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 389k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 389k | #define PASTE(x, y) x ## y |
|
|
|
|
1391 | 389k | Assume(m_to_add.find(tx->GetHash()) == m_to_add.end()); Line | Count | Source | 118 | 389k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) |
|
1392 | 389k | auto newit = m_to_add.emplace(tx, fee, time, entry_height, entry_sequence, spends_coinbase, sigops_cost, lp).first; |
1393 | 389k | CAmount delta{0}; |
1394 | 389k | m_pool->ApplyDelta(tx->GetHash(), delta); |
1395 | 389k | if (delta) m_to_add.modify(newit, [&delta](CTxMemPoolEntry& e) 0 { e.UpdateModifiedFee(delta); }0 ); |
1396 | | |
1397 | 389k | m_entry_vec.push_back(newit); |
1398 | 389k | return newit; |
1399 | 389k | } |
1400 | | |
1401 | | void CTxMemPool::ChangeSet::Apply() |
1402 | 301k | { |
1403 | 301k | LOCK(m_pool->cs); Line | Count | Source | 259 | 301k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) Line | Count | Source | 11 | 301k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) Line | Count | Source | 9 | 301k | #define PASTE2(x, y) PASTE(x, y) Line | Count | Source | 8 | 301k | #define PASTE(x, y) x ## y |
|
|
|
|
1404 | 301k | m_pool->Apply(this); |
1405 | 301k | m_to_add.clear(); |
1406 | 301k | m_to_remove.clear(); |
1407 | 301k | m_entry_vec.clear(); |
1408 | 301k | m_ancestors.clear(); |
1409 | 301k | } |