@aztec/p2p 0.0.1-commit.993d52e → 0.0.1-commit.9a89641

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 (473) 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 +5 -4
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +39 -16
  8. package/dest/client/interface.d.ts +52 -12
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +34 -19
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +120 -73
  13. package/dest/config.d.ts +160 -110
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +139 -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/index.d.ts +1 -2
  23. package/dest/index.d.ts.map +1 -1
  24. package/dest/index.js +0 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +101 -59
  26. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/attestation_pool.js +274 -197
  28. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  29. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +224 -65
  31. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
  32. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/mocks.js +6 -4
  34. package/dest/mem_pools/index.d.ts +1 -2
  35. package/dest/mem_pools/index.d.ts.map +1 -1
  36. package/dest/mem_pools/instrumentation.d.ts +12 -5
  37. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  38. package/dest/mem_pools/instrumentation.js +38 -17
  39. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  40. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  41. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  42. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -3
  43. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +6 -6
  45. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  46. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +5 -4
  48. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
  49. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +3 -1
  51. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
  52. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
  54. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  55. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  56. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +64 -0
  57. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +1 -1
  58. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +3 -4
  60. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +1 -1
  61. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -1
  62. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +6 -7
  63. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +1 -1
  64. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  65. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +6 -5
  66. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +41 -9
  67. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  68. package/dest/mem_pools/tx_pool_v2/interfaces.js +3 -1
  69. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +17 -8
  70. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  71. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +20 -7
  72. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +15 -1
  73. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  74. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +55 -41
  75. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +12 -4
  76. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  77. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +23 -6
  78. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +17 -3
  79. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  80. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +234 -120
  81. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
  82. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  83. package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -15
  84. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  85. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  86. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  87. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +11 -5
  88. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  89. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +11 -3
  90. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +11 -5
  91. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  92. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +23 -3
  93. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +35 -10
  94. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  95. package/dest/msg_validators/proposal_validator/proposal_validator.js +128 -56
  96. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  97. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +8 -15
  99. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  100. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  101. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
  102. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  103. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  104. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  105. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  106. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  107. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  108. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  109. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  110. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  111. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  112. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  113. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  114. package/dest/msg_validators/tx_validator/data_validator.js +36 -2
  115. package/dest/msg_validators/tx_validator/factory.d.ts +25 -7
  116. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  117. package/dest/msg_validators/tx_validator/factory.js +55 -16
  118. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  119. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  120. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  121. package/dest/msg_validators/tx_validator/gas_validator.d.ts +53 -7
  122. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  123. package/dest/msg_validators/tx_validator/gas_validator.js +88 -41
  124. package/dest/msg_validators/tx_validator/index.d.ts +4 -1
  125. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  126. package/dest/msg_validators/tx_validator/index.js +3 -0
  127. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  128. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  129. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  130. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  131. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  132. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  133. package/dest/msg_validators/tx_validator/timestamp_validator.js +1 -1
  134. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  135. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  136. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  137. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  138. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  139. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  140. package/dest/services/data_store.d.ts +1 -1
  141. package/dest/services/data_store.d.ts.map +1 -1
  142. package/dest/services/data_store.js +5 -5
  143. package/dest/services/discv5/discV5_service.d.ts +13 -2
  144. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  145. package/dest/services/discv5/discV5_service.js +119 -23
  146. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  147. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  148. package/dest/services/discv5/persisted_enr_store.js +145 -0
  149. package/dest/services/dummy_service.d.ts +15 -15
  150. package/dest/services/dummy_service.d.ts.map +1 -1
  151. package/dest/services/dummy_service.js +15 -16
  152. package/dest/services/encoding.d.ts +23 -6
  153. package/dest/services/encoding.d.ts.map +1 -1
  154. package/dest/services/encoding.js +32 -16
  155. package/dest/services/gossipsub/topic_score_params.d.ts +6 -12
  156. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  157. package/dest/services/gossipsub/topic_score_params.js +4 -14
  158. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  159. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  160. package/dest/services/libp2p/instrumentation.js +14 -0
  161. package/dest/services/libp2p/libp2p_service.d.ts +46 -47
  162. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  163. package/dest/services/libp2p/libp2p_service.js +460 -320
  164. package/dest/services/peer-manager/metrics.d.ts +3 -1
  165. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  166. package/dest/services/peer-manager/metrics.js +6 -0
  167. package/dest/services/peer-manager/peer_manager.d.ts +20 -3
  168. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  169. package/dest/services/peer-manager/peer_manager.js +83 -26
  170. package/dest/services/peer-manager/peer_scoring.d.ts +34 -2
  171. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  172. package/dest/services/peer-manager/peer_scoring.js +102 -13
  173. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -8
  174. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  175. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +94 -122
  176. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +10 -6
  177. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  178. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  179. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  180. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  181. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  182. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  183. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  184. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  185. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  186. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  187. package/dest/services/reqresp/config.d.ts +15 -3
  188. package/dest/services/reqresp/config.d.ts.map +1 -1
  189. package/dest/services/reqresp/config.js +11 -0
  190. package/dest/services/reqresp/interface.d.ts +16 -18
  191. package/dest/services/reqresp/interface.d.ts.map +1 -1
  192. package/dest/services/reqresp/interface.js +10 -20
  193. package/dest/services/reqresp/metrics.d.ts +1 -1
  194. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  195. package/dest/services/reqresp/metrics.js +0 -1
  196. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  197. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  198. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  199. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  200. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  201. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  202. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
  203. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  204. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
  205. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  206. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  207. package/dest/services/reqresp/protocols/index.js +0 -1
  208. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  209. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  210. package/dest/services/reqresp/protocols/tx.js +1 -3
  211. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  212. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  213. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  214. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  215. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  216. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  217. package/dest/services/reqresp/reqresp.d.ts +7 -29
  218. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  219. package/dest/services/reqresp/reqresp.js +75 -216
  220. package/dest/services/service.d.ts +29 -12
  221. package/dest/services/service.d.ts.map +1 -1
  222. package/dest/services/tx_collection/config.d.ts +2 -23
  223. package/dest/services/tx_collection/config.d.ts.map +1 -1
  224. package/dest/services/tx_collection/config.js +2 -55
  225. package/dest/services/tx_collection/file_store_tx_collection.d.ts +12 -28
  226. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  227. package/dest/services/tx_collection/file_store_tx_collection.js +43 -83
  228. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  229. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  230. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  231. package/dest/services/tx_collection/index.d.ts +2 -3
  232. package/dest/services/tx_collection/index.d.ts.map +1 -1
  233. package/dest/services/tx_collection/index.js +0 -1
  234. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  235. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  236. package/dest/services/tx_collection/instrumentation.js +0 -2
  237. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  238. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  239. package/dest/services/tx_collection/request_tracker.js +84 -0
  240. package/dest/services/tx_collection/tx_collection.d.ts +36 -55
  241. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  242. package/dest/services/tx_collection/tx_collection.js +275 -119
  243. package/dest/services/tx_collection/tx_collection_sink.d.ts +1 -1
  244. package/dest/services/tx_collection/tx_collection_sink.js +2 -2
  245. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  246. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  247. package/dest/services/tx_collection/tx_source.js +13 -8
  248. package/dest/services/tx_file_store/tx_file_store.d.ts +1 -3
  249. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  250. package/dest/services/tx_file_store/tx_file_store.js +4 -14
  251. package/dest/services/tx_provider.d.ts +3 -1
  252. package/dest/services/tx_provider.d.ts.map +1 -1
  253. package/dest/services/tx_provider.js +3 -0
  254. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  255. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  256. package/dest/test-helpers/make-test-p2p-clients.js +5 -2
  257. package/dest/test-helpers/mock-pubsub.d.ts +23 -9
  258. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  259. package/dest/test-helpers/mock-pubsub.js +44 -44
  260. package/dest/test-helpers/reqresp-nodes.d.ts +4 -5
  261. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  262. package/dest/test-helpers/reqresp-nodes.js +16 -18
  263. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  264. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  265. package/dest/test-helpers/test_tx_provider.js +3 -0
  266. package/dest/test-helpers/testbench-utils.d.ts +15 -14
  267. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  268. package/dest/test-helpers/testbench-utils.js +51 -16
  269. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  270. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  271. package/dest/testbench/p2p_client_testbench_worker.js +104 -41
  272. package/dest/testbench/worker_client_manager.d.ts +12 -6
  273. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  274. package/dest/testbench/worker_client_manager.js +57 -11
  275. package/dest/util.d.ts +12 -7
  276. package/dest/util.d.ts.map +1 -1
  277. package/dest/util.js +35 -14
  278. package/dest/versioning.d.ts +3 -6
  279. package/dest/versioning.d.ts.map +1 -1
  280. package/dest/versioning.js +3 -24
  281. package/package.json +15 -16
  282. package/src/bootstrap/bootstrap.ts +17 -3
  283. package/src/client/factory.ts +62 -9
  284. package/src/client/interface.ts +48 -18
  285. package/src/client/p2p_client.ts +140 -106
  286. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  287. package/src/config.ts +241 -57
  288. package/src/errors/p2p-service.error.ts +11 -0
  289. package/src/errors/reqresp.error.ts +13 -19
  290. package/src/index.ts +0 -1
  291. package/src/mem_pools/attestation_pool/attestation_pool.ts +329 -243
  292. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +244 -69
  293. package/src/mem_pools/attestation_pool/mocks.ts +13 -8
  294. package/src/mem_pools/index.ts +0 -3
  295. package/src/mem_pools/instrumentation.ts +27 -17
  296. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  297. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +7 -7
  298. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +4 -5
  299. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -2
  300. package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
  301. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +67 -0
  302. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +1 -3
  303. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -7
  304. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +5 -6
  305. package/src/mem_pools/tx_pool_v2/interfaces.ts +40 -8
  306. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +35 -13
  307. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +62 -41
  308. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +36 -7
  309. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +260 -124
  310. package/src/msg_validators/attestation_validator/README.md +49 -0
  311. package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -14
  312. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
  313. package/src/msg_validators/proposal_validator/README.md +123 -0
  314. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +26 -4
  315. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +43 -7
  316. package/src/msg_validators/proposal_validator/proposal_validator.ts +150 -58
  317. package/src/msg_validators/tx_validator/README.md +17 -3
  318. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -12
  319. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  320. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  321. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  322. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  323. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  324. package/src/msg_validators/tx_validator/data_validator.ts +44 -1
  325. package/src/msg_validators/tx_validator/factory.ts +66 -9
  326. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  327. package/src/msg_validators/tx_validator/gas_validator.ts +117 -39
  328. package/src/msg_validators/tx_validator/index.ts +3 -0
  329. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  330. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  331. package/src/msg_validators/tx_validator/timestamp_validator.ts +1 -1
  332. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  333. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  334. package/src/services/data_store.ts +5 -13
  335. package/src/services/discv5/discV5_service.ts +126 -14
  336. package/src/services/discv5/persisted_enr_store.ts +158 -0
  337. package/src/services/dummy_service.ts +20 -39
  338. package/src/services/encoding.ts +35 -19
  339. package/src/services/gossipsub/README.md +33 -11
  340. package/src/services/gossipsub/topic_score_params.ts +9 -18
  341. package/src/services/libp2p/instrumentation.ts +14 -0
  342. package/src/services/libp2p/libp2p_service.ts +508 -358
  343. package/src/services/peer-manager/metrics.ts +7 -0
  344. package/src/services/peer-manager/peer_manager.ts +91 -25
  345. package/src/services/peer-manager/peer_scoring.ts +102 -8
  346. package/src/services/reqresp/README.md +194 -0
  347. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  348. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +91 -137
  349. package/src/services/reqresp/batch-tx-requester/interface.ts +13 -5
  350. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  351. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  352. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  353. package/src/services/reqresp/config.ts +19 -2
  354. package/src/services/reqresp/interface.ts +21 -47
  355. package/src/services/reqresp/metrics.ts +0 -1
  356. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  357. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
  358. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
  359. package/src/services/reqresp/protocols/index.ts +0 -1
  360. package/src/services/reqresp/protocols/tx.ts +1 -3
  361. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  362. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  363. package/src/services/reqresp/reqresp.ts +87 -260
  364. package/src/services/service.ts +35 -28
  365. package/src/services/tx_collection/config.ts +3 -80
  366. package/src/services/tx_collection/file_store_tx_collection.ts +54 -103
  367. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  368. package/src/services/tx_collection/index.ts +1 -6
  369. package/src/services/tx_collection/instrumentation.ts +1 -7
  370. package/src/services/tx_collection/request_tracker.ts +127 -0
  371. package/src/services/tx_collection/tx_collection.ts +331 -176
  372. package/src/services/tx_collection/tx_collection_sink.ts +2 -2
  373. package/src/services/tx_collection/tx_source.ts +10 -8
  374. package/src/services/tx_file_store/tx_file_store.ts +5 -17
  375. package/src/services/tx_provider.ts +5 -0
  376. package/src/test-helpers/make-test-p2p-clients.ts +4 -1
  377. package/src/test-helpers/mock-pubsub.ts +46 -60
  378. package/src/test-helpers/reqresp-nodes.ts +13 -23
  379. package/src/test-helpers/test_tx_provider.ts +5 -0
  380. package/src/test-helpers/testbench-utils.ts +64 -28
  381. package/src/testbench/p2p_client_testbench_worker.ts +111 -57
  382. package/src/testbench/worker_client_manager.ts +72 -25
  383. package/src/util.ts +33 -18
  384. package/src/versioning.ts +3 -33
  385. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  386. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  387. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -304
  388. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  389. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  390. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  391. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  392. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  393. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  394. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  395. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  396. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  397. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  398. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  399. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  400. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  401. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  402. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  403. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  404. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  405. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  406. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  407. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  408. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  409. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  410. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  411. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  412. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  413. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  414. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  415. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  416. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  417. package/dest/mem_pools/tx_pool/index.js +0 -2
  418. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  419. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  420. package/dest/mem_pools/tx_pool/priority.js +0 -15
  421. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  422. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  423. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  424. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  425. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  426. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  427. package/dest/msg_validators/clock_tolerance.d.ts +0 -21
  428. package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
  429. package/dest/msg_validators/clock_tolerance.js +0 -37
  430. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
  431. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  432. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
  433. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  434. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  435. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  436. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  437. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  438. package/dest/services/reqresp/protocols/block.js +0 -32
  439. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -54
  440. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  441. package/dest/services/tx_collection/fast_tx_collection.js +0 -327
  442. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  443. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  444. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  445. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -49
  446. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  447. package/dest/services/tx_collection/proposal_tx_collector.js +0 -50
  448. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -57
  449. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  450. package/dest/services/tx_collection/slow_tx_collection.js +0 -211
  451. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -345
  452. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  453. package/src/mem_pools/tx_pool/README.md +0 -270
  454. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  455. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  456. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  457. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  458. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  459. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  460. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  461. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  462. package/src/mem_pools/tx_pool/index.ts +0 -2
  463. package/src/mem_pools/tx_pool/priority.ts +0 -20
  464. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  465. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  466. package/src/msg_validators/clock_tolerance.ts +0 -51
  467. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
  468. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  469. package/src/services/reqresp/protocols/block.ts +0 -37
  470. package/src/services/tx_collection/fast_tx_collection.ts +0 -387
  471. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
  472. package/src/services/tx_collection/proposal_tx_collector.ts +0 -113
  473. package/src/services/tx_collection/slow_tx_collection.ts +0 -266
@@ -3,19 +3,33 @@ import { NoCommitteeError } from '@aztec/ethereum/contracts';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
4
  import {
5
5
  type CheckpointAttestation,
6
+ type CoordinationSignatureContext,
6
7
  type P2PValidator,
7
8
  PeerErrorSeverity,
8
9
  type ValidationResult,
10
+ hasValidSignatureContext,
9
11
  } from '@aztec/stdlib/p2p';
10
-
11
- import { isWithinClockTolerance } from '../clock_tolerance.js';
12
+ import type { ConsensusTimetable } from '@aztec/stdlib/timetable';
12
13
 
13
14
  export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
14
15
  protected epochCache: EpochCacheInterface;
15
16
  protected logger: Logger;
17
+ private readonly timetable: ConsensusTimetable;
18
+ protected readonly signatureContext: CoordinationSignatureContext;
19
+ private readonly clockDisparityMs: number;
16
20
 
17
- constructor(epochCache: EpochCacheInterface) {
21
+ constructor(
22
+ epochCache: EpochCacheInterface,
23
+ timetable: ConsensusTimetable,
24
+ opts: {
25
+ signatureContext: CoordinationSignatureContext;
26
+ clockDisparityMs: number;
27
+ },
28
+ ) {
18
29
  this.epochCache = epochCache;
30
+ this.timetable = timetable;
31
+ this.signatureContext = opts.signatureContext;
32
+ this.clockDisparityMs = opts.clockDisparityMs;
19
33
  this.logger = createLogger('p2p:checkpoint-attestation-validator');
20
34
  }
21
35
 
@@ -23,18 +37,36 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
23
37
  const slotNumber = message.payload.header.slotNumber;
24
38
 
25
39
  try {
26
- const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
40
+ // Cross-chain replay check: reject attestations that carry a foreign signing domain.
41
+ if (!hasValidSignatureContext(message.payload, this.signatureContext)) {
42
+ this.logger.warn(`Rejecting checkpoint attestation with foreign signature context for slot ${slotNumber}`, {
43
+ chainId: message.payload.signatureContext.chainId,
44
+ rollupAddress: message.payload.signatureContext.rollupAddress.toString(),
45
+ expectedChainId: this.signatureContext.chainId,
46
+ expectedRollupAddress: this.signatureContext.rollupAddress.toString(),
47
+ });
48
+ return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
49
+ }
27
50
 
28
- if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
29
- // Check if message is for previous slot and within clock tolerance
30
- if (!isWithinClockTolerance(slotNumber, currentSlot, this.epochCache)) {
31
- this.logger.warn(
32
- `Checkpoint attestation slot ${slotNumber} is not current (${currentSlot}) or next (${nextSlot}) slot`,
33
- );
34
- return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
35
- }
36
- this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
37
- return { result: 'ignore' };
51
+ // Accept attestations whose explicit per-slot receive window contains the current wall-clock time.
52
+ // The window spans the build-frame start (attestation_receive_start) to the attestation deadline
53
+ // (target_slot_start + S - 2E), widened by the configured clock-disparity tolerance on both ends, so
54
+ // it covers the build slot, the target slot, and clock-disparity grace. This is the sole arrival
55
+ // gate; attestations are otherwise attributed by content, not by current/next slot.
56
+ const startSeconds = this.timetable.getAttestationReceiveStart(slotNumber);
57
+ const deadlineSeconds = this.timetable.getAttestationDeadline(slotNumber);
58
+ const nowMs = Number(this.epochCache.getEpochAndSlotNow().nowMs);
59
+ if (
60
+ nowMs < startSeconds * 1000 - this.clockDisparityMs ||
61
+ nowMs > deadlineSeconds * 1000 + this.clockDisparityMs
62
+ ) {
63
+ this.logger.warn(`Checkpoint attestation slot ${slotNumber} is outside its receive window`, {
64
+ slotNumber,
65
+ nowMs,
66
+ windowStartSeconds: startSeconds,
67
+ windowDeadlineSeconds: deadlineSeconds,
68
+ });
69
+ return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
38
70
  }
39
71
 
40
72
  // Verify the signature is valid
@@ -1,5 +1,11 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import { type CheckpointAttestation, PeerErrorSeverity, type ValidationResult } from '@aztec/stdlib/p2p';
2
+ import {
3
+ type CheckpointAttestation,
4
+ type CoordinationSignatureContext,
5
+ PeerErrorSeverity,
6
+ type ValidationResult,
7
+ } from '@aztec/stdlib/p2p';
8
+ import type { ConsensusTimetable } from '@aztec/stdlib/timetable';
3
9
  import { Attributes, Metrics, type TelemetryClient, createUpDownCounterWithDefault } from '@aztec/telemetry-client';
4
10
 
5
11
  import type { AttestationPoolApi } from '../../mem_pools/attestation_pool/attestation_pool.js';
@@ -18,10 +24,15 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
18
24
 
19
25
  constructor(
20
26
  epochCache: EpochCacheInterface,
27
+ timetable: ConsensusTimetable,
21
28
  private attestationPool: AttestationPoolApi,
22
29
  telemetryClient: TelemetryClient,
30
+ opts: {
31
+ signatureContext: CoordinationSignatureContext;
32
+ clockDisparityMs: number;
33
+ },
23
34
  ) {
24
- super(epochCache);
35
+ super(epochCache, timetable, opts);
25
36
  this.logger = this.logger.createChild('[FISHERMAN]');
26
37
 
27
38
  const meter = telemetryClient.getMeter('FishermanAttestationValidator');
@@ -54,8 +65,7 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
54
65
  return { result: 'accept' };
55
66
  }
56
67
 
57
- const proposalId = message.archive.toString();
58
- const proposal = await this.attestationPool.getCheckpointProposal(proposalId);
68
+ const proposal = await this.attestationPool.getCheckpointProposal(message.payload.header.slotNumber);
59
69
 
60
70
  if (proposal) {
61
71
  // Compare the attestation payload with the proposal payload
@@ -84,9 +94,7 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
84
94
  }
85
95
  } else {
86
96
  // We might receive attestations before proposals in some cases
87
- this.logger.debug(
88
- `Received attestation for slot ${slotNumberBigInt} but proposal not found yet. ` + `Proposal ID: ${proposalId}`,
89
- );
97
+ this.logger.debug(`Received attestation for slot ${slotNumberBigInt} but proposal not found yet.`);
90
98
  }
91
99
 
92
100
  return { result: 'accept' };
@@ -0,0 +1,123 @@
1
+ # Proposal Validation
2
+
3
+ This module validates `BlockProposal` and `CheckpointProposal` gossipsub messages. Both share the same base `ProposalValidator` (neither subclass overrides `validate()`), with checkpoint-specific logic layered on top in the gossipsub handler.
4
+
5
+ ## BlockProposal
6
+
7
+ **Topic**: `block_proposal` | **Snappy size limit**: 10 MB
8
+
9
+ ### Stage 1: Gossipsub Validation (ProposalValidator)
10
+
11
+ File: `proposal_validator.ts`
12
+
13
+ | # | Rule | Consequence | Severity |
14
+ |---|------|-------------|----------|
15
+ | 1 | **Slot check**: must be `currentSlot` or `nextSlot`. Previous slot within 500ms tolerance: IGNORE. | REJECT | HighToleranceError |
16
+ | 2 | **Signature**: `getSender()` must recover a valid address. If `signedTxs` present, its recovered sender must match. | REJECT | MidToleranceError |
17
+ | 3 | **Txs permitted**: if `disableTransactions`, must have 0 txHashes and 0 embedded txs | REJECT | MidToleranceError |
18
+ | 4 | **Max txs**: `txHashes.length <= maxTxsPerBlock` | REJECT | MidToleranceError |
19
+ | 5 | **Embedded txs in txHashes**: every embedded tx's hash must appear in `txHashes` | REJECT | MidToleranceError |
20
+ | 6 | **Proposer check**: signer must match expected proposer for slot (skipped if committee size = 0) | REJECT | MidToleranceError |
21
+ | 7 | **Tx hash integrity**: each embedded tx's recomputed hash must match declared hash | REJECT | LowToleranceError |
22
+ | 8 | **NoCommitteeError**: epoch cache cannot determine committee | REJECT | LowToleranceError |
23
+
24
+ Deserialization guards: `BlockProposal.fromBuffer` and `SignedTxs.fromBuffer` both enforce `txCount <= MAX_TXS_PER_BLOCK` (65536). Violation -> REJECT + LowToleranceError.
25
+
26
+ ### Stage 2: Mempool (Attestation Pool)
27
+
28
+ | # | Rule | Consequence |
29
+ |---|------|-------------|
30
+ | 9 | **Duplicate**: same archive root already stored | IGNORE (no penalty) |
31
+ | 10 | **Per-position cap**: max 2 proposals per (slot, indexWithinCheckpoint) | REJECT + HighToleranceError |
32
+ | 11 | **Equivocation**: >1 distinct proposal for same (slot, index) | ACCEPT (rebroadcast for detection). At count=2: `duplicateProposalCallback` fires -> slash event (`OffenseType.DUPLICATE_PROPOSAL`, configured via `slashDuplicateProposalPenalty`) |
33
+
34
+ ### Stage 3: Validator-Client Processing (BlockProposalHandler)
35
+
36
+ Only runs on validator nodes. Non-validator nodes use a default handler that triggers tx collection without deep validation.
37
+
38
+ | # | Rule | Failure Reason |
39
+ |---|------|----------------|
40
+ | 12 | Signature re-check | `invalid_proposal` |
41
+ | 13 | ProposalValidator re-run | `invalid_proposal` |
42
+ | 14 | Self-proposal filter | Ignored silently |
43
+ | 15 | Parent block exists (`lastArchive.root` matches known block or genesis) | `parent_block_not_found` |
44
+ | 16 | Parent block slot <= proposal slot | `parent_block_wrong_slot` |
45
+ | 17 | Block number not already in archiver | `block_number_already_exists` |
46
+ | 18 | Checkpoint number consistency (multiple sub-rules for first/non-first blocks) | `invalid_proposal` |
47
+ | 19 | Global variables consistency (non-first block: chainId, version, slot, timestamp, coinbase, feeRecipient, gasFees match parent) | `global_variables_mismatch` |
48
+ | 20 | L1-to-L2 message hash matches `proposal.inHash` | `in_hash_mismatch` |
49
+ | 21 | All txs referenced by `txHashes` obtainable | `txs_not_available` |
50
+ | 22 | **Re-execution**: processed tx count matches `txHashes.length` | `timeout` (ReExTimeoutError) |
51
+ | 23 | **Re-execution**: no failed txs | `failed_txs` (ReExFailedTxsError) -- **SLASHABLE** |
52
+ | 24 | **Re-execution**: archive root and header match proposal | `state_mismatch` (ReExStateMismatchError) -- **SLASHABLE** |
53
+
54
+ **Escape hatch**: during escape hatch periods (`isEscapeHatchOpenAtSlot`), re-execution and slashing are both disabled, and the proposal is rejected locally.
55
+
56
+ **Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0`, committee membership, `alwaysReexecuteBlockProposals`, or `blobClient.canUpload()`.
57
+
58
+ **Slashing**: only `state_mismatch` and `failed_txs` trigger on-chain slashing (`OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL`, gated by `slashBroadcastedInvalidBlockPenalty > 0`). Unknown errors during re-execution do NOT slash.
59
+
60
+ **Embedded tx validation**: txs in `signedTxs` are validated via `createTxValidatorForBlockProposalReceivedTxs` (well-formedness only) when stored in the tx pool. Invalid embedded txs are rejected from the pool but do not cause the block proposal itself to be rejected at gossipsub level.
61
+
62
+ ### Gossipsub Topic Scoring
63
+
64
+ | Parameter | Effect |
65
+ |-----------|--------|
66
+ | P4 (invalidMessageDeliveries) | weight = -20, decay over 4 slots |
67
+ | P3 (meshMessageDeliveries) | Enabled only when `expectedBlockProposalsPerSlot > 0` (MBPS mode) |
68
+ | P1/P2 | Only active when P3 is enabled |
69
+
70
+ ---
71
+
72
+ ## CheckpointProposal
73
+
74
+ **Topic**: `checkpoint_proposal` | **Snappy size limit**: 10 MB
75
+
76
+ ### Stage 1: Gossipsub Validation (ProposalValidator)
77
+
78
+ Same `ProposalValidator.validate()` as BlockProposal (shared implementation, neither subclass overrides it). See BlockProposal Stage 1 rules 1-8.
79
+
80
+ ### Stage 2: Embedded Block Proposal Validation (if `lastBlock` present)
81
+
82
+ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and validated through `BlockProposalValidator.validate()` plus block mempool checks.
83
+
84
+ | Rule | Consequence | File |
85
+ |------|-------------|------|
86
+ | Block proposal must pass `BlockProposalValidator.validate()` | If REJECT: entire checkpoint REJECTED | `libp2p_service.ts` |
87
+ | Block proposal must not exceed per-position cap (2) | Checkpoint REJECTED + HighToleranceError | same |
88
+ | Block equivocation detected (>1 proposals for same slot+index) | Checkpoint REJECTED (block itself is ACCEPT for re-broadcast) | same |
89
+
90
+ ### Stage 3: Mempool (Attestation Pool)
91
+
92
+ | Rule | Consequence | File |
93
+ |------|-------------|------|
94
+ | Duplicate (same archive ID) | IGNORE (no penalty). Embedded block still processed if valid. | `attestation_pool.ts` |
95
+ | Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` = 2 | REJECT + HighToleranceError. Embedded block still processed. | same |
96
+
97
+ ### Stage 4: Equivocation Detection
98
+
99
+ When >1 checkpoint proposals exist for same slot (count > 1): ACCEPT (re-broadcast). At count == 2 (exactly): `duplicateProposalCallback` fires. Proposal NOT further processed. Callback fires only once per equivocation pair.
100
+
101
+ ### Stage 5: Validator-Client Consensus Validation
102
+
103
+ Determines whether the validator signs an attestation.
104
+
105
+ | Rule | Consequence | File |
106
+ |------|-------------|------|
107
+ | Escape hatch open | No attestation | `validator-client/src/validator.ts` |
108
+ | Signature invalid (re-check) | No attestation | same |
109
+ | Self-proposal | No attestation (ignored) | same |
110
+ | `feeAssetPriceModifier` outside [-100, +100] bps | No attestation | same |
111
+ | Not in committee (unless fisherman mode) | No attestation | same |
112
+ | Checkpoint header mismatch (computed vs proposal) | No attestation | same |
113
+ | Archive root mismatch | No attestation | same |
114
+ | Epoch out hash mismatch | No attestation | same |
115
+ | Last block not found / not matching | No attestation | same |
116
+ | Already attested to this or earlier slot | No attestation (unless `attestToEquivocatedProposals`) | same |
117
+
118
+ **`skipCheckpointProposalValidation` config**: when true, the re-execution checks (header/archive/epoch hash) are all skipped. Signature, fee modifier, committee, escape hatch, and equivocation checks still apply.
119
+
120
+ ### Gossipsub Topic Scoring
121
+
122
+ P3 enabled with expected rate of 1 message per slot. P4 weight = -20, max P3 penalty = -34 per topic.
123
+
@@ -1,10 +1,32 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import type { BlockProposal, P2PValidator } from '@aztec/stdlib/p2p';
2
+ import type { BlockProposal, CoordinationSignatureContext, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
3
+ import type { ConsensusTimetable } from '@aztec/stdlib/timetable';
3
4
 
4
5
  import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
5
6
 
6
- export class BlockProposalValidator extends ProposalValidator<BlockProposal> implements P2PValidator<BlockProposal> {
7
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
8
- super(epochCache, opts, 'p2p:block_proposal_validator');
7
+ export class BlockProposalValidator implements P2PValidator<BlockProposal> {
8
+ private proposalValidator: ProposalValidator;
9
+
10
+ constructor(
11
+ epochCache: EpochCacheInterface,
12
+ timetable: ConsensusTimetable,
13
+ opts: {
14
+ txsPermitted: boolean;
15
+ maxTxsPerBlock?: number;
16
+ maxBlocksPerCheckpoint?: number;
17
+ skipSlotValidation?: boolean;
18
+ signatureContext: CoordinationSignatureContext;
19
+ clockDisparityMs: number;
20
+ },
21
+ ) {
22
+ this.proposalValidator = new ProposalValidator(epochCache, timetable, opts, 'p2p:block_proposal_validator');
23
+ }
24
+
25
+ async validate(proposal: BlockProposal): Promise<ValidationResult> {
26
+ const headerResult = await this.proposalValidator.validate(proposal);
27
+ if (headerResult.result !== 'accept') {
28
+ return headerResult;
29
+ }
30
+ return this.proposalValidator.validateTxs(proposal);
9
31
  }
10
32
  }
@@ -1,13 +1,49 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import type { CheckpointProposal, P2PValidator } from '@aztec/stdlib/p2p';
2
+ import type {
3
+ CheckpointProposal,
4
+ CoordinationSignatureContext,
5
+ P2PValidator,
6
+ ValidationResult,
7
+ } from '@aztec/stdlib/p2p';
8
+ import type { ConsensusTimetable } from '@aztec/stdlib/timetable';
3
9
 
4
10
  import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
5
11
 
6
- export class CheckpointProposalValidator
7
- extends ProposalValidator<CheckpointProposal>
8
- implements P2PValidator<CheckpointProposal>
9
- {
10
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
11
- super(epochCache, opts, 'p2p:checkpoint_proposal_validator');
12
+ export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
13
+ private proposalValidator: ProposalValidator;
14
+
15
+ constructor(
16
+ epochCache: EpochCacheInterface,
17
+ timetable: ConsensusTimetable,
18
+ opts: {
19
+ txsPermitted: boolean;
20
+ maxTxsPerBlock?: number;
21
+ maxBlocksPerCheckpoint?: number;
22
+ skipSlotValidation?: boolean;
23
+ signatureContext: CoordinationSignatureContext;
24
+ clockDisparityMs: number;
25
+ },
26
+ ) {
27
+ this.proposalValidator = new ProposalValidator(epochCache, timetable, opts, 'p2p:checkpoint_proposal_validator');
28
+ }
29
+
30
+ async validate(proposal: CheckpointProposal): Promise<ValidationResult> {
31
+ const headerResult = await this.proposalValidator.validate(proposal);
32
+ if (headerResult.result !== 'accept') {
33
+ return headerResult;
34
+ }
35
+
36
+ const blockProposal = proposal.getBlockProposal();
37
+ if (blockProposal) {
38
+ // The terminal block is carried inside the checkpoint proposal rather than gossiped as a
39
+ // standalone block proposal, so apply the per-checkpoint block ceiling to it here too.
40
+ const indexResult = this.proposalValidator.validateBlockIndexWithinCheckpoint(blockProposal);
41
+ if (indexResult.result !== 'accept') {
42
+ return indexResult;
43
+ }
44
+ return this.proposalValidator.validateTxs(blockProposal);
45
+ }
46
+
47
+ return { result: 'accept' };
12
48
  }
13
49
  }
@@ -1,40 +1,91 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { NoCommitteeError } from '@aztec/ethereum/contracts';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
- import { BlockProposal, CheckpointProposal, PeerErrorSeverity, type ValidationResult } from '@aztec/stdlib/p2p';
4
+ import { MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/deserialization';
5
+ import {
6
+ type BlockProposal,
7
+ type CheckpointProposalCore,
8
+ type CoordinationSignatureContext,
9
+ PeerErrorSeverity,
10
+ type ValidationResult,
11
+ hasValidSignatureContext,
12
+ } from '@aztec/stdlib/p2p';
13
+ import type { ConsensusTimetable } from '@aztec/stdlib/timetable';
5
14
 
6
- import { isWithinClockTolerance } from '../clock_tolerance.js';
7
-
8
- export abstract class ProposalValidator<TProposal extends BlockProposal | CheckpointProposal> {
9
- protected epochCache: EpochCacheInterface;
10
- protected logger: Logger;
11
- protected txsPermitted: boolean;
12
- protected maxTxsPerBlock?: number;
15
+ /** Validates header-level and tx-level fields of block and checkpoint proposals. */
16
+ export class ProposalValidator {
17
+ private epochCache: EpochCacheInterface;
18
+ private timetable: ConsensusTimetable;
19
+ private logger: Logger;
20
+ private txsPermitted: boolean;
21
+ private maxTxsPerBlock?: number;
22
+ private skipSlotValidation: boolean;
23
+ private signatureContext: CoordinationSignatureContext;
24
+ private clockDisparityMs: number;
13
25
 
14
26
  constructor(
15
27
  epochCache: EpochCacheInterface,
16
- opts: { txsPermitted: boolean; maxTxsPerBlock?: number },
28
+ timetable: ConsensusTimetable,
29
+ opts: {
30
+ txsPermitted: boolean;
31
+ maxTxsPerBlock?: number;
32
+ maxBlocksPerCheckpoint?: number;
33
+ skipSlotValidation?: boolean;
34
+ signatureContext: CoordinationSignatureContext;
35
+ clockDisparityMs: number;
36
+ },
17
37
  loggerName: string,
18
38
  ) {
19
39
  this.epochCache = epochCache;
40
+ this.timetable = timetable;
20
41
  this.txsPermitted = opts.txsPermitted;
21
42
  this.maxTxsPerBlock = opts.maxTxsPerBlock;
43
+ this.skipSlotValidation = opts.skipSlotValidation ?? false;
44
+ this.signatureContext = opts.signatureContext;
45
+ this.clockDisparityMs = opts.clockDisparityMs;
22
46
  this.logger = createLogger(loggerName);
23
47
  }
24
48
 
25
- public async validate(proposal: TProposal): Promise<ValidationResult> {
49
+ /** Validates header-level fields: slot, signature, and proposer. */
50
+ public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
26
51
  try {
27
- // Slot check
28
- const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
52
+ // Cross-chain replay check: reject proposals that carry a foreign signing domain.
53
+ if (!hasValidSignatureContext(proposal, this.signatureContext)) {
54
+ this.logger.warn(`Penalizing peer for proposal with foreign signature context`, {
55
+ chainId: proposal.signatureContext.chainId,
56
+ rollupAddress: proposal.signatureContext.rollupAddress.toString(),
57
+ expectedChainId: this.signatureContext.chainId,
58
+ expectedRollupAddress: this.signatureContext.rollupAddress.toString(),
59
+ });
60
+ return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
61
+ }
62
+
63
+ // Slot check: the tight checkpoint proposal receive window (`[receiveStart - δ, target_slot_start -
64
+ // E - D + δ]`) is the sole acceptance gate, applied to both block and checkpoint proposals. The
65
+ // window itself bounds which slots are valid, so far/wrong slots fall outside it. Every block
66
+ // proposal for slot N is sent before the checkpoint proposal for slot N, so nothing legitimate can
67
+ // arrive after the checkpoint receive deadline; gating block proposals on the same window rejects
68
+ // late block proposals at p2p ingress. The attestation deadline remains their re-execution/
69
+ // validation deadline downstream, not their arrival gate.
29
70
  const slotNumber = proposal.slotNumber;
30
- if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
31
- // Check if message is for previous slot and within clock tolerance
32
- if (!isWithinClockTolerance(slotNumber, currentSlot, this.epochCache)) {
33
- this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { currentSlot, nextSlot });
71
+ if (!this.skipSlotValidation) {
72
+ // Proposal receive window: [checkpoint_proposal_receive_start, checkpoint_proposal_receive_deadline],
73
+ // widened by the configured clock-disparity tolerance on both ends.
74
+ const startSeconds = this.timetable.getCheckpointProposalReceiveStart(slotNumber);
75
+ const deadlineSeconds = this.timetable.getCheckpointProposalReceiveDeadline(slotNumber);
76
+ const nowMs = Number(this.epochCache.getEpochAndSlotNow().nowMs);
77
+ if (
78
+ nowMs < startSeconds * 1000 - this.clockDisparityMs ||
79
+ nowMs > deadlineSeconds * 1000 + this.clockDisparityMs
80
+ ) {
81
+ this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, {
82
+ slotNumber,
83
+ nowMs,
84
+ windowStartSeconds: startSeconds,
85
+ windowDeadlineSeconds: deadlineSeconds,
86
+ });
34
87
  return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
35
88
  }
36
- this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
37
- return { result: 'ignore' };
38
89
  }
39
90
 
40
91
  // Signature validity
@@ -44,41 +95,13 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
44
95
  return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
45
96
  }
46
97
 
47
- // Transactions permitted check
48
- const embeddedTxCount = proposal.txs?.length ?? 0;
49
- if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
50
- this.logger.warn(
51
- `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
52
- );
53
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
54
- }
55
-
56
- // Max txs per block check
57
- if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
58
- this.logger.warn(
59
- `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
60
- );
61
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
62
- }
63
-
64
- // Embedded txs must be listed in txHashes
65
- const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
66
- const missingTxHashes =
67
- embeddedTxCount > 0
68
- ? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
69
- : [];
70
- if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
71
- this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
72
- embeddedTxCount,
73
- txHashesLength: proposal.txHashes.length,
74
- missingTxHashes,
75
- });
76
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
77
- }
78
-
79
98
  // Proposer check
80
99
  const expectedProposer = await this.epochCache.getProposerAttesterAddressInSlot(slotNumber);
81
- if (expectedProposer !== undefined && !proposer.equals(expectedProposer)) {
100
+ if (expectedProposer === undefined) {
101
+ this.logger.warn(`Penalizing peer for proposal with no expected proposer for current slot ${slotNumber}`);
102
+ return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
103
+ }
104
+ if (!proposer.equals(expectedProposer)) {
82
105
  this.logger.warn(`Penalizing peer for invalid proposer for current slot ${slotNumber}`, {
83
106
  expectedProposer,
84
107
  proposer: proposer.toString(),
@@ -86,13 +109,17 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
86
109
  return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
87
110
  }
88
111
 
89
- // Validate tx hashes for all txs embedded in the proposal
90
- if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
91
- this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`, {
92
- proposer,
93
- slotNumber,
94
- });
95
- return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
112
+ // A block proposal whose index lands at or beyond the hard attestable ceiling is structurally
113
+ // impossible garbage, so reject it immediately at ingress. Indices in
114
+ // `[maxBlocksPerCheckpoint, MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT)` are over the consensus limit
115
+ // but structurally valid proposer misbehavior; they pass gossip validation here so the offending
116
+ // proposal can be retained and re-broadcast as slashing evidence (handled downstream in the p2p
117
+ // service), rather than penalizing the relaying peer.
118
+ if ('indexWithinCheckpoint' in proposal) {
119
+ const indexResult = this.validateBlockIndexWithinCheckpoint(proposal);
120
+ if (indexResult.result !== 'accept') {
121
+ return indexResult;
122
+ }
96
123
  }
97
124
 
98
125
  return { result: 'accept' };
@@ -103,4 +130,69 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
103
130
  throw e;
104
131
  }
105
132
  }
133
+
134
+ /**
135
+ * Rejects a block proposal whose index within its checkpoint lands at or beyond the hard attestable
136
+ * ceiling `MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT` (a structurally impossible index that can never be
137
+ * part of any checkpoint we could attest to). `indexWithinCheckpoint` is 0-based, so a ceiling of 72
138
+ * rejects the 73rd block.
139
+ *
140
+ * Indices in `[maxBlocksPerCheckpoint, MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT)` are over the configured
141
+ * consensus limit but still structurally valid: they are proposer misbehavior, not relaying-peer
142
+ * fault, so they are *not* rejected here. The p2p service retains and re-broadcasts the first such
143
+ * proposal per (slot, proposer) as slashing evidence and skips processing it. Applies to standalone
144
+ * block proposals and to the terminal block embedded in a checkpoint proposal.
145
+ */
146
+ public validateBlockIndexWithinCheckpoint(proposal: BlockProposal): ValidationResult {
147
+ if (proposal.indexWithinCheckpoint >= MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT) {
148
+ this.logger.warn(
149
+ `Penalizing peer for proposal with indexWithinCheckpoint ${proposal.indexWithinCheckpoint} >= attestable ceiling ${MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT}`,
150
+ );
151
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
152
+ }
153
+ return { result: 'accept' };
154
+ }
155
+
156
+ /** Validates transaction-related fields of a block proposal. */
157
+ public async validateTxs(proposal: BlockProposal): Promise<ValidationResult> {
158
+ // Transactions permitted check
159
+ const embeddedTxCount = proposal.txs?.length ?? 0;
160
+ if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
161
+ this.logger.warn(
162
+ `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
163
+ );
164
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
165
+ }
166
+
167
+ // Max txs per block check
168
+ if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
169
+ this.logger.warn(
170
+ `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
171
+ );
172
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
173
+ }
174
+
175
+ // Embedded txs must be listed in txHashes
176
+ const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
177
+ const missingTxHashes =
178
+ embeddedTxCount > 0
179
+ ? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
180
+ : [];
181
+ if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
182
+ this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
183
+ embeddedTxCount,
184
+ txHashesLength: proposal.txHashes.length,
185
+ missingTxHashes,
186
+ });
187
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
188
+ }
189
+
190
+ // Validate tx hashes for all txs embedded in the proposal
191
+ if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
192
+ this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`);
193
+ return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
194
+ }
195
+
196
+ return { result: 'accept' };
197
+ }
106
198
  }
@@ -75,10 +75,12 @@ This validator is invoked on **every** transaction potentially entering the pend
75
75
  - Startup hydration — revalidating persisted non-mined txs on node restart
76
76
 
77
77
  Runs:
78
- - DoubleSpend, BlockHeader, GasLimits, Timestamp
78
+ - DoubleSpend, BlockHeader, GasLimits, MaxFeePerGas, Timestamp, AllowedSetupCalls
79
79
 
80
80
  Operates on `TxMetaData` (pre-built by the pool) rather than full `Tx` objects.
81
81
 
82
+ The `AllowedSetupCallsMetaValidator` checks a precomputed boolean flag (`TxMetaData.allowedSetupCalls`) rather than re-running the full `PhasesTxValidator`. This flag is computed by `createCheckAllowedSetupCalls` when the tx first enters the pool (via `addProtectedTxs` or startup hydration), so the pool migration validator can reject txs with disallowed setup calls without needing the full `Tx` object or its dependencies.
83
+
82
84
  ## Individual Validators
83
85
 
84
86
  | Validator | What it checks | Benchmarked verification duration |
@@ -89,9 +91,11 @@ Operates on `TxMetaData` (pre-built by the pool) rather than full `Tx` objects.
89
91
  | `MetadataTxValidator` | Chain ID, rollup version, protocol contracts hash, VK tree root | 4.18 us |
90
92
  | `TimestampTxValidator` | Transaction has not expired (expiration timestamp vs next slot) | 1.56 us |
91
93
  | `DoubleSpendTxValidator` | Nullifiers do not already exist in the nullifier tree | 106.08 us |
92
- | `GasTxValidator` | Gas limits are within bounds (delegates to `GasLimitsValidator`), max fee per gas meets current block fees, and fee payer has sufficient FeeJuice balance | 1.02 ms |
94
+ | `GasTxValidator` | Gas limits are within bounds (delegates to `GasLimitsValidator`), max fee per gas meets current block fees (delegates to `MaxFeePerGasValidator`), and fee payer has sufficient FeeJuice balance | 1.02 ms |
93
95
  | `GasLimitsValidator` | Gas limits are >= fixed minimums and <= AVM max processable L2 gas. Used standalone in pool migration; also called internally by `GasTxValidator` | 3–10 us |
96
+ | `MaxFeePerGasValidator` | Max fee per gas >= current block gas fees on both dimensions (DA and L2). Used standalone in pool migration; also called internally by `GasTxValidator` | 3–10 us |
94
97
  | `PhasesTxValidator` | Public function calls in setup phase are on the allow list | 10.12–13.12 us |
98
+ | `AllowedSetupCallsMetaValidator` | Checks the precomputed `allowedSetupCalls` flag on `TxMetaData`. Used in pool migration instead of the full `PhasesTxValidator` | — |
95
99
  | `BlockHeaderTxValidator` | Transaction's anchor block hash exists in the archive tree | 98.88 us |
96
100
  | `TxProofValidator` | Client proof verifies correctly | ~250ms |
97
101
 
@@ -107,9 +111,19 @@ Operates on `TxMetaData` (pre-built by the pool) rather than full `Tx` objects.
107
111
  | DoubleSpend | Stage 1 | Yes | — | Yes | Yes |
108
112
  | Gas (balance + limits) | Stage 1 | Optional* | — | Yes | — |
109
113
  | GasLimits (standalone) | — | — | — | — | Yes |
114
+ | MaxFeePerGas (standalone) | — | — | — | — | Yes |
110
115
  | Phases | Stage 1 | Yes | — | Yes | — |
116
+ | AllowedSetupCalls | — | — | — | — | Yes |
111
117
  | BlockHeader | Stage 1 | Yes | — | Yes | Yes |
112
118
  | Proof | Stage 2 | Optional** | Yes | — | — |
113
119
 
114
- \* Gas balance check is skipped when `skipFeeEnforcement` is set (testing/dev). `GasTxValidator` internally delegates to `GasLimitsValidator` as its first step, so gas limits are checked wherever `GasTxValidator` runs. Pool migration uses `GasLimitsValidator` standalone because it doesn't need the balance or fee-per-gas checks.
120
+ \* Gas balance check is skipped when `skipFeeEnforcement` is set (testing/dev). `GasTxValidator` internally delegates to `GasLimitsValidator` and `MaxFeePerGasValidator` as its first steps, so gas limits and fee-per-gas are checked wherever `GasTxValidator` runs. Pool migration uses `GasLimitsValidator` and `MaxFeePerGasValidator` standalone because it doesn't need the balance check.
115
121
  \** Proof verification is skipped for simulations (no verifier provided).
122
+
123
+ The gas-limit bounds `GasLimitsValidator` enforces here — the per-tx protocol maxima and the network admission limits — are documented in [`stdlib/src/gas/README.md`](../../../../stdlib/src/gas/README.md) under "Gas and Data Limits".
124
+
125
+ ## Fee-Per-Gas Rejection Strategy
126
+
127
+ The `MaxFeePerGasValidator` and `InsufficientFeePerGasEvictionRule` reject and evict transactions whose `maxFeesPerGas` falls below the current block's gas fees. This is a simple strategy: if a tx can't pay the current fees, it gets rejected on entry and evicted after each new block.
128
+
129
+ **Caveat**: This may evict transactions that would become valid again if block fees drop. A more nuanced approach would be to define a threshold (e.g., 50%) and only reject/evict when the tx's max fee falls below that fraction of the current fees. The current approach is simpler and ensures the pool doesn't accumulate transactions with low max fees that are unlikely to be mined soon.