@aztec/p2p 0.0.1-commit.21ecf947b → 0.0.1-commit.2448fdb

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 (281) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +6 -6
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +31 -28
  5. package/dest/client/interface.d.ts +10 -19
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +7 -18
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +51 -96
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +6 -7
  11. package/dest/config.d.ts +29 -10
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +80 -31
  14. package/dest/errors/tx-pool.error.d.ts +8 -0
  15. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  16. package/dest/errors/tx-pool.error.js +9 -0
  17. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  18. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  19. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
  20. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  21. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool/priority.js +4 -4
  23. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  24. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  26. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -1
  27. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +9 -0
  29. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  30. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  32. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  33. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +5 -4
  35. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  36. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  38. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -2
  39. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -1
  41. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
  42. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  44. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +2 -2
  45. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +5 -5
  46. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  47. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  48. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +12 -6
  49. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  50. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  51. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
  52. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  53. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  54. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
  55. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  56. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  57. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  58. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  59. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  60. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  61. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +18 -6
  62. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  63. package/dest/mem_pools/tx_pool_v2/interfaces.js +3 -1
  64. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +49 -9
  65. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  66. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +102 -14
  67. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +5 -2
  68. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  69. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +21 -12
  70. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -4
  71. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  72. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +9 -5
  73. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +11 -5
  74. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  75. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +279 -153
  76. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  77. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  78. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  79. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  80. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  81. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  82. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  83. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  84. package/dest/msg_validators/proposal_validator/proposal_validator.js +48 -36
  85. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  86. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  87. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  88. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  89. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  90. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  91. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  92. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  93. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  94. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  95. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  96. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  97. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  98. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  99. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  100. package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
  101. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  102. package/dest/msg_validators/tx_validator/factory.js +247 -60
  103. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  104. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  105. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  106. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  107. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  108. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  109. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  110. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  111. package/dest/msg_validators/tx_validator/index.js +2 -0
  112. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  113. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  114. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  115. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  116. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  117. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  118. package/dest/services/dummy_service.d.ts +4 -4
  119. package/dest/services/dummy_service.d.ts.map +1 -1
  120. package/dest/services/dummy_service.js +4 -4
  121. package/dest/services/encoding.d.ts +6 -2
  122. package/dest/services/encoding.d.ts.map +1 -1
  123. package/dest/services/encoding.js +16 -9
  124. package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
  125. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  126. package/dest/services/gossipsub/topic_score_params.js +32 -10
  127. package/dest/services/libp2p/libp2p_service.d.ts +16 -13
  128. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  129. package/dest/services/libp2p/libp2p_service.js +97 -93
  130. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
  131. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  132. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +5 -9
  133. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
  134. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  135. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -13
  136. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  137. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +25 -46
  138. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  139. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  140. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  141. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  142. package/dest/services/reqresp/reqresp.d.ts +1 -1
  143. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  144. package/dest/services/reqresp/reqresp.js +17 -9
  145. package/dest/services/service.d.ts +5 -3
  146. package/dest/services/service.d.ts.map +1 -1
  147. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -1
  148. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  149. package/dest/services/tx_collection/fast_tx_collection.js +39 -33
  150. package/dest/services/tx_collection/file_store_tx_collection.d.ts +1 -1
  151. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  152. package/dest/services/tx_collection/file_store_tx_collection.js +4 -2
  153. package/dest/services/tx_collection/file_store_tx_source.d.ts +16 -6
  154. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  155. package/dest/services/tx_collection/file_store_tx_source.js +50 -9
  156. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  157. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  158. package/dest/services/tx_collection/instrumentation.js +2 -1
  159. package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
  160. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
  161. package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
  162. package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
  163. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  164. package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
  165. package/dest/services/tx_collection/slow_tx_collection.d.ts +2 -2
  166. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  167. package/dest/services/tx_collection/slow_tx_collection.js +10 -8
  168. package/dest/services/tx_collection/tx_collection.d.ts +5 -4
  169. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  170. package/dest/services/tx_collection/tx_collection_sink.d.ts +6 -5
  171. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  172. package/dest/services/tx_collection/tx_collection_sink.js +13 -22
  173. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  174. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  175. package/dest/services/tx_collection/tx_source.js +26 -7
  176. package/dest/services/tx_file_store/tx_file_store.js +1 -1
  177. package/dest/services/tx_provider.d.ts +3 -3
  178. package/dest/services/tx_provider.d.ts.map +1 -1
  179. package/dest/services/tx_provider.js +4 -4
  180. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  181. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  182. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  183. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  184. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  185. package/dest/test-helpers/mock-pubsub.js +8 -2
  186. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  187. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  188. package/dest/test-helpers/reqresp-nodes.js +2 -2
  189. package/dest/test-helpers/testbench-utils.d.ts +6 -3
  190. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  191. package/dest/test-helpers/testbench-utils.js +3 -2
  192. package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
  193. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  194. package/dest/testbench/p2p_client_testbench_worker.js +13 -12
  195. package/dest/testbench/worker_client_manager.d.ts +3 -1
  196. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  197. package/dest/testbench/worker_client_manager.js +4 -1
  198. package/dest/util.d.ts +2 -2
  199. package/dest/util.d.ts.map +1 -1
  200. package/package.json +14 -14
  201. package/src/client/factory.ts +53 -46
  202. package/src/client/interface.ts +11 -20
  203. package/src/client/p2p_client.ts +55 -126
  204. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -10
  205. package/src/config.ts +115 -33
  206. package/src/errors/tx-pool.error.ts +12 -0
  207. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  208. package/src/mem_pools/tx_pool/priority.ts +4 -4
  209. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  210. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  211. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +11 -0
  212. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  213. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +5 -4
  214. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  215. package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
  216. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
  217. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +2 -2
  218. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -5
  219. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +12 -9
  220. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
  221. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
  222. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  223. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  224. package/src/mem_pools/tx_pool_v2/interfaces.ts +17 -6
  225. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +143 -17
  226. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +25 -14
  227. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +25 -8
  228. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +311 -148
  229. package/src/msg_validators/attestation_validator/README.md +49 -0
  230. package/src/msg_validators/proposal_validator/README.md +123 -0
  231. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  232. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  233. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -40
  234. package/src/msg_validators/tx_validator/README.md +119 -0
  235. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
  236. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  237. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  238. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  239. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  240. package/src/msg_validators/tx_validator/factory.ts +394 -78
  241. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  242. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  243. package/src/msg_validators/tx_validator/index.ts +2 -0
  244. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  245. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  246. package/src/services/dummy_service.ts +6 -6
  247. package/src/services/encoding.ts +16 -8
  248. package/src/services/gossipsub/README.md +29 -14
  249. package/src/services/gossipsub/topic_score_params.ts +49 -13
  250. package/src/services/libp2p/libp2p_service.ts +111 -101
  251. package/src/services/reqresp/README.md +229 -0
  252. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +6 -6
  253. package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
  254. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
  255. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  256. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  257. package/src/services/reqresp/reqresp.ts +19 -11
  258. package/src/services/service.ts +11 -2
  259. package/src/services/tx_collection/fast_tx_collection.ts +51 -30
  260. package/src/services/tx_collection/file_store_tx_collection.ts +7 -3
  261. package/src/services/tx_collection/file_store_tx_source.ts +65 -9
  262. package/src/services/tx_collection/instrumentation.ts +7 -1
  263. package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
  264. package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
  265. package/src/services/tx_collection/slow_tx_collection.ts +8 -9
  266. package/src/services/tx_collection/tx_collection.ts +4 -3
  267. package/src/services/tx_collection/tx_collection_sink.ts +15 -29
  268. package/src/services/tx_collection/tx_source.ts +28 -8
  269. package/src/services/tx_file_store/tx_file_store.ts +1 -1
  270. package/src/services/tx_provider.ts +2 -2
  271. package/src/test-helpers/make-test-p2p-clients.ts +0 -2
  272. package/src/test-helpers/mock-pubsub.ts +13 -6
  273. package/src/test-helpers/reqresp-nodes.ts +2 -5
  274. package/src/test-helpers/testbench-utils.ts +4 -3
  275. package/src/testbench/p2p_client_testbench_worker.ts +21 -17
  276. package/src/testbench/worker_client_manager.ts +11 -4
  277. package/src/util.ts +7 -1
  278. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  279. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  280. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  281. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
@@ -9,6 +9,7 @@ import type { L2Block, L2BlockId, L2BlockSource } from '@aztec/stdlib/block';
9
9
  import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
10
10
  import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
11
11
  import { BlockHeader, Tx, TxHash, type TxValidator } from '@aztec/stdlib/tx';
12
+ import type { TelemetryClient } from '@aztec/telemetry-client';
12
13
 
13
14
  import { TxArchive } from './archive/index.js';
14
15
  import { DeletedPool } from './deleted_pool.js';
@@ -22,8 +23,12 @@ import {
22
23
  LowPriorityPreAddRule,
23
24
  NullifierConflictRule,
24
25
  type PoolOperations,
26
+ type PreAddContext,
25
27
  type PreAddPoolAccess,
28
+ TxPoolRejectionCode,
29
+ type TxPoolRejectionError,
26
30
  } from './eviction/index.js';
31
+ import { TxPoolV2Instrumentation } from './instrumentation.js';
27
32
  import {
28
33
  type AddTxsResult,
29
34
  DEFAULT_TX_POOL_V2_CONFIG,
@@ -56,6 +61,7 @@ export class TxPoolV2Impl {
56
61
  #l2BlockSource: L2BlockSource;
57
62
  #worldStateSynchronizer: WorldStateSynchronizer;
58
63
  #createTxValidator: TxPoolV2Dependencies['createTxValidator'];
64
+ #checkAllowedSetupCalls: TxPoolV2Dependencies['checkAllowedSetupCalls'];
59
65
 
60
66
  // === In-Memory Indices ===
61
67
  #indices: TxPoolIndices = new TxPoolIndices();
@@ -66,6 +72,8 @@ export class TxPoolV2Impl {
66
72
  #deletedPool: DeletedPool;
67
73
  #evictionManager: EvictionManager;
68
74
  #dateProvider: DateProvider;
75
+ #instrumentation: TxPoolV2Instrumentation;
76
+ #evictedTxHashes: Set<string> = new Set();
69
77
  #log: Logger;
70
78
  #callbacks: TxPoolV2Callbacks;
71
79
 
@@ -74,6 +82,7 @@ export class TxPoolV2Impl {
74
82
  archiveStore: AztecAsyncKVStore,
75
83
  deps: TxPoolV2Dependencies,
76
84
  callbacks: TxPoolV2Callbacks,
85
+ telemetry: TelemetryClient,
77
86
  config: Partial<TxPoolV2Config> = {},
78
87
  dateProvider: DateProvider,
79
88
  log: Logger,
@@ -84,11 +93,13 @@ export class TxPoolV2Impl {
84
93
  this.#l2BlockSource = deps.l2BlockSource;
85
94
  this.#worldStateSynchronizer = deps.worldStateSynchronizer;
86
95
  this.#createTxValidator = deps.createTxValidator;
96
+ this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
87
97
 
88
98
  this.#config = { ...DEFAULT_TX_POOL_V2_CONFIG, ...config };
89
99
  this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
90
100
  this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
91
101
  this.#dateProvider = dateProvider;
102
+ this.#instrumentation = new TxPoolV2Instrumentation(telemetry, () => this.#indices.getTotalMetadataBytes());
92
103
  this.#log = log;
93
104
  this.#callbacks = callbacks;
94
105
 
@@ -171,13 +182,42 @@ export class TxPoolV2Impl {
171
182
  this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, { txHashes: toDelete });
172
183
  }
173
184
 
174
- async addPendingTxs(txs: Tx[], opts: { source?: string }): Promise<AddTxsResult> {
185
+ async addPendingTxs(txs: Tx[], opts: { source?: string; feeComparisonOnly?: boolean }): Promise<AddTxsResult> {
175
186
  const accepted: TxHash[] = [];
176
187
  const ignored: TxHash[] = [];
177
188
  const rejected: TxHash[] = [];
189
+ const errors = new Map<string, TxPoolRejectionError>();
178
190
  const acceptedPending = new Set<string>();
179
191
 
192
+ // Phase 1: Pre-compute all throwable I/O outside the transaction.
193
+ // If any pre-computation throws, the entire call fails before mutations happen.
194
+ const precomputed = new Map<string, { meta: TxMetaData; minedBlockId: L2BlockId | undefined; isValid: boolean }>();
195
+
196
+ const validator = await this.#createTxValidator();
197
+
198
+ for (const tx of txs) {
199
+ const txHash = tx.getTxHash();
200
+ const txHashStr = txHash.toString();
201
+
202
+ const meta = await buildTxMetaData(tx);
203
+ const minedBlockId = await this.#getMinedBlockId(txHash);
204
+
205
+ // Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
206
+ let isValid = true;
207
+ if (!minedBlockId) {
208
+ isValid = await this.#validateMeta(meta, validator);
209
+ }
210
+
211
+ precomputed.set(txHashStr, { meta, minedBlockId, isValid });
212
+ }
213
+
214
+ // Phase 2: Apply mutations inside the transaction using only pre-computed results,
215
+ // in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
180
216
  const poolAccess = this.#createPreAddPoolAccess();
217
+ const preAddContext: PreAddContext | undefined =
218
+ opts.feeComparisonOnly !== undefined
219
+ ? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
220
+ : undefined;
181
221
 
182
222
  await this.#store.transactionAsync(async () => {
183
223
  for (const tx of txs) {
@@ -190,30 +230,46 @@ export class TxPoolV2Impl {
190
230
  continue;
191
231
  }
192
232
 
193
- // Check mined status first (applies to all paths)
194
- const minedBlockId = await this.#getMinedBlockId(txHash);
233
+ const { meta, minedBlockId, isValid } = precomputed.get(txHashStr)!;
195
234
  const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
196
235
 
197
236
  if (minedBlockId) {
198
237
  // Already mined - add directly (protection already set if pre-protected)
199
- await this.#addTx(tx, { mined: minedBlockId }, opts);
238
+ await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
200
239
  accepted.push(txHash);
201
240
  } else if (preProtectedSlot !== undefined) {
202
241
  // Pre-protected and not mined - add as protected (bypass validation)
203
- await this.#addTx(tx, { protected: preProtectedSlot }, opts);
242
+ await this.#addTx(tx, { protected: preProtectedSlot }, opts, meta);
204
243
  accepted.push(txHash);
244
+ } else if (!isValid) {
245
+ // Failed pre-computed validation
246
+ rejected.push(txHash);
205
247
  } else {
206
- // Regular pending tx - validate and run pre-add rules
207
- const result = await this.#tryAddRegularPendingTx(tx, opts, poolAccess, acceptedPending, ignored);
248
+ // Regular pending tx - run pre-add rules using pre-computed metadata
249
+ const result = await this.#tryAddRegularPendingTx(
250
+ tx,
251
+ meta,
252
+ opts,
253
+ poolAccess,
254
+ acceptedPending,
255
+ ignored,
256
+ errors,
257
+ preAddContext,
258
+ );
208
259
  if (result.status === 'accepted') {
209
260
  acceptedPending.add(txHashStr);
210
- } else if (result.status === 'rejected') {
211
- rejected.push(txHash);
212
261
  } else {
213
262
  ignored.push(txHash);
214
263
  }
215
264
  }
216
265
  }
266
+
267
+ // Run post-add eviction rules for pending txs (inside transaction for atomicity)
268
+ if (acceptedPending.size > 0) {
269
+ const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
270
+ const uniqueFeePayers = new Set<string>(feePayers);
271
+ await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
272
+ }
217
273
  });
218
274
 
219
275
  // Build final accepted list for pending txs (excludes intra-batch evictions)
@@ -221,61 +277,74 @@ export class TxPoolV2Impl {
221
277
  accepted.push(TxHash.fromString(txHashStr));
222
278
  }
223
279
 
224
- // Run post-add eviction rules for pending txs
225
- if (acceptedPending.size > 0) {
226
- const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
227
- const uniqueFeePayers = new Set<string>(feePayers);
228
- await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
280
+ // Record metrics
281
+ if (ignored.length > 0) {
282
+ this.#instrumentation.recordIgnored(ignored.length);
283
+ }
284
+ if (rejected.length > 0) {
285
+ this.#instrumentation.recordRejected(rejected.length);
229
286
  }
230
287
 
231
- return { accepted, ignored, rejected };
288
+ return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
232
289
  }
233
290
 
234
- /** Validates and adds a regular pending tx. Returns status. */
291
+ /** Adds a validated pending tx, running pre-add rules and evicting conflicts. */
235
292
  async #tryAddRegularPendingTx(
236
293
  tx: Tx,
294
+ precomputedMeta: TxMetaData,
237
295
  opts: { source?: string },
238
296
  poolAccess: PreAddPoolAccess,
239
297
  acceptedPending: Set<string>,
240
298
  ignored: TxHash[],
241
- ): Promise<{ status: 'accepted' | 'ignored' | 'rejected' }> {
242
- const txHash = tx.getTxHash();
243
- const txHashStr = txHash.toString();
244
-
245
- // Build metadata and validate using metadata
246
- const meta = await buildTxMetaData(tx);
247
- if (!(await this.#validateMeta(meta))) {
248
- return { status: 'rejected' };
249
- }
299
+ errors: Map<string, TxPoolRejectionError>,
300
+ preAddContext?: PreAddContext,
301
+ ): Promise<{ status: 'accepted' | 'ignored' }> {
302
+ const txHashStr = tx.getTxHash().toString();
250
303
 
251
304
  // Run pre-add rules
252
- const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
305
+ const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
253
306
 
254
307
  if (preAddResult.shouldIgnore) {
255
- this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
308
+ this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
309
+ if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
310
+ errors.set(txHashStr, preAddResult.reason);
311
+ }
256
312
  return { status: 'ignored' };
257
313
  }
258
314
 
259
- // Evict conflicts
260
- for (const evictHashStr of preAddResult.txHashesToEvict) {
261
- await this.#deleteTx(evictHashStr);
262
- this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
263
- evictedTxHash: evictHashStr,
264
- replacementTxHash: txHashStr,
265
- });
266
- if (acceptedPending.has(evictHashStr)) {
267
- // Evicted tx was from this batch - mark as ignored in result
268
- acceptedPending.delete(evictHashStr);
269
- ignored.push(TxHash.fromString(evictHashStr));
315
+ // Evict conflicts, grouped by rule name for metrics
316
+ if (preAddResult.evictions && preAddResult.evictions.length > 0) {
317
+ const byReason = new Map<string, string[]>();
318
+ for (const { txHash: evictHash, reason } of preAddResult.evictions) {
319
+ const group = byReason.get(reason);
320
+ if (group) {
321
+ group.push(evictHash);
322
+ } else {
323
+ byReason.set(reason, [evictHash]);
324
+ }
325
+ }
326
+ for (const [reason, hashes] of byReason) {
327
+ await this.#evictTxs(hashes, reason);
328
+ }
329
+ for (const evictHashStr of preAddResult.txHashesToEvict) {
330
+ this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
331
+ evictedTxHash: evictHashStr,
332
+ replacementTxHash: txHashStr,
333
+ });
334
+ if (acceptedPending.has(evictHashStr)) {
335
+ // Evicted tx was from this batch - mark as ignored in result
336
+ acceptedPending.delete(evictHashStr);
337
+ ignored.push(TxHash.fromString(evictHashStr));
338
+ }
270
339
  }
271
340
  }
272
341
 
273
342
  // Add the transaction
274
- await this.#addTx(tx, 'pending', opts);
343
+ await this.#addTx(tx, 'pending', opts, precomputedMeta);
275
344
  return { status: 'accepted' };
276
345
  }
277
346
 
278
- async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored' | 'rejected'> {
347
+ async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
279
348
  const txHashStr = tx.getTxHash().toString();
280
349
 
281
350
  // Check if already in pool
@@ -283,14 +352,8 @@ export class TxPoolV2Impl {
283
352
  return 'ignored';
284
353
  }
285
354
 
286
- // Build metadata and validate using metadata
355
+ // Build metadata and check pre-add rules
287
356
  const meta = await buildTxMetaData(tx);
288
- const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
289
- if (validationResult !== true) {
290
- return 'rejected';
291
- }
292
-
293
- // Use pre-add rules
294
357
  const poolAccess = this.#createPreAddPoolAccess();
295
358
  const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
296
359
 
@@ -300,20 +363,25 @@ export class TxPoolV2Impl {
300
363
  async addProtectedTxs(txs: Tx[], block: BlockHeader, opts: { source?: string }): Promise<void> {
301
364
  const slotNumber = block.globalVariables.slotNumber;
302
365
 
366
+ // Precompute setup-call allow-list flags outside the store transaction
367
+ const allowedFlags = await Promise.all(txs.map(tx => this.#checkAllowedSetupCalls(tx)));
368
+
303
369
  await this.#store.transactionAsync(async () => {
304
- for (const tx of txs) {
370
+ for (let i = 0; i < txs.length; i++) {
371
+ const tx = txs[i];
305
372
  const txHash = tx.getTxHash();
306
373
  const txHashStr = txHash.toString();
307
374
  const isNew = !this.#indices.has(txHashStr);
308
375
  const minedBlockId = await this.#getMinedBlockId(txHash);
309
376
 
310
377
  if (isNew) {
378
+ const meta = await buildTxMetaData(tx, allowedFlags[i]);
311
379
  // New tx - add as mined or protected (callback emitted by #addTx)
312
380
  if (minedBlockId) {
313
- await this.#addTx(tx, { mined: minedBlockId }, opts);
381
+ await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
314
382
  this.#indices.setProtection(txHashStr, slotNumber);
315
383
  } else {
316
- await this.#addTx(tx, { protected: slotNumber }, opts);
384
+ await this.#addTx(tx, { protected: slotNumber }, opts, meta);
317
385
  }
318
386
  } else {
319
387
  // Existing tx - update protection and mined status
@@ -327,23 +395,58 @@ export class TxPoolV2Impl {
327
395
  });
328
396
  }
329
397
 
330
- protectTxs(txHashes: TxHash[], block: BlockHeader): TxHash[] {
398
+ async protectTxs(txHashes: TxHash[], block: BlockHeader): Promise<TxHash[]> {
331
399
  const slotNumber = block.globalVariables.slotNumber;
332
400
  const missing: TxHash[] = [];
401
+ let softDeletedHits = 0;
402
+ let missingPreviouslyEvicted = 0;
333
403
 
334
- for (const txHash of txHashes) {
335
- const txHashStr = txHash.toString();
404
+ await this.#store.transactionAsync(async () => {
405
+ for (const txHash of txHashes) {
406
+ const txHashStr = txHash.toString();
336
407
 
337
- if (this.#indices.has(txHashStr)) {
338
- // Update protection for existing tx
339
- this.#indices.updateProtection(txHashStr, slotNumber);
340
- } else {
341
- // Pre-record protection for tx we don't have yet
342
- this.#indices.setProtection(txHashStr, slotNumber);
343
- missing.push(txHash);
408
+ if (this.#indices.has(txHashStr)) {
409
+ // Update protection for existing tx
410
+ this.#indices.updateProtection(txHashStr, slotNumber);
411
+ } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
412
+ // Resurrect soft-deleted tx as protected
413
+ const buffer = await this.#txsDB.getAsync(txHashStr);
414
+ if (buffer) {
415
+ const tx = Tx.fromBuffer(buffer);
416
+ await this.#addTx(tx, { protected: slotNumber });
417
+ softDeletedHits++;
418
+ } else {
419
+ // Data missing despite soft-delete flag — treat as truly missing
420
+ this.#indices.setProtection(txHashStr, slotNumber);
421
+ missing.push(txHash);
422
+ }
423
+ } else {
424
+ // Truly missing — pre-record protection for tx we don't have yet
425
+ this.#indices.setProtection(txHashStr, slotNumber);
426
+ missing.push(txHash);
427
+ if (this.#evictedTxHashes.has(txHashStr)) {
428
+ missingPreviouslyEvicted++;
429
+ }
430
+ }
344
431
  }
432
+ });
433
+
434
+ // Record metrics
435
+ if (softDeletedHits > 0) {
436
+ this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
437
+ }
438
+ if (missing.length > 0) {
439
+ this.#log.debug(`protectTxs missing tx hashes: ${missing.map(h => h.toString()).join(', ')}`);
440
+ this.#instrumentation.recordMissingOnProtect(missing.length);
441
+ }
442
+ if (missingPreviouslyEvicted > 0) {
443
+ this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
345
444
  }
346
445
 
446
+ this.#log.info(
447
+ `Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`,
448
+ );
449
+
347
450
  return missing;
348
451
  }
349
452
 
@@ -387,57 +490,63 @@ export class TxPoolV2Impl {
387
490
  }
388
491
  }
389
492
 
390
- // Step 4: Mark txs as mined (only those we have in the pool)
391
- for (const meta of found) {
392
- this.#indices.markAsMined(meta, blockId);
393
- await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
394
- }
493
+ await this.#store.transactionAsync(async () => {
494
+ // Step 4: Mark txs as mined (only those we have in the pool)
495
+ for (const meta of found) {
496
+ this.#indices.markAsMined(meta, blockId);
497
+ await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
498
+ }
395
499
 
396
- // Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
397
- await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
500
+ // Step 5: Run post-event eviction rules (inside transaction for atomicity)
501
+ await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
502
+ });
398
503
 
399
504
  this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
400
505
  }
401
506
 
402
507
  async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
403
- // Step 0: Clean up slot-deleted txs from previous slots
404
- await this.#deletedPool.cleanupSlotDeleted(slotNumber);
508
+ await this.#store.transactionAsync(async () => {
509
+ // Step 0: Clean up slot-deleted txs from previous slots
510
+ await this.#deletedPool.cleanupSlotDeleted(slotNumber);
405
511
 
406
- // Step 1: Find expired protected txs
407
- const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
512
+ // Step 1: Find expired protected txs
513
+ const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
408
514
 
409
- // Step 2: Clear protection for all expired entries (including those without metadata)
410
- this.#indices.clearProtection(expiredProtected);
515
+ // Step 2: Clear protection for all expired entries (including those without metadata)
516
+ this.#indices.clearProtection(expiredProtected);
411
517
 
412
- // Step 3: Filter to only txs that have metadata and are not mined
413
- const txsToRestore = this.#indices.filterRestorable(expiredProtected);
414
- if (txsToRestore.length === 0) {
415
- return;
416
- }
518
+ // Step 3: Filter to only txs that have metadata and are not mined
519
+ const txsToRestore = this.#indices.filterRestorable(expiredProtected);
520
+ if (txsToRestore.length === 0) {
521
+ this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
522
+ return;
523
+ }
417
524
 
418
- this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
525
+ this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
419
526
 
420
- // Step 4: Validate for pending pool
421
- const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
527
+ // Step 4: Validate for pending pool
528
+ const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
422
529
 
423
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
424
- const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
530
+ // Step 5: Resolve nullifier conflicts and add winners to pending indices
531
+ const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
425
532
 
426
- // Step 6: Delete invalid and evicted txs
427
- await this.#deleteTxsBatch([...invalid, ...toEvict]);
533
+ // Step 6: Delete invalid txs and evict conflict losers
534
+ await this.#deleteTxsBatch(invalid);
535
+ await this.#evictTxs(toEvict, 'NullifierConflict');
428
536
 
429
- // Step 7: Run eviction rules (enforce pool size limit)
430
- if (added.length > 0) {
431
- const feePayers = added.map(meta => meta.feePayer);
432
- const uniqueFeePayers = new Set<string>(feePayers);
433
- await this.#evictionManager.evictAfterNewTxs(
434
- added.map(m => m.txHash),
435
- [...uniqueFeePayers],
436
- );
437
- }
537
+ // Step 7: Run eviction rules (enforce pool size limit)
538
+ if (added.length > 0) {
539
+ const feePayers = added.map(meta => meta.feePayer);
540
+ const uniqueFeePayers = new Set<string>(feePayers);
541
+ await this.#evictionManager.evictAfterNewTxs(
542
+ added.map(m => m.txHash),
543
+ [...uniqueFeePayers],
544
+ );
545
+ }
546
+ });
438
547
  }
439
548
 
440
- async handlePrunedBlocks(latestBlock: L2BlockId): Promise<void> {
549
+ async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
441
550
  // Step 1: Find transactions mined after the prune point
442
551
  const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
443
552
  if (txsToUnmine.length === 0) {
@@ -447,46 +556,60 @@ export class TxPoolV2Impl {
447
556
 
448
557
  this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
449
558
 
450
- // Step 2: Mark ALL un-mined txs with their original mined block number
451
- // This ensures they get soft-deleted if removed later, and only hard-deleted
452
- // when their original mined block is finalized
453
- await this.#deletedPool.markFromPrunedBlock(
454
- txsToUnmine.map(m => ({
455
- txHash: m.txHash,
456
- minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
457
- })),
458
- );
559
+ await this.#store.transactionAsync(async () => {
560
+ // Step 2: Mark ALL un-mined txs with their original mined block number
561
+ // This ensures they get soft-deleted if removed later, and only hard-deleted
562
+ // when their original mined block is finalized
563
+ await this.#deletedPool.markFromPrunedBlock(
564
+ txsToUnmine.map(m => ({
565
+ txHash: m.txHash,
566
+ minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
567
+ })),
568
+ );
459
569
 
460
- // Step 3: Unmine - clear mined status from metadata
461
- for (const meta of txsToUnmine) {
462
- this.#indices.markAsUnmined(meta);
463
- }
570
+ // Step 3: Unmine - clear mined status from metadata
571
+ for (const meta of txsToUnmine) {
572
+ this.#indices.markAsUnmined(meta);
573
+ }
464
574
 
465
- // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
466
- const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
575
+ // If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
576
+ if (options?.deleteAllTxs) {
577
+ const allTxHashes = txsToUnmine.map(m => m.txHash);
578
+ await this.#deleteTxsBatch(allTxHashes);
579
+ this.#log.info(
580
+ `Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
581
+ );
582
+ return;
583
+ }
467
584
 
468
- // Step 4: Validate for pending pool
469
- const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
585
+ // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
586
+ const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
470
587
 
471
- // Step 6: Resolve nullifier conflicts and add winners to pending indices
472
- const { toEvict } = this.#applyNullifierConflictResolution(valid);
588
+ // Step 5: Validate for pending pool
589
+ const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
473
590
 
474
- // Step 7: Delete invalid and evicted txs
475
- await this.#deleteTxsBatch([...invalid, ...toEvict]);
591
+ // Step 6: Resolve nullifier conflicts and add winners to pending indices
592
+ const { toEvict } = this.#applyNullifierConflictResolution(valid);
476
593
 
477
- this.#log.info(
478
- `Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
479
- { txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
480
- );
594
+ // Step 7: Delete invalid txs and evict conflict losers
595
+ await this.#deleteTxsBatch(invalid);
596
+ await this.#evictTxs(toEvict, 'NullifierConflict');
481
597
 
482
- // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
483
- // This handles cases like existing pending txs with invalid fee payer balances
484
- await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
598
+ this.#log.info(
599
+ `Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
600
+ { txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
601
+ );
602
+
603
+ // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
604
+ // This handles cases like existing pending txs with invalid fee payer balances
605
+ await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
606
+ });
485
607
  }
486
608
 
487
609
  async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
488
- // Delete failed txs
489
- await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
610
+ await this.#store.transactionAsync(async () => {
611
+ await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
612
+ });
490
613
 
491
614
  this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
492
615
  }
@@ -497,27 +620,29 @@ export class TxPoolV2Impl {
497
620
  // Step 1: Find mined txs at or before finalized block
498
621
  const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
499
622
 
500
- // Step 2: Collect mined txs for archiving (before deletion)
501
- const txsToArchive: Tx[] = [];
502
- if (this.#archive.isEnabled()) {
503
- for (const txHashStr of minedTxsToFinalize) {
504
- const buffer = await this.#txsDB.getAsync(txHashStr);
505
- if (buffer) {
506
- txsToArchive.push(Tx.fromBuffer(buffer));
623
+ await this.#store.transactionAsync(async () => {
624
+ // Step 2: Collect mined txs for archiving (before deletion)
625
+ const txsToArchive: Tx[] = [];
626
+ if (this.#archive.isEnabled()) {
627
+ for (const txHashStr of minedTxsToFinalize) {
628
+ const buffer = await this.#txsDB.getAsync(txHashStr);
629
+ if (buffer) {
630
+ txsToArchive.push(Tx.fromBuffer(buffer));
631
+ }
507
632
  }
508
633
  }
509
- }
510
634
 
511
- // Step 3: Delete mined txs from active pool
512
- await this.#deleteTxsBatch(minedTxsToFinalize);
635
+ // Step 3: Delete mined txs from active pool
636
+ await this.#deleteTxsBatch(minedTxsToFinalize);
513
637
 
514
- // Step 4: Finalize soft-deleted txs
515
- await this.#deletedPool.finalizeBlock(blockNumber);
638
+ // Step 4: Finalize soft-deleted txs
639
+ await this.#deletedPool.finalizeBlock(blockNumber);
516
640
 
517
- // Step 5: Archive mined txs
518
- if (txsToArchive.length > 0) {
519
- await this.#archive.archiveTxs(txsToArchive);
520
- }
641
+ // Step 5: Archive mined txs
642
+ if (txsToArchive.length > 0) {
643
+ await this.#archive.archiveTxs(txsToArchive);
644
+ }
645
+ });
521
646
 
522
647
  if (minedTxsToFinalize.length > 0) {
523
648
  this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
@@ -637,8 +762,17 @@ export class TxPoolV2Impl {
637
762
 
638
763
  // === Metrics ===
639
764
 
640
- countTxs(): { pending: number; protected: number; mined: number } {
641
- return this.#indices.countTxs();
765
+ countTxs(): {
766
+ pending: number;
767
+ protected: number;
768
+ mined: number;
769
+ softDeleted: number;
770
+ totalMetadataBytes: number;
771
+ } {
772
+ return {
773
+ ...this.#indices.countTxs(),
774
+ softDeleted: this.#deletedPool.getSoftDeletedCount(),
775
+ };
642
776
  }
643
777
 
644
778
  // ============================================================================
@@ -653,9 +787,10 @@ export class TxPoolV2Impl {
653
787
  tx: Tx,
654
788
  state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
655
789
  opts: { source?: string } = {},
790
+ precomputedMeta?: TxMetaData,
656
791
  ): Promise<TxMetaData> {
657
792
  const txHashStr = tx.getTxHash().toString();
658
- const meta = await buildTxMetaData(tx);
793
+ const meta = precomputedMeta ?? (await buildTxMetaData(tx));
659
794
  meta.receivedAt = this.#dateProvider.now();
660
795
 
661
796
  await this.#txsDB.set(txHashStr, tx.toBuffer());
@@ -672,9 +807,11 @@ export class TxPoolV2Impl {
672
807
  }
673
808
 
674
809
  const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
675
- this.#log.verbose(`Added ${stateStr} tx ${txHashStr}`, {
810
+ this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
676
811
  eventName: 'tx-added-to-pool',
812
+ txHash: txHashStr,
677
813
  state: stateStr,
814
+ source: opts.source,
678
815
  });
679
816
 
680
817
  return meta;
@@ -702,6 +839,29 @@ export class TxPoolV2Impl {
702
839
  }
703
840
  }
704
841
 
842
+ /** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */
843
+ async #evictTxs(txHashes: string[], reason: string): Promise<void> {
844
+ if (txHashes.length === 0) {
845
+ return;
846
+ }
847
+ this.#instrumentation.recordEvictions(txHashes.length, reason);
848
+ for (const txHashStr of txHashes) {
849
+ this.#log.debug(`Evicting tx ${txHashStr}`, { txHash: txHashStr, reason });
850
+ this.#addToEvictedCache(txHashStr);
851
+ }
852
+ await this.#deleteTxsBatch(txHashes);
853
+ }
854
+
855
+ /** Adds a tx hash to the bounded evicted cache, evicting the oldest entry if at capacity. */
856
+ #addToEvictedCache(txHashStr: string): void {
857
+ if (this.#evictedTxHashes.size >= this.#config.evictedTxCacheSize) {
858
+ // FIFO eviction: remove the first (oldest) entry
859
+ const oldest = this.#evictedTxHashes.values().next().value!;
860
+ this.#evictedTxHashes.delete(oldest);
861
+ }
862
+ this.#evictedTxHashes.add(txHashStr);
863
+ }
864
+
705
865
  // ============================================================================
706
866
  // PRIVATE HELPERS - Validation & Conflict Resolution
707
867
  // ============================================================================
@@ -812,7 +972,8 @@ export class TxPoolV2Impl {
812
972
 
813
973
  try {
814
974
  const tx = Tx.fromBuffer(buffer);
815
- const meta = await buildTxMetaData(tx);
975
+ const allowedSetupCalls = await this.#checkAllowedSetupCalls(tx);
976
+ const meta = await buildTxMetaData(tx, allowedSetupCalls);
816
977
  loaded.push({ tx, meta });
817
978
  } catch (err) {
818
979
  this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, { err });
@@ -857,7 +1018,9 @@ export class TxPoolV2Impl {
857
1018
  if (preAddResult.shouldIgnore) {
858
1019
  // Transaction rejected - mark for deletion from DB
859
1020
  rejected.push(meta.txHash);
860
- this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason}`);
1021
+ this.#log.debug(
1022
+ `Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`,
1023
+ );
861
1024
  continue;
862
1025
  }
863
1026
 
@@ -893,7 +1056,7 @@ export class TxPoolV2Impl {
893
1056
  getFeePayerPendingTxs: (feePayer: string) => this.#indices.getFeePayerPendingTxs(feePayer),
894
1057
  getPendingTxCount: () => this.#indices.getPendingTxCount(),
895
1058
  getLowestPriorityPending: (limit: number) => this.#indices.getLowestPriorityPending(limit),
896
- deleteTxs: (txHashes: string[]) => this.#deleteTxsBatch(txHashes),
1059
+ deleteTxs: (txHashes: string[], reason?: string) => this.#evictTxs(txHashes, reason ?? 'unknown'),
897
1060
  };
898
1061
  }
899
1062