@aztec/p2p 0.0.1-commit.4d79d1f2d → 0.0.1-commit.4d9804df

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 (499) hide show
  1. package/README.md +130 -3
  2. package/dest/bootstrap/bootstrap.d.ts +1 -1
  3. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  4. package/dest/bootstrap/bootstrap.js +22 -6
  5. package/dest/client/factory.d.ts +9 -8
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +50 -34
  8. package/dest/client/interface.d.ts +59 -27
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +40 -34
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +162 -135
  13. package/dest/config.d.ts +164 -100
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +149 -49
  16. package/dest/errors/p2p-service.error.d.ts +9 -0
  17. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  18. package/dest/errors/p2p-service.error.js +10 -0
  19. package/dest/errors/reqresp.error.d.ts +9 -16
  20. package/dest/errors/reqresp.error.d.ts.map +1 -1
  21. package/dest/errors/reqresp.error.js +10 -17
  22. package/dest/errors/tx-pool.error.d.ts +8 -0
  23. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  24. package/dest/errors/tx-pool.error.js +9 -0
  25. package/dest/index.d.ts +1 -2
  26. package/dest/index.d.ts.map +1 -1
  27. package/dest/index.js +0 -1
  28. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +103 -59
  29. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool.js +278 -196
  31. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  32. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +224 -65
  34. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  35. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/mocks.js +7 -5
  37. package/dest/mem_pools/index.d.ts +1 -2
  38. package/dest/mem_pools/index.d.ts.map +1 -1
  39. package/dest/mem_pools/instrumentation.d.ts +12 -5
  40. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  41. package/dest/mem_pools/instrumentation.js +38 -17
  42. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  43. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  45. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +32 -15
  46. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +95 -24
  48. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  49. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  51. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  52. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +8 -4
  54. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  55. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  57. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
  58. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
  60. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  61. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  62. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  63. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
  64. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  65. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  66. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
  67. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
  68. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  69. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  70. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
  71. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  72. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  73. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
  74. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  75. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  76. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
  77. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  78. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  79. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  80. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  81. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  82. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  83. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +60 -14
  84. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  85. package/dest/mem_pools/tx_pool_v2/interfaces.js +6 -1
  86. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +59 -15
  87. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  88. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +116 -20
  89. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +26 -3
  90. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  91. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +79 -43
  92. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +20 -7
  93. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  94. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +34 -12
  95. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +29 -7
  96. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  97. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +473 -211
  98. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
  99. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  100. package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -15
  101. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  102. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  103. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  104. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +12 -5
  105. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  106. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +11 -3
  107. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +12 -5
  108. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  109. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +23 -3
  110. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +36 -9
  111. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  112. package/dest/msg_validators/proposal_validator/proposal_validator.js +130 -48
  113. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  114. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  115. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
  116. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  117. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  118. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
  119. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  120. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  121. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  122. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  123. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  124. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  125. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  126. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  127. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  128. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  129. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  130. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  131. package/dest/msg_validators/tx_validator/data_validator.js +36 -2
  132. package/dest/msg_validators/tx_validator/factory.d.ts +133 -7
  133. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  134. package/dest/msg_validators/tx_validator/factory.js +261 -61
  135. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  136. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  137. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  138. package/dest/msg_validators/tx_validator/gas_validator.d.ts +104 -3
  139. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  140. package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
  141. package/dest/msg_validators/tx_validator/index.d.ts +5 -1
  142. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  143. package/dest/msg_validators/tx_validator/index.js +4 -0
  144. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  145. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  146. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  147. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  148. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  149. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  150. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  151. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  152. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  153. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +2 -2
  154. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  155. package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
  156. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  157. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  158. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  159. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  160. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  161. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  162. package/dest/services/data_store.d.ts +1 -1
  163. package/dest/services/data_store.d.ts.map +1 -1
  164. package/dest/services/data_store.js +5 -5
  165. package/dest/services/discv5/discV5_service.d.ts +13 -2
  166. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  167. package/dest/services/discv5/discV5_service.js +119 -23
  168. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  169. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  170. package/dest/services/discv5/persisted_enr_store.js +145 -0
  171. package/dest/services/dummy_service.d.ts +18 -18
  172. package/dest/services/dummy_service.d.ts.map +1 -1
  173. package/dest/services/dummy_service.js +19 -20
  174. package/dest/services/encoding.d.ts +23 -6
  175. package/dest/services/encoding.d.ts.map +1 -1
  176. package/dest/services/encoding.js +41 -24
  177. package/dest/services/gossipsub/topic_score_params.d.ts +23 -17
  178. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  179. package/dest/services/gossipsub/topic_score_params.js +36 -24
  180. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  181. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  182. package/dest/services/libp2p/instrumentation.js +14 -0
  183. package/dest/services/libp2p/libp2p_service.d.ts +57 -56
  184. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  185. package/dest/services/libp2p/libp2p_service.js +483 -373
  186. package/dest/services/peer-manager/metrics.d.ts +3 -1
  187. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  188. package/dest/services/peer-manager/metrics.js +6 -0
  189. package/dest/services/peer-manager/peer_manager.d.ts +20 -3
  190. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  191. package/dest/services/peer-manager/peer_manager.js +83 -26
  192. package/dest/services/peer-manager/peer_scoring.d.ts +34 -2
  193. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  194. package/dest/services/peer-manager/peer_scoring.js +102 -13
  195. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +5 -8
  196. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  197. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +95 -127
  198. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +11 -11
  199. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  200. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
  201. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  202. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
  203. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  204. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  205. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  206. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  207. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  208. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  209. package/dest/services/reqresp/config.d.ts +15 -3
  210. package/dest/services/reqresp/config.d.ts.map +1 -1
  211. package/dest/services/reqresp/config.js +11 -0
  212. package/dest/services/reqresp/interface.d.ts +16 -18
  213. package/dest/services/reqresp/interface.d.ts.map +1 -1
  214. package/dest/services/reqresp/interface.js +10 -20
  215. package/dest/services/reqresp/metrics.d.ts +1 -1
  216. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  217. package/dest/services/reqresp/metrics.js +0 -1
  218. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  219. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  220. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  221. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  222. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  223. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  224. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
  225. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  226. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
  227. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  228. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  229. package/dest/services/reqresp/protocols/index.js +0 -1
  230. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  231. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  232. package/dest/services/reqresp/protocols/tx.js +1 -3
  233. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  234. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  235. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  236. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  237. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  238. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  239. package/dest/services/reqresp/reqresp.d.ts +7 -29
  240. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  241. package/dest/services/reqresp/reqresp.js +75 -216
  242. package/dest/services/service.d.ts +29 -14
  243. package/dest/services/service.d.ts.map +1 -1
  244. package/dest/services/tx_collection/config.d.ts +8 -17
  245. package/dest/services/tx_collection/config.d.ts.map +1 -1
  246. package/dest/services/tx_collection/config.js +17 -40
  247. package/dest/services/tx_collection/file_store_tx_collection.d.ts +25 -32
  248. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  249. package/dest/services/tx_collection/file_store_tx_collection.js +96 -87
  250. package/dest/services/tx_collection/file_store_tx_source.d.ts +17 -6
  251. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  252. package/dest/services/tx_collection/file_store_tx_source.js +53 -10
  253. package/dest/services/tx_collection/index.d.ts +2 -3
  254. package/dest/services/tx_collection/index.d.ts.map +1 -1
  255. package/dest/services/tx_collection/index.js +0 -1
  256. package/dest/services/tx_collection/instrumentation.js +1 -2
  257. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  258. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  259. package/dest/services/tx_collection/request_tracker.js +84 -0
  260. package/dest/services/tx_collection/tx_collection.d.ts +39 -55
  261. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  262. package/dest/services/tx_collection/tx_collection.js +280 -108
  263. package/dest/services/tx_collection/tx_collection_sink.d.ts +7 -6
  264. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  265. package/dest/services/tx_collection/tx_collection_sink.js +15 -24
  266. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  267. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  268. package/dest/services/tx_collection/tx_source.js +29 -7
  269. package/dest/services/tx_file_store/tx_file_store.d.ts +3 -4
  270. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  271. package/dest/services/tx_file_store/tx_file_store.js +13 -20
  272. package/dest/services/tx_provider.d.ts +5 -3
  273. package/dest/services/tx_provider.d.ts.map +1 -1
  274. package/dest/services/tx_provider.js +7 -4
  275. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  276. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  277. package/dest/test-helpers/make-test-p2p-clients.js +5 -3
  278. package/dest/test-helpers/mock-pubsub.d.ts +26 -12
  279. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  280. package/dest/test-helpers/mock-pubsub.js +51 -45
  281. package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
  282. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  283. package/dest/test-helpers/reqresp-nodes.js +17 -19
  284. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  285. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  286. package/dest/test-helpers/test_tx_provider.js +3 -0
  287. package/dest/test-helpers/testbench-utils.d.ts +22 -16
  288. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  289. package/dest/test-helpers/testbench-utils.js +56 -16
  290. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  291. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  292. package/dest/testbench/p2p_client_testbench_worker.js +111 -48
  293. package/dest/testbench/worker_client_manager.d.ts +12 -6
  294. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  295. package/dest/testbench/worker_client_manager.js +57 -11
  296. package/dest/util.d.ts +13 -8
  297. package/dest/util.d.ts.map +1 -1
  298. package/dest/util.js +35 -14
  299. package/dest/versioning.d.ts +3 -6
  300. package/dest/versioning.d.ts.map +1 -1
  301. package/dest/versioning.js +3 -24
  302. package/package.json +16 -16
  303. package/src/bootstrap/bootstrap.ts +17 -3
  304. package/src/client/factory.ts +95 -51
  305. package/src/client/interface.ts +59 -35
  306. package/src/client/p2p_client.ts +186 -196
  307. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  308. package/src/config.ts +259 -57
  309. package/src/errors/p2p-service.error.ts +11 -0
  310. package/src/errors/reqresp.error.ts +13 -19
  311. package/src/errors/tx-pool.error.ts +12 -0
  312. package/src/index.ts +0 -1
  313. package/src/mem_pools/attestation_pool/attestation_pool.ts +336 -242
  314. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +244 -69
  315. package/src/mem_pools/attestation_pool/mocks.ts +14 -8
  316. package/src/mem_pools/index.ts +0 -3
  317. package/src/mem_pools/instrumentation.ts +27 -17
  318. package/src/mem_pools/tx_pool_v2/README.md +52 -28
  319. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  320. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +114 -27
  321. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  322. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +8 -4
  323. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  324. package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
  325. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  326. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
  327. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
  328. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
  329. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
  330. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
  331. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
  332. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  333. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  334. package/src/mem_pools/tx_pool_v2/interfaces.ts +61 -14
  335. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +170 -28
  336. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +91 -43
  337. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +54 -14
  338. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +527 -207
  339. package/src/msg_validators/attestation_validator/README.md +49 -0
  340. package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -14
  341. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
  342. package/src/msg_validators/proposal_validator/README.md +123 -0
  343. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +26 -4
  344. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +43 -7
  345. package/src/msg_validators/proposal_validator/proposal_validator.ts +155 -49
  346. package/src/msg_validators/tx_validator/README.md +129 -0
  347. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +6 -15
  348. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  349. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  350. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  351. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  352. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  353. package/src/msg_validators/tx_validator/data_validator.ts +44 -1
  354. package/src/msg_validators/tx_validator/factory.ts +413 -80
  355. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  356. package/src/msg_validators/tx_validator/gas_validator.ts +195 -54
  357. package/src/msg_validators/tx_validator/index.ts +4 -0
  358. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  359. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  360. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  361. package/src/msg_validators/tx_validator/timestamp_validator.ts +7 -7
  362. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  363. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  364. package/src/services/data_store.ts +5 -13
  365. package/src/services/discv5/discV5_service.ts +126 -14
  366. package/src/services/discv5/persisted_enr_store.ts +158 -0
  367. package/src/services/dummy_service.ts +26 -45
  368. package/src/services/encoding.ts +40 -24
  369. package/src/services/gossipsub/README.md +59 -22
  370. package/src/services/gossipsub/topic_score_params.ts +58 -31
  371. package/src/services/libp2p/instrumentation.ts +14 -0
  372. package/src/services/libp2p/libp2p_service.ts +554 -428
  373. package/src/services/peer-manager/metrics.ts +7 -0
  374. package/src/services/peer-manager/peer_manager.ts +91 -25
  375. package/src/services/peer-manager/peer_scoring.ts +102 -8
  376. package/src/services/reqresp/README.md +194 -0
  377. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  378. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +92 -138
  379. package/src/services/reqresp/batch-tx-requester/interface.ts +14 -10
  380. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
  381. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  382. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  383. package/src/services/reqresp/config.ts +19 -2
  384. package/src/services/reqresp/interface.ts +21 -47
  385. package/src/services/reqresp/metrics.ts +0 -1
  386. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  387. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
  388. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
  389. package/src/services/reqresp/protocols/index.ts +0 -1
  390. package/src/services/reqresp/protocols/tx.ts +1 -3
  391. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  392. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  393. package/src/services/reqresp/reqresp.ts +87 -260
  394. package/src/services/service.ts +42 -30
  395. package/src/services/tx_collection/config.ts +24 -59
  396. package/src/services/tx_collection/file_store_tx_collection.ts +108 -107
  397. package/src/services/tx_collection/file_store_tx_source.ts +69 -10
  398. package/src/services/tx_collection/index.ts +1 -6
  399. package/src/services/tx_collection/instrumentation.ts +1 -1
  400. package/src/services/tx_collection/request_tracker.ts +127 -0
  401. package/src/services/tx_collection/tx_collection.ts +342 -156
  402. package/src/services/tx_collection/tx_collection_sink.ts +17 -31
  403. package/src/services/tx_collection/tx_source.ts +29 -8
  404. package/src/services/tx_file_store/tx_file_store.ts +11 -21
  405. package/src/services/tx_provider.ts +7 -2
  406. package/src/test-helpers/make-test-p2p-clients.ts +4 -3
  407. package/src/test-helpers/mock-pubsub.ts +59 -66
  408. package/src/test-helpers/reqresp-nodes.ts +15 -28
  409. package/src/test-helpers/test_tx_provider.ts +5 -0
  410. package/src/test-helpers/testbench-utils.ts +74 -31
  411. package/src/testbench/p2p_client_testbench_worker.ts +120 -63
  412. package/src/testbench/worker_client_manager.ts +72 -25
  413. package/src/util.ts +40 -19
  414. package/src/versioning.ts +3 -33
  415. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  416. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  417. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
  418. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  419. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  420. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  421. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  422. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  423. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  424. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  425. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  426. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  427. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  428. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  429. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  430. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  431. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  432. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  433. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  434. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  435. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  436. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  437. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  438. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  439. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  440. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  441. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  442. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  443. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  444. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  445. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  446. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  447. package/dest/mem_pools/tx_pool/index.js +0 -2
  448. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  449. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  450. package/dest/mem_pools/tx_pool/priority.js +0 -15
  451. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  452. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  453. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  454. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  455. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  456. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  457. package/dest/msg_validators/clock_tolerance.d.ts +0 -21
  458. package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
  459. package/dest/msg_validators/clock_tolerance.js +0 -37
  460. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  461. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  462. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  463. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  464. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  465. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  466. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  467. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  468. package/dest/services/reqresp/protocols/block.js +0 -32
  469. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -54
  470. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  471. package/dest/services/tx_collection/fast_tx_collection.js +0 -321
  472. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
  473. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  474. package/dest/services/tx_collection/proposal_tx_collector.js +0 -49
  475. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -55
  476. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  477. package/dest/services/tx_collection/slow_tx_collection.js +0 -206
  478. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -336
  479. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  480. package/src/mem_pools/tx_pool/README.md +0 -270
  481. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  482. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  483. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  484. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  485. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  486. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  487. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  488. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  489. package/src/mem_pools/tx_pool/index.ts +0 -2
  490. package/src/mem_pools/tx_pool/priority.ts +0 -20
  491. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  492. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  493. package/src/msg_validators/clock_tolerance.ts +0 -51
  494. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
  495. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  496. package/src/services/reqresp/protocols/block.ts +0 -37
  497. package/src/services/tx_collection/fast_tx_collection.ts +0 -366
  498. package/src/services/tx_collection/proposal_tx_collector.ts +0 -112
  499. package/src/services/tx_collection/slow_tx_collection.ts +0 -262
@@ -1,4 +1,5 @@
1
- import { BlockNumber } from '@aztec/foundation/branded-types';
1
+ import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { FifoSet } from '@aztec/foundation/fifo-set';
2
3
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
3
4
  import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
4
5
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
@@ -6,10 +7,16 @@ import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
6
7
  import { Tx, TxHash } from '@aztec/stdlib/tx';
7
8
  import { TxArchive } from './archive/index.js';
8
9
  import { DeletedPool } from './deleted_pool.js';
9
- import { EvictionManager, FeePayerBalanceEvictionRule, FeePayerBalancePreAddRule, InvalidTxsAfterMiningRule, InvalidTxsAfterReorgRule, LowPriorityEvictionRule, LowPriorityPreAddRule, NullifierConflictRule } from './eviction/index.js';
10
+ import { EvictionManager, FeePayerBalanceEvictionRule, FeePayerBalancePreAddRule, InsufficientFeePerGasEvictionRule, InvalidTxsAfterMiningRule, InvalidTxsAfterReorgRule, LowPriorityEvictionRule, LowPriorityPreAddRule, NullifierConflictRule, TxPoolRejectionCode } from './eviction/index.js';
11
+ import { TxPoolV2Instrumentation } from './instrumentation.js';
10
12
  import { DEFAULT_TX_POOL_V2_CONFIG } from './interfaces.js';
11
13
  import { buildTxMetaData, checkNullifierConflict } from './tx_metadata.js';
12
14
  import { TxPoolIndices } from './tx_pool_indices.js';
15
+ /**
16
+ * Maximum number of full transactions to load into memory at once when finalizing a block.
17
+ * Bounds peak memory while archiving and hard-deleting mined txs (~23k txs/epoch at 10 TPS would
18
+ * otherwise OOM the node).
19
+ */ const FINALIZE_BLOCK_CHUNK_SIZE = 100;
13
20
  /**
14
21
  * Implementation of TxPoolV2 logic.
15
22
  *
@@ -17,11 +24,13 @@ import { TxPoolIndices } from './tx_pool_indices.js';
17
24
  */ export class TxPoolV2Impl {
18
25
  // === Persistence ===
19
26
  #store;
20
- #txsDB;
27
+ /** Tx data without its proof. Proofs live in #proofsDB so a tx can be read without loading its proof. */ #txsDB;
28
+ /** Tx proofs, keyed by tx hash. Written and deleted in lockstep with #txsDB. */ #proofsDB;
21
29
  // === Dependencies ===
22
30
  #l2BlockSource;
23
31
  #worldStateSynchronizer;
24
32
  #createTxValidator;
33
+ #checkAllowedSetupCalls;
25
34
  // === In-Memory Indices ===
26
35
  #indices = new TxPoolIndices();
27
36
  // === Config & Services ===
@@ -29,20 +38,28 @@ import { TxPoolIndices } from './tx_pool_indices.js';
29
38
  #archive;
30
39
  #deletedPool;
31
40
  #evictionManager;
41
+ #dateProvider;
42
+ #instrumentation;
43
+ #evictedTxHashes;
32
44
  #log;
33
45
  #callbacks;
34
- constructor(store, archiveStore, deps, callbacks, config = {}, log){
46
+ constructor(store, archiveStore, deps, callbacks, telemetry, config = {}, dateProvider, log){
35
47
  this.#store = store;
36
48
  this.#txsDB = store.openMap('txs');
49
+ this.#proofsDB = store.openMap('tx_proofs');
37
50
  this.#l2BlockSource = deps.l2BlockSource;
38
51
  this.#worldStateSynchronizer = deps.worldStateSynchronizer;
39
52
  this.#createTxValidator = deps.createTxValidator;
53
+ this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
40
54
  this.#config = {
41
55
  ...DEFAULT_TX_POOL_V2_CONFIG,
42
56
  ...config
43
57
  };
58
+ this.#evictedTxHashes = FifoSet.withLimit(this.#config.evictedTxCacheSize);
44
59
  this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
45
- this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
60
+ this.#deletedPool = new DeletedPool(store, (txHashStr)=>this.#deleteTxData(txHashStr), log);
61
+ this.#dateProvider = dateProvider;
62
+ this.#instrumentation = new TxPoolV2Instrumentation(telemetry, ()=>this.#indices.getTotalMetadataBytes());
46
63
  this.#log = log;
47
64
  this.#callbacks = callbacks;
48
65
  // Setup eviction manager with rules
@@ -55,6 +72,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
55
72
  }));
56
73
  // Post-event eviction rules (run after events to check ALL pending txs)
57
74
  this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
75
+ this.#evictionManager.registerRule(new InsufficientFeePerGasEvictionRule(deps.blockMinFeesProvider));
58
76
  this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(deps.worldStateSynchronizer));
59
77
  this.#evictionManager.registerRule(new FeePayerBalanceEvictionRule(deps.worldStateSynchronizer));
60
78
  // LowPriorityEvictionRule handles cases where txs become pending via prepareForSlot (unprotect)
@@ -75,30 +93,63 @@ import { TxPoolIndices } from './tx_pool_indices.js';
75
93
  */ async hydrateFromDatabase() {
76
94
  // Step 0: Hydrate deleted pool state
77
95
  await this.#deletedPool.hydrateFromDatabase();
78
- // Step 1: Load all transactions from DB (excluding soft-deleted)
79
- const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
80
- // Step 2: Check mined status for each tx
81
- await this.#markMinedStatusBatch(loaded.map((l)=>l.meta));
82
- // Step 3: Partition by mined status
83
- const mined = [];
84
- const nonMined = [];
85
- for (const entry of loaded){
86
- if (entry.meta.minedL2BlockId !== undefined) {
87
- mined.push(entry.meta);
96
+ // Step 1: Stream txs from DB, building metadata and mined status one at a time.
97
+ const minedMetas = [];
98
+ const pendingMetas = [];
99
+ const deserializationErrors = [];
100
+ for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()){
101
+ // Skip soft-deleted transactions - they stay in DB but not in indices
102
+ if (this.#deletedPool.isSoftDeleted(txHashStr)) {
103
+ continue;
104
+ }
105
+ let meta;
106
+ let txEffect;
107
+ try {
108
+ const tx = Tx.fromBuffer(buffer);
109
+ // Resolve allowed-setup-calls and the tx effect concurrently
110
+ // getTxEffect failures are non-fatal (we just treat the tx as not-yet-mined), so
111
+ // its rejection is swallowed before the Promise.all so it can't fail-fast the batch.
112
+ const txEffectPromise = this.#l2BlockSource.getTxEffect(tx.getTxHash()).catch((err)=>{
113
+ this.#log.warn(`Failed to check mined status for tx ${txHashStr}`, {
114
+ err
115
+ });
116
+ return undefined;
117
+ });
118
+ const [allowedSetupCalls, fetchedTxEffect] = await Promise.all([
119
+ this.#checkAllowedSetupCalls(tx),
120
+ txEffectPromise
121
+ ]);
122
+ meta = await buildTxMetaData(tx, allowedSetupCalls);
123
+ txEffect = fetchedTxEffect;
124
+ } catch (err) {
125
+ this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, {
126
+ err
127
+ });
128
+ deserializationErrors.push(txHashStr);
129
+ continue;
130
+ }
131
+ if (txEffect) {
132
+ meta.minedL2BlockId = {
133
+ number: txEffect.l2BlockNumber,
134
+ hash: txEffect.l2BlockHash.toString()
135
+ };
136
+ }
137
+ if (meta.minedL2BlockId !== undefined) {
138
+ minedMetas.push(meta);
88
139
  } else {
89
- nonMined.push(entry);
140
+ pendingMetas.push(meta);
90
141
  }
91
142
  }
92
- // Step 4: Validate non-mined transactions
93
- const { valid, invalid } = await this.#revalidateMetadata(nonMined.map((e)=>e.meta), 'on startup');
94
- // Step 5: Populate mined indices (these don't need conflict resolution)
95
- for (const meta of mined){
143
+ // Step 2: Validate non-mined transactions
144
+ const { valid, invalid } = await this.#revalidateMetadata(pendingMetas, 'on startup');
145
+ // Step 3: Populate mined indices (these don't need conflict resolution)
146
+ for (const meta of minedMetas){
96
147
  this.#indices.addMined(meta);
97
148
  }
98
- // Step 6: Rebuild pending pool by running pre-add rules for each tx
149
+ // Step 4: Rebuild pending pool by running pre-add rules for each tx
99
150
  // This resolves nullifier conflicts, fee payer balance issues, and pool size limits
100
151
  const { rejected } = await this.#rebuildPendingPool(valid);
101
- // Step 7: Delete invalid and rejected txs from DB only (indices were never populated for these)
152
+ // Step 5: Delete invalid and rejected txs from DB only (indices were never populated for these)
102
153
  const toDelete = [
103
154
  ...deserializationErrors,
104
155
  ...invalid,
@@ -109,17 +160,46 @@ import { TxPoolIndices } from './tx_pool_indices.js';
109
160
  }
110
161
  await this.#store.transactionAsync(async ()=>{
111
162
  for (const txHashStr of toDelete){
112
- await this.#txsDB.delete(txHashStr);
163
+ await this.#deleteTxData(txHashStr);
113
164
  }
114
165
  });
115
- this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`);
166
+ this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, {
167
+ txHashes: toDelete
168
+ });
116
169
  }
117
170
  async addPendingTxs(txs, opts) {
118
171
  const accepted = [];
119
172
  const ignored = [];
120
173
  const rejected = [];
174
+ const errors = new Map();
121
175
  const acceptedPending = new Set();
176
+ // Phase 1: Pre-compute all throwable I/O outside the transaction.
177
+ // If any pre-computation throws, the entire call fails before mutations happen.
178
+ const precomputed = new Map();
179
+ const validator = await this.#createTxValidator();
180
+ for (const tx of txs){
181
+ const txHash = tx.getTxHash();
182
+ const txHashStr = txHash.toString();
183
+ const meta = await buildTxMetaData(tx);
184
+ const minedBlockId = await this.#getMinedBlockId(txHash);
185
+ // Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
186
+ let isValid = true;
187
+ if (!minedBlockId) {
188
+ isValid = await this.#validateMeta(meta, validator);
189
+ }
190
+ precomputed.set(txHashStr, {
191
+ meta,
192
+ minedBlockId,
193
+ isValid
194
+ });
195
+ }
196
+ // Phase 2: Apply mutations inside the transaction using only pre-computed results,
197
+ // in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
122
198
  const poolAccess = this.#createPreAddPoolAccess();
199
+ const preAddContext = opts.feeComparisonOnly !== undefined ? {
200
+ feeComparisonOnly: opts.feeComparisonOnly,
201
+ priceBumpPercentage: this.#config.priceBumpPercentage
202
+ } : undefined;
123
203
  await this.#store.transactionAsync(async ()=>{
124
204
  for (const tx of txs){
125
205
  const txHash = tx.getTxHash();
@@ -129,82 +209,112 @@ import { TxPoolIndices } from './tx_pool_indices.js';
129
209
  ignored.push(txHash);
130
210
  continue;
131
211
  }
132
- // Check mined status first (applies to all paths)
133
- const minedBlockId = await this.#getMinedBlockId(txHash);
212
+ const { meta, minedBlockId, isValid } = precomputed.get(txHashStr);
134
213
  const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
135
214
  if (minedBlockId) {
136
215
  // Already mined - add directly (protection already set if pre-protected)
137
216
  await this.#addTx(tx, {
138
217
  mined: minedBlockId
139
- }, opts);
218
+ }, opts, meta);
140
219
  accepted.push(txHash);
141
220
  } else if (preProtectedSlot !== undefined) {
142
221
  // Pre-protected and not mined - add as protected (bypass validation)
143
222
  await this.#addTx(tx, {
144
223
  protected: preProtectedSlot
145
- }, opts);
224
+ }, opts, meta);
146
225
  accepted.push(txHash);
226
+ } else if (!isValid) {
227
+ // Failed pre-computed validation
228
+ rejected.push(txHash);
147
229
  } else {
148
- // Regular pending tx - validate and run pre-add rules
149
- const result = await this.#tryAddRegularPendingTx(tx, opts, poolAccess, acceptedPending, ignored);
230
+ // Regular pending tx - run pre-add rules using pre-computed metadata
231
+ const result = await this.#tryAddRegularPendingTx(tx, meta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext);
150
232
  if (result.status === 'accepted') {
151
233
  acceptedPending.add(txHashStr);
152
- } else if (result.status === 'rejected') {
153
- rejected.push(txHash);
154
234
  } else {
155
235
  ignored.push(txHash);
156
236
  }
157
237
  }
158
238
  }
239
+ // Run post-add eviction rules for pending txs (inside transaction for atomicity)
240
+ if (acceptedPending.size > 0) {
241
+ const feePayers = Array.from(acceptedPending).map((txHash)=>this.#indices.getMetadata(txHash).feePayer);
242
+ const uniqueFeePayers = new Set(feePayers);
243
+ await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
244
+ ...uniqueFeePayers
245
+ ]);
246
+ }
159
247
  });
160
248
  // Build final accepted list for pending txs (excludes intra-batch evictions)
161
249
  for (const txHashStr of acceptedPending){
162
250
  accepted.push(TxHash.fromString(txHashStr));
163
251
  }
164
- // Run post-add eviction rules for pending txs
165
- if (acceptedPending.size > 0) {
166
- const feePayers = Array.from(acceptedPending).map((txHash)=>this.#indices.getMetadata(txHash).feePayer);
167
- const uniqueFeePayers = new Set(feePayers);
168
- await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
169
- ...uniqueFeePayers
170
- ]);
252
+ // Record metrics
253
+ if (ignored.length > 0) {
254
+ this.#instrumentation.recordIgnored(ignored.length);
255
+ }
256
+ if (rejected.length > 0) {
257
+ this.#instrumentation.recordRejected(rejected.length);
171
258
  }
172
259
  return {
173
260
  accepted,
174
261
  ignored,
175
- rejected
262
+ rejected,
263
+ ...errors.size > 0 ? {
264
+ errors
265
+ } : {}
176
266
  };
177
267
  }
178
- /** Validates and adds a regular pending tx. Returns status. */ async #tryAddRegularPendingTx(tx, opts, poolAccess, acceptedPending, ignored) {
179
- const txHash = tx.getTxHash();
180
- const txHashStr = txHash.toString();
181
- // Build metadata and validate using metadata
182
- const meta = await buildTxMetaData(tx);
183
- if (!await this.#validateMeta(meta)) {
184
- return {
185
- status: 'rejected'
186
- };
187
- }
268
+ /** Adds a validated pending tx, running pre-add rules and evicting conflicts. */ async #tryAddRegularPendingTx(tx, precomputedMeta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext) {
269
+ const txHashStr = tx.getTxHash().toString();
188
270
  // Run pre-add rules
189
- const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
271
+ const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
190
272
  if (preAddResult.shouldIgnore) {
191
- this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
273
+ this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
274
+ if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
275
+ errors.set(txHashStr, preAddResult.reason);
276
+ }
192
277
  return {
193
278
  status: 'ignored'
194
279
  };
195
280
  }
196
- // Evict conflicts
197
- for (const evictHashStr of preAddResult.txHashesToEvict){
198
- await this.#deleteTx(evictHashStr);
199
- this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`);
200
- if (acceptedPending.has(evictHashStr)) {
201
- // Evicted tx was from this batch - mark as ignored in result
202
- acceptedPending.delete(evictHashStr);
203
- ignored.push(TxHash.fromString(evictHashStr));
281
+ // Evict conflicts, grouped by rule name for metrics
282
+ if (preAddResult.evictions && preAddResult.evictions.length > 0) {
283
+ const byReason = new Map();
284
+ for (const { txHash: evictHash, reason } of preAddResult.evictions){
285
+ const group = byReason.get(reason);
286
+ if (group) {
287
+ group.push(evictHash);
288
+ } else {
289
+ byReason.set(reason, [
290
+ evictHash
291
+ ]);
292
+ }
293
+ }
294
+ for (const [reason, hashes] of byReason){
295
+ await this.#evictTxs(hashes, reason);
296
+ }
297
+ for (const evictHashStr of preAddResult.txHashesToEvict){
298
+ this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
299
+ evictedTxHash: evictHashStr,
300
+ replacementTxHash: txHashStr
301
+ });
302
+ if (acceptedPending.has(evictHashStr)) {
303
+ // Evicted tx was from this batch - mark as ignored in result
304
+ acceptedPending.delete(evictHashStr);
305
+ ignored.push(TxHash.fromString(evictHashStr));
306
+ }
204
307
  }
205
308
  }
309
+ // Randomly drop the transaction for testing purposes (report as accepted so it propagates)
310
+ if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
311
+ this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
312
+ return {
313
+ status: 'accepted'
314
+ };
315
+ }
206
316
  // Add the transaction
207
- await this.#addTx(tx, 'pending', opts);
317
+ await this.#addTx(tx, 'pending', opts, precomputedMeta);
208
318
  return {
209
319
  status: 'accepted'
210
320
  };
@@ -213,38 +323,44 @@ import { TxPoolIndices } from './tx_pool_indices.js';
213
323
  const txHashStr = tx.getTxHash().toString();
214
324
  // Check if already in pool
215
325
  if (this.#indices.has(txHashStr)) {
326
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
216
327
  return 'ignored';
217
328
  }
218
- // Build metadata and validate using metadata
329
+ // Build metadata and check pre-add rules
219
330
  const meta = await buildTxMetaData(tx);
220
- const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
221
- if (validationResult !== true) {
222
- return 'rejected';
223
- }
224
- // Use pre-add rules
225
331
  const poolAccess = this.#createPreAddPoolAccess();
226
332
  const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
227
- return preAddResult.shouldIgnore ? 'ignored' : 'accepted';
333
+ if (preAddResult.shouldIgnore) {
334
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
335
+ reason: preAddResult.reason?.message ?? 'no reason provided'
336
+ });
337
+ return 'ignored';
338
+ }
339
+ return 'accepted';
228
340
  }
229
341
  async addProtectedTxs(txs, block, opts) {
230
342
  const slotNumber = block.globalVariables.slotNumber;
343
+ // Precompute setup-call allow-list flags outside the store transaction
344
+ const allowedFlags = await Promise.all(txs.map((tx)=>this.#checkAllowedSetupCalls(tx)));
231
345
  await this.#store.transactionAsync(async ()=>{
232
- for (const tx of txs){
346
+ for(let i = 0; i < txs.length; i++){
347
+ const tx = txs[i];
233
348
  const txHash = tx.getTxHash();
234
349
  const txHashStr = txHash.toString();
235
350
  const isNew = !this.#indices.has(txHashStr);
236
351
  const minedBlockId = await this.#getMinedBlockId(txHash);
237
352
  if (isNew) {
353
+ const meta = await buildTxMetaData(tx, allowedFlags[i]);
238
354
  // New tx - add as mined or protected (callback emitted by #addTx)
239
355
  if (minedBlockId) {
240
356
  await this.#addTx(tx, {
241
357
  mined: minedBlockId
242
- }, opts);
358
+ }, opts, meta);
243
359
  this.#indices.setProtection(txHashStr, slotNumber);
244
360
  } else {
245
361
  await this.#addTx(tx, {
246
362
  protected: slotNumber
247
- }, opts);
363
+ }, opts, meta);
248
364
  }
249
365
  } else {
250
366
  // Existing tx - update protection and mined status
@@ -257,20 +373,54 @@ import { TxPoolIndices } from './tx_pool_indices.js';
257
373
  }
258
374
  });
259
375
  }
260
- protectTxs(txHashes, block) {
376
+ async protectTxs(txHashes, block) {
261
377
  const slotNumber = block.globalVariables.slotNumber;
262
378
  const missing = [];
263
- for (const txHash of txHashes){
264
- const txHashStr = txHash.toString();
265
- if (this.#indices.has(txHashStr)) {
266
- // Update protection for existing tx
267
- this.#indices.updateProtection(txHashStr, slotNumber);
268
- } else {
269
- // Pre-record protection for tx we don't have yet
270
- this.#indices.setProtection(txHashStr, slotNumber);
271
- missing.push(txHash);
379
+ let softDeletedHits = 0;
380
+ let missingPreviouslyEvicted = 0;
381
+ await this.#store.transactionAsync(async ()=>{
382
+ for (const txHash of txHashes){
383
+ const txHashStr = txHash.toString();
384
+ if (this.#indices.has(txHashStr)) {
385
+ // Update protection for existing tx
386
+ this.#indices.updateProtection(txHashStr, slotNumber);
387
+ } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
388
+ // Resurrect soft-deleted tx as protected. Load the proof too: #addTx rewrites both entries, so re-adding
389
+ // a proofless tx would wipe the stored proof.
390
+ const buffer = await this.#txsDB.getAsync(txHashStr);
391
+ if (buffer) {
392
+ const tx = await this.#loadTxWithProof(txHashStr, buffer);
393
+ await this.#addTx(tx, {
394
+ protected: slotNumber
395
+ });
396
+ softDeletedHits++;
397
+ } else {
398
+ // Data missing despite soft-delete flag — treat as truly missing
399
+ this.#indices.setProtection(txHashStr, slotNumber);
400
+ missing.push(txHash);
401
+ }
402
+ } else {
403
+ // Truly missing — pre-record protection for tx we don't have yet
404
+ this.#indices.setProtection(txHashStr, slotNumber);
405
+ missing.push(txHash);
406
+ if (this.#evictedTxHashes.has(txHashStr)) {
407
+ missingPreviouslyEvicted++;
408
+ }
409
+ }
272
410
  }
411
+ });
412
+ // Record metrics
413
+ if (softDeletedHits > 0) {
414
+ this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
415
+ }
416
+ if (missing.length > 0) {
417
+ this.#log.debug(`protectTxs missing tx hashes: ${missing.map((h)=>h.toString()).join(', ')}`);
418
+ this.#instrumentation.recordMissingOnProtect(missing.length);
419
+ }
420
+ if (missingPreviouslyEvicted > 0) {
421
+ this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
273
422
  }
423
+ this.#log.info(`Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`);
274
424
  return missing;
275
425
  }
276
426
  async addMinedTxs(txs, block, opts) {
@@ -309,36 +459,77 @@ import { TxPoolIndices } from './tx_pool_indices.js';
309
459
  found.push(meta);
310
460
  }
311
461
  }
312
- // Step 4: Mark txs as mined (only those we have in the pool)
313
- for (const meta of found){
314
- this.#indices.markAsMined(meta, blockId);
315
- await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
462
+ await this.#store.transactionAsync(async ()=>{
463
+ // Step 4: Mark txs as mined (only those we have in the pool)
464
+ for (const meta of found){
465
+ this.#indices.markAsMined(meta, blockId);
466
+ await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
467
+ }
468
+ // Step 5: Run post-event eviction rules (inside transaction for atomicity)
469
+ await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
470
+ });
471
+ if (found.length > 0) {
472
+ // receivedAt is 0 for txs hydrated from the DB on restart (true receive time lost) — leave
473
+ // their delay undefined so the metric isn't polluted by epoch-sized values.
474
+ const now = this.#dateProvider.now();
475
+ this.#callbacks.onTxsMined(found.map((m)=>({
476
+ txHash: m.txHash,
477
+ minedDelayMs: m.receivedAt > 0 ? now - m.receivedAt : undefined
478
+ })));
316
479
  }
317
- // Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
318
- await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
319
480
  this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
320
481
  }
321
482
  async prepareForSlot(slotNumber) {
322
- // Step 1: Find expired protected txs
323
- const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
324
- // Step 2: Clear protection for all expired entries (including those without metadata)
325
- this.#indices.clearProtection(expiredProtected);
326
- // Step 3: Filter to only txs that have metadata and are not mined
327
- const txsToRestore = this.#indices.filterRestorable(expiredProtected);
328
- if (txsToRestore.length === 0) {
329
- return;
330
- }
331
- this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
332
- // Step 4: Validate for pending pool
333
- const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
334
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
483
+ await this.#store.transactionAsync(async ()=>{
484
+ // Step 0: Clean up slot-deleted txs from previous slots
485
+ await this.#deletedPool.cleanupSlotDeleted(slotNumber);
486
+ // Step 1: Find expired protected txs
487
+ const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
488
+ // Step 2: Clear protection for all expired entries (including those without metadata)
489
+ this.#indices.clearProtection(expiredProtected);
490
+ // Step 3: Filter to only txs that have metadata and are not mined
491
+ const txsToRestore = this.#indices.filterRestorable(expiredProtected);
492
+ if (txsToRestore.length === 0) {
493
+ this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
494
+ return;
495
+ }
496
+ this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
497
+ await this.#restoreUnprotectedToPending(txsToRestore, 'during prepareForSlot');
498
+ });
499
+ }
500
+ async unprotectTxs(txHashes, slotNumber) {
501
+ const hashStrs = txHashes.map((h)=>h.toString());
502
+ await this.#store.transactionAsync(async ()=>{
503
+ // Only release entries still recorded at this exact slot. A tx that another, still-live proposal
504
+ // raised to a higher slot via updateProtection must keep that protection. Mined txs have no
505
+ // protection entry and so are never matched here.
506
+ const matching = this.#indices.findProtectedTxsAtSlot(hashStrs, slotNumber);
507
+ if (matching.length === 0) {
508
+ this.#log.debug(`Unprotecting txs for slot ${slotNumber}: no matching protections to release`);
509
+ return;
510
+ }
511
+ this.#indices.clearProtection(matching);
512
+ const txsToRestore = this.#indices.filterRestorable(matching);
513
+ if (txsToRestore.length === 0) {
514
+ return;
515
+ }
516
+ this.#log.info(`Unprotecting ${txsToRestore.length} txs from failed proposal at slot ${slotNumber}`);
517
+ await this.#restoreUnprotectedToPending(txsToRestore, 'during unprotectTxs');
518
+ });
519
+ }
520
+ /**
521
+ * Returns just-unprotected txs to the pending pool: revalidates them, resolves nullifier
522
+ * conflicts, deletes losers, then enforces the pool size limit. Must run inside a store
523
+ * transaction; callers clear the protection entries before invoking.
524
+ */ async #restoreUnprotectedToPending(txsToRestore, context) {
525
+ // Step 1: Validate for pending pool
526
+ const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, context);
527
+ // Step 2: Resolve nullifier conflicts and add winners to pending indices
335
528
  const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
336
- // Step 6: Delete invalid and evicted txs
337
- await this.#deleteTxsBatch([
338
- ...invalid,
339
- ...toEvict
340
- ]);
341
- // Step 7: Run eviction rules (enforce pool size limit)
529
+ // Step 3: Delete invalid txs and evict conflict losers
530
+ await this.#deleteTxsBatch(invalid);
531
+ await this.#evictTxs(toEvict, 'NullifierConflict');
532
+ // Step 4: Run eviction rules (enforce pool size limit)
342
533
  if (added.length > 0) {
343
534
  const feePayers = added.map((meta)=>meta.feePayer);
344
535
  const uniqueFeePayers = new Set(feePayers);
@@ -347,7 +538,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
347
538
  ]);
348
539
  }
349
540
  }
350
- async handlePrunedBlocks(latestBlock) {
541
+ async handlePrunedBlocks(latestBlock, options) {
351
542
  // Step 1: Find transactions mined after the prune point
352
543
  const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
353
544
  if (txsToUnmine.length === 0) {
@@ -355,76 +546,149 @@ import { TxPoolIndices } from './tx_pool_indices.js';
355
546
  return;
356
547
  }
357
548
  this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
358
- // Step 2: Mark ALL un-mined txs with their original mined block number
359
- // This ensures they get soft-deleted if removed later, and only hard-deleted
360
- // when their original mined block is finalized
361
- await this.#deletedPool.markFromPrunedBlock(txsToUnmine.map((m)=>({
362
- txHash: m.txHash,
363
- minedAtBlock: BlockNumber(m.minedL2BlockId.number)
364
- })));
365
- // Step 3: Unmine - clear mined status from metadata
366
- for (const meta of txsToUnmine){
367
- this.#indices.markAsUnmined(meta);
368
- }
369
- // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
370
- const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
371
- // Step 4: Validate for pending pool
372
- const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
373
- // Step 6: Resolve nullifier conflicts and add winners to pending indices
374
- const { toEvict } = this.#applyNullifierConflictResolution(valid);
375
- // Step 7: Delete invalid and evicted txs
376
- await this.#deleteTxsBatch([
377
- ...invalid,
378
- ...toEvict
379
- ]);
380
- // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
381
- // This handles cases like existing pending txs with invalid fee payer balances
382
- await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
549
+ await this.#store.transactionAsync(async ()=>{
550
+ // Step 2: Mark ALL un-mined txs with their original mined block number
551
+ // This ensures they get soft-deleted if removed later, and only hard-deleted
552
+ // when their original mined block is finalized
553
+ await this.#deletedPool.markFromPrunedBlock(txsToUnmine.map((m)=>({
554
+ txHash: m.txHash,
555
+ minedAtBlock: BlockNumber(m.minedL2BlockId.number)
556
+ })));
557
+ // Step 3: Unmine - clear mined status from metadata
558
+ for (const meta of txsToUnmine){
559
+ this.#indices.markAsUnmined(meta);
560
+ }
561
+ // If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
562
+ if (options?.deleteAllTxs) {
563
+ const allTxHashes = txsToUnmine.map((m)=>m.txHash);
564
+ await this.#deleteTxsBatch(allTxHashes);
565
+ this.#log.info(`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`);
566
+ return;
567
+ }
568
+ // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
569
+ const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
570
+ // Step 5: Validate for pending pool
571
+ const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
572
+ // Step 6: Resolve nullifier conflicts and add winners to pending indices
573
+ const { toEvict } = this.#applyNullifierConflictResolution(valid);
574
+ // Step 7: Delete invalid txs and evict conflict losers
575
+ await this.#deleteTxsBatch(invalid);
576
+ await this.#evictTxs(toEvict, 'NullifierConflict');
577
+ 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`, {
578
+ txHashesRestored: valid.map((m)=>m.txHash),
579
+ txHashesInvalid: invalid,
580
+ txHashesEvicted: toEvict
581
+ });
582
+ // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
583
+ // This handles cases like existing pending txs with invalid fee payer balances
584
+ await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
585
+ });
383
586
  }
384
587
  async handleFailedExecution(txHashes) {
385
- // Delete failed txs
386
- await this.#deleteTxsBatch(txHashes.map((h)=>h.toString()));
387
- this.#log.info(`Deleted ${txHashes.length} failed txs`);
588
+ await this.#store.transactionAsync(async ()=>{
589
+ await this.#deleteTxsBatch(txHashes.map((h)=>h.toString()));
590
+ });
591
+ this.#log.info(`Deleted ${txHashes.length} failed txs`, {
592
+ txHashes: txHashes.map((h)=>h.toString())
593
+ });
388
594
  }
389
595
  async handleFinalizedBlock(block) {
390
596
  const blockNumber = block.globalVariables.blockNumber;
391
- // Step 1: Find mined txs at or before finalized block
392
- const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
393
- // Step 2: Collect mined txs for archiving (before deletion)
394
- const txsToArchive = [];
597
+ // Hold finalized txs for a configurable margin behind the finalized tip so a prover still
598
+ // proving an epoch with already-finalized blocks isn't starved of its txs. 0 deletes at the finalized tip.
599
+ const cutoffBlock = await this.#finalizationCutoffBlock(block);
600
+ // Step 1: Find mined txs at or before the cutoff block
601
+ const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(cutoffBlock);
602
+ // Step 2: Archive in chunks if archiving is enabled. Hydrating an entire epoch's worth of
603
+ // mined txs at once would OOM under load. When archiving is disabled there is no need to hydrate the txs at all.
395
604
  if (this.#archive.isEnabled()) {
396
- for (const txHashStr of minedTxsToFinalize){
397
- const buffer = await this.#txsDB.getAsync(txHashStr);
398
- if (buffer) {
399
- txsToArchive.push(Tx.fromBuffer(buffer));
605
+ for(let i = 0; i < minedTxsToFinalize.length; i += FINALIZE_BLOCK_CHUNK_SIZE){
606
+ const chunk = minedTxsToFinalize.slice(i, i + FINALIZE_BLOCK_CHUNK_SIZE);
607
+ const txsToArchive = [];
608
+ for (const txHashStr of chunk){
609
+ const buffer = await this.#txsDB.getAsync(txHashStr);
610
+ if (buffer) {
611
+ txsToArchive.push(Tx.fromBuffer(buffer));
612
+ }
613
+ }
614
+ if (txsToArchive.length > 0) {
615
+ await this.#archive.archiveTxs(txsToArchive);
400
616
  }
401
617
  }
402
618
  }
403
- // Step 3: Delete mined txs from active pool
404
- await this.#deleteTxsBatch(minedTxsToFinalize);
405
- // Step 4: Finalize soft-deleted txs
406
- await this.#deletedPool.finalizeBlock(blockNumber);
407
- // Step 5: Archive mined txs
408
- if (txsToArchive.length > 0) {
409
- await this.#archive.archiveTxs(txsToArchive);
410
- }
619
+ // Step 3: Delete mined txs from the active pool and finalize soft-deleted txs in one
620
+ // transaction. Only tx hashes are touched here, so memory is bounded and atomicity is preserved.
621
+ await this.#store.transactionAsync(async ()=>{
622
+ await this.#deleteTxsBatch(minedTxsToFinalize);
623
+ await this.#deletedPool.finalizeBlock(cutoffBlock);
624
+ });
411
625
  if (minedTxsToFinalize.length > 0) {
412
- this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`);
626
+ this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${cutoffBlock}`, {
627
+ txHashes: minedTxsToFinalize,
628
+ finalizedBlockNumber: blockNumber,
629
+ cutoffBlock
630
+ });
413
631
  }
414
632
  }
633
+ /**
634
+ * Resolves the block up to which finalized txs may be deleted, given `keepFinalizedTxsForSlots`.
635
+ * With a margin of 0 this is just the finalized block. Otherwise we keep txs whose block is within
636
+ * the margin (in slots) of the finalized tip: take the target slot `finalizedSlot - margin`, find the
637
+ * latest checkpoint at or before it with a single reverse range query (`limit: 1`), and use that
638
+ * checkpoint's last block as the cutoff. This rounds to a checkpoint boundary, so it can retain slightly
639
+ * more than the configured margin but never less, and never deletes past the finalized block.
640
+ */ async #finalizationCutoffBlock(block) {
641
+ const keepSlots = this.#config.keepFinalizedTxsForSlots;
642
+ if (keepSlots <= 0) {
643
+ return block.globalVariables.blockNumber;
644
+ }
645
+ // The goal here really is to ensure we keep transactions long enough for them to be proven.
646
+ // So we could be smart and calculate the number of slots until the end of the proof submission window.
647
+ // Our approach here is a lot simpler however and we just keep transactions for the configured number
648
+ // of slots past L1 finalisation. This means we may keep transactions in the mined pool for longer
649
+ // than strictly necessary.
650
+ const targetSlot = block.getSlot() - keepSlots;
651
+ if (targetSlot < 0) {
652
+ // The margin reaches past genesis: keep everything.
653
+ return BlockNumber(0);
654
+ }
655
+ const [checkpoint] = await this.#l2BlockSource.getCheckpointsData({
656
+ fromSlot: SlotNumber(targetSlot),
657
+ limit: 1,
658
+ reverse: true
659
+ });
660
+ // No checkpoint at or before the target slot (e.g. early chain): keep everything.
661
+ return checkpoint ? BlockNumber(checkpoint.startBlock + checkpoint.blockCount - 1) : BlockNumber(0);
662
+ }
415
663
  // === Query Methods ===
416
- async getTxByHash(txHash) {
417
- const buffer = await this.#txsDB.getAsync(txHash.toString());
418
- return buffer ? Tx.fromBuffer(buffer) : undefined;
664
+ async getTxByHash(txHash, opts = {}) {
665
+ const txHashStr = txHash.toString();
666
+ const buffer = await this.#txsDB.getAsync(txHashStr);
667
+ if (!buffer) {
668
+ return undefined;
669
+ }
670
+ return opts.includeProof === false ? Tx.fromBuffer(buffer) : this.#loadTxWithProof(txHashStr, buffer);
419
671
  }
420
- async getTxsByHash(txHashes) {
672
+ async getTxsByHash(txHashes, opts = {}) {
421
673
  const results = [];
422
674
  for (const h of txHashes){
423
- const buffer = await this.#txsDB.getAsync(h.toString());
424
- results.push(buffer ? Tx.fromBuffer(buffer) : undefined);
675
+ results.push(await this.getTxByHash(h, opts));
425
676
  }
426
677
  return results;
427
678
  }
679
+ /** Deserializes a tx blob loaded from #txsDB together with its separately-stored proof. */ async #loadTxWithProof(txHashStr, buffer) {
680
+ const proofBuffer = await this.#proofsDB.getAsync(txHashStr);
681
+ if (!proofBuffer) {
682
+ // #addTx always writes a proof entry (an empty proof serializes to a 4-byte sentinel), so a missing entry
683
+ // means the blob/proof invariant is broken. Return the proofless tx but flag it, since a consumer that needs
684
+ // the proof (eg serving peers) would otherwise fail far away from the root cause.
685
+ this.#log.warn(`Missing stored proof for tx ${txHashStr}`, {
686
+ txHash: txHashStr
687
+ });
688
+ return Tx.fromBuffer(buffer);
689
+ }
690
+ return Tx.fromBuffers(buffer, proofBuffer);
691
+ }
428
692
  hasTxs(txHashes) {
429
693
  return txHashes.map((h)=>{
430
694
  const hashStr = h.toString();
@@ -448,9 +712,19 @@ import { TxPoolIndices } from './tx_pool_indices.js';
448
712
  ...this.#indices.iteratePendingByPriority('desc')
449
713
  ].map((hash)=>TxHash.fromString(hash));
450
714
  }
715
+ getEligiblePendingTxHashes() {
716
+ const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
717
+ return [
718
+ ...this.#indices.iterateEligiblePendingByPriority('desc', maxReceivedAt)
719
+ ].map((hash)=>TxHash.fromString(hash));
720
+ }
451
721
  getPendingTxCount() {
452
722
  return this.#indices.getPendingTxCount();
453
723
  }
724
+ hasEligiblePendingTxs(minCount) {
725
+ const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
726
+ return this.#indices.hasEligiblePendingTxs(maxReceivedAt, minCount);
727
+ }
454
728
  getMinedTxHashes() {
455
729
  return this.#indices.getMinedTxs().map(([hash, blockId])=>[
456
730
  TxHash.fromString(hash),
@@ -487,6 +761,12 @@ import { TxPoolIndices } from './tx_pool_indices.js';
487
761
  this.#config.archivedTxLimit = config.archivedTxLimit;
488
762
  this.#archive.updateLimit(config.archivedTxLimit);
489
763
  }
764
+ if (config.minTxPoolAgeMs !== undefined) {
765
+ this.#config.minTxPoolAgeMs = config.minTxPoolAgeMs;
766
+ }
767
+ if (config.keepFinalizedTxsForSlots !== undefined) {
768
+ this.#config.keepFinalizedTxsForSlots = config.keepFinalizedTxsForSlots;
769
+ }
490
770
  // Update eviction rules with new config
491
771
  this.#evictionManager.updateConfig(config);
492
772
  }
@@ -501,7 +781,10 @@ import { TxPoolIndices } from './tx_pool_indices.js';
501
781
  }
502
782
  // === Metrics ===
503
783
  countTxs() {
504
- return this.#indices.countTxs();
784
+ return {
785
+ ...this.#indices.countTxs(),
786
+ softDeleted: this.#deletedPool.getSoftDeletedCount()
787
+ };
505
788
  }
506
789
  // ============================================================================
507
790
  // PRIVATE HELPERS - Transaction Management
@@ -509,10 +792,13 @@ import { TxPoolIndices } from './tx_pool_indices.js';
509
792
  /**
510
793
  * Adds a new transaction to the pool with the specified state.
511
794
  * Emits onTxsAdded callback immediately after DB write.
512
- */ async #addTx(tx, state, opts = {}) {
795
+ */ async #addTx(tx, state, opts = {}, precomputedMeta) {
513
796
  const txHashStr = tx.getTxHash().toString();
514
- const meta = await buildTxMetaData(tx);
515
- await this.#txsDB.set(txHashStr, tx.toBuffer());
797
+ const meta = precomputedMeta ?? await buildTxMetaData(tx);
798
+ meta.receivedAt = this.#dateProvider.now();
799
+ await this.#txsDB.set(txHashStr, tx.withoutProof().toBuffer());
800
+ await this.#proofsDB.set(txHashStr, tx.chonkProof.toBuffer());
801
+ await this.#deletedPool.clearSoftDeleted(txHashStr);
516
802
  this.#callbacks.onTxsAdded([
517
803
  tx
518
804
  ], opts);
@@ -525,9 +811,11 @@ import { TxPoolIndices } from './tx_pool_indices.js';
525
811
  this.#indices.addMined(meta);
526
812
  }
527
813
  const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
528
- this.#log.verbose(`Added ${stateStr} tx ${txHashStr}`, {
814
+ this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
529
815
  eventName: 'tx-added-to-pool',
530
- state: stateStr
816
+ txHash: txHashStr,
817
+ state: stateStr,
818
+ source: opts.source
531
819
  });
532
820
  return meta;
533
821
  }
@@ -545,11 +833,29 @@ import { TxPoolIndices } from './tx_pool_indices.js';
545
833
  ]);
546
834
  await this.#deletedPool.deleteTx(txHashStr);
547
835
  }
836
+ /** Hard-deletes a tx's stored data (tx blob and proof) from the DB. */ async #deleteTxData(txHashStr) {
837
+ await this.#txsDB.delete(txHashStr);
838
+ await this.#proofsDB.delete(txHashStr);
839
+ }
548
840
  /** Deletes a batch of transactions, emitting callbacks individually for each. */ async #deleteTxsBatch(txHashes) {
549
841
  for (const txHashStr of txHashes){
550
842
  await this.#deleteTx(txHashStr);
551
843
  }
552
844
  }
845
+ /** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */ async #evictTxs(txHashes, reason) {
846
+ if (txHashes.length === 0) {
847
+ return;
848
+ }
849
+ this.#instrumentation.recordEvictions(txHashes.length, reason);
850
+ for (const txHashStr of txHashes){
851
+ this.#log.debug(`Evicting tx ${txHashStr}`, {
852
+ txHash: txHashStr,
853
+ reason
854
+ });
855
+ this.#evictedTxHashes.add(txHashStr);
856
+ }
857
+ await this.#deleteTxsBatch(txHashes);
858
+ }
553
859
  // ============================================================================
554
860
  // PRIVATE HELPERS - Validation & Conflict Resolution
555
861
  // ============================================================================
@@ -630,50 +936,6 @@ import { TxPoolIndices } from './tx_pool_indices.js';
630
936
  hash: txEffect.l2BlockHash.toString()
631
937
  };
632
938
  }
633
- /** Loads all transactions from the database, returning loaded txs and deserialization errors */ async #loadAllTxsFromDb() {
634
- const loaded = [];
635
- const errors = [];
636
- for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()){
637
- // Skip soft-deleted transactions - they stay in DB but not in indices
638
- if (this.#deletedPool.isSoftDeleted(txHashStr)) {
639
- continue;
640
- }
641
- try {
642
- const tx = Tx.fromBuffer(buffer);
643
- const meta = await buildTxMetaData(tx);
644
- loaded.push({
645
- tx,
646
- meta
647
- });
648
- } catch (err) {
649
- this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, {
650
- err
651
- });
652
- errors.push(txHashStr);
653
- }
654
- }
655
- return {
656
- loaded,
657
- errors
658
- };
659
- }
660
- /** Queries block source and marks mined status on transaction metadata */ async #markMinedStatusBatch(metas) {
661
- for (const meta of metas){
662
- try {
663
- const txEffect = await this.#l2BlockSource.getTxEffect(TxHash.fromString(meta.txHash));
664
- if (txEffect) {
665
- meta.minedL2BlockId = {
666
- number: txEffect.l2BlockNumber,
667
- hash: txEffect.l2BlockHash.toString()
668
- };
669
- }
670
- } catch (err) {
671
- this.#log.warn(`Failed to check mined status for tx ${meta.txHash}`, {
672
- err
673
- });
674
- }
675
- }
676
- }
677
939
  /**
678
940
  * Rebuilds the pending pool by processing each tx through pre-add rules.
679
941
  * Starts with an empty pending pool and adds txs one by one, resolving conflicts.
@@ -688,7 +950,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
688
950
  if (preAddResult.shouldIgnore) {
689
951
  // Transaction rejected - mark for deletion from DB
690
952
  rejected.push(meta.txHash);
691
- this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason}`);
953
+ this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`);
692
954
  continue;
693
955
  }
694
956
  // Evict any conflicting txs identified by pre-add rules
@@ -724,7 +986,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
724
986
  getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),
725
987
  getPendingTxCount: ()=>this.#indices.getPendingTxCount(),
726
988
  getLowestPriorityPending: (limit)=>this.#indices.getLowestPriorityPending(limit),
727
- deleteTxs: (txHashes)=>this.#deleteTxsBatch(txHashes)
989
+ deleteTxs: (txHashes, reason)=>this.#evictTxs(txHashes, reason ?? 'unknown')
728
990
  };
729
991
  }
730
992
  #createPreAddPoolAccess() {
@@ -740,7 +1002,7 @@ import { TxPoolIndices } from './tx_pool_indices.js';
740
1002
  getFeePayerBalance: async (feePayer)=>{
741
1003
  const db = this.#worldStateSynchronizer.getCommitted();
742
1004
  const publicStateSource = new DatabasePublicStateSource(db);
743
- const balance = await publicStateSource.storageRead(ProtocolContractAddress.FeeJuice, await computeFeePayerBalanceStorageSlot(AztecAddress.fromString(feePayer)));
1005
+ const balance = await publicStateSource.storageRead(ProtocolContractAddress.FeeJuice, await computeFeePayerBalanceStorageSlot(AztecAddress.fromStringUnsafe(feePayer)));
744
1006
  return balance.toBigInt();
745
1007
  },
746
1008
  getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),