@aztec/p2p 0.0.1-commit.9593d84 → 0.0.1-commit.96bb3f7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/dest/client/factory.d.ts +2 -2
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +2 -3
  4. package/dest/client/interface.d.ts +18 -5
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +16 -19
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +460 -127
  9. package/dest/config.d.ts +4 -7
  10. package/dest/config.d.ts.map +1 -1
  11. package/dest/config.js +8 -11
  12. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +61 -42
  13. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  15. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  16. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +227 -264
  17. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +21 -18
  18. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  19. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +114 -109
  20. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +17 -16
  21. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  22. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +89 -128
  23. package/dest/mem_pools/attestation_pool/mocks.d.ts +9 -8
  24. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  25. package/dest/mem_pools/attestation_pool/mocks.js +10 -9
  26. package/dest/mem_pools/instrumentation.d.ts +7 -1
  27. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  28. package/dest/mem_pools/instrumentation.js +30 -12
  29. package/dest/mem_pools/interface.d.ts +3 -4
  30. package/dest/mem_pools/interface.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +30 -25
  32. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  33. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +262 -324
  34. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +18 -0
  35. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
  36. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +56 -0
  37. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +83 -0
  38. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
  39. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +5 -0
  40. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts +15 -0
  41. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts.map +1 -0
  42. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.js +88 -0
  43. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
  44. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  45. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
  46. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
  47. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  48. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
  49. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
  50. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  51. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
  52. package/dest/mem_pools/tx_pool/index.d.ts +1 -2
  53. package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
  54. package/dest/mem_pools/tx_pool/index.js +0 -1
  55. package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
  56. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  57. package/dest/mem_pools/tx_pool/priority.js +6 -1
  58. package/dest/mem_pools/tx_pool/tx_pool.d.ts +11 -6
  59. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  60. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  61. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  62. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +30 -24
  63. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -4
  64. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  65. package/dest/msg_validators/attestation_validator/attestation_validator.js +13 -11
  66. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -5
  67. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  68. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +7 -10
  69. package/dest/msg_validators/index.d.ts +2 -2
  70. package/dest/msg_validators/index.d.ts.map +1 -1
  71. package/dest/msg_validators/index.js +1 -1
  72. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +9 -0
  73. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
  74. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +6 -0
  75. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +9 -0
  76. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
  77. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +6 -0
  78. package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
  79. package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
  80. package/dest/msg_validators/proposal_validator/index.js +3 -0
  81. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -0
  82. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
  83. package/dest/msg_validators/{block_proposal_validator/block_proposal_validator.js → proposal_validator/proposal_validator.js} +20 -22
  84. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +23 -0
  85. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -0
  86. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +183 -0
  87. package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
  88. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  89. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
  90. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  92. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  93. package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
  94. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  95. package/dest/msg_validators/tx_validator/factory.js +1 -1
  96. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
  97. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
  99. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
  100. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
  101. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  102. package/dest/services/dummy_service.d.ts +6 -2
  103. package/dest/services/dummy_service.d.ts.map +1 -1
  104. package/dest/services/dummy_service.js +3 -0
  105. package/dest/services/encoding.d.ts +1 -1
  106. package/dest/services/encoding.d.ts.map +1 -1
  107. package/dest/services/encoding.js +5 -3
  108. package/dest/services/libp2p/instrumentation.d.ts +1 -1
  109. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  110. package/dest/services/libp2p/instrumentation.js +15 -68
  111. package/dest/services/libp2p/libp2p_service.d.ts +30 -13
  112. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  113. package/dest/services/libp2p/libp2p_service.js +707 -153
  114. package/dest/services/peer-manager/metrics.d.ts +6 -1
  115. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  116. package/dest/services/peer-manager/metrics.js +18 -21
  117. package/dest/services/peer-manager/peer_manager.d.ts +2 -2
  118. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  119. package/dest/services/peer-manager/peer_manager.js +4 -12
  120. package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
  121. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  122. package/dest/services/peer-manager/peer_scoring.js +2 -5
  123. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -1
  124. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  125. package/dest/services/reqresp/interface.d.ts +2 -2
  126. package/dest/services/reqresp/interface.d.ts.map +1 -1
  127. package/dest/services/reqresp/interface.js +1 -1
  128. package/dest/services/reqresp/metrics.d.ts +1 -1
  129. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  130. package/dest/services/reqresp/metrics.js +5 -21
  131. package/dest/services/reqresp/protocols/auth.d.ts +2 -2
  132. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
  133. package/dest/services/reqresp/protocols/auth.js +2 -2
  134. package/dest/services/reqresp/protocols/block.d.ts +1 -1
  135. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  136. package/dest/services/reqresp/protocols/block.js +3 -2
  137. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +2 -2
  138. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  139. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +1 -1
  140. package/dest/services/reqresp/protocols/status.d.ts +5 -4
  141. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  142. package/dest/services/reqresp/protocols/status.js +6 -3
  143. package/dest/services/reqresp/protocols/tx.d.ts +2 -3
  144. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  145. package/dest/services/reqresp/reqresp.js +402 -24
  146. package/dest/services/service.d.ts +16 -3
  147. package/dest/services/service.d.ts.map +1 -1
  148. package/dest/services/tx_collection/config.js +1 -1
  149. package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -3
  150. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  151. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  152. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  153. package/dest/services/tx_collection/instrumentation.js +4 -14
  154. package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -5
  155. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  156. package/dest/services/tx_collection/tx_collection.d.ts +11 -10
  157. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  158. package/dest/services/tx_provider.d.ts +6 -4
  159. package/dest/services/tx_provider.d.ts.map +1 -1
  160. package/dest/services/tx_provider.js +11 -2
  161. package/dest/services/tx_provider_instrumentation.d.ts +5 -2
  162. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  163. package/dest/services/tx_provider_instrumentation.js +13 -13
  164. package/dest/test-helpers/mock-tx-helpers.js +1 -1
  165. package/dest/test-helpers/reqresp-nodes.d.ts +2 -2
  166. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  167. package/dest/testbench/p2p_client_testbench_worker.js +26 -11
  168. package/dest/testbench/worker_client_manager.d.ts +1 -1
  169. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  170. package/dest/testbench/worker_client_manager.js +6 -1
  171. package/package.json +16 -16
  172. package/src/client/factory.ts +5 -10
  173. package/src/client/interface.ts +19 -4
  174. package/src/client/p2p_client.ts +104 -157
  175. package/src/config.ts +10 -16
  176. package/src/mem_pools/attestation_pool/attestation_pool.ts +68 -41
  177. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +233 -289
  178. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +163 -141
  179. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +141 -164
  180. package/src/mem_pools/attestation_pool/mocks.ts +15 -11
  181. package/src/mem_pools/instrumentation.ts +38 -14
  182. package/src/mem_pools/interface.ts +2 -4
  183. package/src/mem_pools/tx_pool/README.md +255 -0
  184. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +314 -373
  185. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +71 -0
  186. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +93 -0
  187. package/src/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.ts +108 -0
  188. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
  189. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
  190. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
  191. package/src/mem_pools/tx_pool/index.ts +0 -1
  192. package/src/mem_pools/tx_pool/priority.ts +8 -1
  193. package/src/mem_pools/tx_pool/tx_pool.ts +11 -5
  194. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +23 -17
  195. package/src/msg_validators/attestation_validator/attestation_validator.ts +17 -14
  196. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +9 -12
  197. package/src/msg_validators/index.ts +1 -1
  198. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +10 -0
  199. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +13 -0
  200. package/src/msg_validators/proposal_validator/index.ts +3 -0
  201. package/src/msg_validators/{block_proposal_validator/block_proposal_validator.ts → proposal_validator/proposal_validator.ts} +24 -29
  202. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +206 -0
  203. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  204. package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
  205. package/src/msg_validators/tx_validator/data_validator.ts +12 -4
  206. package/src/msg_validators/tx_validator/factory.ts +3 -2
  207. package/src/msg_validators/tx_validator/metadata_validator.ts +13 -5
  208. package/src/msg_validators/tx_validator/test_utils.ts +1 -1
  209. package/src/msg_validators/tx_validator/timestamp_validator.ts +5 -2
  210. package/src/services/dummy_service.ts +6 -0
  211. package/src/services/encoding.ts +4 -2
  212. package/src/services/libp2p/instrumentation.ts +14 -68
  213. package/src/services/libp2p/libp2p_service.ts +342 -123
  214. package/src/services/peer-manager/metrics.ts +22 -21
  215. package/src/services/peer-manager/peer_manager.ts +5 -4
  216. package/src/services/peer-manager/peer_scoring.ts +1 -5
  217. package/src/services/reqresp/connection-sampler/connection_sampler.ts +3 -1
  218. package/src/services/reqresp/interface.ts +1 -1
  219. package/src/services/reqresp/metrics.ts +7 -23
  220. package/src/services/reqresp/protocols/auth.ts +2 -2
  221. package/src/services/reqresp/protocols/block.ts +3 -2
  222. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
  223. package/src/services/reqresp/protocols/status.ts +11 -9
  224. package/src/services/reqresp/protocols/tx.ts +1 -2
  225. package/src/services/service.ts +19 -4
  226. package/src/services/tx_collection/config.ts +1 -1
  227. package/src/services/tx_collection/fast_tx_collection.ts +3 -2
  228. package/src/services/tx_collection/instrumentation.ts +4 -21
  229. package/src/services/tx_collection/slow_tx_collection.ts +5 -5
  230. package/src/services/tx_collection/tx_collection.ts +10 -9
  231. package/src/services/tx_provider.ts +21 -5
  232. package/src/services/tx_provider_instrumentation.ts +18 -14
  233. package/src/test-helpers/mock-pubsub.ts +1 -1
  234. package/src/test-helpers/mock-tx-helpers.ts +1 -1
  235. package/src/test-helpers/reqresp-nodes.ts +1 -1
  236. package/src/testbench/p2p_client_testbench_worker.ts +36 -12
  237. package/src/testbench/worker_client_manager.ts +6 -1
  238. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -80
  239. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
  240. package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -238
  241. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
  242. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
  243. package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
  244. package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
  245. package/dest/msg_validators/block_proposal_validator/index.js +0 -1
  246. package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -283
  247. package/src/msg_validators/block_proposal_validator/index.ts +0 -1
@@ -1,14 +1,14 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { insertIntoSortedArray } from '@aztec/foundation/array';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
4
  import { toArray } from '@aztec/foundation/iterable';
3
5
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
6
  import type { TypedEventEmitter } from '@aztec/foundation/types';
5
- import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap, AztecAsyncSingleton } from '@aztec/kv-store';
6
- import { ProtocolContractAddress } from '@aztec/protocol-contracts';
7
- import { GasFees } from '@aztec/stdlib/gas';
8
- import type { MerkleTreeReadOperations, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
7
+ import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
8
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
+ import type { MerkleTreeReadOperations, ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
9
10
  import { ChonkProof } from '@aztec/stdlib/proofs';
10
11
  import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
11
- import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
12
12
  import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
13
13
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
14
14
 
@@ -16,49 +16,46 @@ import assert from 'assert';
16
16
  import EventEmitter from 'node:events';
17
17
 
18
18
  import { ArchiveCache } from '../../msg_validators/tx_validator/archive_cache.js';
19
- import { GasTxValidator } from '../../msg_validators/tx_validator/gas_validator.js';
20
19
  import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
20
+ import { EvictionManager } from './eviction/eviction_manager.js';
21
+ import type { PendingTxInfo, TxBlockReference, TxPoolOperations } from './eviction/eviction_strategy.js';
22
+ import { InsufficientFeePayerBalanceRule } from './eviction/insufficient_fee_payer_balance_rule.js';
23
+ import { InvalidTxsAfterMiningRule } from './eviction/invalid_txs_after_mining_rule.js';
24
+ import { InvalidTxsAfterReorgRule } from './eviction/invalid_txs_after_reorg_rule.js';
25
+ import { LowPriorityEvictionRule } from './eviction/low_priority_eviction_rule.js';
21
26
  import { getPendingTxPriority } from './priority.js';
22
27
  import type { TxPool, TxPoolEvents, TxPoolOptions } from './tx_pool.js';
23
28
 
24
29
  /**
25
30
  * KV implementation of the Transaction Pool.
26
31
  */
27
- export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<TxPoolEvents>) implements TxPool {
32
+ export class AztecKVTxPool
33
+ extends (EventEmitter as new () => TypedEventEmitter<TxPoolEvents>)
34
+ implements TxPool, TxPoolOperations
35
+ {
28
36
  #store: AztecAsyncKVStore;
29
37
 
30
38
  /** Our tx pool, stored as a Map, with K: tx hash and V: the transaction. */
31
39
  #txs: AztecAsyncMap<string, Buffer>;
32
40
 
33
- /** The maximum cumulative tx size that the pending txs in the pool take up. */
34
- #maxTxPoolSize: number = 0;
35
-
36
- /** The tx evicion logic will kick after pool size is greater than maxTxPoolSize * txPoolOverflowFactor */
37
- txPoolOverflowFactor: number = 1;
41
+ /** Holds the historical block for each tx */
42
+ #pendingTxHashToHistoricalBlockHeaderHash: AztecAsyncMap<string, string>;
38
43
 
39
44
  /** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
40
- #minedTxHashToBlock: AztecAsyncMap<string, number>;
45
+ #minedTxHashToBlock: AztecAsyncMap<string, BlockNumber>;
41
46
 
42
47
  /** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */
43
48
  #pendingTxPriorityToHash: AztecAsyncMultiMap<string, string>;
44
49
 
45
- /** Index from tx hash to its tx size (in bytes), filtered by pending txs. */
46
- #pendingTxHashToSize: AztecAsyncMap<string, number>;
47
-
48
- /** Index from tx hash to its header hash, filtered by pending txs. */
49
- #pendingTxHashToHeaderHash: AztecAsyncMap<string, string>;
50
-
51
50
  /** Map from tx hash to the block number it was originally mined in (for soft-deleted txs). */
52
- #deletedMinedTxHashes: AztecAsyncMap<string, number>;
51
+ #deletedMinedTxHashes: AztecAsyncMap<string, BlockNumber>;
53
52
 
54
53
  /** MultiMap from block number to deleted mined tx hashes for efficient cleanup. */
55
- #blockToDeletedMinedTxHash: AztecAsyncMultiMap<number, string>;
54
+ #blockToDeletedMinedTxHash: AztecAsyncMultiMap<BlockNumber, string>;
56
55
 
57
- /** The cumulative tx size in bytes that the pending txs in the pool take up. */
58
- #pendingTxSize: AztecAsyncSingleton<number>;
56
+ #historicalHeaderToTxHash: AztecAsyncMultiMap<string, string>;
59
57
 
60
- /** In-memory mapping of pending tx hashes to the hydrated pending tx in the pool. */
61
- #pendingTxs: Map<string, Tx>;
58
+ #feePayerToTxHash: AztecAsyncMultiMap<string, string>;
62
59
 
63
60
  /** In-memory set of txs that should not be evicted from the pool. */
64
61
  #nonEvictableTxs: Set<string>;
@@ -75,8 +72,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
75
72
  /** Number of txs to archive. */
76
73
  #archivedTxLimit: number = 0;
77
74
 
78
- /** The world state synchronizer used in the node. */
79
- #worldStateSynchronizer: WorldStateSynchronizer;
75
+ #evictionManager: EvictionManager;
80
76
 
81
77
  #log: Logger;
82
78
 
@@ -93,7 +89,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
93
89
  constructor(
94
90
  store: AztecAsyncKVStore,
95
91
  archive: AztecAsyncKVStore,
96
- worldStateSynchronizer: WorldStateSynchronizer,
92
+ worldState: ReadonlyWorldStateAccess,
97
93
  telemetry: TelemetryClient = getTelemetryClient(),
98
94
  config: TxPoolOptions = {},
99
95
  log = createLogger('p2p:tx_pool'),
@@ -101,18 +97,30 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
101
97
  super();
102
98
 
103
99
  this.#log = log;
100
+
101
+ this.#evictionManager = new EvictionManager(this);
102
+ this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
103
+ this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(worldState));
104
+ this.#evictionManager.registerRule(new InsufficientFeePayerBalanceRule(worldState));
105
+ this.#evictionManager.registerRule(
106
+ new LowPriorityEvictionRule({
107
+ //NOTE: 0 effectively disables low priority eviction
108
+ maxPoolSize: config.maxPendingTxCount ?? 0,
109
+ }),
110
+ );
111
+
104
112
  this.updateConfig(config);
105
113
 
106
114
  this.#txs = store.openMap('txs');
107
115
  this.#minedTxHashToBlock = store.openMap('txHashToBlockMined');
108
116
  this.#pendingTxPriorityToHash = store.openMultiMap('pendingTxFeeToHash');
109
- this.#pendingTxHashToSize = store.openMap('pendingTxHashToSize');
110
- this.#pendingTxHashToHeaderHash = store.openMap('pendingTxHashToHeaderHash');
111
- this.#pendingTxSize = store.openSingleton('pendingTxSize');
112
117
  this.#deletedMinedTxHashes = store.openMap('deletedMinedTxHashes');
113
118
  this.#blockToDeletedMinedTxHash = store.openMultiMap('blockToDeletedMinedTxHash');
114
119
 
115
- this.#pendingTxs = new Map<string, Tx>();
120
+ this.#pendingTxHashToHistoricalBlockHeaderHash = store.openMap('txHistoricalBlock');
121
+ this.#historicalHeaderToTxHash = store.openMultiMap('historicalHeaderToPendingTxHash');
122
+ this.#feePayerToTxHash = store.openMultiMap('feePayerToPendingTxHash');
123
+
116
124
  this.#nonEvictableTxs = new Set<string>();
117
125
 
118
126
  this.#archivedTxs = archive.openMap('archivedTxs');
@@ -120,7 +128,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
120
128
 
121
129
  this.#store = store;
122
130
  this.#archive = archive;
123
- this.#worldStateSynchronizer = worldStateSynchronizer;
131
+
124
132
  this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, this.countTxs, () => store.estimateSize());
125
133
  }
126
134
 
@@ -141,6 +149,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
141
149
  }
142
150
  return true;
143
151
  }
152
+
144
153
  /**
145
154
  * Marks transactions as mined in a block and updates the pool state accordingly.
146
155
  * Removes the transactions from the pending set and adds them to the mined set.
@@ -153,68 +162,72 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
153
162
  return Promise.resolve();
154
163
  }
155
164
 
156
- const minedNullifiers = new Set<string>();
157
- const minedFeePayers = new Set<string>();
165
+ const uniqueMinedNullifiers: Fr[] = [];
166
+ const uniqueMinedFeePayers: AztecAddress[] = [];
158
167
 
159
- await this.#store.transactionAsync(async () => {
160
- let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
161
- for (const hash of txHashes) {
162
- const key = hash.toString();
168
+ try {
169
+ await this.#store.transactionAsync(async () => {
170
+ for (const hash of txHashes) {
171
+ const key = hash.toString();
172
+ await this.#minedTxHashToBlock.set(key, blockHeader.globalVariables.blockNumber);
173
+
174
+ const tx = await this.getPendingTxByHash(hash);
175
+ if (tx) {
176
+ const nullifiers = tx.data.getNonEmptyNullifiers();
177
+
178
+ nullifiers.forEach(nullifier => insertIntoSortedArray(uniqueMinedNullifiers, nullifier, Fr.cmp, false));
179
+ insertIntoSortedArray(
180
+ uniqueMinedFeePayers,
181
+ tx.data.feePayer,
182
+ (a, b) => a.toField().cmp(b.toField()),
183
+ false,
184
+ );
185
+
186
+ await this.removePendingTxIndicesInDbTx(tx, key);
187
+ }
163
188
 
164
- // If this tx was previously soft-deleted, remove it from the deleted sets
165
- if (await this.#deletedMinedTxHashes.hasAsync(key)) {
166
- const originalBlock = await this.#deletedMinedTxHashes.getAsync(key);
167
- await this.#deletedMinedTxHashes.delete(key);
168
- // Remove from block-to-hash mapping
169
- if (originalBlock !== undefined) {
170
- await this.#blockToDeletedMinedTxHash.deleteValue(originalBlock, key);
189
+ // If this tx was previously soft-deleted, remove it from the deleted sets
190
+ if (await this.#deletedMinedTxHashes.hasAsync(key)) {
191
+ const originalBlock = await this.#deletedMinedTxHashes.getAsync(key);
192
+ await this.#deletedMinedTxHashes.delete(key);
193
+ // Remove from block-to-hash mapping
194
+ if (originalBlock !== undefined) {
195
+ await this.#blockToDeletedMinedTxHash.deleteValue(originalBlock, key);
196
+ }
171
197
  }
172
198
  }
199
+ });
173
200
 
174
- await this.#minedTxHashToBlock.set(key, blockHeader.globalVariables.blockNumber);
175
-
176
- const tx = await this.getPendingTxByHash(hash);
177
- if (tx) {
178
- const nullifiers = tx.data.getNonEmptyNullifiers();
179
- nullifiers.forEach(nullifier => minedNullifiers.add(nullifier.toString()));
180
- minedFeePayers.add(tx.data.feePayer.toString());
181
- pendingTxSize -= tx.getSize();
182
- await this.removePendingTxIndices(tx, key);
183
- }
184
- }
185
- await this.#pendingTxSize.set(pendingTxSize);
201
+ await this.#evictionManager.evictAfterNewBlock(blockHeader, uniqueMinedNullifiers, uniqueMinedFeePayers);
186
202
 
187
- await this.evictInvalidTxsAfterMining(txHashes, blockHeader, minedNullifiers, minedFeePayers);
188
- });
189
- // We update this after the transaction above. This ensures that the non-evictable transactions are not evicted
190
- // until any that have been mined are marked as such.
191
- // The non-evictable set is not considered when evicting transactions that are invalid after a block is mined.
192
- this.#nonEvictableTxs.clear();
203
+ this.#metrics.transactionsRemoved(txHashes.map(hash => hash.toBigInt()));
204
+ } catch (err) {
205
+ this.#log.warn('Unexpected error when marking txs as mined', { err });
206
+ }
193
207
  }
194
208
 
195
- public async markMinedAsPending(txHashes: TxHash[]): Promise<void> {
209
+ public async markMinedAsPending(txHashes: TxHash[], latestBlock: BlockNumber): Promise<void> {
196
210
  if (txHashes.length === 0) {
197
211
  return Promise.resolve();
198
212
  }
199
- await this.#store.transactionAsync(async () => {
200
- let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
201
- for (const hash of txHashes) {
202
- const key = hash.toString();
203
- await this.#minedTxHashToBlock.delete(key);
204
-
205
- // Rehydrate the tx in the in-memory pending txs mapping
206
- const tx = await this.getPendingTxByHash(hash);
207
- if (tx) {
208
- await this.addPendingTxIndices(tx, key);
209
- pendingTxSize += tx.getSize();
213
+ try {
214
+ await this.#store.transactionAsync(async () => {
215
+ for (const hash of txHashes) {
216
+ const key = hash.toString();
217
+ await this.#minedTxHashToBlock.delete(key);
218
+
219
+ // Rehydrate the tx in the in-memory pending txs mapping
220
+ const tx = await this.getPendingTxByHash(hash);
221
+ if (tx) {
222
+ await this.addPendingTxIndicesInDbTx(tx, key);
223
+ }
210
224
  }
211
- }
212
-
213
- await this.#pendingTxSize.set(pendingTxSize);
214
- });
225
+ });
215
226
 
216
- await this.evictInvalidTxsAfterReorg(txHashes);
217
- await this.evictLowPriorityTxs(txHashes);
227
+ await this.#evictionManager.evictAfterChainPrune(latestBlock);
228
+ } catch (err) {
229
+ this.#log.warn('Unexpected error when marking mined txs as pending', { err });
230
+ }
218
231
  }
219
232
 
220
233
  public async getPendingTxHashes(): Promise<TxHash[]> {
@@ -222,38 +235,6 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
222
235
  return vals.map(TxHash.fromString);
223
236
  }
224
237
 
225
- public async getMinedTxHashes(): Promise<[TxHash, number][]> {
226
- const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
227
- return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
228
- }
229
-
230
- public async getPendingTxCount(): Promise<number> {
231
- return (await this.#pendingTxHashToHeaderHash.sizeAsync()) ?? 0;
232
- }
233
-
234
- public async getMinedTxCount(): Promise<number> {
235
- return (await this.#minedTxHashToBlock.sizeAsync()) ?? 0;
236
- }
237
-
238
- public async getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | 'deleted' | undefined> {
239
- const key = txHash.toString();
240
- const [isMined, isKnown, isDeleted] = await Promise.all([
241
- this.#minedTxHashToBlock.hasAsync(key),
242
- this.#txs.hasAsync(key),
243
- this.#deletedMinedTxHashes.hasAsync(key),
244
- ]);
245
-
246
- if (isDeleted) {
247
- return 'deleted';
248
- } else if (isMined) {
249
- return 'mined';
250
- } else if (isKnown) {
251
- return 'pending';
252
- } else {
253
- return undefined;
254
- }
255
- }
256
-
257
238
  /**
258
239
  * Checks if a transaction exists in the pool and returns it.
259
240
  * @param txHash - The generated tx hash.
@@ -291,43 +272,53 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
291
272
  /**
292
273
  * Adds a list of transactions to the pool. Duplicates are ignored.
293
274
  * @param txs - An array of txs to be added to the pool.
294
- * @returns Empty promise.
275
+ * @returns count of added transactions
295
276
  */
296
277
  public async addTxs(txs: Tx[], opts: { source?: string } = {}): Promise<number> {
278
+ if (txs.length === 0) {
279
+ return Promise.resolve(0);
280
+ }
281
+
297
282
  const addedTxs: Tx[] = [];
298
283
  const hashesAndStats = txs.map(tx => ({ txHash: tx.getTxHash(), txStats: tx.getStats() }));
299
- await this.#store.transactionAsync(async () => {
300
- let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
301
- await Promise.all(
302
- txs.map(async (tx, i) => {
303
- const { txHash, txStats } = hashesAndStats[i];
304
- const key = txHash.toString();
305
- if (await this.#txs.hasAsync(key)) {
306
- this.#log.debug(`Tx ${txHash.toString()} already exists in the pool`);
307
- return;
308
- }
309
-
310
- this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
311
- eventName: 'tx-added-to-pool',
312
- ...txStats,
313
- } satisfies TxAddedToPoolStats);
314
-
315
- await this.#txs.set(key, tx.toBuffer());
316
- addedTxs.push(tx as Tx);
284
+ try {
285
+ await this.#store.transactionAsync(async () => {
286
+ await Promise.all(
287
+ txs.map(async (tx, i) => {
288
+ const { txHash, txStats } = hashesAndStats[i];
289
+ const key = txHash.toString();
290
+ if (await this.#txs.hasAsync(key)) {
291
+ this.#log.debug(`Tx ${txHash.toString()} already exists in the pool`);
292
+ return;
293
+ }
317
294
 
318
- if (!(await this.#minedTxHashToBlock.hasAsync(key))) {
319
- pendingTxSize += tx.getSize();
320
- await this.addPendingTxIndices(tx, key);
321
- this.#metrics.recordSize(tx);
322
- }
323
- }),
324
- );
295
+ this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
296
+ eventName: 'tx-added-to-pool',
297
+ ...txStats,
298
+ } satisfies TxAddedToPoolStats);
299
+
300
+ await this.#txs.set(key, tx.toBuffer());
301
+ addedTxs.push(tx as Tx);
302
+ await this.#pendingTxHashToHistoricalBlockHeaderHash.set(
303
+ key,
304
+ (await tx.data.constants.anchorBlockHeader.hash()).toString(),
305
+ );
306
+
307
+ if (!(await this.#minedTxHashToBlock.hasAsync(key))) {
308
+ await this.addPendingTxIndicesInDbTx(tx, key);
309
+ this.#metrics.recordSize(tx);
310
+ }
311
+ }),
312
+ );
313
+ });
325
314
 
326
- await this.#pendingTxSize.set(pendingTxSize);
327
- await this.evictLowPriorityTxs(hashesAndStats.map(({ txHash }) => txHash));
328
- });
315
+ await this.#evictionManager.evictAfterNewTxs(addedTxs.map(({ txHash }) => txHash));
316
+ } catch (err) {
317
+ this.#log.warn('Unexpected error when adding txs', { err });
318
+ }
329
319
 
330
320
  if (addedTxs.length > 0) {
321
+ this.#metrics.transactionsAdded(addedTxs);
331
322
  this.emit('txs-added', { ...opts, txs: addedTxs });
332
323
  }
333
324
  return addedTxs.length;
@@ -339,54 +330,62 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
339
330
  * @param txHashes - An array of tx hashes to be deleted from the tx pool.
340
331
  * @returns Empty promise.
341
332
  */
342
- public deleteTxs(txHashes: TxHash[], opts: { eviction?: boolean; permanently?: boolean } = {}): Promise<void> {
333
+ public deleteTxs(txHashes: TxHash[], opts?: { permanently?: boolean }): Promise<void> {
343
334
  if (txHashes.length === 0) {
344
335
  return Promise.resolve();
345
336
  }
337
+
346
338
  const deletedTxs: Tx[] = [];
347
339
  const poolDbTx = this.#store.transactionAsync(async () => {
348
- let pendingTxSize = (await this.#pendingTxSize.getAsync()) ?? 0;
349
340
  for (const hash of txHashes) {
350
341
  const key = hash.toString();
351
342
  const tx = await this.getTxByHash(hash);
343
+ if (!tx) {
344
+ this.#log.trace(`Skipping deletion of missing tx ${key} from pool`);
345
+ continue;
346
+ }
352
347
 
353
- if (tx) {
354
- const minedBlockNumber = await this.#minedTxHashToBlock.getAsync(key);
355
-
356
- if (minedBlockNumber !== undefined) {
357
- await this.#minedTxHashToBlock.delete(key);
358
- if (opts.permanently) {
359
- // Permanently delete mined transactions if specified
360
- this.#log.trace(`Deleting mined tx ${key} from pool`);
361
- await this.#txs.delete(key);
362
- } else {
363
- // Soft-delete mined transactions: remove from mined set but keep in storage
364
- this.#log.trace(`Soft-deleting mined tx ${key} from pool`);
365
- await this.#deletedMinedTxHashes.set(key, minedBlockNumber);
366
- await this.#blockToDeletedMinedTxHash.set(minedBlockNumber, key);
367
- }
368
- } else {
369
- // Permanently delete pending transactions
370
- this.#log.trace(`Deleting pending tx ${key} from pool`);
371
- pendingTxSize -= tx.getSize();
372
- await this.removePendingTxIndices(tx, key);
373
- await this.#txs.delete(key);
374
- }
375
-
376
- if (!opts.eviction && this.#archivedTxLimit) {
348
+ const minedBlockNumber = await this.#minedTxHashToBlock.getAsync(key);
349
+ const txIsPending = minedBlockNumber === undefined;
350
+ if (txIsPending) {
351
+ await this.deletePendingTx(tx, key);
352
+ } else {
353
+ await this.deleteMinedTx(key, minedBlockNumber!, opts?.permanently ?? false);
354
+ const shouldArchiveTx = this.#archivedTxLimit && !opts?.permanently;
355
+ if (shouldArchiveTx) {
377
356
  deletedTxs.push(tx);
378
357
  }
379
- } else {
380
- this.#log.trace(`Skipping deletion of missing tx ${key} from pool`);
381
358
  }
382
359
  }
383
-
384
- await this.#pendingTxSize.set(pendingTxSize);
385
360
  });
361
+ this.#metrics.transactionsRemoved(txHashes.map(hash => hash.toBigInt()));
386
362
  this.#log.debug(`Deleted ${txHashes.length} txs from pool`, { txHashes });
363
+
387
364
  return this.#archivedTxLimit ? poolDbTx.then(() => this.archiveTxs(deletedTxs)) : poolDbTx;
388
365
  }
389
366
 
367
+ private async deleteMinedTx(txHash: `0x${string}`, minedBlockNumber: BlockNumber, permanently: boolean) {
368
+ await this.#minedTxHashToBlock.delete(txHash);
369
+ if (permanently) {
370
+ this.#log.trace(`Deleting mined tx ${txHash} from pool`);
371
+ await this.#txs.delete(txHash);
372
+ return;
373
+ }
374
+
375
+ // Soft-delete mined transactions: remove from mined set but keep in storage
376
+ this.#log.trace(`Soft-deleting mined tx ${txHash} from pool`);
377
+ await this.#deletedMinedTxHashes.set(txHash, minedBlockNumber);
378
+ await this.#blockToDeletedMinedTxHash.set(minedBlockNumber, txHash);
379
+ }
380
+
381
+ private async deletePendingTx(tx: Tx, txHash: `0x${string}`) {
382
+ // We always permanently delete pending transactions
383
+ this.#log.trace(`Deleting pending tx ${txHash} from pool`);
384
+ await this.removePendingTxIndices(tx, txHash);
385
+ await this.#txs.delete(txHash);
386
+ await this.#pendingTxHashToHistoricalBlockHeaderHash.delete(txHash);
387
+ }
388
+
390
389
  /**
391
390
  * Gets all the transactions stored in the pool.
392
391
  * @returns Array of tx objects in the order they were added to the pool.
@@ -405,30 +404,101 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
405
404
  return vals.map(x => TxHash.fromString(x));
406
405
  }
407
406
 
408
- public updateConfig({ maxTxPoolSize, txPoolOverflowFactor, archivedTxLimit }: TxPoolOptions): void {
409
- if (typeof maxTxPoolSize === 'number') {
410
- assert(maxTxPoolSize >= 0, 'maxTxPoolSize must be greater or equal to 0');
411
- this.#maxTxPoolSize = maxTxPoolSize;
407
+ public async getPendingTxInfos(): Promise<PendingTxInfo[]> {
408
+ const vals = await toArray(this.#pendingTxPriorityToHash.valuesAsync());
409
+ const results = await Promise.all(vals.map(val => this.getPendingTxInfo(TxHash.fromString(val))));
410
+ return results.filter((info): info is PendingTxInfo => info !== undefined);
411
+ }
412
412
 
413
- if (maxTxPoolSize === 0) {
414
- this.#log.info(`Disabling maximum tx mempool size. Tx eviction stopped`);
415
- } else {
416
- this.#log.info(`Setting maximum tx mempool size`, { maxTxPoolSize });
413
+ private async getPendingTxInfo(txHash: TxHash): Promise<PendingTxInfo | undefined> {
414
+ let historicalBlockHash = await this.#pendingTxHashToHistoricalBlockHeaderHash.getAsync(txHash.toString());
415
+ // Not all tx might have this index created.
416
+ if (!historicalBlockHash) {
417
+ const tx = await this.getPendingTxByHash(txHash);
418
+ if (!tx) {
419
+ this.#log.warn(`PendingTxInfo:tx ${txHash} not found`);
420
+ return undefined;
417
421
  }
422
+
423
+ historicalBlockHash = (await tx.data.constants.anchorBlockHeader.hash()).toString();
424
+ await this.#pendingTxHashToHistoricalBlockHeaderHash.set(txHash.toString(), historicalBlockHash);
425
+ }
426
+
427
+ return {
428
+ txHash,
429
+ blockHash: Fr.fromString(historicalBlockHash),
430
+ isEvictable: !this.#nonEvictableTxs.has(txHash.toString()),
431
+ };
432
+ }
433
+
434
+ public async getPendingTxsReferencingBlocks(blockHashes: Fr[]): Promise<TxBlockReference[]> {
435
+ const result: TxBlockReference[] = [];
436
+ for (const blockHash of blockHashes) {
437
+ const chunk = await toArray(this.#historicalHeaderToTxHash.getValuesAsync(blockHash.toString()));
438
+ result.push(
439
+ ...chunk.map(txHash => ({
440
+ txHash: TxHash.fromString(txHash),
441
+ blockHash,
442
+ isEvictable: !this.#nonEvictableTxs.has(txHash),
443
+ })),
444
+ );
418
445
  }
419
446
 
420
- if (typeof txPoolOverflowFactor === 'number') {
421
- assert(txPoolOverflowFactor >= 1, 'txPoolOveflowFactor must be greater or equal to 1');
422
- this.txPoolOverflowFactor = txPoolOverflowFactor;
423
- this.#log.info(`Allowing tx pool size to grow above limit`, { maxTxPoolSize, txPoolOverflowFactor });
447
+ return result;
448
+ }
449
+
450
+ public async getPendingTxsWithFeePayer(feePayers: AztecAddress[]): Promise<PendingTxInfo[]> {
451
+ const result: PendingTxInfo[] = [];
452
+ for (const feePayer of feePayers) {
453
+ const chunk = await toArray(this.#feePayerToTxHash.getValuesAsync(feePayer.toString()));
454
+ const infos = await Promise.all(chunk.map(txHash => this.getPendingTxInfo(TxHash.fromString(txHash))));
455
+ result.push(...infos.filter((info): info is PendingTxInfo => info !== undefined));
456
+ }
457
+
458
+ return result;
459
+ }
460
+
461
+ public async getMinedTxHashes(): Promise<[TxHash, BlockNumber][]> {
462
+ const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
463
+ return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
464
+ }
465
+
466
+ public async getPendingTxCount(): Promise<number> {
467
+ return (await this.#pendingTxPriorityToHash.sizeAsync()) ?? 0;
468
+ }
469
+
470
+ public async getMinedTxCount(): Promise<number> {
471
+ return (await this.#minedTxHashToBlock.sizeAsync()) ?? 0;
472
+ }
473
+
474
+ public async getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | 'deleted' | undefined> {
475
+ const key = txHash.toString();
476
+ const [isMined, isKnown, isDeleted] = await Promise.all([
477
+ this.#minedTxHashToBlock.hasAsync(key),
478
+ this.#txs.hasAsync(key),
479
+ this.#deletedMinedTxHashes.hasAsync(key),
480
+ ]);
481
+
482
+ if (isDeleted) {
483
+ return 'deleted';
484
+ } else if (isMined) {
485
+ return 'mined';
486
+ } else if (isKnown) {
487
+ return 'pending';
488
+ } else {
489
+ return undefined;
424
490
  }
491
+ }
425
492
 
426
- if (typeof archivedTxLimit === 'number') {
427
- assert(archivedTxLimit >= 0, 'archivedTxLimit must be greater or equal to 0');
428
- this.#archivedTxLimit = archivedTxLimit;
493
+ public updateConfig(cfg: TxPoolOptions): void {
494
+ if (typeof cfg.archivedTxLimit === 'number') {
495
+ assert(cfg.archivedTxLimit >= 0, 'archivedTxLimit must be greater or equal to 0');
496
+ this.#archivedTxLimit = cfg.archivedTxLimit;
429
497
  }
430
498
 
431
- // deletedMinedCleanupThresholdMs is no longer used in block-based cleanup
499
+ if (this.#evictionManager) {
500
+ this.#evictionManager.updateConfig(cfg);
501
+ }
432
502
  }
433
503
 
434
504
  public markTxsAsNonEvictable(txHashes: TxHash[]): Promise<void> {
@@ -436,17 +506,26 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
436
506
  return Promise.resolve();
437
507
  }
438
508
 
509
+ public clearNonEvictableTxs(): Promise<void> {
510
+ // Clear the non-evictable set after completing the DB updates above.
511
+ // This ensures pinned (non-evictable) txs are protected while we mark mined txs,
512
+ // but they won't remain pinned indefinitely across blocks. Note that eviction rules
513
+ // (including post-mining invalidation) respect the non-evictable flag while it is set.
514
+ this.#nonEvictableTxs.clear();
515
+ return Promise.resolve();
516
+ }
517
+
439
518
  /**
440
519
  * Permanently deletes deleted mined transactions from blocks up to and including the specified block number.
441
520
  * @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
442
521
  * @returns The number of transactions permanently deleted.
443
522
  */
444
- public async cleanupDeletedMinedTxs(blockNumber: number): Promise<number> {
523
+ public async cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number> {
445
524
  let deletedCount = 0;
446
- const txHashesToDelete: string[] = [];
447
- const blocksToDelete: number[] = [];
448
-
449
525
  await this.#store.transactionAsync(async () => {
526
+ const txHashesToDelete: string[] = [];
527
+ const blocksToDelete: BlockNumber[] = [];
528
+
450
529
  // Iterate through all entries and check block numbers
451
530
  for await (const [block, txHash] of this.#blockToDeletedMinedTxHash.entriesAsync()) {
452
531
  if (block <= blockNumber) {
@@ -460,6 +539,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
460
539
  deletedCount++;
461
540
  }
462
541
  }
542
+ this.#metrics.transactionsRemoved(txHashesToDelete);
463
543
 
464
544
  // Clean up block-to-hash mapping - delete all values for each block
465
545
  for (const block of blocksToDelete) {
@@ -476,15 +556,6 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
476
556
  return deletedCount;
477
557
  }
478
558
 
479
- /**
480
- * Creates a GasTxValidator instance.
481
- * @param db - DB for the validator to use
482
- * @returns A GasTxValidator instance
483
- */
484
- protected createGasTxValidator(db: MerkleTreeReadOperations): GasTxValidator {
485
- return new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, GasFees.empty());
486
- }
487
-
488
559
  /**
489
560
  * Creates an ArchiveCache instance.
490
561
  * @param db - DB for the cache to use
@@ -501,20 +572,12 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
501
572
  * @returns The transaction, if found, 'undefined' otherwise.
502
573
  */
503
574
  private async getPendingTxByHash(txHash: TxHash | string): Promise<Tx | undefined> {
504
- let key;
505
575
  if (typeof txHash === 'string') {
506
- key = txHash;
507
576
  txHash = TxHash.fromString(txHash);
508
- } else {
509
- key = txHash.toString();
510
577
  }
511
578
 
512
- if (this.#pendingTxs.has(key)) {
513
- return this.#pendingTxs.get(key);
514
- }
515
579
  const tx = await this.getTxByHash(txHash);
516
580
  if (tx) {
517
- this.#pendingTxs.set(key, tx);
518
581
  return tx;
519
582
  }
520
583
  return undefined;
@@ -522,6 +585,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
522
585
 
523
586
  /**
524
587
  * Archives a list of txs for future reference. The number of archived txs is limited by the specified archivedTxLimit.
588
+ * Note: Pending txs should not be archived, only finalized txs
525
589
  * @param txs - The list of transactions to archive.
526
590
  * @returns Empty promise.
527
591
  */
@@ -529,6 +593,10 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
529
593
  if (txs.length === 0) {
530
594
  return;
531
595
  }
596
+ if (this.#archivedTxLimit === 0) {
597
+ return;
598
+ }
599
+
532
600
  try {
533
601
  const txHashes = await Promise.all(txs.map(tx => tx.getTxHash()));
534
602
  await this.#archive.transactionAsync(async () => {
@@ -568,183 +636,56 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
568
636
  }
569
637
  }
570
638
 
571
- /**
572
- * Evicts pending txs with the lowest priority fees from the pool to accomodate the max tx count and cumulative max tx size
573
- * after new txs are added.
574
- *
575
- * @param newTxHashes - The tx hashes of the new txs added to the pool.
576
- * @returns The total number of txs evicted from the pool and the number of new txs that were evicted.
577
- */
578
- private async evictLowPriorityTxs(
579
- newTxHashes: TxHash[],
580
- ): Promise<{ numLowPriorityTxsEvicted: number; numNewTxsEvicted: number }> {
581
- if (this.#maxTxPoolSize === undefined || this.#maxTxPoolSize === 0) {
582
- return { numLowPriorityTxsEvicted: 0, numNewTxsEvicted: 0 };
583
- }
584
-
585
- let numNewTxsEvicted = 0;
586
- const txsToEvict: TxHash[] = [];
587
-
588
- let pendingTxsSize = (await this.#pendingTxSize.getAsync()) ?? 0;
589
- if (pendingTxsSize > this.#maxTxPoolSize * this.txPoolOverflowFactor) {
590
- for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()) {
591
- if (this.#nonEvictableTxs.has(txHash.toString())) {
592
- continue;
593
- }
594
- const txSize =
595
- (await this.#pendingTxHashToSize.getAsync(txHash.toString())) ??
596
- (await this.getPendingTxByHash(txHash))?.getSize();
597
-
598
- this.#log.verbose(`Evicting tx ${txHash} from pool due to low priority to satisfy max tx size limit`, {
599
- txHash,
600
- txSize,
601
- });
602
-
603
- txsToEvict.push(TxHash.fromString(txHash));
604
-
605
- if (txSize) {
606
- pendingTxsSize -= txSize;
607
- if (pendingTxsSize <= this.#maxTxPoolSize) {
608
- break;
609
- }
610
- }
611
- }
612
- numNewTxsEvicted += newTxHashes.filter(txHash => txsToEvict.includes(txHash)).length;
613
- }
614
-
615
- if (txsToEvict.length > 0) {
616
- await this.deleteTxs(txsToEvict, { eviction: true });
617
- }
618
- return {
619
- numLowPriorityTxsEvicted: txsToEvict.length,
620
- numNewTxsEvicted,
621
- };
639
+ // Assumes being called within a DB transaction
640
+ private async addPendingTxIndicesInDbTx(tx: Tx, txHash: string): Promise<void> {
641
+ await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), txHash);
642
+ await this.#historicalHeaderToTxHash.set((await tx.data.constants.anchorBlockHeader.hash()).toString(), txHash);
643
+ await this.#feePayerToTxHash.set(tx.data.feePayer.toString(), txHash);
622
644
  }
623
645
 
624
- /**
625
- * Evicts invalid pending txs from the pool after a txs from a block are mined.
626
- * Eviction criteria includes:
627
- * - txs with nullifiers that are already included in the mined block
628
- * - txs with an insufficient fee payer balance
629
- * - txs with an expiration timestamp lower than that of the mined block
630
- *
631
- * @param minedTxHashes - The tx hashes of the txs mined in the block.
632
- * @param blockHeader - The header of the mined block.
633
- * @returns The total number of txs evicted from the pool.
634
- */
635
- private async evictInvalidTxsAfterMining(
636
- minedTxHashes: TxHash[],
637
- blockHeader: BlockHeader,
638
- minedNullifiers: Set<string>,
639
- minedFeePayers: Set<string>,
640
- ): Promise<number> {
641
- if (minedTxHashes.length === 0) {
642
- return 0;
643
- }
644
-
645
- const { blockNumber, timestamp } = blockHeader.globalVariables;
646
-
647
- // Wait for world state to be synced to at least the mined block number
648
- await this.#worldStateSynchronizer.syncImmediate(blockNumber);
649
-
650
- const db = this.#worldStateSynchronizer.getCommitted();
651
- const gasTxValidator = this.createGasTxValidator(db);
652
-
653
- const txsToEvict: TxHash[] = [];
654
- for await (const txHash of this.#pendingTxPriorityToHash.valuesAsync()) {
655
- const tx = await this.getPendingTxByHash(txHash);
656
- if (!tx) {
657
- continue;
658
- }
659
-
660
- // Evict pending txs that share nullifiers with mined txs
661
- const txNullifiers = tx.data.getNonEmptyNullifiers();
662
- if (txNullifiers.some(nullifier => minedNullifiers.has(nullifier.toString()))) {
663
- this.#log.verbose(`Evicting tx ${txHash} from pool due to a duplicate nullifier with a mined tx`);
664
- txsToEvict.push(TxHash.fromString(txHash));
665
- continue;
666
- }
667
-
668
- // Evict pending txs with an insufficient fee payer balance
669
- if (
670
- minedFeePayers.has(tx.data.feePayer.toString()) &&
671
- (await gasTxValidator.validateTxFee(tx)).result === 'invalid'
672
- ) {
673
- this.#log.verbose(`Evicting tx ${txHash} from pool due to an insufficient fee payer balance`);
674
- txsToEvict.push(TxHash.fromString(txHash));
675
- continue;
676
- }
646
+ private async addPendingTxIndices(tx: Tx, txHash: string): Promise<void> {
647
+ return await this.#store.transactionAsync(async () => {
648
+ await this.addPendingTxIndicesInDbTx(tx, txHash);
649
+ });
650
+ }
677
651
 
678
- // Evict pending txs with an expiration timestamp less than or equal to the mined block timestamp
679
- const includeByTimestamp = tx.data.includeByTimestamp;
680
- if (includeByTimestamp <= timestamp) {
681
- this.#log.verbose(
682
- `Evicting tx ${txHash} from pool due to the tx being expired (includeByTimestamp: ${includeByTimestamp}, mined block timestamp: ${timestamp})`,
683
- );
684
- txsToEvict.push(TxHash.fromString(txHash));
685
- continue;
686
- }
687
- }
652
+ // Assumes being called within a DB transaction
653
+ private async removePendingTxIndicesInDbTx(tx: Tx, txHash: string): Promise<void> {
654
+ await this.#pendingTxPriorityToHash.deleteValue(getPendingTxPriority(tx), txHash);
655
+ await this.#historicalHeaderToTxHash.deleteValue(
656
+ (await tx.data.constants.anchorBlockHeader.hash()).toString(),
657
+ txHash,
658
+ );
659
+ await this.#feePayerToTxHash.deleteValue(tx.data.feePayer.toString(), txHash);
660
+ }
688
661
 
689
- if (txsToEvict.length > 0) {
690
- await this.deleteTxs(txsToEvict, { eviction: true });
691
- }
692
- return txsToEvict.length;
662
+ private async removePendingTxIndices(tx: Tx, txHash: string): Promise<void> {
663
+ return await this.#store.transactionAsync(async () => {
664
+ await this.removePendingTxIndicesInDbTx(tx, txHash);
665
+ });
693
666
  }
694
667
 
695
668
  /**
696
- * Evicts pending txs that no longer have valid archive roots or fee payer balances from the pool after a reorg.
697
- *
698
- * @param txHashes - The tx hashes of the txs that were moved from mined to pending.
699
- * @returns The total number of txs evicted from the pool.
669
+ * Returns up to `limit` lowest-priority evictable pending tx hashes without hydrating transactions.
670
+ * Iterates the priority index in ascending order and skips non-evictable txs.
700
671
  */
701
- private async evictInvalidTxsAfterReorg(txHashes: TxHash[]): Promise<number> {
702
- if (txHashes.length === 0) {
703
- return 0;
704
- }
705
-
706
- await this.#worldStateSynchronizer.syncImmediate();
707
- const db = this.#worldStateSynchronizer.getCommitted();
708
- const archiveCache = this.createArchiveCache(db);
709
- const gasTxValidator = this.createGasTxValidator(db);
710
-
672
+ public async getLowestPriorityEvictable(limit: number): Promise<TxHash[]> {
711
673
  const txsToEvict: TxHash[] = [];
674
+ if (limit <= 0) {
675
+ return txsToEvict;
676
+ }
712
677
 
713
- for await (const [txHash, headerHash] of this.#pendingTxHashToHeaderHash.entriesAsync()) {
714
- const tx = await this.getPendingTxByHash(txHash);
715
- if (!tx) {
716
- continue;
717
- }
718
-
719
- const [index] = await archiveCache.getArchiveIndices([Fr.fromString(headerHash)]);
720
- if (index === undefined) {
721
- this.#log.verbose(`Evicting tx ${txHash} from pool due to an invalid archive root`);
722
- txsToEvict.push(TxHash.fromString(txHash));
678
+ for await (const txHashStr of this.#pendingTxPriorityToHash.valuesAsync()) {
679
+ if (this.#nonEvictableTxs.has(txHashStr)) {
723
680
  continue;
724
681
  }
725
682
 
726
- if ((await gasTxValidator.validateTxFee(tx)).result === 'invalid') {
727
- this.#log.verbose(`Evicting tx ${txHash} from pool due to an insufficient fee payer balance`);
728
- txsToEvict.push(TxHash.fromString(txHash));
683
+ txsToEvict.push(TxHash.fromString(txHashStr));
684
+ if (txsToEvict.length >= limit) {
685
+ break;
729
686
  }
730
687
  }
731
688
 
732
- if (txsToEvict.length > 0) {
733
- await this.deleteTxs(txsToEvict, { eviction: true });
734
- }
735
- return txsToEvict.length;
736
- }
737
-
738
- private async addPendingTxIndices(tx: Tx, txHash: string): Promise<void> {
739
- await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), txHash);
740
- await this.#pendingTxHashToSize.set(txHash, tx.getSize());
741
- await this.#pendingTxHashToHeaderHash.set(txHash, (await tx.data.constants.anchorBlockHeader.hash()).toString());
742
- }
743
-
744
- private async removePendingTxIndices(tx: Tx, txHash: string): Promise<void> {
745
- await this.#pendingTxPriorityToHash.deleteValue(getPendingTxPriority(tx), txHash);
746
- await this.#pendingTxHashToSize.delete(txHash);
747
- await this.#pendingTxHashToHeaderHash.delete(txHash);
748
- this.#pendingTxs.delete(txHash);
689
+ return txsToEvict;
749
690
  }
750
691
  }