12
12
13
13
#include < list>
14
14
#include < unordered_map>
15
+ #include < vector>
15
16
17
+ /* * Maximum kilobytes for transactions to store for processing during reorg */
18
+ static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20'000 ;
16
19
/* *
17
20
* DisconnectedBlockTransactions
18
21
@@ -38,11 +41,28 @@ class DisconnectedBlockTransactions {
38
41
/* * Cached dynamic memory usage for the CTransactions (memory for the shared pointers is
39
42
* included in the container calculations). */
40
43
uint64_t cachedInnerUsage = 0 ;
44
+ const size_t m_max_mem_usage;
41
45
std::list<CTransactionRef> queuedTx;
42
46
using TxList = decltype(queuedTx);
43
47
std::unordered_map<uint256, TxList::iterator, SaltedTxidHasher> iters_by_txid;
44
48
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
+
45
63
public:
64
+ DisconnectedBlockTransactions (size_t max_mem_usage) : m_max_mem_usage{max_mem_usage} {}
65
+
46
66
// It's almost certainly a logic bug if we don't clear out queuedTx before
47
67
// destruction, as we add to it while disconnecting blocks, and then we
48
68
// need to re-process remaining transactions to ensure mempool consistency.
@@ -66,15 +86,17 @@ class DisconnectedBlockTransactions {
66
86
* We assume that callers never pass multiple transactions with the same txid, otherwise things
67
87
* can go very wrong in removeForBlock due to queuedTx containing an item without a
68
88
* corresponding entry in iters_by_txid.
89
+ * @returns vector of transactions that were evicted for size-limiting.
69
90
*/
70
- void AddTransactionsFromBlock (const std::vector<CTransactionRef>& vtx)
91
+ [[nodiscard]] std::vector<CTransactionRef> AddTransactionsFromBlock (const std::vector<CTransactionRef>& vtx)
71
92
{
72
93
iters_by_txid.reserve (iters_by_txid.size () + vtx.size ());
73
94
for (auto block_it = vtx.rbegin (); block_it != vtx.rend (); ++block_it) {
74
95
auto it = queuedTx.insert (queuedTx.end (), *block_it);
75
96
iters_by_txid.emplace ((*block_it)->GetHash (), it);
76
97
cachedInnerUsage += RecursiveDynamicUsage (**block_it);
77
98
}
99
+ return LimitMemoryUsage ();
78
100
}
79
101
80
102
/* * Remove any entries that are in this block. */
@@ -95,19 +117,6 @@ class DisconnectedBlockTransactions {
95
117
}
96
118
}
97
119
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
-
111
120
size_t size () const { return queuedTx.size (); }
112
121
113
122
void clear ()
0 commit comments