1212
1313#include < list>
1414#include < unordered_map>
15+ #include < vector>
1516
17+ /* * Maximum kilobytes for transactions to store for processing during reorg */
18+ static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20'000 ;
1619/* *
1720 * DisconnectedBlockTransactions
1821
@@ -38,11 +41,28 @@ class DisconnectedBlockTransactions {
3841 /* * Cached dynamic memory usage for the CTransactions (memory for the shared pointers is
3942 * included in the container calculations). */
4043 uint64_t cachedInnerUsage = 0 ;
44+ const size_t m_max_mem_usage;
4145 std::list<CTransactionRef> queuedTx;
4246 using TxList = decltype (queuedTx);
4347 std::unordered_map<uint256, TxList::iterator, SaltedTxidHasher> iters_by_txid;
4448
49+ /* * Trim the earliest-added entries until we are within memory bounds. */
50+ std::vector<CTransactionRef> LimitMemoryUsage ()
51+ {
52+ std::vector<CTransactionRef> evicted;
53+
54+ while (!queuedTx.empty () && DynamicMemoryUsage () > m_max_mem_usage) {
55+ evicted.emplace_back (queuedTx.front ());
56+ cachedInnerUsage -= RecursiveDynamicUsage (*queuedTx.front ());
57+ iters_by_txid.erase (queuedTx.front ()->GetHash ());
58+ queuedTx.pop_front ();
59+ }
60+ return evicted;
61+ }
62+
4563public:
64+ DisconnectedBlockTransactions (size_t max_mem_usage) : m_max_mem_usage{max_mem_usage} {}
65+
4666 // It's almost certainly a logic bug if we don't clear out queuedTx before
4767 // destruction, as we add to it while disconnecting blocks, and then we
4868 // need to re-process remaining transactions to ensure mempool consistency.
@@ -66,15 +86,17 @@ class DisconnectedBlockTransactions {
6686 * We assume that callers never pass multiple transactions with the same txid, otherwise things
6787 * can go very wrong in removeForBlock due to queuedTx containing an item without a
6888 * corresponding entry in iters_by_txid.
89+ * @returns vector of transactions that were evicted for size-limiting.
6990 */
70- void AddTransactionsFromBlock (const std::vector<CTransactionRef>& vtx)
91+ [[nodiscard]] std::vector<CTransactionRef> AddTransactionsFromBlock (const std::vector<CTransactionRef>& vtx)
7192 {
7293 iters_by_txid.reserve (iters_by_txid.size () + vtx.size ());
7394 for (auto block_it = vtx.rbegin (); block_it != vtx.rend (); ++block_it) {
7495 auto it = queuedTx.insert (queuedTx.end (), *block_it);
7596 iters_by_txid.emplace ((*block_it)->GetHash (), it);
7697 cachedInnerUsage += RecursiveDynamicUsage (**block_it);
7798 }
99+ return LimitMemoryUsage ();
78100 }
79101
80102 /* * Remove any entries that are in this block. */
@@ -95,19 +117,6 @@ class DisconnectedBlockTransactions {
95117 }
96118 }
97119
98- /* * Remove the first entry and update memory usage. */
99- CTransactionRef take_first ()
100- {
101- CTransactionRef first_tx;
102- if (!queuedTx.empty ()) {
103- first_tx = queuedTx.front ();
104- cachedInnerUsage -= RecursiveDynamicUsage (*queuedTx.front ());
105- iters_by_txid.erase (queuedTx.front ()->GetHash ());
106- queuedTx.pop_front ();
107- }
108- return first_tx;
109- }
110-
111120 size_t size () const { return queuedTx.size (); }
112121
113122 void clear ()
0 commit comments