@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,5 +1,7 @@
1
1
  import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { FifoSet } from '@aztec/foundation/fifo-set';
2
3
  import type { Logger } from '@aztec/foundation/log';
4
+ import type { DateProvider } from '@aztec/foundation/timer';
3
5
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
4
6
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
5
7
  import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
@@ -8,6 +10,7 @@ import type { L2Block, L2BlockId, L2BlockSource } from '@aztec/stdlib/block';
8
10
  import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
9
11
  import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
10
12
  import { BlockHeader, Tx, TxHash, type TxValidator } from '@aztec/stdlib/tx';
13
+ import type { TelemetryClient } from '@aztec/telemetry-client';
11
14
 
12
15
  import { TxArchive } from './archive/index.js';
13
16
  import { DeletedPool } from './deleted_pool.js';
@@ -15,14 +18,19 @@ import {
15
18
  EvictionManager,
16
19
  FeePayerBalanceEvictionRule,
17
20
  FeePayerBalancePreAddRule,
21
+ InsufficientFeePerGasEvictionRule,
18
22
  InvalidTxsAfterMiningRule,
19
23
  InvalidTxsAfterReorgRule,
20
24
  LowPriorityEvictionRule,
21
25
  LowPriorityPreAddRule,
22
26
  NullifierConflictRule,
23
27
  type PoolOperations,
28
+ type PreAddContext,
24
29
  type PreAddPoolAccess,
30
+ TxPoolRejectionCode,
31
+ type TxPoolRejectionError,
25
32
  } from './eviction/index.js';
33
+ import { TxPoolV2Instrumentation } from './instrumentation.js';
26
34
  import {
27
35
  type AddTxsResult,
28
36
  DEFAULT_TX_POOL_V2_CONFIG,
@@ -33,12 +41,28 @@ import {
33
41
  import { type TxMetaData, type TxState, buildTxMetaData, checkNullifierConflict } from './tx_metadata.js';
34
42
  import { TxPoolIndices } from './tx_pool_indices.js';
35
43
 
44
+ /**
45
+ * Maximum number of full transactions to load into memory at once when finalizing a block.
46
+ * Bounds peak memory while archiving and hard-deleting mined txs (~23k txs/epoch at 10 TPS would
47
+ * otherwise OOM the node).
48
+ */
49
+ const FINALIZE_BLOCK_CHUNK_SIZE = 100;
50
+
36
51
  /**
37
52
  * Callbacks for the implementation to notify the outer class about events and metrics.
38
53
  */
54
+ /** A tx that has just transitioned to mined, with the time it spent in the pool. */
55
+ export interface MinedTxInfo {
56
+ txHash: string;
57
+ /** Wall-clock ms from receipt into the pool to being marked mined. Undefined when the
58
+ * receive time is unknown (e.g. a tx hydrated from the DB on restart, receivedAt === 0). */
59
+ minedDelayMs?: number;
60
+ }
61
+
39
62
  export interface TxPoolV2Callbacks {
40
63
  onTxsAdded: (txs: Tx[], opts: { source?: string }) => void;
41
64
  onTxsRemoved: (txHashes: string[] | bigint[]) => void;
65
+ onTxsMined: (minedTxs: MinedTxInfo[]) => void;
42
66
  }
43
67
 
44
68
  /**
@@ -49,12 +73,16 @@ export interface TxPoolV2Callbacks {
49
73
  export class TxPoolV2Impl {
50
74
  // === Persistence ===
51
75
  #store: AztecAsyncKVStore;
76
+ /** Tx data without its proof. Proofs live in #proofsDB so a tx can be read without loading its proof. */
52
77
  #txsDB: AztecAsyncMap<string, Buffer>;
78
+ /** Tx proofs, keyed by tx hash. Written and deleted in lockstep with #txsDB. */
79
+ #proofsDB: AztecAsyncMap<string, Buffer>;
53
80
 
54
81
  // === Dependencies ===
55
82
  #l2BlockSource: L2BlockSource;
56
83
  #worldStateSynchronizer: WorldStateSynchronizer;
57
84
  #createTxValidator: TxPoolV2Dependencies['createTxValidator'];
85
+ #checkAllowedSetupCalls: TxPoolV2Dependencies['checkAllowedSetupCalls'];
58
86
 
59
87
  // === In-Memory Indices ===
60
88
  #indices: TxPoolIndices = new TxPoolIndices();
@@ -64,6 +92,9 @@ export class TxPoolV2Impl {
64
92
  #archive: TxArchive;
65
93
  #deletedPool: DeletedPool;
66
94
  #evictionManager: EvictionManager;
95
+ #dateProvider: DateProvider;
96
+ #instrumentation: TxPoolV2Instrumentation;
97
+ #evictedTxHashes: FifoSet<string>;
67
98
  #log: Logger;
68
99
  #callbacks: TxPoolV2Callbacks;
69
100
 
@@ -72,19 +103,26 @@ export class TxPoolV2Impl {
72
103
  archiveStore: AztecAsyncKVStore,
73
104
  deps: TxPoolV2Dependencies,
74
105
  callbacks: TxPoolV2Callbacks,
106
+ telemetry: TelemetryClient,
75
107
  config: Partial<TxPoolV2Config> = {},
108
+ dateProvider: DateProvider,
76
109
  log: Logger,
77
110
  ) {
78
111
  this.#store = store;
79
112
  this.#txsDB = store.openMap('txs');
113
+ this.#proofsDB = store.openMap('tx_proofs');
80
114
 
81
115
  this.#l2BlockSource = deps.l2BlockSource;
82
116
  this.#worldStateSynchronizer = deps.worldStateSynchronizer;
83
117
  this.#createTxValidator = deps.createTxValidator;
118
+ this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
84
119
 
85
120
  this.#config = { ...DEFAULT_TX_POOL_V2_CONFIG, ...config };
121
+ this.#evictedTxHashes = FifoSet.withLimit<string>(this.#config.evictedTxCacheSize);
86
122
  this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
87
- this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
123
+ this.#deletedPool = new DeletedPool(store, txHashStr => this.#deleteTxData(txHashStr), log);
124
+ this.#dateProvider = dateProvider;
125
+ this.#instrumentation = new TxPoolV2Instrumentation(telemetry, () => this.#indices.getTotalMetadataBytes());
88
126
  this.#log = log;
89
127
  this.#callbacks = callbacks;
90
128
 
@@ -100,6 +138,7 @@ export class TxPoolV2Impl {
100
138
 
101
139
  // Post-event eviction rules (run after events to check ALL pending txs)
102
140
  this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
141
+ this.#evictionManager.registerRule(new InsufficientFeePerGasEvictionRule(deps.blockMinFeesProvider));
103
142
  this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(deps.worldStateSynchronizer));
104
143
  this.#evictionManager.registerRule(new FeePayerBalanceEvictionRule(deps.worldStateSynchronizer));
105
144
  // LowPriorityEvictionRule handles cases where txs become pending via prepareForSlot (unprotect)
@@ -122,58 +161,115 @@ export class TxPoolV2Impl {
122
161
  // Step 0: Hydrate deleted pool state
123
162
  await this.#deletedPool.hydrateFromDatabase();
124
163
 
125
- // Step 1: Load all transactions from DB (excluding soft-deleted)
126
- const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
164
+ // Step 1: Stream txs from DB, building metadata and mined status one at a time.
165
+ const minedMetas: TxMetaData[] = [];
166
+ const pendingMetas: TxMetaData[] = [];
167
+ const deserializationErrors: string[] = [];
127
168
 
128
- // Step 2: Check mined status for each tx
129
- await this.#markMinedStatusBatch(loaded.map(l => l.meta));
169
+ for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()) {
170
+ // Skip soft-deleted transactions - they stay in DB but not in indices
171
+ if (this.#deletedPool.isSoftDeleted(txHashStr)) {
172
+ continue;
173
+ }
130
174
 
131
- // Step 3: Partition by mined status
132
- const mined: TxMetaData[] = [];
133
- const nonMined: { tx: Tx; meta: TxMetaData }[] = [];
134
- for (const entry of loaded) {
135
- if (entry.meta.minedL2BlockId !== undefined) {
136
- mined.push(entry.meta);
175
+ let meta: TxMetaData;
176
+ let txEffect: Awaited<ReturnType<L2BlockSource['getTxEffect']>>;
177
+ try {
178
+ const tx = Tx.fromBuffer(buffer);
179
+ // Resolve allowed-setup-calls and the tx effect concurrently
180
+ // getTxEffect failures are non-fatal (we just treat the tx as not-yet-mined), so
181
+ // its rejection is swallowed before the Promise.all so it can't fail-fast the batch.
182
+ const txEffectPromise = this.#l2BlockSource.getTxEffect(tx.getTxHash()).catch(err => {
183
+ this.#log.warn(`Failed to check mined status for tx ${txHashStr}`, { err });
184
+ return undefined;
185
+ });
186
+ const [allowedSetupCalls, fetchedTxEffect] = await Promise.all([
187
+ this.#checkAllowedSetupCalls(tx),
188
+ txEffectPromise,
189
+ ]);
190
+ meta = await buildTxMetaData(tx, allowedSetupCalls);
191
+ txEffect = fetchedTxEffect;
192
+ } catch (err) {
193
+ this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, { err });
194
+ deserializationErrors.push(txHashStr);
195
+ continue;
196
+ }
197
+
198
+ if (txEffect) {
199
+ meta.minedL2BlockId = {
200
+ number: txEffect.l2BlockNumber,
201
+ hash: txEffect.l2BlockHash.toString(),
202
+ };
203
+ }
204
+
205
+ if (meta.minedL2BlockId !== undefined) {
206
+ minedMetas.push(meta);
137
207
  } else {
138
- nonMined.push(entry);
208
+ pendingMetas.push(meta);
139
209
  }
140
210
  }
141
211
 
142
- // Step 4: Validate non-mined transactions
143
- const { valid, invalid } = await this.#revalidateMetadata(
144
- nonMined.map(e => e.meta),
145
- 'on startup',
146
- );
212
+ // Step 2: Validate non-mined transactions
213
+ const { valid, invalid } = await this.#revalidateMetadata(pendingMetas, 'on startup');
147
214
 
148
- // Step 5: Populate mined indices (these don't need conflict resolution)
149
- for (const meta of mined) {
215
+ // Step 3: Populate mined indices (these don't need conflict resolution)
216
+ for (const meta of minedMetas) {
150
217
  this.#indices.addMined(meta);
151
218
  }
152
219
 
153
- // Step 6: Rebuild pending pool by running pre-add rules for each tx
220
+ // Step 4: Rebuild pending pool by running pre-add rules for each tx
154
221
  // This resolves nullifier conflicts, fee payer balance issues, and pool size limits
155
222
  const { rejected } = await this.#rebuildPendingPool(valid);
156
223
 
157
- // Step 7: Delete invalid and rejected txs from DB only (indices were never populated for these)
224
+ // Step 5: Delete invalid and rejected txs from DB only (indices were never populated for these)
158
225
  const toDelete = [...deserializationErrors, ...invalid, ...rejected];
159
226
  if (toDelete.length === 0) {
160
227
  return;
161
228
  }
162
229
  await this.#store.transactionAsync(async () => {
163
230
  for (const txHashStr of toDelete) {
164
- await this.#txsDB.delete(txHashStr);
231
+ await this.#deleteTxData(txHashStr);
165
232
  }
166
233
  });
167
- this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`);
234
+ this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, { txHashes: toDelete });
168
235
  }
169
236
 
170
- async addPendingTxs(txs: Tx[], opts: { source?: string }): Promise<AddTxsResult> {
237
+ async addPendingTxs(txs: Tx[], opts: { source?: string; feeComparisonOnly?: boolean }): Promise<AddTxsResult> {
171
238
  const accepted: TxHash[] = [];
172
239
  const ignored: TxHash[] = [];
173
240
  const rejected: TxHash[] = [];
241
+ const errors = new Map<string, TxPoolRejectionError>();
174
242
  const acceptedPending = new Set<string>();
175
243
 
244
+ // Phase 1: Pre-compute all throwable I/O outside the transaction.
245
+ // If any pre-computation throws, the entire call fails before mutations happen.
246
+ const precomputed = new Map<string, { meta: TxMetaData; minedBlockId: L2BlockId | undefined; isValid: boolean }>();
247
+
248
+ const validator = await this.#createTxValidator();
249
+
250
+ for (const tx of txs) {
251
+ const txHash = tx.getTxHash();
252
+ const txHashStr = txHash.toString();
253
+
254
+ const meta = await buildTxMetaData(tx);
255
+ const minedBlockId = await this.#getMinedBlockId(txHash);
256
+
257
+ // Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
258
+ let isValid = true;
259
+ if (!minedBlockId) {
260
+ isValid = await this.#validateMeta(meta, validator);
261
+ }
262
+
263
+ precomputed.set(txHashStr, { meta, minedBlockId, isValid });
264
+ }
265
+
266
+ // Phase 2: Apply mutations inside the transaction using only pre-computed results,
267
+ // in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
176
268
  const poolAccess = this.#createPreAddPoolAccess();
269
+ const preAddContext: PreAddContext | undefined =
270
+ opts.feeComparisonOnly !== undefined
271
+ ? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
272
+ : undefined;
177
273
 
178
274
  await this.#store.transactionAsync(async () => {
179
275
  for (const tx of txs) {
@@ -186,30 +282,46 @@ export class TxPoolV2Impl {
186
282
  continue;
187
283
  }
188
284
 
189
- // Check mined status first (applies to all paths)
190
- const minedBlockId = await this.#getMinedBlockId(txHash);
285
+ const { meta, minedBlockId, isValid } = precomputed.get(txHashStr)!;
191
286
  const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
192
287
 
193
288
  if (minedBlockId) {
194
289
  // Already mined - add directly (protection already set if pre-protected)
195
- await this.#addTx(tx, { mined: minedBlockId }, opts);
290
+ await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
196
291
  accepted.push(txHash);
197
292
  } else if (preProtectedSlot !== undefined) {
198
293
  // Pre-protected and not mined - add as protected (bypass validation)
199
- await this.#addTx(tx, { protected: preProtectedSlot }, opts);
294
+ await this.#addTx(tx, { protected: preProtectedSlot }, opts, meta);
200
295
  accepted.push(txHash);
296
+ } else if (!isValid) {
297
+ // Failed pre-computed validation
298
+ rejected.push(txHash);
201
299
  } else {
202
- // Regular pending tx - validate and run pre-add rules
203
- const result = await this.#tryAddRegularPendingTx(tx, opts, poolAccess, acceptedPending, ignored);
300
+ // Regular pending tx - run pre-add rules using pre-computed metadata
301
+ const result = await this.#tryAddRegularPendingTx(
302
+ tx,
303
+ meta,
304
+ opts,
305
+ poolAccess,
306
+ acceptedPending,
307
+ ignored,
308
+ errors,
309
+ preAddContext,
310
+ );
204
311
  if (result.status === 'accepted') {
205
312
  acceptedPending.add(txHashStr);
206
- } else if (result.status === 'rejected') {
207
- rejected.push(txHash);
208
313
  } else {
209
314
  ignored.push(txHash);
210
315
  }
211
316
  }
212
317
  }
318
+
319
+ // Run post-add eviction rules for pending txs (inside transaction for atomicity)
320
+ if (acceptedPending.size > 0) {
321
+ const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
322
+ const uniqueFeePayers = new Set<string>(feePayers);
323
+ await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
324
+ }
213
325
  });
214
326
 
215
327
  // Build final accepted list for pending txs (excludes intra-batch evictions)
@@ -217,96 +329,124 @@ export class TxPoolV2Impl {
217
329
  accepted.push(TxHash.fromString(txHashStr));
218
330
  }
219
331
 
220
- // Run post-add eviction rules for pending txs
221
- if (acceptedPending.size > 0) {
222
- const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
223
- const uniqueFeePayers = new Set<string>(feePayers);
224
- await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
332
+ // Record metrics
333
+ if (ignored.length > 0) {
334
+ this.#instrumentation.recordIgnored(ignored.length);
335
+ }
336
+ if (rejected.length > 0) {
337
+ this.#instrumentation.recordRejected(rejected.length);
225
338
  }
226
339
 
227
- return { accepted, ignored, rejected };
340
+ return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
228
341
  }
229
342
 
230
- /** Validates and adds a regular pending tx. Returns status. */
343
+ /** Adds a validated pending tx, running pre-add rules and evicting conflicts. */
231
344
  async #tryAddRegularPendingTx(
232
345
  tx: Tx,
346
+ precomputedMeta: TxMetaData,
233
347
  opts: { source?: string },
234
348
  poolAccess: PreAddPoolAccess,
235
349
  acceptedPending: Set<string>,
236
350
  ignored: TxHash[],
237
- ): Promise<{ status: 'accepted' | 'ignored' | 'rejected' }> {
238
- const txHash = tx.getTxHash();
239
- const txHashStr = txHash.toString();
240
-
241
- // Build metadata and validate using metadata
242
- const meta = await buildTxMetaData(tx);
243
- if (!(await this.#validateMeta(meta))) {
244
- return { status: 'rejected' };
245
- }
351
+ errors: Map<string, TxPoolRejectionError>,
352
+ preAddContext?: PreAddContext,
353
+ ): Promise<{ status: 'accepted' | 'ignored' }> {
354
+ const txHashStr = tx.getTxHash().toString();
246
355
 
247
356
  // Run pre-add rules
248
- const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
357
+ const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
249
358
 
250
359
  if (preAddResult.shouldIgnore) {
251
- this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
360
+ this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
361
+ if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
362
+ errors.set(txHashStr, preAddResult.reason);
363
+ }
252
364
  return { status: 'ignored' };
253
365
  }
254
366
 
255
- // Evict conflicts
256
- for (const evictHashStr of preAddResult.txHashesToEvict) {
257
- await this.#deleteTx(evictHashStr);
258
- this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`);
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));
367
+ // Evict conflicts, grouped by rule name for metrics
368
+ if (preAddResult.evictions && preAddResult.evictions.length > 0) {
369
+ const byReason = new Map<string, string[]>();
370
+ for (const { txHash: evictHash, reason } of preAddResult.evictions) {
371
+ const group = byReason.get(reason);
372
+ if (group) {
373
+ group.push(evictHash);
374
+ } else {
375
+ byReason.set(reason, [evictHash]);
376
+ }
377
+ }
378
+ for (const [reason, hashes] of byReason) {
379
+ await this.#evictTxs(hashes, reason);
380
+ }
381
+ for (const evictHashStr of preAddResult.txHashesToEvict) {
382
+ this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
383
+ evictedTxHash: evictHashStr,
384
+ replacementTxHash: txHashStr,
385
+ });
386
+ if (acceptedPending.has(evictHashStr)) {
387
+ // Evicted tx was from this batch - mark as ignored in result
388
+ acceptedPending.delete(evictHashStr);
389
+ ignored.push(TxHash.fromString(evictHashStr));
390
+ }
263
391
  }
264
392
  }
265
393
 
394
+ // Randomly drop the transaction for testing purposes (report as accepted so it propagates)
395
+ if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
396
+ this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
397
+ return { status: 'accepted' };
398
+ }
399
+
266
400
  // Add the transaction
267
- await this.#addTx(tx, 'pending', opts);
401
+ await this.#addTx(tx, 'pending', opts, precomputedMeta);
268
402
  return { status: 'accepted' };
269
403
  }
270
404
 
271
- async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored' | 'rejected'> {
405
+ async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
272
406
  const txHashStr = tx.getTxHash().toString();
273
407
 
274
408
  // Check if already in pool
275
409
  if (this.#indices.has(txHashStr)) {
410
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
276
411
  return 'ignored';
277
412
  }
278
413
 
279
- // Build metadata and validate using metadata
414
+ // Build metadata and check pre-add rules
280
415
  const meta = await buildTxMetaData(tx);
281
- const validationResult = await this.#validateMeta(meta, undefined, 'can add pending');
282
- if (validationResult !== true) {
283
- return 'rejected';
284
- }
285
-
286
- // Use pre-add rules
287
416
  const poolAccess = this.#createPreAddPoolAccess();
288
417
  const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
289
418
 
290
- return preAddResult.shouldIgnore ? 'ignored' : 'accepted';
419
+ if (preAddResult.shouldIgnore) {
420
+ this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
421
+ reason: preAddResult.reason?.message ?? 'no reason provided',
422
+ });
423
+ return 'ignored';
424
+ }
425
+ return 'accepted';
291
426
  }
292
427
 
293
428
  async addProtectedTxs(txs: Tx[], block: BlockHeader, opts: { source?: string }): Promise<void> {
294
429
  const slotNumber = block.globalVariables.slotNumber;
295
430
 
431
+ // Precompute setup-call allow-list flags outside the store transaction
432
+ const allowedFlags = await Promise.all(txs.map(tx => this.#checkAllowedSetupCalls(tx)));
433
+
296
434
  await this.#store.transactionAsync(async () => {
297
- for (const tx of txs) {
435
+ for (let i = 0; i < txs.length; i++) {
436
+ const tx = txs[i];
298
437
  const txHash = tx.getTxHash();
299
438
  const txHashStr = txHash.toString();
300
439
  const isNew = !this.#indices.has(txHashStr);
301
440
  const minedBlockId = await this.#getMinedBlockId(txHash);
302
441
 
303
442
  if (isNew) {
443
+ const meta = await buildTxMetaData(tx, allowedFlags[i]);
304
444
  // New tx - add as mined or protected (callback emitted by #addTx)
305
445
  if (minedBlockId) {
306
- await this.#addTx(tx, { mined: minedBlockId }, opts);
446
+ await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
307
447
  this.#indices.setProtection(txHashStr, slotNumber);
308
448
  } else {
309
- await this.#addTx(tx, { protected: slotNumber }, opts);
449
+ await this.#addTx(tx, { protected: slotNumber }, opts, meta);
310
450
  }
311
451
  } else {
312
452
  // Existing tx - update protection and mined status
@@ -320,23 +460,59 @@ export class TxPoolV2Impl {
320
460
  });
321
461
  }
322
462
 
323
- protectTxs(txHashes: TxHash[], block: BlockHeader): TxHash[] {
463
+ async protectTxs(txHashes: TxHash[], block: BlockHeader): Promise<TxHash[]> {
324
464
  const slotNumber = block.globalVariables.slotNumber;
325
465
  const missing: TxHash[] = [];
466
+ let softDeletedHits = 0;
467
+ let missingPreviouslyEvicted = 0;
326
468
 
327
- for (const txHash of txHashes) {
328
- const txHashStr = txHash.toString();
469
+ await this.#store.transactionAsync(async () => {
470
+ for (const txHash of txHashes) {
471
+ const txHashStr = txHash.toString();
329
472
 
330
- if (this.#indices.has(txHashStr)) {
331
- // Update protection for existing tx
332
- this.#indices.updateProtection(txHashStr, slotNumber);
333
- } else {
334
- // Pre-record protection for tx we don't have yet
335
- this.#indices.setProtection(txHashStr, slotNumber);
336
- missing.push(txHash);
473
+ if (this.#indices.has(txHashStr)) {
474
+ // Update protection for existing tx
475
+ this.#indices.updateProtection(txHashStr, slotNumber);
476
+ } else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
477
+ // Resurrect soft-deleted tx as protected. Load the proof too: #addTx rewrites both entries, so re-adding
478
+ // a proofless tx would wipe the stored proof.
479
+ const buffer = await this.#txsDB.getAsync(txHashStr);
480
+ if (buffer) {
481
+ const tx = await this.#loadTxWithProof(txHashStr, buffer);
482
+ await this.#addTx(tx, { protected: slotNumber });
483
+ softDeletedHits++;
484
+ } else {
485
+ // Data missing despite soft-delete flag — treat as truly missing
486
+ this.#indices.setProtection(txHashStr, slotNumber);
487
+ missing.push(txHash);
488
+ }
489
+ } else {
490
+ // Truly missing — pre-record protection for tx we don't have yet
491
+ this.#indices.setProtection(txHashStr, slotNumber);
492
+ missing.push(txHash);
493
+ if (this.#evictedTxHashes.has(txHashStr)) {
494
+ missingPreviouslyEvicted++;
495
+ }
496
+ }
337
497
  }
498
+ });
499
+
500
+ // Record metrics
501
+ if (softDeletedHits > 0) {
502
+ this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
503
+ }
504
+ if (missing.length > 0) {
505
+ this.#log.debug(`protectTxs missing tx hashes: ${missing.map(h => h.toString()).join(', ')}`);
506
+ this.#instrumentation.recordMissingOnProtect(missing.length);
507
+ }
508
+ if (missingPreviouslyEvicted > 0) {
509
+ this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
338
510
  }
339
511
 
512
+ this.#log.info(
513
+ `Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`,
514
+ );
515
+
340
516
  return missing;
341
517
  }
342
518
 
@@ -380,43 +556,97 @@ export class TxPoolV2Impl {
380
556
  }
381
557
  }
382
558
 
383
- // Step 4: Mark txs as mined (only those we have in the pool)
384
- for (const meta of found) {
385
- this.#indices.markAsMined(meta, blockId);
386
- await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
387
- }
559
+ await this.#store.transactionAsync(async () => {
560
+ // Step 4: Mark txs as mined (only those we have in the pool)
561
+ for (const meta of found) {
562
+ this.#indices.markAsMined(meta, blockId);
563
+ await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
564
+ }
565
+
566
+ // Step 5: Run post-event eviction rules (inside transaction for atomicity)
567
+ await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
568
+ });
388
569
 
389
- // Step 5: Run eviction rules (remove pending txs with conflicting nullifiers/expired timestamps)
390
- await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
570
+ if (found.length > 0) {
571
+ // receivedAt is 0 for txs hydrated from the DB on restart (true receive time lost) — leave
572
+ // their delay undefined so the metric isn't polluted by epoch-sized values.
573
+ const now = this.#dateProvider.now();
574
+ this.#callbacks.onTxsMined(
575
+ found.map(m => ({
576
+ txHash: m.txHash,
577
+ minedDelayMs: m.receivedAt > 0 ? now - m.receivedAt : undefined,
578
+ })),
579
+ );
580
+ }
391
581
 
392
582
  this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
393
583
  }
394
584
 
395
585
  async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
396
- // Step 1: Find expired protected txs
397
- const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
586
+ await this.#store.transactionAsync(async () => {
587
+ // Step 0: Clean up slot-deleted txs from previous slots
588
+ await this.#deletedPool.cleanupSlotDeleted(slotNumber);
398
589
 
399
- // Step 2: Clear protection for all expired entries (including those without metadata)
400
- this.#indices.clearProtection(expiredProtected);
590
+ // Step 1: Find expired protected txs
591
+ const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
401
592
 
402
- // Step 3: Filter to only txs that have metadata and are not mined
403
- const txsToRestore = this.#indices.filterRestorable(expiredProtected);
404
- if (txsToRestore.length === 0) {
405
- return;
406
- }
593
+ // Step 2: Clear protection for all expired entries (including those without metadata)
594
+ this.#indices.clearProtection(expiredProtected);
407
595
 
408
- this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
596
+ // Step 3: Filter to only txs that have metadata and are not mined
597
+ const txsToRestore = this.#indices.filterRestorable(expiredProtected);
598
+ if (txsToRestore.length === 0) {
599
+ this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
600
+ return;
601
+ }
409
602
 
410
- // Step 4: Validate for pending pool
411
- const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
603
+ this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
604
+ await this.#restoreUnprotectedToPending(txsToRestore, 'during prepareForSlot');
605
+ });
606
+ }
607
+
608
+ async unprotectTxs(txHashes: TxHash[], slotNumber: SlotNumber): Promise<void> {
609
+ const hashStrs = txHashes.map(h => h.toString());
610
+
611
+ await this.#store.transactionAsync(async () => {
612
+ // Only release entries still recorded at this exact slot. A tx that another, still-live proposal
613
+ // raised to a higher slot via updateProtection must keep that protection. Mined txs have no
614
+ // protection entry and so are never matched here.
615
+ const matching = this.#indices.findProtectedTxsAtSlot(hashStrs, slotNumber);
616
+ if (matching.length === 0) {
617
+ this.#log.debug(`Unprotecting txs for slot ${slotNumber}: no matching protections to release`);
618
+ return;
619
+ }
620
+
621
+ this.#indices.clearProtection(matching);
412
622
 
413
- // Step 5: Resolve nullifier conflicts and add winners to pending indices
623
+ const txsToRestore = this.#indices.filterRestorable(matching);
624
+ if (txsToRestore.length === 0) {
625
+ return;
626
+ }
627
+
628
+ this.#log.info(`Unprotecting ${txsToRestore.length} txs from failed proposal at slot ${slotNumber}`);
629
+ await this.#restoreUnprotectedToPending(txsToRestore, 'during unprotectTxs');
630
+ });
631
+ }
632
+
633
+ /**
634
+ * Returns just-unprotected txs to the pending pool: revalidates them, resolves nullifier
635
+ * conflicts, deletes losers, then enforces the pool size limit. Must run inside a store
636
+ * transaction; callers clear the protection entries before invoking.
637
+ */
638
+ async #restoreUnprotectedToPending(txsToRestore: TxMetaData[], context: string): Promise<void> {
639
+ // Step 1: Validate for pending pool
640
+ const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, context);
641
+
642
+ // Step 2: Resolve nullifier conflicts and add winners to pending indices
414
643
  const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
415
644
 
416
- // Step 6: Delete invalid and evicted txs
417
- await this.#deleteTxsBatch([...invalid, ...toEvict]);
645
+ // Step 3: Delete invalid txs and evict conflict losers
646
+ await this.#deleteTxsBatch(invalid);
647
+ await this.#evictTxs(toEvict, 'NullifierConflict');
418
648
 
419
- // Step 7: Run eviction rules (enforce pool size limit)
649
+ // Step 4: Run eviction rules (enforce pool size limit)
420
650
  if (added.length > 0) {
421
651
  const feePayers = added.map(meta => meta.feePayer);
422
652
  const uniqueFeePayers = new Set<string>(feePayers);
@@ -427,7 +657,7 @@ export class TxPoolV2Impl {
427
657
  }
428
658
  }
429
659
 
430
- async handlePrunedBlocks(latestBlock: L2BlockId): Promise<void> {
660
+ async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
431
661
  // Step 1: Find transactions mined after the prune point
432
662
  const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
433
663
  if (txsToUnmine.length === 0) {
@@ -437,94 +667,174 @@ export class TxPoolV2Impl {
437
667
 
438
668
  this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
439
669
 
440
- // Step 2: Mark ALL un-mined txs with their original mined block number
441
- // This ensures they get soft-deleted if removed later, and only hard-deleted
442
- // when their original mined block is finalized
443
- await this.#deletedPool.markFromPrunedBlock(
444
- txsToUnmine.map(m => ({
445
- txHash: m.txHash,
446
- minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
447
- })),
448
- );
670
+ await this.#store.transactionAsync(async () => {
671
+ // Step 2: Mark ALL un-mined txs with their original mined block number
672
+ // This ensures they get soft-deleted if removed later, and only hard-deleted
673
+ // when their original mined block is finalized
674
+ await this.#deletedPool.markFromPrunedBlock(
675
+ txsToUnmine.map(m => ({
676
+ txHash: m.txHash,
677
+ minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
678
+ })),
679
+ );
449
680
 
450
- // Step 3: Unmine - clear mined status from metadata
451
- for (const meta of txsToUnmine) {
452
- this.#indices.markAsUnmined(meta);
453
- }
681
+ // Step 3: Unmine - clear mined status from metadata
682
+ for (const meta of txsToUnmine) {
683
+ this.#indices.markAsUnmined(meta);
684
+ }
454
685
 
455
- // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
456
- const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
686
+ // If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
687
+ if (options?.deleteAllTxs) {
688
+ const allTxHashes = txsToUnmine.map(m => m.txHash);
689
+ await this.#deleteTxsBatch(allTxHashes);
690
+ this.#log.info(
691
+ `Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
692
+ );
693
+ return;
694
+ }
457
695
 
458
- // Step 4: Validate for pending pool
459
- const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
696
+ // Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
697
+ const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
460
698
 
461
- // Step 6: Resolve nullifier conflicts and add winners to pending indices
462
- const { toEvict } = this.#applyNullifierConflictResolution(valid);
699
+ // Step 5: Validate for pending pool
700
+ const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
463
701
 
464
- // Step 7: Delete invalid and evicted txs
465
- await this.#deleteTxsBatch([...invalid, ...toEvict]);
702
+ // Step 6: Resolve nullifier conflicts and add winners to pending indices
703
+ const { toEvict } = this.#applyNullifierConflictResolution(valid);
466
704
 
467
- // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
468
- // This handles cases like existing pending txs with invalid fee payer balances
469
- await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
705
+ // Step 7: Delete invalid txs and evict conflict losers
706
+ await this.#deleteTxsBatch(invalid);
707
+ await this.#evictTxs(toEvict, 'NullifierConflict');
708
+
709
+ this.#log.info(
710
+ `Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
711
+ { txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
712
+ );
713
+
714
+ // Step 8: Run eviction rules for ALL pending txs (not just restored ones)
715
+ // This handles cases like existing pending txs with invalid fee payer balances
716
+ await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
717
+ });
470
718
  }
471
719
 
472
720
  async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
473
- // Delete failed txs
474
- await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
721
+ await this.#store.transactionAsync(async () => {
722
+ await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
723
+ });
475
724
 
476
- this.#log.info(`Deleted ${txHashes.length} failed txs`);
725
+ this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
477
726
  }
478
727
 
479
728
  async handleFinalizedBlock(block: BlockHeader): Promise<void> {
480
729
  const blockNumber = block.globalVariables.blockNumber;
481
730
 
482
- // Step 1: Find mined txs at or before finalized block
483
- const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
731
+ // Hold finalized txs for a configurable margin behind the finalized tip so a prover still
732
+ // proving an epoch with already-finalized blocks isn't starved of its txs. 0 deletes at the finalized tip.
733
+ const cutoffBlock = await this.#finalizationCutoffBlock(block);
734
+
735
+ // Step 1: Find mined txs at or before the cutoff block
736
+ const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(cutoffBlock);
484
737
 
485
- // Step 2: Collect mined txs for archiving (before deletion)
486
- const txsToArchive: Tx[] = [];
738
+ // Step 2: Archive in chunks if archiving is enabled. Hydrating an entire epoch's worth of
739
+ // mined txs at once would OOM under load. When archiving is disabled there is no need to hydrate the txs at all.
487
740
  if (this.#archive.isEnabled()) {
488
- for (const txHashStr of minedTxsToFinalize) {
489
- const buffer = await this.#txsDB.getAsync(txHashStr);
490
- if (buffer) {
491
- txsToArchive.push(Tx.fromBuffer(buffer));
741
+ for (let i = 0; i < minedTxsToFinalize.length; i += FINALIZE_BLOCK_CHUNK_SIZE) {
742
+ const chunk = minedTxsToFinalize.slice(i, i + FINALIZE_BLOCK_CHUNK_SIZE);
743
+ const txsToArchive: Tx[] = [];
744
+ for (const txHashStr of chunk) {
745
+ const buffer = await this.#txsDB.getAsync(txHashStr);
746
+ if (buffer) {
747
+ txsToArchive.push(Tx.fromBuffer(buffer));
748
+ }
749
+ }
750
+ if (txsToArchive.length > 0) {
751
+ await this.#archive.archiveTxs(txsToArchive);
492
752
  }
493
753
  }
494
754
  }
495
755
 
496
- // Step 3: Delete mined txs from active pool
497
- await this.#deleteTxsBatch(minedTxsToFinalize);
756
+ // Step 3: Delete mined txs from the active pool and finalize soft-deleted txs in one
757
+ // transaction. Only tx hashes are touched here, so memory is bounded and atomicity is preserved.
758
+ await this.#store.transactionAsync(async () => {
759
+ await this.#deleteTxsBatch(minedTxsToFinalize);
760
+ await this.#deletedPool.finalizeBlock(cutoffBlock);
761
+ });
498
762
 
499
- // Step 4: Finalize soft-deleted txs
500
- await this.#deletedPool.finalizeBlock(blockNumber);
763
+ if (minedTxsToFinalize.length > 0) {
764
+ this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${cutoffBlock}`, {
765
+ txHashes: minedTxsToFinalize,
766
+ finalizedBlockNumber: blockNumber,
767
+ cutoffBlock,
768
+ });
769
+ }
770
+ }
501
771
 
502
- // Step 5: Archive mined txs
503
- if (txsToArchive.length > 0) {
504
- await this.#archive.archiveTxs(txsToArchive);
772
+ /**
773
+ * Resolves the block up to which finalized txs may be deleted, given `keepFinalizedTxsForSlots`.
774
+ * With a margin of 0 this is just the finalized block. Otherwise we keep txs whose block is within
775
+ * the margin (in slots) of the finalized tip: take the target slot `finalizedSlot - margin`, find the
776
+ * latest checkpoint at or before it with a single reverse range query (`limit: 1`), and use that
777
+ * checkpoint's last block as the cutoff. This rounds to a checkpoint boundary, so it can retain slightly
778
+ * more than the configured margin but never less, and never deletes past the finalized block.
779
+ */
780
+ async #finalizationCutoffBlock(block: BlockHeader): Promise<BlockNumber> {
781
+ const keepSlots = this.#config.keepFinalizedTxsForSlots;
782
+ if (keepSlots <= 0) {
783
+ return block.globalVariables.blockNumber;
505
784
  }
506
785
 
507
- if (minedTxsToFinalize.length > 0) {
508
- this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`);
786
+ // The goal here really is to ensure we keep transactions long enough for them to be proven.
787
+ // So we could be smart and calculate the number of slots until the end of the proof submission window.
788
+ // Our approach here is a lot simpler however and we just keep transactions for the configured number
789
+ // of slots past L1 finalisation. This means we may keep transactions in the mined pool for longer
790
+ // than strictly necessary.
791
+ const targetSlot = block.getSlot() - keepSlots;
792
+ if (targetSlot < 0) {
793
+ // The margin reaches past genesis: keep everything.
794
+ return BlockNumber(0);
509
795
  }
796
+
797
+ const [checkpoint] = await this.#l2BlockSource.getCheckpointsData({
798
+ fromSlot: SlotNumber(targetSlot),
799
+ limit: 1,
800
+ reverse: true,
801
+ });
802
+ // No checkpoint at or before the target slot (e.g. early chain): keep everything.
803
+ return checkpoint ? BlockNumber(checkpoint.startBlock + checkpoint.blockCount - 1) : BlockNumber(0);
510
804
  }
511
805
 
512
806
  // === Query Methods ===
513
807
 
514
- async getTxByHash(txHash: TxHash): Promise<Tx | undefined> {
515
- const buffer = await this.#txsDB.getAsync(txHash.toString());
516
- return buffer ? Tx.fromBuffer(buffer) : undefined;
808
+ async getTxByHash(txHash: TxHash, opts: { includeProof?: boolean } = {}): Promise<Tx | undefined> {
809
+ const txHashStr = txHash.toString();
810
+ const buffer = await this.#txsDB.getAsync(txHashStr);
811
+ if (!buffer) {
812
+ return undefined;
813
+ }
814
+ return opts.includeProof === false ? Tx.fromBuffer(buffer) : this.#loadTxWithProof(txHashStr, buffer);
517
815
  }
518
816
 
519
- async getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
817
+ async getTxsByHash(txHashes: TxHash[], opts: { includeProof?: boolean } = {}): Promise<(Tx | undefined)[]> {
520
818
  const results: (Tx | undefined)[] = [];
521
819
  for (const h of txHashes) {
522
- const buffer = await this.#txsDB.getAsync(h.toString());
523
- results.push(buffer ? Tx.fromBuffer(buffer) : undefined);
820
+ results.push(await this.getTxByHash(h, opts));
524
821
  }
525
822
  return results;
526
823
  }
527
824
 
825
+ /** Deserializes a tx blob loaded from #txsDB together with its separately-stored proof. */
826
+ async #loadTxWithProof(txHashStr: string, buffer: Buffer): Promise<Tx> {
827
+ const proofBuffer = await this.#proofsDB.getAsync(txHashStr);
828
+ if (!proofBuffer) {
829
+ // #addTx always writes a proof entry (an empty proof serializes to a 4-byte sentinel), so a missing entry
830
+ // means the blob/proof invariant is broken. Return the proofless tx but flag it, since a consumer that needs
831
+ // the proof (eg serving peers) would otherwise fail far away from the root cause.
832
+ this.#log.warn(`Missing stored proof for tx ${txHashStr}`, { txHash: txHashStr });
833
+ return Tx.fromBuffer(buffer);
834
+ }
835
+ return Tx.fromBuffers(buffer, proofBuffer);
836
+ }
837
+
528
838
  hasTxs(txHashes: TxHash[]): boolean[] {
529
839
  return txHashes.map(h => {
530
840
  const hashStr = h.toString();
@@ -549,10 +859,22 @@ export class TxPoolV2Impl {
549
859
  return [...this.#indices.iteratePendingByPriority('desc')].map(hash => TxHash.fromString(hash));
550
860
  }
551
861
 
862
+ getEligiblePendingTxHashes(): TxHash[] {
863
+ const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
864
+ return [...this.#indices.iterateEligiblePendingByPriority('desc', maxReceivedAt)].map(hash =>
865
+ TxHash.fromString(hash),
866
+ );
867
+ }
868
+
552
869
  getPendingTxCount(): number {
553
870
  return this.#indices.getPendingTxCount();
554
871
  }
555
872
 
873
+ hasEligiblePendingTxs(minCount: number): boolean {
874
+ const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
875
+ return this.#indices.hasEligiblePendingTxs(maxReceivedAt, minCount);
876
+ }
877
+
556
878
  getMinedTxHashes(): [TxHash, L2BlockId][] {
557
879
  return this.#indices.getMinedTxs().map(([hash, blockId]) => [TxHash.fromString(hash), blockId]);
558
880
  }
@@ -593,6 +915,12 @@ export class TxPoolV2Impl {
593
915
  this.#config.archivedTxLimit = config.archivedTxLimit;
594
916
  this.#archive.updateLimit(config.archivedTxLimit);
595
917
  }
918
+ if (config.minTxPoolAgeMs !== undefined) {
919
+ this.#config.minTxPoolAgeMs = config.minTxPoolAgeMs;
920
+ }
921
+ if (config.keepFinalizedTxsForSlots !== undefined) {
922
+ this.#config.keepFinalizedTxsForSlots = config.keepFinalizedTxsForSlots;
923
+ }
596
924
  // Update eviction rules with new config
597
925
  this.#evictionManager.updateConfig(config);
598
926
  }
@@ -610,8 +938,17 @@ export class TxPoolV2Impl {
610
938
 
611
939
  // === Metrics ===
612
940
 
613
- countTxs(): { pending: number; protected: number; mined: number } {
614
- return this.#indices.countTxs();
941
+ countTxs(): {
942
+ pending: number;
943
+ protected: number;
944
+ mined: number;
945
+ softDeleted: number;
946
+ totalMetadataBytes: number;
947
+ } {
948
+ return {
949
+ ...this.#indices.countTxs(),
950
+ softDeleted: this.#deletedPool.getSoftDeletedCount(),
951
+ };
615
952
  }
616
953
 
617
954
  // ============================================================================
@@ -626,11 +963,15 @@ export class TxPoolV2Impl {
626
963
  tx: Tx,
627
964
  state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
628
965
  opts: { source?: string } = {},
966
+ precomputedMeta?: TxMetaData,
629
967
  ): Promise<TxMetaData> {
630
968
  const txHashStr = tx.getTxHash().toString();
631
- const meta = await buildTxMetaData(tx);
969
+ const meta = precomputedMeta ?? (await buildTxMetaData(tx));
970
+ meta.receivedAt = this.#dateProvider.now();
632
971
 
633
- await this.#txsDB.set(txHashStr, tx.toBuffer());
972
+ await this.#txsDB.set(txHashStr, tx.withoutProof().toBuffer());
973
+ await this.#proofsDB.set(txHashStr, tx.chonkProof.toBuffer());
974
+ await this.#deletedPool.clearSoftDeleted(txHashStr);
634
975
  this.#callbacks.onTxsAdded([tx], opts);
635
976
 
636
977
  if (state === 'pending') {
@@ -643,9 +984,11 @@ export class TxPoolV2Impl {
643
984
  }
644
985
 
645
986
  const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
646
- this.#log.verbose(`Added ${stateStr} tx ${txHashStr}`, {
987
+ this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
647
988
  eventName: 'tx-added-to-pool',
989
+ txHash: txHashStr,
648
990
  state: stateStr,
991
+ source: opts.source,
649
992
  });
650
993
 
651
994
  return meta;
@@ -666,6 +1009,12 @@ export class TxPoolV2Impl {
666
1009
  await this.#deletedPool.deleteTx(txHashStr);
667
1010
  }
668
1011
 
1012
+ /** Hard-deletes a tx's stored data (tx blob and proof) from the DB. */
1013
+ async #deleteTxData(txHashStr: string): Promise<void> {
1014
+ await this.#txsDB.delete(txHashStr);
1015
+ await this.#proofsDB.delete(txHashStr);
1016
+ }
1017
+
669
1018
  /** Deletes a batch of transactions, emitting callbacks individually for each. */
670
1019
  async #deleteTxsBatch(txHashes: string[]): Promise<void> {
671
1020
  for (const txHashStr of txHashes) {
@@ -673,6 +1022,19 @@ export class TxPoolV2Impl {
673
1022
  }
674
1023
  }
675
1024
 
1025
+ /** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */
1026
+ async #evictTxs(txHashes: string[], reason: string): Promise<void> {
1027
+ if (txHashes.length === 0) {
1028
+ return;
1029
+ }
1030
+ this.#instrumentation.recordEvictions(txHashes.length, reason);
1031
+ for (const txHashStr of txHashes) {
1032
+ this.#log.debug(`Evicting tx ${txHashStr}`, { txHash: txHashStr, reason });
1033
+ this.#evictedTxHashes.add(txHashStr);
1034
+ }
1035
+ await this.#deleteTxsBatch(txHashes);
1036
+ }
1037
+
676
1038
  // ============================================================================
677
1039
  // PRIVATE HELPERS - Validation & Conflict Resolution
678
1040
  // ============================================================================
@@ -767,50 +1129,6 @@ export class TxPoolV2Impl {
767
1129
  };
768
1130
  }
769
1131
 
770
- /** Loads all transactions from the database, returning loaded txs and deserialization errors */
771
- async #loadAllTxsFromDb(): Promise<{
772
- loaded: { tx: Tx; meta: TxMetaData }[];
773
- errors: string[];
774
- }> {
775
- const loaded: { tx: Tx; meta: TxMetaData }[] = [];
776
- const errors: string[] = [];
777
-
778
- for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()) {
779
- // Skip soft-deleted transactions - they stay in DB but not in indices
780
- if (this.#deletedPool.isSoftDeleted(txHashStr)) {
781
- continue;
782
- }
783
-
784
- try {
785
- const tx = Tx.fromBuffer(buffer);
786
- const meta = await buildTxMetaData(tx);
787
- loaded.push({ tx, meta });
788
- } catch (err) {
789
- this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, { err });
790
- errors.push(txHashStr);
791
- }
792
- }
793
-
794
- return { loaded, errors };
795
- }
796
-
797
- /** Queries block source and marks mined status on transaction metadata */
798
- async #markMinedStatusBatch(metas: TxMetaData[]): Promise<void> {
799
- for (const meta of metas) {
800
- try {
801
- const txEffect = await this.#l2BlockSource.getTxEffect(TxHash.fromString(meta.txHash));
802
- if (txEffect) {
803
- meta.minedL2BlockId = {
804
- number: txEffect.l2BlockNumber,
805
- hash: txEffect.l2BlockHash.toString(),
806
- };
807
- }
808
- } catch (err) {
809
- this.#log.warn(`Failed to check mined status for tx ${meta.txHash}`, { err });
810
- }
811
- }
812
- }
813
-
814
1132
  /**
815
1133
  * Rebuilds the pending pool by processing each tx through pre-add rules.
816
1134
  * Starts with an empty pending pool and adds txs one by one, resolving conflicts.
@@ -828,7 +1146,9 @@ export class TxPoolV2Impl {
828
1146
  if (preAddResult.shouldIgnore) {
829
1147
  // Transaction rejected - mark for deletion from DB
830
1148
  rejected.push(meta.txHash);
831
- this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason}`);
1149
+ this.#log.debug(
1150
+ `Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`,
1151
+ );
832
1152
  continue;
833
1153
  }
834
1154
 
@@ -864,7 +1184,7 @@ export class TxPoolV2Impl {
864
1184
  getFeePayerPendingTxs: (feePayer: string) => this.#indices.getFeePayerPendingTxs(feePayer),
865
1185
  getPendingTxCount: () => this.#indices.getPendingTxCount(),
866
1186
  getLowestPriorityPending: (limit: number) => this.#indices.getLowestPriorityPending(limit),
867
- deleteTxs: (txHashes: string[]) => this.#deleteTxsBatch(txHashes),
1187
+ deleteTxs: (txHashes: string[], reason?: string) => this.#evictTxs(txHashes, reason ?? 'unknown'),
868
1188
  };
869
1189
  }
870
1190
 
@@ -883,7 +1203,7 @@ export class TxPoolV2Impl {
883
1203
  const publicStateSource = new DatabasePublicStateSource(db);
884
1204
  const balance = await publicStateSource.storageRead(
885
1205
  ProtocolContractAddress.FeeJuice,
886
- await computeFeePayerBalanceStorageSlot(AztecAddress.fromString(feePayer)),
1206
+ await computeFeePayerBalanceStorageSlot(AztecAddress.fromStringUnsafe(feePayer)),
887
1207
  );
888
1208
  return balance.toBigInt();
889
1209
  },