/Users/eugenesiegel/btc/bitcoin/src/kernel/disconnected_transactions.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2023-present The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #include <kernel/disconnected_transactions.h> | 
| 6 |  |  | 
| 7 |  | #include <cassert> | 
| 8 |  | #include <core_memusage.h> | 
| 9 |  | #include <memusage.h> | 
| 10 |  | #include <primitives/transaction.h> | 
| 11 |  | #include <util/hasher.h> | 
| 12 |  |  | 
| 13 |  | #include <memory> | 
| 14 |  | #include <utility> | 
| 15 |  |  | 
| 16 |  | // It's almost certainly a logic bug if we don't clear out queuedTx before | 
| 17 |  | // destruction, as we add to it while disconnecting blocks, and then we | 
| 18 |  | // need to re-process remaining transactions to ensure mempool consistency. | 
| 19 |  | // For now, assert() that we've emptied out this object on destruction. | 
| 20 |  | // This assert() can always be removed if the reorg-processing code were | 
| 21 |  | // to be refactored such that this assumption is no longer true (for | 
| 22 |  | // instance if there was some other way we cleaned up the mempool after a | 
| 23 |  | // reorg, besides draining this object). | 
| 24 |  | DisconnectedBlockTransactions::~DisconnectedBlockTransactions() | 
| 25 | 24.9k | { | 
| 26 | 24.9k |     assert(queuedTx.empty()); | 
| 27 | 24.9k |     assert(iters_by_txid.empty()); | 
| 28 | 24.9k |     assert(cachedInnerUsage == 0); | 
| 29 | 24.9k | } | 
| 30 |  |  | 
| 31 |  | std::vector<CTransactionRef> DisconnectedBlockTransactions::LimitMemoryUsage() | 
| 32 | 78 | { | 
| 33 | 78 |     std::vector<CTransactionRef> evicted; | 
| 34 |  |  | 
| 35 | 78 |     while (!queuedTx.empty() && DynamicMemoryUsage() > m_max_mem_usage) { | 
| 36 | 0 |         evicted.emplace_back(queuedTx.front()); | 
| 37 | 0 |         cachedInnerUsage -= RecursiveDynamicUsage(queuedTx.front()); | 
| 38 | 0 |         iters_by_txid.erase(queuedTx.front()->GetHash()); | 
| 39 | 0 |         queuedTx.pop_front(); | 
| 40 | 0 |     } | 
| 41 | 78 |     return evicted; | 
| 42 | 78 | } | 
| 43 |  |  | 
| 44 |  | size_t DisconnectedBlockTransactions::DynamicMemoryUsage() const | 
| 45 | 78 | { | 
| 46 | 78 |     return cachedInnerUsage + memusage::DynamicUsage(iters_by_txid) + memusage::DynamicUsage(queuedTx); | 
| 47 | 78 | } | 
| 48 |  |  | 
| 49 |  | [[nodiscard]] std::vector<CTransactionRef> DisconnectedBlockTransactions::AddTransactionsFromBlock(const std::vector<CTransactionRef>& vtx) | 
| 50 | 78 | { | 
| 51 | 78 |     iters_by_txid.reserve(iters_by_txid.size() + vtx.size()); | 
| 52 | 156 |     for (auto block_it = vtx.rbegin(); block_it != vtx.rend(); ++block_it78) { | 
| 53 | 78 |         auto it = queuedTx.insert(queuedTx.end(), *block_it); | 
| 54 | 78 |         auto [_, inserted] = iters_by_txid.emplace((*block_it)->GetHash(), it); | 
| 55 | 78 |         assert(inserted); // callers may never pass multiple transactions with the same txid | 
| 56 | 78 |         cachedInnerUsage += RecursiveDynamicUsage(*block_it); | 
| 57 | 78 |     } | 
| 58 | 78 |     return LimitMemoryUsage(); | 
| 59 | 78 | } | 
| 60 |  |  | 
| 61 |  | void DisconnectedBlockTransactions::removeForBlock(const std::vector<CTransactionRef>& vtx) | 
| 62 | 21.7k | { | 
| 63 |  |     // Short-circuit in the common case of a block being added to the tip | 
| 64 | 21.7k |     if (queuedTx.empty()) { | 
| 65 | 21.6k |         return; | 
| 66 | 21.6k |     } | 
| 67 | 312 |     for (const auto& tx : vtx)156{ | 
| 68 | 312 |         auto iter = iters_by_txid.find(tx->GetHash()); | 
| 69 | 312 |         if (iter != iters_by_txid.end()) { | 
| 70 | 0 |             auto list_iter = iter->second; | 
| 71 | 0 |             iters_by_txid.erase(iter); | 
| 72 | 0 |             cachedInnerUsage -= RecursiveDynamicUsage(*list_iter); | 
| 73 | 0 |             queuedTx.erase(list_iter); | 
| 74 | 0 |         } | 
| 75 | 312 |     } | 
| 76 | 156 | } | 
| 77 |  |  | 
| 78 |  | void DisconnectedBlockTransactions::clear() | 
| 79 | 78 | { | 
| 80 | 78 |     cachedInnerUsage = 0; | 
| 81 | 78 |     iters_by_txid.clear(); | 
| 82 | 78 |     queuedTx.clear(); | 
| 83 | 78 | } | 
| 84 |  |  | 
| 85 |  | std::list<CTransactionRef> DisconnectedBlockTransactions::take() | 
| 86 | 78 | { | 
| 87 | 78 |     std::list<CTransactionRef> ret = std::move(queuedTx); | 
| 88 | 78 |     clear(); | 
| 89 | 78 |     return ret; | 
| 90 | 78 | } |