@aztec/p2p 0.0.1-commit.43c09e3f → 0.0.1-commit.4d3c002

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 (449) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +11 -11
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +55 -17
  5. package/dest/client/interface.d.ts +54 -34
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +41 -52
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +170 -224
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +21 -11
  11. package/dest/config.d.ts +55 -18
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +102 -38
  14. package/dest/errors/p2p-service.error.d.ts +9 -0
  15. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  16. package/dest/errors/p2p-service.error.js +10 -0
  17. package/dest/errors/tx-pool.error.d.ts +8 -0
  18. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  19. package/dest/errors/tx-pool.error.js +9 -0
  20. package/dest/index.d.ts +2 -2
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -88
  24. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool.js +446 -3
  26. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
  27. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  28. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +353 -87
  29. package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
  30. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
  31. package/dest/mem_pools/attestation_pool/index.js +1 -2
  32. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  33. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  34. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  35. package/dest/mem_pools/index.d.ts +3 -3
  36. package/dest/mem_pools/index.d.ts.map +1 -1
  37. package/dest/mem_pools/index.js +1 -1
  38. package/dest/mem_pools/instrumentation.d.ts +4 -2
  39. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  40. package/dest/mem_pools/instrumentation.js +16 -14
  41. package/dest/mem_pools/interface.d.ts +5 -5
  42. package/dest/mem_pools/interface.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
  44. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
  45. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
  46. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  47. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  48. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  49. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  50. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  51. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +7 -3
  52. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  53. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  54. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  55. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -2
  56. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  57. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -1
  58. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
  59. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  60. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  61. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
  62. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +7 -5
  63. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  64. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  65. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
  66. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  67. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  68. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
  69. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  70. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  71. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
  72. package/dest/mem_pools/tx_pool_v2/index.d.ts +3 -2
  73. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  74. package/dest/mem_pools/tx_pool_v2/index.js +2 -1
  75. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  76. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  77. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  78. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +34 -12
  79. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  80. package/dest/mem_pools/tx_pool_v2/interfaces.js +5 -1
  81. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +78 -15
  82. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  83. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +144 -18
  84. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +108 -0
  85. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
  86. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +337 -0
  87. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +12 -5
  88. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  89. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +23 -6
  90. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +14 -5
  91. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  92. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +476 -594
  93. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  94. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  95. package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
  96. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +3 -3
  97. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  99. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  100. package/dest/msg_validators/clock_tolerance.js +4 -3
  101. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  102. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  103. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  104. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  105. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  106. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  107. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  108. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  109. package/dest/msg_validators/proposal_validator/proposal_validator.js +53 -41
  110. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
  111. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  112. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  113. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  114. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  115. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  116. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  117. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  118. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  119. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
  120. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  121. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  122. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  123. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  124. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  125. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  126. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  127. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  128. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
  129. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  130. package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
  131. package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
  132. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  133. package/dest/msg_validators/tx_validator/factory.js +247 -60
  134. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  135. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  136. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  137. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  138. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  139. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  140. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  141. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  142. package/dest/msg_validators/tx_validator/index.js +2 -0
  143. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  144. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  145. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  146. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  147. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  148. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  149. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  150. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  151. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  152. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
  153. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  154. package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
  155. package/dest/services/discv5/discV5_service.d.ts +1 -1
  156. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  157. package/dest/services/discv5/discV5_service.js +5 -2
  158. package/dest/services/dummy_service.d.ts +16 -6
  159. package/dest/services/dummy_service.d.ts.map +1 -1
  160. package/dest/services/dummy_service.js +15 -5
  161. package/dest/services/encoding.d.ts +7 -3
  162. package/dest/services/encoding.d.ts.map +1 -1
  163. package/dest/services/encoding.js +18 -11
  164. package/dest/services/gossipsub/index.d.ts +3 -0
  165. package/dest/services/gossipsub/index.d.ts.map +1 -0
  166. package/dest/services/gossipsub/index.js +2 -0
  167. package/dest/services/gossipsub/scoring.d.ts +21 -3
  168. package/dest/services/gossipsub/scoring.d.ts.map +1 -1
  169. package/dest/services/gossipsub/scoring.js +24 -7
  170. package/dest/services/gossipsub/topic_score_params.d.ts +173 -0
  171. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
  172. package/dest/services/gossipsub/topic_score_params.js +346 -0
  173. package/dest/services/libp2p/libp2p_service.d.ts +108 -51
  174. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  175. package/dest/services/libp2p/libp2p_service.js +568 -383
  176. package/dest/services/peer-manager/metrics.d.ts +3 -1
  177. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  178. package/dest/services/peer-manager/metrics.js +6 -0
  179. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  180. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  181. package/dest/services/peer-manager/peer_manager.js +24 -9
  182. package/dest/services/peer-manager/peer_scoring.d.ts +5 -2
  183. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  184. package/dest/services/peer-manager/peer_scoring.js +53 -12
  185. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +14 -10
  186. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  187. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +89 -112
  188. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +4 -7
  189. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  190. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
  191. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  192. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
  193. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  194. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  195. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  196. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  197. package/dest/services/reqresp/interface.d.ts +10 -1
  198. package/dest/services/reqresp/interface.d.ts.map +1 -1
  199. package/dest/services/reqresp/interface.js +15 -1
  200. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +7 -5
  201. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  202. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +16 -11
  203. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +21 -10
  204. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  205. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +27 -11
  206. package/dest/services/reqresp/protocols/tx.d.ts +7 -1
  207. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  208. package/dest/services/reqresp/protocols/tx.js +20 -0
  209. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  210. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  211. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  212. package/dest/services/reqresp/reqresp.d.ts +1 -1
  213. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  214. package/dest/services/reqresp/reqresp.js +30 -14
  215. package/dest/services/service.d.ts +45 -4
  216. package/dest/services/service.d.ts.map +1 -1
  217. package/dest/services/tx_collection/config.d.ts +22 -4
  218. package/dest/services/tx_collection/config.d.ts.map +1 -1
  219. package/dest/services/tx_collection/config.js +49 -3
  220. package/dest/services/tx_collection/fast_tx_collection.d.ts +6 -8
  221. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  222. package/dest/services/tx_collection/fast_tx_collection.js +88 -88
  223. package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -0
  224. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
  225. package/dest/services/tx_collection/file_store_tx_collection.js +167 -0
  226. package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
  227. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
  228. package/dest/services/tx_collection/file_store_tx_source.js +100 -0
  229. package/dest/services/tx_collection/index.d.ts +3 -2
  230. package/dest/services/tx_collection/index.d.ts.map +1 -1
  231. package/dest/services/tx_collection/index.js +1 -0
  232. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  233. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  234. package/dest/services/tx_collection/instrumentation.js +2 -1
  235. package/dest/services/tx_collection/proposal_tx_collector.d.ts +15 -15
  236. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  237. package/dest/services/tx_collection/proposal_tx_collector.js +6 -6
  238. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  239. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  240. package/dest/services/tx_collection/request_tracker.js +84 -0
  241. package/dest/services/tx_collection/slow_tx_collection.d.ts +7 -3
  242. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  243. package/dest/services/tx_collection/slow_tx_collection.js +60 -26
  244. package/dest/services/tx_collection/tx_collection.d.ts +23 -13
  245. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  246. package/dest/services/tx_collection/tx_collection.js +75 -3
  247. package/dest/services/tx_collection/tx_collection_sink.d.ts +18 -8
  248. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  249. package/dest/services/tx_collection/tx_collection_sink.js +26 -29
  250. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  251. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  252. package/dest/services/tx_collection/tx_source.js +26 -7
  253. package/dest/services/tx_file_store/config.d.ts +1 -3
  254. package/dest/services/tx_file_store/config.d.ts.map +1 -1
  255. package/dest/services/tx_file_store/config.js +0 -4
  256. package/dest/services/tx_file_store/tx_file_store.d.ts +4 -3
  257. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  258. package/dest/services/tx_file_store/tx_file_store.js +9 -6
  259. package/dest/services/tx_provider.d.ts +4 -4
  260. package/dest/services/tx_provider.d.ts.map +1 -1
  261. package/dest/services/tx_provider.js +9 -8
  262. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
  263. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  264. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  265. package/dest/test-helpers/mock-pubsub.d.ts +37 -4
  266. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  267. package/dest/test-helpers/mock-pubsub.js +113 -5
  268. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  269. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  270. package/dest/test-helpers/reqresp-nodes.js +9 -4
  271. package/dest/test-helpers/testbench-utils.d.ts +43 -38
  272. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  273. package/dest/test-helpers/testbench-utils.js +149 -61
  274. package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
  275. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  276. package/dest/testbench/p2p_client_testbench_worker.js +58 -28
  277. package/dest/testbench/worker_client_manager.d.ts +3 -1
  278. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  279. package/dest/testbench/worker_client_manager.js +6 -3
  280. package/dest/util.d.ts +9 -5
  281. package/dest/util.d.ts.map +1 -1
  282. package/dest/util.js +2 -10
  283. package/package.json +14 -14
  284. package/src/client/factory.ts +106 -30
  285. package/src/client/interface.ts +65 -35
  286. package/src/client/p2p_client.ts +205 -269
  287. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +34 -15
  288. package/src/config.ts +158 -44
  289. package/src/errors/p2p-service.error.ts +11 -0
  290. package/src/errors/tx-pool.error.ts +12 -0
  291. package/src/index.ts +1 -1
  292. package/src/mem_pools/attestation_pool/attestation_pool.ts +499 -91
  293. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +442 -102
  294. package/src/mem_pools/attestation_pool/index.ts +9 -2
  295. package/src/mem_pools/attestation_pool/mocks.ts +2 -1
  296. package/src/mem_pools/index.ts +2 -2
  297. package/src/mem_pools/instrumentation.ts +17 -13
  298. package/src/mem_pools/interface.ts +4 -4
  299. package/src/mem_pools/tx_pool_v2/README.md +112 -17
  300. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
  301. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  302. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +7 -3
  303. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  304. package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
  305. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
  306. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
  307. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -5
  308. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
  309. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
  310. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
  311. package/src/mem_pools/tx_pool_v2/index.ts +2 -1
  312. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  313. package/src/mem_pools/tx_pool_v2/interfaces.ts +34 -12
  314. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +209 -26
  315. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +430 -0
  316. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +37 -8
  317. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +518 -678
  318. package/src/msg_validators/attestation_validator/README.md +49 -0
  319. package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
  320. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +2 -2
  321. package/src/msg_validators/clock_tolerance.ts +4 -3
  322. package/src/msg_validators/proposal_validator/README.md +123 -0
  323. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  324. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  325. package/src/msg_validators/proposal_validator/proposal_validator.ts +69 -45
  326. package/src/msg_validators/tx_validator/README.md +119 -0
  327. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
  328. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  329. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  330. package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
  331. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  332. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  333. package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
  334. package/src/msg_validators/tx_validator/factory.ts +394 -78
  335. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  336. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  337. package/src/msg_validators/tx_validator/index.ts +2 -0
  338. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  339. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  340. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  341. package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
  342. package/src/services/discv5/discV5_service.ts +5 -2
  343. package/src/services/dummy_service.ts +24 -7
  344. package/src/services/encoding.ts +18 -10
  345. package/src/services/gossipsub/README.md +641 -0
  346. package/src/services/gossipsub/index.ts +2 -0
  347. package/src/services/gossipsub/scoring.ts +29 -5
  348. package/src/services/gossipsub/topic_score_params.ts +487 -0
  349. package/src/services/libp2p/libp2p_service.ts +599 -418
  350. package/src/services/peer-manager/metrics.ts +7 -0
  351. package/src/services/peer-manager/peer_manager.ts +28 -9
  352. package/src/services/peer-manager/peer_scoring.ts +46 -5
  353. package/src/services/reqresp/README.md +229 -0
  354. package/src/services/reqresp/batch-tx-requester/README.md +53 -14
  355. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +89 -122
  356. package/src/services/reqresp/batch-tx-requester/interface.ts +3 -6
  357. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
  358. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  359. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  360. package/src/services/reqresp/interface.ts +26 -1
  361. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +23 -14
  362. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +38 -15
  363. package/src/services/reqresp/protocols/tx.ts +22 -0
  364. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  365. package/src/services/reqresp/reqresp.ts +35 -15
  366. package/src/services/service.ts +60 -3
  367. package/src/services/tx_collection/config.ts +74 -6
  368. package/src/services/tx_collection/fast_tx_collection.ts +94 -97
  369. package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
  370. package/src/services/tx_collection/file_store_tx_source.ts +129 -0
  371. package/src/services/tx_collection/index.ts +2 -1
  372. package/src/services/tx_collection/instrumentation.ts +7 -1
  373. package/src/services/tx_collection/proposal_tx_collector.ts +21 -27
  374. package/src/services/tx_collection/request_tracker.ts +127 -0
  375. package/src/services/tx_collection/slow_tx_collection.ts +66 -33
  376. package/src/services/tx_collection/tx_collection.ts +114 -19
  377. package/src/services/tx_collection/tx_collection_sink.ts +30 -34
  378. package/src/services/tx_collection/tx_source.ts +28 -8
  379. package/src/services/tx_file_store/config.ts +0 -6
  380. package/src/services/tx_file_store/tx_file_store.ts +10 -8
  381. package/src/services/tx_provider.ts +10 -9
  382. package/src/test-helpers/make-test-p2p-clients.ts +4 -6
  383. package/src/test-helpers/mock-pubsub.ts +153 -9
  384. package/src/test-helpers/reqresp-nodes.ts +9 -7
  385. package/src/test-helpers/testbench-utils.ts +156 -74
  386. package/src/testbench/p2p_client_testbench_worker.ts +64 -31
  387. package/src/testbench/worker_client_manager.ts +13 -6
  388. package/src/util.ts +15 -16
  389. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
  390. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
  391. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -218
  392. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
  393. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
  394. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -180
  395. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  396. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  397. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  398. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  399. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  400. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  401. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  402. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  403. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  404. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  405. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  406. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  407. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  408. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  409. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  410. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  411. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  412. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  413. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  414. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  415. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  416. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  417. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  418. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  419. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  420. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  421. package/dest/mem_pools/tx_pool/index.js +0 -2
  422. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  423. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  424. package/dest/mem_pools/tx_pool/priority.js +0 -15
  425. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  426. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  427. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  428. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  429. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  430. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  431. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  432. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  433. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  434. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
  435. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
  436. package/src/mem_pools/tx_pool/README.md +0 -270
  437. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  438. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  439. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  440. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  441. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  442. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  443. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  444. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  445. package/src/mem_pools/tx_pool/index.ts +0 -2
  446. package/src/mem_pools/tx_pool/priority.ts +0 -20
  447. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  448. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  449. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
@@ -1,12 +1,16 @@
1
+ import { BlockNumber } from '@aztec/foundation/branded-types';
1
2
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
2
3
  import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
3
4
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
4
5
  import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
5
6
  import { Tx, TxHash } from '@aztec/stdlib/tx';
6
7
  import { TxArchive } from './archive/index.js';
7
- import { EvictionManager, FeePayerBalanceEvictionRule, FeePayerBalancePreAddRule, InvalidTxsAfterMiningRule, InvalidTxsAfterReorgRule, LowPriorityEvictionRule, LowPriorityPreAddRule, NullifierConflictRule } from './eviction/index.js';
8
+ import { DeletedPool } from './deleted_pool.js';
9
+ import { EvictionManager, FeePayerBalanceEvictionRule, FeePayerBalancePreAddRule, InvalidTxsAfterMiningRule, InvalidTxsAfterReorgRule, LowPriorityEvictionRule, LowPriorityPreAddRule, NullifierConflictRule, TxPoolRejectionCode } from './eviction/index.js';
10
+ import { TxPoolV2Instrumentation } from './instrumentation.js';
8
11
  import { DEFAULT_TX_POOL_V2_CONFIG } from './interfaces.js';
9
- import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } from './tx_metadata.js';
12
+ import { buildTxMetaData, checkNullifierConflict } from './tx_metadata.js';
13
+ import { TxPoolIndices } from './tx_pool_indices.js';
10
14
  /**
11
15
  * Implementation of TxPoolV2 logic.
12
16
  *
@@ -18,33 +22,35 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
18
22
  // === Dependencies ===
19
23
  #l2BlockSource;
20
24
  #worldStateSynchronizer;
21
- #pendingTxValidator;
25
+ #createTxValidator;
26
+ #checkAllowedSetupCalls;
22
27
  // === In-Memory Indices ===
23
- /** Primary metadata store: txHash -> TxMetaData */ #metadata = new Map();
24
- /** Nullifier to txHash index (pending txs only) */ #nullifierToTxHash = new Map();
25
- /** Fee payer to txHashes index (pending txs only) */ #feePayerToTxHashes = new Map();
26
- /**
27
- * Pending txHashes grouped by priority fee.
28
- * Outer map: priorityFee -> Set of txHashes at that fee level.
29
- */ #pendingByPriority = new Map();
30
- /** Protected transactions: txHash -> slotNumber. Includes txs we have and txs we expect to receive. */ #protectedTransactions = new Map();
28
+ #indices = new TxPoolIndices();
31
29
  // === Config & Services ===
32
30
  #config;
33
31
  #archive;
32
+ #deletedPool;
34
33
  #evictionManager;
34
+ #dateProvider;
35
+ #instrumentation;
36
+ #evictedTxHashes = new Set();
35
37
  #log;
36
38
  #callbacks;
37
- constructor(store, archiveStore, deps, callbacks, config = {}, log){
39
+ constructor(store, archiveStore, deps, callbacks, telemetry, config = {}, dateProvider, log){
38
40
  this.#store = store;
39
41
  this.#txsDB = store.openMap('txs');
40
42
  this.#l2BlockSource = deps.l2BlockSource;
41
43
  this.#worldStateSynchronizer = deps.worldStateSynchronizer;
42
- this.#pendingTxValidator = deps.pendingTxValidator;
44
+ this.#createTxValidator = deps.createTxValidator;
45
+ this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
43
46
  this.#config = {
44
47
  ...DEFAULT_TX_POOL_V2_CONFIG,
45
48
  ...config
46
49
  };
47
50
  this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
51
+ this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
52
+ this.#dateProvider = dateProvider;
53
+ this.#instrumentation = new TxPoolV2Instrumentation(telemetry, ()=>this.#indices.getTotalMetadataBytes());
48
54
  this.#log = log;
49
55
  this.#callbacks = callbacks;
50
56
  // Setup eviction manager with rules
@@ -75,20 +81,32 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
75
81
  * Note: Protected status is lost on restart. All non-mined txs are rebuilt as pending
76
82
  * by running pre-add rules to resolve nullifier conflicts, balance checks, and pool size limits.
77
83
  */ async hydrateFromDatabase() {
78
- // Step 1: Load all transactions from DB
84
+ // Step 0: Hydrate deleted pool state
85
+ await this.#deletedPool.hydrateFromDatabase();
86
+ // Step 1: Load all transactions from DB (excluding soft-deleted)
79
87
  const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
80
88
  // Step 2: Check mined status for each tx
81
89
  await this.#markMinedStatusBatch(loaded.map((l)=>l.meta));
82
90
  // Step 3: Partition by mined status
83
- const { mined, nonMined } = this.#partitionByMinedStatus(loaded);
91
+ const mined = [];
92
+ const nonMined = [];
93
+ for (const entry of loaded){
94
+ if (entry.meta.minedL2BlockId !== undefined) {
95
+ mined.push(entry.meta);
96
+ } else {
97
+ nonMined.push(entry);
98
+ }
99
+ }
84
100
  // Step 4: Validate non-mined transactions
85
- const { valid, invalid } = await this.#validateNonMinedTxs(nonMined);
101
+ const { valid, invalid } = await this.#revalidateMetadata(nonMined.map((e)=>e.meta), 'on startup');
86
102
  // Step 5: Populate mined indices (these don't need conflict resolution)
87
- this.#populateMinedIndices(mined);
103
+ for (const meta of mined){
104
+ this.#indices.addMined(meta);
105
+ }
88
106
  // Step 6: Rebuild pending pool by running pre-add rules for each tx
89
107
  // This resolves nullifier conflicts, fee payer balance issues, and pool size limits
90
108
  const { rejected } = await this.#rebuildPendingPool(valid);
91
- // Step 7: Delete invalid and rejected txs from DB
109
+ // Step 7: Delete invalid and rejected txs from DB only (indices were never populated for these)
92
110
  const toDelete = [
93
111
  ...deserializationErrors,
94
112
  ...invalid,
@@ -102,104 +120,158 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
102
120
  await this.#txsDB.delete(txHashStr);
103
121
  }
104
122
  });
105
- this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`);
123
+ this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, {
124
+ txHashes: toDelete
125
+ });
106
126
  }
107
127
  async addPendingTxs(txs, opts) {
108
128
  const accepted = [];
109
129
  const ignored = [];
110
130
  const rejected = [];
111
- const newlyAdded = [];
131
+ const errors = new Map();
112
132
  const acceptedPending = new Set();
133
+ // Phase 1: Pre-compute all throwable I/O outside the transaction.
134
+ // If any pre-computation throws, the entire call fails before mutations happen.
135
+ const precomputed = new Map();
136
+ const validator = await this.#createTxValidator();
137
+ for (const tx of txs){
138
+ const txHash = tx.getTxHash();
139
+ const txHashStr = txHash.toString();
140
+ const meta = await buildTxMetaData(tx);
141
+ const minedBlockId = await this.#getMinedBlockId(txHash);
142
+ // Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
143
+ let isValid = true;
144
+ if (!minedBlockId) {
145
+ isValid = await this.#validateMeta(meta, validator);
146
+ }
147
+ precomputed.set(txHashStr, {
148
+ meta,
149
+ minedBlockId,
150
+ isValid
151
+ });
152
+ }
153
+ // Phase 2: Apply mutations inside the transaction using only pre-computed results,
154
+ // in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
113
155
  const poolAccess = this.#createPreAddPoolAccess();
156
+ const preAddContext = opts.feeComparisonOnly !== undefined ? {
157
+ feeComparisonOnly: opts.feeComparisonOnly,
158
+ priceBumpPercentage: this.#config.priceBumpPercentage
159
+ } : undefined;
114
160
  await this.#store.transactionAsync(async ()=>{
115
161
  for (const tx of txs){
116
162
  const txHash = tx.getTxHash();
117
163
  const txHashStr = txHash.toString();
118
164
  // Skip duplicates
119
- if (this.#isDuplicateTx(txHashStr)) {
165
+ if (this.#indices.has(txHashStr)) {
120
166
  ignored.push(txHash);
121
167
  continue;
122
168
  }
123
- // Check mined status first (applies to all paths)
124
- const minedBlockId = await this.#getMinedBlockId(txHash);
125
- const preProtectedSlot = this.#protectedTransactions.get(txHashStr);
169
+ const { meta, minedBlockId, isValid } = precomputed.get(txHashStr);
170
+ const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
126
171
  if (minedBlockId) {
127
172
  // Already mined - add directly (protection already set if pre-protected)
128
- await this.#addNewMinedTx(tx, minedBlockId);
173
+ await this.#addTx(tx, {
174
+ mined: minedBlockId
175
+ }, opts, meta);
129
176
  accepted.push(txHash);
130
- newlyAdded.push(tx);
131
177
  } else if (preProtectedSlot !== undefined) {
132
178
  // Pre-protected and not mined - add as protected (bypass validation)
133
- await this.#addNewProtectedTx(tx, preProtectedSlot);
179
+ await this.#addTx(tx, {
180
+ protected: preProtectedSlot
181
+ }, opts, meta);
134
182
  accepted.push(txHash);
135
- newlyAdded.push(tx);
183
+ } else if (!isValid) {
184
+ // Failed pre-computed validation
185
+ rejected.push(txHash);
136
186
  } else {
137
- // Regular pending tx - validate and run pre-add rules
138
- const result = await this.#tryAddRegularPendingTx(tx, poolAccess, acceptedPending, ignored);
187
+ // Regular pending tx - run pre-add rules using pre-computed metadata
188
+ const result = await this.#tryAddRegularPendingTx(tx, meta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext);
139
189
  if (result.status === 'accepted') {
140
190
  acceptedPending.add(txHashStr);
141
- newlyAdded.push(tx);
142
- } else if (result.status === 'rejected') {
143
- rejected.push(txHash);
144
191
  } else {
145
192
  ignored.push(txHash);
146
193
  }
147
194
  }
148
195
  }
196
+ // Run post-add eviction rules for pending txs (inside transaction for atomicity)
197
+ if (acceptedPending.size > 0) {
198
+ const feePayers = Array.from(acceptedPending).map((txHash)=>this.#indices.getMetadata(txHash).feePayer);
199
+ const uniqueFeePayers = new Set(feePayers);
200
+ await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
201
+ ...uniqueFeePayers
202
+ ]);
203
+ }
149
204
  });
150
205
  // Build final accepted list for pending txs (excludes intra-batch evictions)
151
206
  for (const txHashStr of acceptedPending){
152
207
  accepted.push(TxHash.fromString(txHashStr));
153
208
  }
154
- // Run post-add eviction rules for pending txs
155
- if (acceptedPending.size > 0) {
156
- const feePayers = Array.from(acceptedPending).map((txHash)=>this.#metadata.get(txHash).feePayer);
157
- const uniqueFeePayers = new Set(feePayers);
158
- await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
159
- ...uniqueFeePayers
160
- ]);
209
+ // Record metrics
210
+ if (ignored.length > 0) {
211
+ this.#instrumentation.recordIgnored(ignored.length);
161
212
  }
162
- // Emit events
163
- if (newlyAdded.length > 0) {
164
- this.#callbacks.onTxsAdded(newlyAdded, opts);
213
+ if (rejected.length > 0) {
214
+ this.#instrumentation.recordRejected(rejected.length);
165
215
  }
166
216
  return {
167
217
  accepted,
168
218
  ignored,
169
- rejected
219
+ rejected,
220
+ ...errors.size > 0 ? {
221
+ errors
222
+ } : {}
170
223
  };
171
224
  }
172
- /** Validates and adds a regular pending tx. Returns status. */ async #tryAddRegularPendingTx(tx, poolAccess, acceptedPending, ignored) {
173
- const txHash = tx.getTxHash();
174
- const txHashStr = txHash.toString();
175
- // Validate transaction
176
- const validationResult = await this.#pendingTxValidator.validateTx(tx);
177
- if (validationResult.result !== 'valid') {
178
- this.#log.info(`Rejecting tx ${txHashStr}: ${validationResult.reason?.join(', ')}`);
179
- return {
180
- status: 'rejected'
181
- };
182
- }
183
- // Build metadata and run pre-add rules
184
- const meta = await buildTxMetaData(tx);
185
- const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
225
+ /** Adds a validated pending tx, running pre-add rules and evicting conflicts. */ async #tryAddRegularPendingTx(tx, precomputedMeta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext) {
226
+ const txHashStr = tx.getTxHash().toString();
227
+ // Run pre-add rules
228
+ const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
186
229
  if (preAddResult.shouldIgnore) {
187
- this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
230
+ this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
231
+ if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
232
+ errors.set(txHashStr, preAddResult.reason);
233
+ }
188
234
  return {
189
235
  status: 'ignored'
190
236
  };
191
237
  }
192
- // Evict conflicts (tracking intra-batch evictions)
193
- for (const evictHashStr of preAddResult.txHashesToEvict){
194
- await this.#deleteTx(evictHashStr);
195
- this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`);
196
- if (acceptedPending.has(evictHashStr)) {
197
- acceptedPending.delete(evictHashStr);
198
- ignored.push(TxHash.fromString(evictHashStr));
238
+ // Evict conflicts, grouped by rule name for metrics
239
+ if (preAddResult.evictions && preAddResult.evictions.length > 0) {
240
+ const byReason = new Map();
241
+ for (const { txHash: evictHash, reason } of preAddResult.evictions){
242
+ const group = byReason.get(reason);
243
+ if (group) {
244
+ group.push(evictHash);
245
+ } else {
246
+ byReason.set(reason, [
247
+ evictHash
248
+ ]);
249
+ }
250
+ }
251
+ for (const [reason, hashes] of byReason){
252
+ await this.#evictTxs(hashes, reason);
199
253
  }
254
+ for (const evictHashStr of preAddResult.txHashesToEvict){
255
+ this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
256
+ evictedTxHash: evictHashStr,
257
+ replacementTxHash: txHashStr
258
+ });
259
+ if (acceptedPending.has(evictHashStr)) {
260
+ // Evicted tx was from this batch - mark as ignored in result
261
+ acceptedPending.delete(evictHashStr);
262
+ ignored.push(TxHash.fromString(evictHashStr));
263
+ }
264
+ }
265
+ }
266
+ // Randomly drop the transaction for testing purposes (report as accepted so it propagates)
267
+ if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
268
+ this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
269
+ return {
270
+ status: 'accepted'
271
+ };
200
272
  }
201
273
  // Add the transaction
202
- await this.#addNewPendingTx(tx);
274
+ await this.#addTx(tx, 'pending', opts, precomputedMeta);
203
275
  return {
204
276
  status: 'accepted'
205
277
  };
@@ -207,89 +279,125 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
207
279
  async canAddPendingTx(tx) {
208
280
  const txHashStr = tx.getTxHash().toString();
209
281
  // Check if already in pool
210
- if (this.#metadata.has(txHashStr)) {
282
+ if (this.#indices.has(txHashStr)) {
283
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
211
284
  return 'ignored';
212
285
  }
213
- // Validate transaction
214
- const validationResult = await this.#pendingTxValidator.validateTx(tx);
215
- if (validationResult.result !== 'valid') {
216
- return 'rejected';
217
- }
218
- // Build metadata and use pre-add rules
286
+ // Build metadata and check pre-add rules
219
287
  const meta = await buildTxMetaData(tx);
220
288
  const poolAccess = this.#createPreAddPoolAccess();
221
289
  const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
222
- return preAddResult.shouldIgnore ? 'ignored' : 'accepted';
290
+ if (preAddResult.shouldIgnore) {
291
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
292
+ reason: preAddResult.reason?.message ?? 'no reason provided'
293
+ });
294
+ return 'ignored';
295
+ }
296
+ return 'accepted';
223
297
  }
224
298
  async addProtectedTxs(txs, block, opts) {
225
299
  const slotNumber = block.globalVariables.slotNumber;
226
- const newlyAdded = [];
300
+ // Precompute setup-call allow-list flags outside the store transaction
301
+ const allowedFlags = await Promise.all(txs.map((tx)=>this.#checkAllowedSetupCalls(tx)));
227
302
  await this.#store.transactionAsync(async ()=>{
228
- for (const tx of txs){
303
+ for(let i = 0; i < txs.length; i++){
304
+ const tx = txs[i];
229
305
  const txHash = tx.getTxHash();
230
306
  const txHashStr = txHash.toString();
231
- const isNew = !this.#metadata.has(txHashStr);
307
+ const isNew = !this.#indices.has(txHashStr);
232
308
  const minedBlockId = await this.#getMinedBlockId(txHash);
233
309
  if (isNew) {
234
- // New tx - add as mined or protected
310
+ const meta = await buildTxMetaData(tx, allowedFlags[i]);
311
+ // New tx - add as mined or protected (callback emitted by #addTx)
235
312
  if (minedBlockId) {
236
- await this.#addNewMinedTx(tx, minedBlockId);
237
- this.#protectedTransactions.set(txHashStr, slotNumber);
313
+ await this.#addTx(tx, {
314
+ mined: minedBlockId
315
+ }, opts, meta);
316
+ this.#indices.setProtection(txHashStr, slotNumber);
238
317
  } else {
239
- await this.#addNewProtectedTx(tx, slotNumber);
318
+ await this.#addTx(tx, {
319
+ protected: slotNumber
320
+ }, opts, meta);
240
321
  }
241
- newlyAdded.push(tx);
242
322
  } else {
243
323
  // Existing tx - update protection and mined status
244
- this.#updateProtection(txHashStr, slotNumber);
324
+ this.#indices.updateProtection(txHashStr, slotNumber);
245
325
  if (minedBlockId) {
246
- this.#markAsMined(this.#metadata.get(txHashStr), minedBlockId);
326
+ const meta = this.#indices.getMetadata(txHashStr);
327
+ this.#indices.markAsMined(meta, minedBlockId);
247
328
  }
248
329
  }
249
330
  }
250
331
  });
251
- if (newlyAdded.length > 0) {
252
- this.#callbacks.onTxsAdded(newlyAdded, opts);
253
- }
254
332
  }
255
- protectTxs(txHashes, block) {
333
+ async protectTxs(txHashes, block) {
256
334
  const slotNumber = block.globalVariables.slotNumber;
257
335
  const missing = [];
258
- for (const txHash of txHashes){
259
- const txHashStr = txHash.toString();
260
- if (this.#metadata.has(txHashStr)) {
261
- // Step 1a: Update protection for existing tx
262
- this.#updateProtection(txHashStr, slotNumber);
263
- } else {
264
- // Step 1b: Pre-record protection for tx we don't have yet
265
- this.#protectedTransactions.set(txHashStr, slotNumber);
266
- missing.push(txHash);
336
+ let softDeletedHits = 0;
337
+ let missingPreviouslyEvicted = 0;
338
+ await this.#store.transactionAsync(async ()=>{
339
+ for (const txHash of txHashes){
340
+ const txHashStr = txHash.toString();
341
+ if (this.#indices.has(txHashStr)) {
342
+ // Update protection for existing tx
343
+ this.#indices.updateProtection(txHashStr, slotNumber);
344
+ } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
345
+ // Resurrect soft-deleted tx as protected
346
+ const buffer = await this.#txsDB.getAsync(txHashStr);
347
+ if (buffer) {
348
+ const tx = Tx.fromBuffer(buffer);
349
+ await this.#addTx(tx, {
350
+ protected: slotNumber
351
+ });
352
+ softDeletedHits++;
353
+ } else {
354
+ // Data missing despite soft-delete flag — treat as truly missing
355
+ this.#indices.setProtection(txHashStr, slotNumber);
356
+ missing.push(txHash);
357
+ }
358
+ } else {
359
+ // Truly missing — pre-record protection for tx we don't have yet
360
+ this.#indices.setProtection(txHashStr, slotNumber);
361
+ missing.push(txHash);
362
+ if (this.#evictedTxHashes.has(txHashStr)) {
363
+ missingPreviouslyEvicted++;
364
+ }
365
+ }
267
366
  }
367
+ });
368
+ // Record metrics
369
+ if (softDeletedHits > 0) {
370
+ this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
371
+ }
372
+ if (missing.length > 0) {
373
+ this.#log.debug(`protectTxs missing tx hashes: ${missing.map((h)=>h.toString()).join(', ')}`);
374
+ this.#instrumentation.recordMissingOnProtect(missing.length);
375
+ }
376
+ if (missingPreviouslyEvicted > 0) {
377
+ this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
268
378
  }
379
+ this.#log.info(`Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`);
269
380
  return missing;
270
381
  }
271
382
  async addMinedTxs(txs, block, opts) {
272
383
  // Step 1: Build block ID
273
384
  const blockId = await this.#buildBlockId(block);
274
- const newlyAdded = [];
275
385
  await this.#store.transactionAsync(async ()=>{
276
386
  for (const tx of txs){
277
387
  const txHashStr = tx.getTxHash().toString();
278
- const existingMeta = this.#metadata.get(txHashStr);
388
+ const existingMeta = this.#indices.getMetadata(txHashStr);
279
389
  if (existingMeta) {
280
- // Step 2a: Mark existing tx as mined
281
- this.#markAsMined(existingMeta, blockId);
390
+ // Mark existing tx as mined
391
+ this.#indices.markAsMined(existingMeta, blockId);
282
392
  } else {
283
- // Step 2b: Add new mined tx
284
- await this.#addNewMinedTx(tx, blockId);
285
- newlyAdded.push(tx);
393
+ // Add new mined tx (callback emitted by #addTx)
394
+ await this.#addTx(tx, {
395
+ mined: blockId
396
+ }, opts);
286
397
  }
398
+ await this.#deletedPool.clearIfMinedHigher(txHashStr, blockId.number);
287
399
  }
288
400
  });
289
- // Step 3: Emit events for newly added txs
290
- if (newlyAdded.length > 0) {
291
- this.#callbacks.onTxsAdded(newlyAdded, opts);
292
- }
293
401
  }
294
402
  async handleMinedBlock(block) {
295
403
  // Step 1: Build block ID
@@ -301,102 +409,141 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
301
409
  const feePayers = [];
302
410
  const found = [];
303
411
  for (const txHash of txHashes){
304
- const meta = this.#metadata.get(txHash.toString());
412
+ const meta = this.#indices.getMetadata(txHash.toString());
305
413
  if (meta) {
306
414
  feePayers.push(meta.feePayer);
307
415
  found.push(meta);
308
416
  }
309
417
  }
310
- // Step 4: Mark txs as mined (only those we have in the pool)
311
- this.#markTxsAsMined(found, blockId);
312
- // Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
313
- await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
314
- this.#callbacks.onTxsRemoved(txHashes.map((h)=>h.toBigInt()));
418
+ await this.#store.transactionAsync(async ()=>{
419
+ // Step 4: Mark txs as mined (only those we have in the pool)
420
+ for (const meta of found){
421
+ this.#indices.markAsMined(meta, blockId);
422
+ await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
423
+ }
424
+ // Step 5: Run post-event eviction rules (inside transaction for atomicity)
425
+ await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
426
+ });
427
+ if (found.length > 0) {
428
+ this.#callbacks.onTxsMined(found.map((m)=>m.txHash));
429
+ }
315
430
  this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
316
431
  }
317
432
  async prepareForSlot(slotNumber) {
318
- // Step 1: Find expired protected txs
319
- const expiredProtected = this.#findExpiredProtectedTxs(slotNumber);
320
- // Step 2: Clear protection for all expired entries (including those without metadata)
321
- this.#clearProtection(expiredProtected);
322
- // Step 3: Filter to only txs that have metadata and are not mined
323
- const txsToRestore = this.#filterRestorable(expiredProtected);
324
- if (txsToRestore.length === 0) {
325
- return;
326
- }
327
- this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
328
- // Step 4: Validate for pending pool
329
- const { valid, invalid } = await this.#validateForPending(txsToRestore);
330
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
331
- const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
332
- // Step 6: Delete invalid and evicted txs
333
- await this.#deleteTxsBatch([
334
- ...invalid,
335
- ...toEvict
336
- ]);
337
- // Step 7: Run eviction rules (enforce pool size limit)
338
- if (added.length > 0) {
339
- const feePayers = added.map((meta)=>meta.feePayer);
340
- const uniqueFeePayers = new Set(feePayers);
341
- await this.#evictionManager.evictAfterNewTxs(added.map((m)=>m.txHash), [
342
- ...uniqueFeePayers
343
- ]);
344
- }
433
+ await this.#store.transactionAsync(async ()=>{
434
+ // Step 0: Clean up slot-deleted txs from previous slots
435
+ await this.#deletedPool.cleanupSlotDeleted(slotNumber);
436
+ // Step 1: Find expired protected txs
437
+ const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
438
+ // Step 2: Clear protection for all expired entries (including those without metadata)
439
+ this.#indices.clearProtection(expiredProtected);
440
+ // Step 3: Filter to only txs that have metadata and are not mined
441
+ const txsToRestore = this.#indices.filterRestorable(expiredProtected);
442
+ if (txsToRestore.length === 0) {
443
+ this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
444
+ return;
445
+ }
446
+ this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
447
+ // Step 4: Validate for pending pool
448
+ const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
449
+ // Step 5: Resolve nullifier conflicts and add winners to pending indices
450
+ const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
451
+ // Step 6: Delete invalid txs and evict conflict losers
452
+ await this.#deleteTxsBatch(invalid);
453
+ await this.#evictTxs(toEvict, 'NullifierConflict');
454
+ // Step 7: Run eviction rules (enforce pool size limit)
455
+ if (added.length > 0) {
456
+ const feePayers = added.map((meta)=>meta.feePayer);
457
+ const uniqueFeePayers = new Set(feePayers);
458
+ await this.#evictionManager.evictAfterNewTxs(added.map((m)=>m.txHash), [
459
+ ...uniqueFeePayers
460
+ ]);
461
+ }
462
+ });
345
463
  }
346
- async handlePrunedBlocks(latestBlock) {
464
+ async handlePrunedBlocks(latestBlock, options) {
347
465
  // Step 1: Find transactions mined after the prune point
348
- const txsToUnmine = this.#findTxsMinedAfter(latestBlock.number);
466
+ const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
349
467
  if (txsToUnmine.length === 0) {
350
468
  this.#log.debug(`No transactions to un-mine for prune to block ${latestBlock.number}`);
351
469
  return;
352
470
  }
353
471
  this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
354
- // Step 2: Unmine - clear mined status from metadata
355
- this.#unmineTxs(txsToUnmine);
356
- // Step 3: Filter out protected txs (they'll be handled by prepareForSlot)
357
- const unprotectedTxs = this.#filterUnprotected(txsToUnmine);
358
- // Step 4: Validate for pending pool
359
- const { valid, invalid } = await this.#validateForPending(unprotectedTxs);
360
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
361
- const { toEvict } = this.#applyNullifierConflictResolution(valid);
362
- // Step 6: Delete invalid and evicted txs
363
- await this.#deleteTxsBatch([
364
- ...invalid,
365
- ...toEvict
366
- ]);
367
- // Step 7: Run eviction rules for ALL pending txs (not just restored ones)
368
- // This handles cases like existing pending txs with invalid fee payer balances
369
- await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
472
+ await this.#store.transactionAsync(async ()=>{
473
+ // Step 2: Mark ALL un-mined txs with their original mined block number
474
+ // This ensures they get soft-deleted if removed later, and only hard-deleted
475
+ // when their original mined block is finalized
476
+ await this.#deletedPool.markFromPrunedBlock(txsToUnmine.map((m)=>({
477
+ txHash: m.txHash,
478
+ minedAtBlock: BlockNumber(m.minedL2BlockId.number)
479
+ })));
480
+ // Step 3: Unmine - clear mined status from metadata
481
+ for (const meta of txsToUnmine){
482
+ this.#indices.markAsUnmined(meta);
483
+ }
484
+ // If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
485
+ if (options?.deleteAllTxs) {
486
+ const allTxHashes = txsToUnmine.map((m)=>m.txHash);
487
+ await this.#deleteTxsBatch(allTxHashes);
488
+ this.#log.info(`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`);
489
+ return;
490
+ }
491
+ // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
492
+ const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
493
+ // Step 5: Validate for pending pool
494
+ const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
495
+ // Step 6: Resolve nullifier conflicts and add winners to pending indices
496
+ const { toEvict } = this.#applyNullifierConflictResolution(valid);
497
+ // Step 7: Delete invalid txs and evict conflict losers
498
+ await this.#deleteTxsBatch(invalid);
499
+ await this.#evictTxs(toEvict, 'NullifierConflict');
500
+ this.#log.info(`Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`, {
501
+ txHashesRestored: valid.map((m)=>m.txHash),
502
+ txHashesInvalid: invalid,
503
+ txHashesEvicted: toEvict
504
+ });
505
+ // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
506
+ // This handles cases like existing pending txs with invalid fee payer balances
507
+ await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
508
+ });
370
509
  }
371
510
  async handleFailedExecution(txHashes) {
372
- // Step 1: Delete failed txs
373
- await this.#deleteTxsBatch(txHashes.map((h)=>h.toString()));
374
- this.#log.info(`Deleted ${txHashes.length} failed txs`);
511
+ await this.#store.transactionAsync(async ()=>{
512
+ await this.#deleteTxsBatch(txHashes.map((h)=>h.toString()));
513
+ });
514
+ this.#log.info(`Deleted ${txHashes.length} failed txs`, {
515
+ txHashes: txHashes.map((h)=>h.toString())
516
+ });
375
517
  }
376
518
  async handleFinalizedBlock(block) {
377
519
  const blockNumber = block.globalVariables.blockNumber;
378
- // Step 1: Find txs mined at or before finalized block
379
- const txsToFinalize = this.#findTxsMinedAtOrBefore(blockNumber);
380
- if (txsToFinalize.length === 0) {
381
- return;
382
- }
383
- // Step 2: Collect txs for archiving (before deletion)
384
- const txsToArchive = [];
385
- if (this.#archive.isEnabled()) {
386
- for (const txHashStr of txsToFinalize){
387
- const buffer = await this.#txsDB.getAsync(txHashStr);
388
- if (buffer) {
389
- txsToArchive.push(Tx.fromBuffer(buffer));
520
+ // Step 1: Find mined txs at or before finalized block
521
+ const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
522
+ await this.#store.transactionAsync(async ()=>{
523
+ // Step 2: Collect mined txs for archiving (before deletion)
524
+ const txsToArchive = [];
525
+ if (this.#archive.isEnabled()) {
526
+ for (const txHashStr of minedTxsToFinalize){
527
+ const buffer = await this.#txsDB.getAsync(txHashStr);
528
+ if (buffer) {
529
+ txsToArchive.push(Tx.fromBuffer(buffer));
530
+ }
390
531
  }
391
532
  }
533
+ // Step 3: Delete mined txs from active pool
534
+ await this.#deleteTxsBatch(minedTxsToFinalize);
535
+ // Step 4: Finalize soft-deleted txs
536
+ await this.#deletedPool.finalizeBlock(blockNumber);
537
+ // Step 5: Archive mined txs
538
+ if (txsToArchive.length > 0) {
539
+ await this.#archive.archiveTxs(txsToArchive);
540
+ }
541
+ });
542
+ if (minedTxsToFinalize.length > 0) {
543
+ this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
544
+ txHashes: minedTxsToFinalize
545
+ });
392
546
  }
393
- // Step 3: Delete from active pool
394
- await this.#deleteTxsBatch(txsToFinalize);
395
- // Step 4: Archive
396
- if (txsToArchive.length > 0) {
397
- await this.#archive.archiveTxs(txsToArchive);
398
- }
399
- this.#log.info(`Finalized ${txsToFinalize.length} txs from blocks up to ${blockNumber}`);
400
547
  }
401
548
  // === Query Methods ===
402
549
  async getTxByHash(txHash) {
@@ -412,42 +559,46 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
412
559
  return results;
413
560
  }
414
561
  hasTxs(txHashes) {
415
- return txHashes.map((h)=>this.#metadata.has(h.toString()));
562
+ return txHashes.map((h)=>{
563
+ const hashStr = h.toString();
564
+ return this.#indices.has(hashStr) || this.#deletedPool.isSoftDeleted(hashStr);
565
+ });
416
566
  }
417
567
  getTxStatus(txHash) {
418
- const meta = this.#metadata.get(txHash.toString());
419
- if (!meta) {
420
- return undefined;
568
+ const txHashStr = txHash.toString();
569
+ const meta = this.#indices.getMetadata(txHashStr);
570
+ if (meta) {
571
+ return this.#indices.getTxState(meta);
421
572
  }
422
- return this.#getTxState(meta);
573
+ // Check if soft-deleted
574
+ if (this.#deletedPool.isSoftDeleted(txHashStr)) {
575
+ return 'deleted';
576
+ }
577
+ return undefined;
423
578
  }
424
579
  getPendingTxHashes() {
425
580
  return [
426
- ...this.#iteratePendingByPriority('desc')
581
+ ...this.#indices.iteratePendingByPriority('desc')
582
+ ].map((hash)=>TxHash.fromString(hash));
583
+ }
584
+ getEligiblePendingTxHashes() {
585
+ const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
586
+ return [
587
+ ...this.#indices.iterateEligiblePendingByPriority('desc', maxReceivedAt)
427
588
  ].map((hash)=>TxHash.fromString(hash));
428
589
  }
429
590
  getPendingTxCount() {
430
- let count = 0;
431
- for (const hashes of this.#pendingByPriority.values()){
432
- count += hashes.size;
433
- }
434
- return count;
591
+ return this.#indices.getPendingTxCount();
435
592
  }
436
593
  getMinedTxHashes() {
437
- const result = [];
438
- for (const [txHash, meta] of this.#metadata){
439
- if (meta.minedL2BlockId !== undefined) {
440
- result.push([
441
- TxHash.fromString(txHash),
442
- meta.minedL2BlockId
443
- ]);
444
- }
445
- }
446
- return result;
594
+ return this.#indices.getMinedTxs().map(([hash, blockId])=>[
595
+ TxHash.fromString(hash),
596
+ blockId
597
+ ]);
447
598
  }
448
599
  getMinedTxCount() {
449
600
  let count = 0;
450
- for (const meta of this.#metadata.values()){
601
+ for (const [, meta] of this.#indices.iterateMetadata()){
451
602
  if (meta.minedL2BlockId !== undefined) {
452
603
  count++;
453
604
  }
@@ -455,26 +606,16 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
455
606
  return count;
456
607
  }
457
608
  isEmpty() {
458
- return this.#metadata.size === 0;
609
+ return this.#indices.isEmpty();
459
610
  }
460
611
  getTxCount() {
461
- return this.#metadata.size;
612
+ return this.#indices.getTxCount();
462
613
  }
463
614
  getArchivedTxByHash(txHash) {
464
615
  return this.#archive.getTxByHash(txHash);
465
616
  }
466
617
  getLowestPriorityPending(limit) {
467
- if (limit <= 0) {
468
- return [];
469
- }
470
- const result = [];
471
- for (const hash of this.#iteratePendingByPriority('asc')){
472
- result.push(TxHash.fromString(hash));
473
- if (result.length >= limit) {
474
- break;
475
- }
476
- }
477
- return result;
618
+ return this.#indices.getLowestPriorityPending(limit).map((h)=>TxHash.fromString(h));
478
619
  }
479
620
  // === Configuration ===
480
621
  updateConfig(config) {
@@ -485,138 +626,122 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
485
626
  this.#config.archivedTxLimit = config.archivedTxLimit;
486
627
  this.#archive.updateLimit(config.archivedTxLimit);
487
628
  }
629
+ if (config.minTxPoolAgeMs !== undefined) {
630
+ this.#config.minTxPoolAgeMs = config.minTxPoolAgeMs;
631
+ }
488
632
  // Update eviction rules with new config
489
633
  this.#evictionManager.updateConfig(config);
490
634
  }
491
635
  // === Pool Read Access ===
492
636
  getPoolReadAccess() {
493
637
  return {
494
- getMetadata: (txHash)=>this.#metadata.get(txHash),
495
- getTxHashByNullifier: (nullifier)=>this.#nullifierToTxHash.get(nullifier),
496
- getTxHashesByFeePayer: (feePayer)=>this.#feePayerToTxHashes.get(feePayer),
497
- getPendingTxCount: ()=>this.getPendingTxCount()
638
+ getMetadata: (txHash)=>this.#indices.getMetadata(txHash),
639
+ getTxHashByNullifier: (nullifier)=>this.#indices.getTxHashByNullifier(nullifier),
640
+ getTxHashesByFeePayer: (feePayer)=>this.#indices.getTxHashesByFeePayer(feePayer),
641
+ getPendingTxCount: ()=>this.#indices.getPendingTxCount()
498
642
  };
499
643
  }
500
644
  // === Metrics ===
501
645
  countTxs() {
502
- let pending = 0;
503
- let protected_ = 0;
504
- let mined = 0;
505
- for (const meta of this.#metadata.values()){
506
- const state = this.#getTxState(meta);
507
- if (state === 'pending') {
508
- pending++;
509
- } else if (state === 'protected') {
510
- protected_++;
511
- } else if (state === 'mined') {
512
- mined++;
513
- }
514
- }
515
646
  return {
516
- pending,
517
- protected: protected_,
518
- mined
647
+ ...this.#indices.countTxs(),
648
+ softDeleted: this.#deletedPool.getSoftDeletedCount()
519
649
  };
520
650
  }
521
651
  // ============================================================================
522
- // PRIVATE QUERY IMPLEMENTATIONS
652
+ // PRIVATE HELPERS - Transaction Management
523
653
  // ============================================================================
524
654
  /**
525
- * Derives the transaction state from its metadata and protection status.
526
- * A transaction is:
527
- * - 'mined' if it has a minedL2BlockId
528
- * - 'protected' if it's in the protectedTransactions map (but not mined)
529
- * - 'pending' otherwise
530
- */ #getTxState(meta) {
531
- if (meta.minedL2BlockId !== undefined) {
532
- return 'mined';
533
- } else if (this.#protectedTransactions.has(meta.txHash)) {
534
- return 'protected';
655
+ * Adds a new transaction to the pool with the specified state.
656
+ * Emits onTxsAdded callback immediately after DB write.
657
+ */ async #addTx(tx, state, opts = {}, precomputedMeta) {
658
+ const txHashStr = tx.getTxHash().toString();
659
+ const meta = precomputedMeta ?? await buildTxMetaData(tx);
660
+ meta.receivedAt = this.#dateProvider.now();
661
+ await this.#txsDB.set(txHashStr, tx.toBuffer());
662
+ await this.#deletedPool.clearSoftDeleted(txHashStr);
663
+ this.#callbacks.onTxsAdded([
664
+ tx
665
+ ], opts);
666
+ if (state === 'pending') {
667
+ this.#indices.addPending(meta);
668
+ } else if ('protected' in state) {
669
+ this.#indices.addProtected(meta, state.protected);
535
670
  } else {
536
- return 'pending';
671
+ meta.minedL2BlockId = state.mined;
672
+ this.#indices.addMined(meta);
537
673
  }
674
+ const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
675
+ this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
676
+ eventName: 'tx-added-to-pool',
677
+ txHash: txHashStr,
678
+ state: stateStr,
679
+ source: opts.source
680
+ });
681
+ return meta;
538
682
  }
539
683
  /**
540
- * Iterates pending transaction hashes in priority order.
541
- * @param order - 'desc' for highest priority first, 'asc' for lowest priority first
542
- */ *#iteratePendingByPriority(order) {
543
- // Use shared comparators, negating for descending order
544
- const feeCompareFn = order === 'desc' ? (a, b)=>compareFee(b, a) : (a, b)=>compareFee(a, b);
545
- const hashCompareFn = order === 'desc' ? (a, b)=>compareTxHash(b, a) : (a, b)=>compareTxHash(a, b);
546
- const sortedFees = [
547
- ...this.#pendingByPriority.keys()
548
- ].sort(feeCompareFn);
549
- for (const fee of sortedFees){
550
- const hashesAtFee = this.#pendingByPriority.get(fee);
551
- const sortedHashes = [
552
- ...hashesAtFee
553
- ].sort(hashCompareFn);
554
- for (const hash of sortedHashes){
555
- yield hash;
556
- }
557
- }
684
+ * Deletes a transaction from both indices and DB.
685
+ * Emits onTxsRemoved callback immediately after DB delete.
686
+ */ /**
687
+ * Deletes a transaction from the pool.
688
+ * Delegates to DeletedPool which decides soft vs hard delete based on whether
689
+ * the tx is from a pruned block.
690
+ */ async #deleteTx(txHashStr) {
691
+ this.#indices.remove(txHashStr);
692
+ this.#callbacks.onTxsRemoved([
693
+ txHashStr
694
+ ]);
695
+ await this.#deletedPool.deleteTx(txHashStr);
558
696
  }
559
- // ============================================================================
560
- // HELPER FUNCTIONS - Pipeline Step Functions
561
- // ============================================================================
562
- // --- Finding & Filtering Steps ---
563
- /** Finds all transactions mined in blocks after the given block number */ #findTxsMinedAfter(blockNumber) {
564
- const result = [];
565
- for (const meta of this.#metadata.values()){
566
- if (meta.minedL2BlockId !== undefined && meta.minedL2BlockId.number > blockNumber) {
567
- result.push(meta);
568
- }
697
+ /** Deletes a batch of transactions, emitting callbacks individually for each. */ async #deleteTxsBatch(txHashes) {
698
+ for (const txHashStr of txHashes){
699
+ await this.#deleteTx(txHashStr);
569
700
  }
570
- return result;
571
701
  }
572
- /** Finds tx hashes mined at or before the given block number */ #findTxsMinedAtOrBefore(blockNumber) {
573
- const result = [];
574
- for (const [txHashStr, meta] of this.#metadata){
575
- if (meta.minedL2BlockId !== undefined && meta.minedL2BlockId.number <= blockNumber) {
576
- result.push(txHashStr);
577
- }
702
+ /** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */ async #evictTxs(txHashes, reason) {
703
+ if (txHashes.length === 0) {
704
+ return;
578
705
  }
579
- return result;
580
- }
581
- /** Finds protected tx hashes from slots earlier than the given slot number */ #findExpiredProtectedTxs(slotNumber) {
582
- const result = [];
583
- for (const [txHashStr, protectedSlot] of this.#protectedTransactions){
584
- if (protectedSlot < slotNumber) {
585
- result.push(txHashStr);
586
- }
706
+ this.#instrumentation.recordEvictions(txHashes.length, reason);
707
+ for (const txHashStr of txHashes){
708
+ this.#log.debug(`Evicting tx ${txHashStr}`, {
709
+ txHash: txHashStr,
710
+ reason
711
+ });
712
+ this.#addToEvictedCache(txHashStr);
587
713
  }
588
- return result;
714
+ await this.#deleteTxsBatch(txHashes);
589
715
  }
590
- /** Filters out transactions that are currently protected */ #filterUnprotected(txs) {
591
- return txs.filter((meta)=>!this.#protectedTransactions.has(meta.txHash));
716
+ /** Adds a tx hash to the bounded evicted cache, evicting the oldest entry if at capacity. */ #addToEvictedCache(txHashStr) {
717
+ if (this.#evictedTxHashes.size >= this.#config.evictedTxCacheSize) {
718
+ // FIFO eviction: remove the first (oldest) entry
719
+ const oldest = this.#evictedTxHashes.values().next().value;
720
+ this.#evictedTxHashes.delete(oldest);
721
+ }
722
+ this.#evictedTxHashes.add(txHashStr);
592
723
  }
593
- /** Filters to transactions that have metadata and are not mined */ #filterRestorable(txHashes) {
594
- const result = [];
595
- for (const txHashStr of txHashes){
596
- const meta = this.#metadata.get(txHashStr);
597
- if (meta && meta.minedL2BlockId === undefined) {
598
- result.push(meta);
599
- }
724
+ // ============================================================================
725
+ // PRIVATE HELPERS - Validation & Conflict Resolution
726
+ // ============================================================================
727
+ /** Validates transaction metadata, returning true if valid */ async #validateMeta(meta, validator, context) {
728
+ const txValidator = validator ?? await this.#createTxValidator();
729
+ const result = await txValidator.validateTx(meta);
730
+ if (result.result !== 'valid') {
731
+ const contextStr = context ? ` ${context}` : '';
732
+ this.#log.info(`Tx ${meta.txHash}${contextStr} failed validation: ${result.reason?.join(', ')}`);
733
+ return false;
600
734
  }
601
- return result;
735
+ return true;
602
736
  }
603
- // --- Validation & Conflict Resolution Steps ---
604
- /** Validates transactions for pending pool, returning valid and invalid groups */ async #validateForPending(txs) {
737
+ /** Validates metadata directly */ async #revalidateMetadata(metas, context) {
605
738
  const valid = [];
606
739
  const invalid = [];
607
- for (const meta of txs){
608
- const buffer = await this.#txsDB.getAsync(meta.txHash);
609
- if (!buffer) {
610
- this.#log.warn(`Tx ${meta.txHash} not found in DB during validation`);
611
- invalid.push(meta.txHash);
612
- continue;
613
- }
614
- const tx = Tx.fromBuffer(buffer);
615
- const result = await this.#pendingTxValidator.validateTx(tx);
616
- if (result.result === 'valid') {
740
+ const validator = await this.#createTxValidator();
741
+ for (const meta of metas){
742
+ if (await this.#validateMeta(meta, validator, context)) {
617
743
  valid.push(meta);
618
744
  } else {
619
- this.#log.info(`Tx ${meta.txHash} failed validation: ${result.reason?.join(', ')}`);
620
745
  invalid.push(meta.txHash);
621
746
  }
622
747
  }
@@ -633,7 +758,7 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
633
758
  const added = [];
634
759
  const toEvict = [];
635
760
  for (const meta of txs){
636
- const conflict = checkNullifierConflict(meta, (nullifier)=>this.#nullifierToTxHash.get(nullifier), (txHash)=>this.#metadata.get(txHash));
761
+ const conflict = checkNullifierConflict(meta, (nullifier)=>this.#indices.getTxHashByNullifier(nullifier), (txHash)=>this.#indices.getMetadata(txHash));
637
762
  if (conflict.shouldIgnore) {
638
763
  // Lower priority than existing - don't add, mark for deletion
639
764
  toEvict.push(meta.txHash);
@@ -642,13 +767,13 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
642
767
  toEvict.push(...conflict.txHashesToEvict);
643
768
  // Remove evicted from indices immediately for subsequent checks
644
769
  for (const evictHash of conflict.txHashesToEvict){
645
- const evictMeta = this.#metadata.get(evictHash);
770
+ const evictMeta = this.#indices.getMetadata(evictHash);
646
771
  if (evictMeta) {
647
- this.#removeFromPendingIndices(evictMeta);
772
+ this.#indices.removeFromPendingIndices(evictMeta);
648
773
  }
649
774
  }
650
775
  // Add to pending indices immediately so subsequent txs in the batch see this tx
651
- this.#addToPendingIndices(meta);
776
+ this.#indices.addToPendingIndices(meta);
652
777
  added.push(meta);
653
778
  }
654
779
  }
@@ -657,32 +782,10 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
657
782
  toEvict
658
783
  };
659
784
  }
660
- // --- State Transition Steps ---
661
- /** Clears the mined status from transactions, returning them for further processing */ #unmineTxs(txs) {
662
- for (const meta of txs){
663
- meta.minedL2BlockId = undefined;
664
- }
665
- return txs;
666
- }
667
- /** Removes protection from tx hashes and clears them from the protected map */ #clearProtection(txHashes) {
668
- for (const txHashStr of txHashes){
669
- this.#protectedTransactions.delete(txHashStr);
670
- }
671
- }
672
- // --- Batch Operation Steps ---
673
- /** Deletes a batch of transactions permanently */ async #deleteTxsBatch(txHashes) {
674
- if (txHashes.length === 0) {
675
- return;
676
- }
677
- await this.#store.transactionAsync(async ()=>{
678
- for (const txHashStr of txHashes){
679
- await this.#deleteTx(txHashStr);
680
- }
681
- });
682
- this.#callbacks.onTxsRemoved(txHashes);
683
- }
684
- // --- Block & Tx Info Steps ---
685
- /** Builds a block ID from a block header */ async #buildBlockId(block) {
785
+ // ============================================================================
786
+ // PRIVATE HELPERS - Block & Hydration
787
+ // ============================================================================
788
+ async #buildBlockId(block) {
686
789
  return {
687
790
  number: block.globalVariables.blockNumber,
688
791
  hash: (await block.hash()).toString()
@@ -698,43 +801,18 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
698
801
  hash: txEffect.l2BlockHash.toString()
699
802
  };
700
803
  }
701
- /** Marks a batch of transactions as mined */ #markTxsAsMined(metas, blockId) {
702
- for (const meta of metas){
703
- this.#markAsMined(meta, blockId);
704
- }
705
- }
706
- // --- Add Transaction Steps ---
707
- /** Persists a transaction to the database */ async #persistTx(txHashStr, tx) {
708
- await this.#txsDB.set(txHashStr, tx.toBuffer());
709
- }
710
- /** Adds a new transaction as protected, returning its metadata */ async #addNewProtectedTx(tx, slotNumber) {
711
- const txHashStr = tx.getTxHash().toString();
712
- const meta = await buildTxMetaData(tx);
713
- this.#protectedTransactions.set(txHashStr, slotNumber);
714
- await this.#persistTx(txHashStr, tx);
715
- this.#metadata.set(txHashStr, meta);
716
- // Don't add to pending indices since it's protected
717
- this.#log.verbose(`Added protected tx ${txHashStr} for slot ${slotNumber}`);
718
- return meta;
719
- }
720
- /** Adds a new transaction as mined, returning its metadata */ async #addNewMinedTx(tx, blockId) {
721
- const txHashStr = tx.getTxHash().toString();
722
- const meta = await buildTxMetaData(tx);
723
- meta.minedL2BlockId = blockId;
724
- await this.#persistTx(txHashStr, tx);
725
- this.#metadata.set(txHashStr, meta);
726
- // Don't add to pending indices since it's mined
727
- this.#log.verbose(`Added mined tx ${txHashStr} from block ${blockId.number}`);
728
- return meta;
729
- }
730
- // --- Hydration Steps ---
731
804
  /** Loads all transactions from the database, returning loaded txs and deserialization errors */ async #loadAllTxsFromDb() {
732
805
  const loaded = [];
733
806
  const errors = [];
734
807
  for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()){
808
+ // Skip soft-deleted transactions - they stay in DB but not in indices
809
+ if (this.#deletedPool.isSoftDeleted(txHashStr)) {
810
+ continue;
811
+ }
735
812
  try {
736
813
  const tx = Tx.fromBuffer(buffer);
737
- const meta = await buildTxMetaData(tx);
814
+ const allowedSetupCalls = await this.#checkAllowedSetupCalls(tx);
815
+ const meta = await buildTxMetaData(tx, allowedSetupCalls);
738
816
  loaded.push({
739
817
  tx,
740
818
  meta
@@ -768,43 +846,6 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
768
846
  }
769
847
  }
770
848
  }
771
- /** Partitions transactions by mined status */ #partitionByMinedStatus(txs) {
772
- const mined = [];
773
- const nonMined = [];
774
- for (const entry of txs){
775
- if (entry.meta.minedL2BlockId !== undefined) {
776
- mined.push(entry.meta);
777
- } else {
778
- nonMined.push(entry);
779
- }
780
- }
781
- return {
782
- mined,
783
- nonMined
784
- };
785
- }
786
- /** Validates non-mined transactions, returning valid metadata and invalid hashes */ async #validateNonMinedTxs(txs) {
787
- const valid = [];
788
- const invalid = [];
789
- for (const { tx, meta } of txs){
790
- const result = await this.#pendingTxValidator.validateTx(tx);
791
- if (result.result === 'valid') {
792
- valid.push(meta);
793
- } else {
794
- this.#log.info(`Removing invalid tx ${meta.txHash} on startup: ${result.reason?.join(', ')}`);
795
- invalid.push(meta.txHash);
796
- }
797
- }
798
- return {
799
- valid,
800
- invalid
801
- };
802
- }
803
- /** Populates metadata index for mined transactions */ #populateMinedIndices(metas) {
804
- for (const meta of metas){
805
- this.#metadata.set(meta.txHash, meta);
806
- }
807
- }
808
849
  /**
809
850
  * Rebuilds the pending pool by processing each tx through pre-add rules.
810
851
  * Starts with an empty pending pool and adds txs one by one, resolving conflicts.
@@ -819,22 +860,22 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
819
860
  if (preAddResult.shouldIgnore) {
820
861
  // Transaction rejected - mark for deletion from DB
821
862
  rejected.push(meta.txHash);
822
- this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason}`);
863
+ this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`);
823
864
  continue;
824
865
  }
825
866
  // Evict any conflicting txs identified by pre-add rules
826
867
  for (const evictHashStr of preAddResult.txHashesToEvict){
827
- const evictMeta = this.#metadata.get(evictHashStr);
868
+ const evictMeta = this.#indices.getMetadata(evictHashStr);
828
869
  if (evictMeta) {
829
- this.#removeFromPendingIndices(evictMeta);
830
- this.#metadata.delete(evictHashStr);
870
+ this.#indices.removeFromPendingIndices(evictMeta);
871
+ this.#indices.remove(evictHashStr);
831
872
  rejected.push(evictHashStr);
832
873
  accepted.delete(evictHashStr);
833
874
  this.#log.debug(`Evicted tx ${evictHashStr} during rebuild due to conflict with ${meta.txHash}`);
834
875
  }
835
876
  }
836
- // Add to metadata and pending indices
837
- this.#addToIndices(meta);
877
+ // Add to indices
878
+ this.#indices.addPending(meta);
838
879
  accepted.add(meta.txHash);
839
880
  }
840
881
  this.#log.info(`Rebuilt pending pool: ${accepted.size} accepted, ${rejected.length} rejected`);
@@ -845,197 +886,38 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
845
886
  rejected
846
887
  };
847
888
  }
848
- // --- Add Pending Tx Steps ---
849
- /** Checks if a tx is a duplicate (already in pool) */ #isDuplicateTx(txHashStr) {
850
- return this.#metadata.has(txHashStr);
851
- }
852
- /** Adds a new pending tx to the pool, returning its metadata */ async #addNewPendingTx(tx) {
853
- const txHashStr = tx.getTxHash().toString();
854
- const meta = await buildTxMetaData(tx);
855
- await this.#persistTx(txHashStr, tx);
856
- this.#addToIndices(meta);
857
- this.#log.verbose(`Added tx ${txHashStr} to pool`, {
858
- eventName: 'tx-added-to-pool',
859
- state: this.#getTxState(meta)
860
- });
861
- return meta;
862
- }
863
- // ============================================================================
864
- // HELPER FUNCTIONS - Index Management
865
- // ============================================================================
866
- #addToIndices(meta) {
867
- this.#metadata.set(meta.txHash, meta);
868
- if (this.#getTxState(meta) === 'pending') {
869
- this.#addToPendingIndices(meta);
870
- }
871
- // Protected and mined txs don't go into pending indices
872
- }
873
- #addToPendingIndices(meta) {
874
- // Add to nullifier index
875
- for (const nullifier of meta.nullifiers){
876
- this.#nullifierToTxHash.set(nullifier, meta.txHash);
877
- }
878
- // Add to fee payer index
879
- let feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
880
- if (!feePayerSet) {
881
- feePayerSet = new Set();
882
- this.#feePayerToTxHashes.set(meta.feePayer, feePayerSet);
883
- }
884
- feePayerSet.add(meta.txHash);
885
- // Add to priority bucket
886
- let prioritySet = this.#pendingByPriority.get(meta.priorityFee);
887
- if (!prioritySet) {
888
- prioritySet = new Set();
889
- this.#pendingByPriority.set(meta.priorityFee, prioritySet);
890
- }
891
- prioritySet.add(meta.txHash);
892
- }
893
- #removeFromPendingIndices(meta) {
894
- // Remove from nullifier index
895
- for (const nullifier of meta.nullifiers){
896
- this.#nullifierToTxHash.delete(nullifier);
897
- }
898
- // Remove from fee payer index
899
- const feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
900
- if (feePayerSet) {
901
- feePayerSet.delete(meta.txHash);
902
- if (feePayerSet.size === 0) {
903
- this.#feePayerToTxHashes.delete(meta.feePayer);
904
- }
905
- }
906
- // Remove from priority map
907
- const hashSet = this.#pendingByPriority.get(meta.priorityFee);
908
- if (hashSet) {
909
- hashSet.delete(meta.txHash);
910
- if (hashSet.size === 0) {
911
- this.#pendingByPriority.delete(meta.priorityFee);
912
- }
913
- }
914
- }
915
- #updateProtection(txHashStr, slotNumber) {
916
- const currentSlot = this.#protectedTransactions.get(txHashStr);
917
- // Only update if not already protected at an equal or later slot
918
- if (currentSlot !== undefined && currentSlot >= slotNumber) {
919
- return;
920
- }
921
- // Remove from pending indices if transitioning from pending to protected
922
- if (currentSlot === undefined) {
923
- const meta = this.#metadata.get(txHashStr);
924
- if (meta) {
925
- this.#removeFromPendingIndices(meta);
926
- }
927
- }
928
- this.#protectedTransactions.set(txHashStr, slotNumber);
929
- }
930
- #markAsMined(meta, blockId) {
931
- meta.minedL2BlockId = blockId;
932
- // Safe to call unconditionally - removeFromPendingIndices is idempotent
933
- this.#removeFromPendingIndices(meta);
934
- }
935
- async #deleteTx(txHashStr) {
936
- const meta = this.#metadata.get(txHashStr);
937
- if (!meta) {
938
- return;
939
- }
940
- // Remove from all indices
941
- this.#metadata.delete(txHashStr);
942
- this.#protectedTransactions.delete(txHashStr);
943
- this.#removeFromPendingIndices(meta);
944
- // Remove from persistence
945
- await this.#txsDB.delete(txHashStr);
946
- }
947
889
  // ============================================================================
948
- // HELPER FUNCTIONS - Adapters
890
+ // PRIVATE HELPERS - Pool Access Adapters
949
891
  // ============================================================================
950
- /** Gets all pending transactions for a given fee payer. */ #getFeePayerPendingTxs(feePayer) {
951
- const txHashes = this.#feePayerToTxHashes.get(feePayer);
952
- if (!txHashes) {
953
- return [];
954
- }
955
- const result = [];
956
- for (const txHashStr of txHashes){
957
- const meta = this.#metadata.get(txHashStr);
958
- if (meta && this.#getTxState(meta) === 'pending') {
959
- result.push(meta);
960
- }
961
- }
962
- return result;
963
- }
964
- /**
965
- * Creates a PoolOperations adapter for use with the eviction manager.
966
- */ #createPoolOperations() {
892
+ #createPoolOperations() {
967
893
  return {
968
- getPendingTxs: ()=>{
969
- const result = [];
970
- for (const hashSet of this.#pendingByPriority.values()){
971
- for (const txHashStr of hashSet){
972
- const meta = this.#metadata.get(txHashStr);
973
- if (meta) {
974
- result.push(meta);
975
- }
976
- }
977
- }
978
- return result;
979
- },
980
- getPendingFeePayers: ()=>{
981
- return Array.from(this.#feePayerToTxHashes.keys());
982
- },
983
- getFeePayerPendingTxs: (feePayer)=>{
984
- return this.#getFeePayerPendingTxs(feePayer);
985
- },
986
- getPendingTxCount: ()=>{
987
- return this.getPendingTxCount();
988
- },
989
- getLowestPriorityPending: (limit)=>{
990
- return this.getLowestPriorityPending(limit).map((h)=>h.toString());
991
- },
992
- deleteTxs: async (txHashes)=>{
993
- await this.#store.transactionAsync(async ()=>{
994
- for (const txHashStr of txHashes){
995
- await this.#deleteTx(txHashStr);
996
- }
997
- });
998
- this.#callbacks.onTxsRemoved(txHashes);
999
- }
894
+ getPendingTxs: ()=>this.#indices.getPendingTxs(),
895
+ getPendingFeePayers: ()=>this.#indices.getPendingFeePayers(),
896
+ getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),
897
+ getPendingTxCount: ()=>this.#indices.getPendingTxCount(),
898
+ getLowestPriorityPending: (limit)=>this.#indices.getLowestPriorityPending(limit),
899
+ deleteTxs: (txHashes, reason)=>this.#evictTxs(txHashes, reason ?? 'unknown')
1000
900
  };
1001
901
  }
1002
- /**
1003
- * Creates a PreAddPoolAccess adapter for use with pre-add eviction rules.
1004
- * All methods work with strings and TxMetaData for efficiency.
1005
- */ #createPreAddPoolAccess() {
902
+ #createPreAddPoolAccess() {
1006
903
  return {
1007
904
  getMetadata: (txHashStr)=>{
1008
- const meta = this.#metadata.get(txHashStr);
1009
- if (!meta || this.#getTxState(meta) !== 'pending') {
905
+ const meta = this.#indices.getMetadata(txHashStr);
906
+ if (!meta || this.#indices.getTxState(meta) !== 'pending') {
1010
907
  return undefined;
1011
908
  }
1012
909
  return meta;
1013
910
  },
1014
- getTxHashByNullifier: (nullifier)=>{
1015
- return this.#nullifierToTxHash.get(nullifier);
1016
- },
911
+ getTxHashByNullifier: (nullifier)=>this.#indices.getTxHashByNullifier(nullifier),
1017
912
  getFeePayerBalance: async (feePayer)=>{
1018
913
  const db = this.#worldStateSynchronizer.getCommitted();
1019
914
  const publicStateSource = new DatabasePublicStateSource(db);
1020
915
  const balance = await publicStateSource.storageRead(ProtocolContractAddress.FeeJuice, await computeFeePayerBalanceStorageSlot(AztecAddress.fromString(feePayer)));
1021
916
  return balance.toBigInt();
1022
917
  },
1023
- getFeePayerPendingTxs: (feePayer)=>{
1024
- return this.#getFeePayerPendingTxs(feePayer);
1025
- },
1026
- getPendingTxCount: ()=>{
1027
- return this.getPendingTxCount();
1028
- },
1029
- getLowestPriorityPendingTx: ()=>{
1030
- // Iterate in ascending order to find the lowest priority
1031
- for (const txHashStr of this.#iteratePendingByPriority('asc')){
1032
- const meta = this.#metadata.get(txHashStr);
1033
- if (meta) {
1034
- return meta;
1035
- }
1036
- }
1037
- return undefined;
1038
- }
918
+ getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),
919
+ getPendingTxCount: ()=>this.#indices.getPendingTxCount(),
920
+ getLowestPriorityPendingTx: ()=>this.#indices.getLowestPriorityPendingTx()
1039
921
  };
1040
922
  }
1041
923
  }