@aztec/p2p 0.0.1-commit.5914bae → 0.0.1-commit.59a0419c6

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 (286) hide show
  1. package/dest/client/factory.d.ts +4 -3
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +17 -15
  4. package/dest/client/interface.d.ts +9 -2
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +3 -2
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +30 -8
  9. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +21 -7
  10. package/dest/config.d.ts +107 -103
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +17 -12
  13. package/dest/errors/p2p-service.error.d.ts +9 -0
  14. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  15. package/dest/errors/p2p-service.error.js +10 -0
  16. package/dest/index.d.ts +1 -2
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +0 -1
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +7 -5
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.js +16 -9
  22. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
  23. package/dest/mem_pools/index.d.ts +1 -2
  24. package/dest/mem_pools/index.d.ts.map +1 -1
  25. package/dest/mem_pools/instrumentation.d.ts +4 -2
  26. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  27. package/dest/mem_pools/instrumentation.js +16 -14
  28. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
  29. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
  31. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  32. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  33. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  34. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  35. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +10 -5
  36. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/interfaces.js +1 -0
  38. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +9 -7
  39. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +13 -6
  41. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  42. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -43
  44. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
  45. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  47. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +2 -1
  48. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +20 -2
  50. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
  51. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  52. package/dest/msg_validators/attestation_validator/attestation_validator.js +20 -11
  53. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -2
  54. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  55. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
  56. package/dest/msg_validators/clock_tolerance.d.ts +12 -1
  57. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  58. package/dest/msg_validators/clock_tolerance.js +54 -3
  59. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
  60. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +2 -1
  62. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  63. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
  64. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  65. package/dest/msg_validators/proposal_validator/proposal_validator.js +19 -11
  66. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  67. package/dest/msg_validators/tx_validator/factory.d.ts +2 -2
  68. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  69. package/dest/msg_validators/tx_validator/factory.js +3 -3
  70. package/dest/msg_validators/tx_validator/gas_validator.d.ts +36 -4
  71. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  72. package/dest/msg_validators/tx_validator/gas_validator.js +50 -33
  73. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  74. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  75. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  76. package/dest/services/data_store.d.ts +1 -1
  77. package/dest/services/data_store.d.ts.map +1 -1
  78. package/dest/services/data_store.js +5 -5
  79. package/dest/services/dummy_service.d.ts +6 -3
  80. package/dest/services/dummy_service.d.ts.map +1 -1
  81. package/dest/services/dummy_service.js +6 -1
  82. package/dest/services/gossipsub/topic_score_params.d.ts +13 -2
  83. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  84. package/dest/services/gossipsub/topic_score_params.js +21 -4
  85. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  86. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  87. package/dest/services/libp2p/instrumentation.js +14 -0
  88. package/dest/services/libp2p/libp2p_service.d.ts +19 -27
  89. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  90. package/dest/services/libp2p/libp2p_service.js +158 -133
  91. package/dest/services/peer-manager/metrics.d.ts +3 -1
  92. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  93. package/dest/services/peer-manager/metrics.js +6 -0
  94. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  95. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  96. package/dest/services/peer-manager/peer_manager.js +39 -11
  97. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  98. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  99. package/dest/services/peer-manager/peer_scoring.js +32 -10
  100. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
  101. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  102. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +82 -101
  103. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
  104. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  105. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  106. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  107. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  108. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  109. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  110. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  111. package/dest/services/reqresp/config.d.ts +3 -3
  112. package/dest/services/reqresp/config.d.ts.map +1 -1
  113. package/dest/services/reqresp/interface.d.ts +14 -9
  114. package/dest/services/reqresp/interface.d.ts.map +1 -1
  115. package/dest/services/reqresp/interface.js +10 -11
  116. package/dest/services/reqresp/metrics.d.ts +1 -1
  117. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  118. package/dest/services/reqresp/metrics.js +0 -1
  119. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  120. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  121. package/dest/services/reqresp/protocols/index.js +0 -1
  122. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  123. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  124. package/dest/services/reqresp/protocols/tx.js +1 -3
  125. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  126. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  127. package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
  128. package/dest/services/reqresp/reqresp.d.ts +4 -2
  129. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  130. package/dest/services/reqresp/reqresp.js +13 -3
  131. package/dest/services/service.d.ts +5 -2
  132. package/dest/services/service.d.ts.map +1 -1
  133. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
  134. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  135. package/dest/services/tx_collection/fast_tx_collection.js +57 -73
  136. package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
  137. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  138. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  139. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  140. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  141. package/dest/services/tx_collection/request_tracker.js +84 -0
  142. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  143. package/dest/services/tx_collection/tx_collection.d.ts +3 -6
  144. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  145. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  146. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  147. package/dest/test-helpers/make-test-p2p-clients.js +4 -1
  148. package/dest/test-helpers/mock-pubsub.d.ts +11 -3
  149. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  150. package/dest/test-helpers/mock-pubsub.js +36 -11
  151. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  152. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  153. package/dest/test-helpers/reqresp-nodes.js +5 -3
  154. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  155. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  156. package/dest/test-helpers/testbench-utils.js +21 -2
  157. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  158. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  159. package/dest/testbench/p2p_client_testbench_worker.js +73 -17
  160. package/dest/testbench/worker_client_manager.d.ts +8 -1
  161. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  162. package/dest/testbench/worker_client_manager.js +51 -2
  163. package/dest/util.d.ts +1 -1
  164. package/package.json +14 -14
  165. package/src/client/factory.ts +25 -19
  166. package/src/client/interface.ts +9 -1
  167. package/src/client/p2p_client.ts +34 -9
  168. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +21 -9
  169. package/src/config.ts +29 -17
  170. package/src/errors/p2p-service.error.ts +11 -0
  171. package/src/index.ts +0 -1
  172. package/src/mem_pools/attestation_pool/attestation_pool.ts +17 -12
  173. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  174. package/src/mem_pools/index.ts +0 -3
  175. package/src/mem_pools/instrumentation.ts +17 -13
  176. package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
  177. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  178. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
  179. package/src/mem_pools/tx_pool_v2/interfaces.ts +10 -4
  180. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +24 -12
  181. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
  182. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +3 -0
  183. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +21 -1
  184. package/src/msg_validators/attestation_validator/README.md +1 -1
  185. package/src/msg_validators/attestation_validator/attestation_validator.ts +21 -9
  186. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
  187. package/src/msg_validators/clock_tolerance.ts +72 -3
  188. package/src/msg_validators/proposal_validator/README.md +4 -4
  189. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -1
  190. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +4 -1
  191. package/src/msg_validators/proposal_validator/proposal_validator.ts +17 -10
  192. package/src/msg_validators/tx_validator/README.md +11 -3
  193. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  194. package/src/msg_validators/tx_validator/factory.ts +3 -1
  195. package/src/msg_validators/tx_validator/gas_validator.ts +82 -33
  196. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  197. package/src/services/data_store.ts +5 -13
  198. package/src/services/dummy_service.ts +8 -2
  199. package/src/services/gossipsub/topic_score_params.ts +36 -4
  200. package/src/services/libp2p/instrumentation.ts +14 -0
  201. package/src/services/libp2p/libp2p_service.ts +154 -143
  202. package/src/services/peer-manager/metrics.ts +7 -0
  203. package/src/services/peer-manager/peer_manager.ts +45 -11
  204. package/src/services/peer-manager/peer_scoring.ts +27 -5
  205. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  206. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +78 -111
  207. package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
  208. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  209. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  210. package/src/services/reqresp/config.ts +2 -2
  211. package/src/services/reqresp/interface.ts +21 -11
  212. package/src/services/reqresp/metrics.ts +0 -1
  213. package/src/services/reqresp/protocols/index.ts +0 -1
  214. package/src/services/reqresp/protocols/tx.ts +1 -3
  215. package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
  216. package/src/services/reqresp/reqresp.ts +21 -2
  217. package/src/services/service.ts +6 -1
  218. package/src/services/tx_collection/fast_tx_collection.ts +57 -83
  219. package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
  220. package/src/services/tx_collection/request_tracker.ts +127 -0
  221. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  222. package/src/services/tx_collection/tx_collection.ts +3 -5
  223. package/src/test-helpers/make-test-p2p-clients.ts +3 -1
  224. package/src/test-helpers/mock-pubsub.ts +34 -5
  225. package/src/test-helpers/reqresp-nodes.ts +5 -3
  226. package/src/test-helpers/testbench-utils.ts +29 -3
  227. package/src/testbench/p2p_client_testbench_worker.ts +74 -15
  228. package/src/testbench/worker_client_manager.ts +57 -2
  229. package/src/util.ts +1 -1
  230. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  231. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  232. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  233. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  234. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  235. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  236. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  237. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  238. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  239. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  240. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  241. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
  242. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  243. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  244. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  245. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  246. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  247. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  248. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  249. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  250. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  251. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  252. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  253. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  254. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  255. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  256. package/dest/mem_pools/tx_pool/index.js +0 -2
  257. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  258. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  259. package/dest/mem_pools/tx_pool/priority.js +0 -15
  260. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  261. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  262. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  263. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  264. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  265. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
  266. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  267. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  268. package/dest/services/reqresp/protocols/block.js +0 -32
  269. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  270. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  271. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  272. package/src/mem_pools/tx_pool/README.md +0 -270
  273. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  274. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  275. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  276. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
  277. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  278. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  279. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  280. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  281. package/src/mem_pools/tx_pool/index.ts +0 -2
  282. package/src/mem_pools/tx_pool/priority.ts +0 -20
  283. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  284. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
  285. package/src/services/reqresp/protocols/block.ts +0 -37
  286. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
@@ -8,14 +8,21 @@ import {
8
8
  type ValidationResult,
9
9
  } from '@aztec/stdlib/p2p';
10
10
 
11
- import { isWithinClockTolerance } from '../clock_tolerance.js';
11
+ import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
12
12
 
13
13
  export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
14
14
  protected epochCache: EpochCacheInterface;
15
15
  protected logger: Logger;
16
+ private readonly pipeliningWindow: PipeliningWindow;
16
17
 
17
- constructor(epochCache: EpochCacheInterface) {
18
+ constructor(
19
+ epochCache: EpochCacheInterface,
20
+ opts: {
21
+ l1PublishingTime?: number;
22
+ },
23
+ ) {
18
24
  this.epochCache = epochCache;
25
+ this.pipeliningWindow = new PipeliningWindow(epochCache, { l1PublishingTime: opts.l1PublishingTime });
19
26
  this.logger = createLogger('p2p:checkpoint-attestation-validator');
20
27
  }
21
28
 
@@ -23,18 +30,23 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
23
30
  const slotNumber = message.payload.header.slotNumber;
24
31
 
25
32
  try {
26
- const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
33
+ // Use target slots since proposals target pipeline slots (slot + 1 when pipelining).
34
+ const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
27
35
 
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)) {
36
+ if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
37
+ // When pipelining, accept attestations for the current slot (built in the previous slot)
38
+ // until the target slot reaches its L1 publish cutoff.
39
+ if (this.pipeliningWindow.acceptsAttestation(slotNumber)) {
40
+ // Fall through to remaining validation (signature, committee, etc.)
41
+ } else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
31
42
  this.logger.warn(
32
- `Checkpoint attestation slot ${slotNumber} is not current (${currentSlot}) or next (${nextSlot}) slot`,
43
+ `Checkpoint attestation slot ${slotNumber} is not current (${targetSlot}) or next (${nextSlot}) slot`,
33
44
  );
34
45
  return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
46
+ } else {
47
+ this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
48
+ return { result: 'ignore' };
35
49
  }
36
- this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
37
- return { result: 'ignore' };
38
50
  }
39
51
 
40
52
  // Verify the signature is valid
@@ -20,8 +20,11 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
20
20
  epochCache: EpochCacheInterface,
21
21
  private attestationPool: AttestationPoolApi,
22
22
  telemetryClient: TelemetryClient,
23
+ opts: {
24
+ l1PublishingTime?: number;
25
+ } = {},
23
26
  ) {
24
- super(epochCache);
27
+ super(epochCache, opts);
25
28
  this.logger = this.logger.createChild('[FISHERMAN]');
26
29
 
27
30
  const meter = telemetryClient.getMeter('FishermanAttestationValidator');
@@ -1,5 +1,6 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { DEFAULT_P2P_PROPAGATION_TIME, createPipelinedCheckpointTimingModel } from '@aztec/stdlib/timetable';
3
4
 
4
5
  /**
5
6
  * Maximum clock disparity tolerance for P2P message validation (in milliseconds).
@@ -36,10 +37,11 @@ export function isWithinClockTolerance(
36
37
  }
37
38
 
38
39
  // Check how far we are into the current slot (in milliseconds)
39
- const { ts: slotStartTs, nowMs, slot } = epochCache.getEpochAndSlotNow();
40
+ const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
41
+ const targetSlot = epochCache.getTargetSlot();
40
42
 
41
- // Sanity check: ensure the epoch cache's current slot matches the expected current slot
42
- if (slot !== currentSlot) {
43
+ // Sanity check: ensure the epoch cache's target slot matches the expected current slot
44
+ if (targetSlot !== currentSlot) {
43
45
  return false;
44
46
  }
45
47
 
@@ -49,3 +51,70 @@ export function isWithinClockTolerance(
49
51
 
50
52
  return elapsedMs < MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
51
53
  }
54
+
55
+ /**
56
+ * Checks if a message should be accepted under the pipelining grace period.
57
+ *
58
+ * When pipelining is enabled, `targetSlot = slotNow + 1`. A proposal built in slot N-1
59
+ * for slot N arrives when validators are in slot N, so their `targetSlot = N+1`.
60
+ * This function accepts proposals for the current wallclock slot if we're within the
61
+ * first `windowSeconds` seconds of the slot (the pipelining grace period). - see stdlib/timetable/index.ts
62
+ *
63
+ * @param messageSlot - The slot number from the received message
64
+ * @param epochCache - EpochCache to get timing and pipelining state
65
+ * @param windowSeconds - The window grace period allowed for attestations into the next slot
66
+ * @returns true if pipelining is enabled, the message is for the current slot, and we're within the grace period
67
+ */
68
+ function isWithinPipeliningWindow(
69
+ messageSlot: SlotNumber,
70
+ epochCache: EpochCacheInterface,
71
+ windowSeconds: number,
72
+ ): boolean {
73
+ if (!epochCache.isProposerPipeliningEnabled()) {
74
+ return false;
75
+ }
76
+
77
+ const currentSlot = epochCache.getSlotNow();
78
+ if (messageSlot !== currentSlot) {
79
+ return false;
80
+ }
81
+
82
+ const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
83
+ const slotStartMs = slotStartTs * 1000n;
84
+ const elapsedMs = Number(nowMs - slotStartMs);
85
+ const windowMs = windowSeconds * 1000 + MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
86
+
87
+ return elapsedMs < windowMs;
88
+ }
89
+
90
+ export class PipeliningWindow {
91
+ private readonly proposalWindowIntoTargetSlot: number;
92
+ private readonly attestationWindowIntoTargetSlot: number;
93
+
94
+ constructor(
95
+ private readonly epochCache: EpochCacheInterface,
96
+ opts: {
97
+ p2pPropagationTime?: number;
98
+ l1PublishingTime?: number;
99
+ } = {},
100
+ ) {
101
+ const l1Constants = epochCache.getL1Constants();
102
+ const checkpointTiming = createPipelinedCheckpointTimingModel({
103
+ aztecSlotDuration: l1Constants.slotDuration,
104
+ ethereumSlotDuration: l1Constants.ethereumSlotDuration,
105
+ l1PublishingTime: opts.l1PublishingTime ?? l1Constants.ethereumSlotDuration,
106
+ p2pPropagationTime: opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME,
107
+ });
108
+
109
+ this.proposalWindowIntoTargetSlot = checkpointTiming.proposalWindowIntoTargetSlot;
110
+ this.attestationWindowIntoTargetSlot = checkpointTiming.attestationWindowIntoTargetSlot;
111
+ }
112
+
113
+ public acceptsProposal(messageSlot: SlotNumber): boolean {
114
+ return isWithinPipeliningWindow(messageSlot, this.epochCache, this.proposalWindowIntoTargetSlot);
115
+ }
116
+
117
+ public acceptsAttestation(messageSlot: SlotNumber): boolean {
118
+ return isWithinPipeliningWindow(messageSlot, this.epochCache, this.attestationWindowIntoTargetSlot);
119
+ }
120
+ }
@@ -28,7 +28,7 @@ Deserialization guards: `BlockProposal.fromBuffer` and `SignedTxs.fromBuffer` bo
28
28
  | # | Rule | Consequence |
29
29
  |---|------|-------------|
30
30
  | 9 | **Duplicate**: same archive root already stored | IGNORE (no penalty) |
31
- | 10 | **Per-position cap**: max 3 proposals per (slot, indexWithinCheckpoint) | REJECT + HighToleranceError |
31
+ | 10 | **Per-position cap**: max 2 proposals per (slot, indexWithinCheckpoint) | REJECT + HighToleranceError |
32
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
33
 
34
34
  ### Stage 3: Validator-Client Processing (BlockProposalHandler)
@@ -53,7 +53,7 @@ Only runs on validator nodes. Non-validator nodes use a default handler that tri
53
53
 
54
54
  **Escape hatch**: during escape hatch periods (`isEscapeHatchOpenAtSlot`), re-execution and slashing are both disabled, and the proposal is rejected locally.
55
55
 
56
- **Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0` with `validatorReexecute`, committee membership with `validatorReexecute`, `alwaysReexecuteBlockProposals`, or `blobClient.canUpload()`.
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
57
 
58
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
59
 
@@ -84,7 +84,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
84
84
  | Rule | Consequence | File |
85
85
  |------|-------------|------|
86
86
  | Block proposal must pass `BlockProposalValidator.validate()` | If REJECT: entire checkpoint REJECTED | `libp2p_service.ts` |
87
- | Block proposal must not exceed per-position cap (3) | Checkpoint REJECTED + HighToleranceError | same |
87
+ | Block proposal must not exceed per-position cap (2) | Checkpoint REJECTED + HighToleranceError | same |
88
88
  | Block equivocation detected (>1 proposals for same slot+index) | Checkpoint REJECTED (block itself is ACCEPT for re-broadcast) | same |
89
89
 
90
90
  ### Stage 3: Mempool (Attestation Pool)
@@ -92,7 +92,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
92
92
  | Rule | Consequence | File |
93
93
  |------|-------------|------|
94
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` = 5 | REJECT + HighToleranceError. Embedded block still processed. | same |
95
+ | Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` = 2 | REJECT + HighToleranceError. Embedded block still processed. | same |
96
96
 
97
97
  ### Stage 4: Equivocation Detection
98
98
 
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
6
6
  export class BlockProposalValidator implements P2PValidator<BlockProposal> {
7
7
  private proposalValidator: ProposalValidator;
8
8
 
9
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
9
+ constructor(
10
+ epochCache: EpochCacheInterface,
11
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
12
+ ) {
10
13
  this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
11
14
  }
12
15
 
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
6
6
  export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
7
7
  private proposalValidator: ProposalValidator;
8
8
 
9
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
9
+ constructor(
10
+ epochCache: EpochCacheInterface,
11
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
12
+ ) {
10
13
  this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
11
14
  }
12
15
 
@@ -8,7 +8,7 @@ import {
8
8
  type ValidationResult,
9
9
  } from '@aztec/stdlib/p2p';
10
10
 
11
- import { isWithinClockTolerance } from '../clock_tolerance.js';
11
+ import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
12
12
 
13
13
  /** Validates header-level and tx-level fields of block and checkpoint proposals. */
14
14
  export class ProposalValidator {
@@ -16,32 +16,39 @@ export class ProposalValidator {
16
16
  private logger: Logger;
17
17
  private txsPermitted: boolean;
18
18
  private maxTxsPerBlock?: number;
19
+ private pipeliningWindow: PipeliningWindow;
19
20
 
20
21
  constructor(
21
22
  epochCache: EpochCacheInterface,
22
- opts: { txsPermitted: boolean; maxTxsPerBlock?: number },
23
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
23
24
  loggerName: string,
24
25
  ) {
25
26
  this.epochCache = epochCache;
26
27
  this.txsPermitted = opts.txsPermitted;
27
28
  this.maxTxsPerBlock = opts.maxTxsPerBlock;
29
+ this.pipeliningWindow = new PipeliningWindow(epochCache, { p2pPropagationTime: opts.p2pPropagationTime });
28
30
  this.logger = createLogger(loggerName);
29
31
  }
30
32
 
31
33
  /** Validates header-level fields: slot, signature, and proposer. */
32
34
  public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
33
35
  try {
34
- // Slot check
35
- const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
36
+ // Slot check: use target slots since proposals target pipeline slots (slot + 1 when pipelining).
37
+ const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
38
+
36
39
  const slotNumber = proposal.slotNumber;
37
- if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
38
- // Check if message is for previous slot and within clock tolerance
39
- if (!isWithinClockTolerance(slotNumber, currentSlot, this.epochCache)) {
40
- this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { currentSlot, nextSlot });
40
+ if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
41
+ // When pipelining, accept proposals for the current slot (built in the previous slot)
42
+ // if they're still within the shared proposal acceptance window.
43
+ if (this.pipeliningWindow.acceptsProposal(slotNumber)) {
44
+ // Fall through to remaining validation (signature, proposer, etc.)
45
+ } else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
46
+ this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { targetSlot, nextSlot });
41
47
  return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
48
+ } else {
49
+ this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
50
+ return { result: 'ignore' };
42
51
  }
43
- this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
44
- return { result: 'ignore' };
45
52
  }
46
53
 
47
54
  // Signature validity
@@ -75,7 +75,7 @@ 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, AllowedSetupCalls
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
 
@@ -91,8 +91,9 @@ The `AllowedSetupCallsMetaValidator` checks a precomputed boolean flag (`TxMetaD
91
91
  | `MetadataTxValidator` | Chain ID, rollup version, protocol contracts hash, VK tree root | 4.18 us |
92
92
  | `TimestampTxValidator` | Transaction has not expired (expiration timestamp vs next slot) | 1.56 us |
93
93
  | `DoubleSpendTxValidator` | Nullifiers do not already exist in the nullifier tree | 106.08 us |
94
- | `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 |
95
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 |
96
97
  | `PhasesTxValidator` | Public function calls in setup phase are on the allow list | 10.12–13.12 us |
97
98
  | `AllowedSetupCallsMetaValidator` | Checks the precomputed `allowedSetupCalls` flag on `TxMetaData`. Used in pool migration instead of the full `PhasesTxValidator` | — |
98
99
  | `BlockHeaderTxValidator` | Transaction's anchor block hash exists in the archive tree | 98.88 us |
@@ -110,10 +111,17 @@ The `AllowedSetupCallsMetaValidator` checks a precomputed boolean flag (`TxMetaD
110
111
  | DoubleSpend | Stage 1 | Yes | — | Yes | Yes |
111
112
  | Gas (balance + limits) | Stage 1 | Optional* | — | Yes | — |
112
113
  | GasLimits (standalone) | — | — | — | — | Yes |
114
+ | MaxFeePerGas (standalone) | — | — | — | — | Yes |
113
115
  | Phases | Stage 1 | Yes | — | Yes | — |
114
116
  | AllowedSetupCalls | — | — | — | — | Yes |
115
117
  | BlockHeader | Stage 1 | Yes | — | Yes | Yes |
116
118
  | Proof | Stage 2 | Optional** | Yes | — | — |
117
119
 
118
- \* 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.
119
121
  \** Proof verification is skipped for simulations (no verifier provided).
122
+
123
+ ## Fee-Per-Gas Rejection Strategy
124
+
125
+ 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.
126
+
127
+ **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.
@@ -15,7 +15,7 @@ export class ArchiveCache implements ArchiveSource {
15
15
  }
16
16
 
17
17
  public async getArchiveIndices(archives: BlockHash[]): Promise<(bigint | undefined)[]> {
18
- const toCheckDb = archives.filter(n => !this.archives.has(n.toString())).map(n => n.toFr());
18
+ const toCheckDb = archives.filter(n => !this.archives.has(n.toString()));
19
19
  const dbHits = await this.db.findLeafIndices(MerkleTreeId.ARCHIVE, toCheckDb);
20
20
  dbHits.forEach((x, index) => {
21
21
  if (x !== undefined) {
@@ -56,7 +56,7 @@ import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_valid
56
56
  import { ContractInstanceTxValidator } from './contract_instance_validator.js';
57
57
  import { DataTxValidator } from './data_validator.js';
58
58
  import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
59
- import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
59
+ import { GasLimitsValidator, GasTxValidator, MaxFeePerGasValidator } from './gas_validator.js';
60
60
  import { MetadataTxValidator } from './metadata_validator.js';
61
61
  import { NullifierCache } from './nullifier_cache.js';
62
62
  import { AllowedSetupCallsMetaValidator, PhasesTxValidator } from './phases_validator.js';
@@ -423,6 +423,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
423
423
  timestamp: bigint,
424
424
  blockNumber: BlockNumber,
425
425
  gasLimitOpts: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
426
+ gasFees: GasFees,
426
427
  bindings?: LoggerBindings,
427
428
  ): Promise<TxValidator<TxMetaData>> {
428
429
  await worldStateSynchronizer.syncImmediate();
@@ -440,6 +441,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
440
441
  };
441
442
  return new AggregateTxValidator<TxMetaData>(
442
443
  new GasLimitsValidator<TxMetaData>({ ...gasLimitOpts, bindings }),
444
+ new MaxFeePerGasValidator<TxMetaData>(gasFees, bindings),
443
445
  new TimestampTxValidator<TxMetaData>({ timestamp, blockNumber }, bindings),
444
446
  new DoubleSpendTxValidator<TxMetaData>(nullifierSource, bindings),
445
447
  new BlockHeaderTxValidator<TxMetaData>(archiveSource, bindings),
@@ -36,6 +36,18 @@ export interface HasGasLimitData {
36
36
  };
37
37
  }
38
38
 
39
+ /** Structural interface for types that carry max fee per gas data, used by {@link MaxFeePerGasValidator}. */
40
+ export interface HasMaxFeePerGasData {
41
+ txHash: { toString(): string };
42
+ data: {
43
+ constants: {
44
+ txContext: {
45
+ gasSettings: { maxFeesPerGas: GasFees };
46
+ };
47
+ };
48
+ };
49
+ }
50
+
39
51
  /**
40
52
  * Validates that a transaction's gas limits are within acceptable bounds.
41
53
  *
@@ -87,7 +99,12 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
87
99
  gasLimits,
88
100
  minGasLimits,
89
101
  });
90
- return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
102
+ return {
103
+ result: 'invalid',
104
+ reason: [
105
+ `${TX_ERROR_INSUFFICIENT_GAS_LIMIT} (required=da:${minGasLimits.daGas},l2:${minGasLimits.l2Gas} got=da:${gasLimits.daGas},l2:${gasLimits.l2Gas})`,
106
+ ],
107
+ };
91
108
  }
92
109
 
93
110
  if (gasLimits.l2Gas > this.#effectiveMaxL2Gas) {
@@ -97,7 +114,10 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
97
114
  rollupManaLimit: this.#rollupManaLimit,
98
115
  maxBlockL2Gas: this.#maxBlockL2Gas,
99
116
  });
100
- return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
117
+ return {
118
+ result: 'invalid',
119
+ reason: [`${TX_ERROR_GAS_LIMIT_TOO_HIGH} (l2Gas=${gasLimits.l2Gas}, max=${this.#effectiveMaxL2Gas})`],
120
+ };
101
121
  }
102
122
 
103
123
  if (gasLimits.daGas > this.#effectiveMaxDAGas) {
@@ -106,22 +126,70 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
106
126
  effectiveMaxDAGas: this.#effectiveMaxDAGas,
107
127
  maxBlockDAGas: this.#maxBlockDAGas,
108
128
  });
109
- return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
129
+ return {
130
+ result: 'invalid',
131
+ reason: [`${TX_ERROR_GAS_LIMIT_TOO_HIGH} (daGas=${gasLimits.daGas}, max=${this.#effectiveMaxDAGas})`],
132
+ };
110
133
  }
111
134
 
112
135
  return { result: 'valid' };
113
136
  }
114
137
  }
115
138
 
139
+ /**
140
+ * Validates that a transaction's max fee per gas meets the current block's gas fees.
141
+ *
142
+ * Rejects transactions whose maxFeesPerGas is below the current block's gas fees
143
+ * on either dimension (DA or L2). This is a cheap, stateless check.
144
+ *
145
+ * Generic over T so it can validate both full {@link Tx} objects and {@link TxMetaData}
146
+ * (used during pending pool migration).
147
+ *
148
+ * Used by: pending pool migration (via factory), and indirectly by {@link GasTxValidator}.
149
+ */
150
+ export class MaxFeePerGasValidator<T extends HasMaxFeePerGasData> implements TxValidator<T> {
151
+ #log: Logger;
152
+ #gasFees: GasFees;
153
+
154
+ constructor(gasFees: GasFees, bindings?: LoggerBindings) {
155
+ this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
156
+ this.#gasFees = gasFees;
157
+ }
158
+
159
+ validateTx(tx: T): Promise<TxValidationResult> {
160
+ return Promise.resolve(this.validateMaxFeePerGas(tx));
161
+ }
162
+
163
+ /** Checks maxFeesPerGas >= current block gas fees on both dimensions. */
164
+ validateMaxFeePerGas(tx: T): TxValidationResult {
165
+ const maxFeesPerGas = tx.data.constants.txContext.gasSettings.maxFeesPerGas;
166
+ const notEnoughMaxFees =
167
+ maxFeesPerGas.feePerDaGas < this.#gasFees.feePerDaGas || maxFeesPerGas.feePerL2Gas < this.#gasFees.feePerL2Gas;
168
+
169
+ if (notEnoughMaxFees) {
170
+ this.#log.verbose(`Rejecting transaction ${tx.txHash.toString()} due to insufficient fee per gas`, {
171
+ txMaxFeesPerGas: maxFeesPerGas.toInspect(),
172
+ currentGasFees: this.#gasFees.toInspect(),
173
+ });
174
+ return {
175
+ result: 'invalid',
176
+ reason: [
177
+ `${TX_ERROR_INSUFFICIENT_FEE_PER_GAS} (maxFee=da:${maxFeesPerGas.feePerDaGas},l2:${maxFeesPerGas.feePerL2Gas} required=da:${this.#gasFees.feePerDaGas},l2:${this.#gasFees.feePerL2Gas})`,
178
+ ],
179
+ };
180
+ }
181
+ return { result: 'valid' };
182
+ }
183
+ }
184
+
116
185
  /**
117
186
  * Validates that a transaction can pay its gas fees.
118
187
  *
119
188
  * Runs three checks in order:
120
189
  * 1. **Gas limits** (delegates to {@link GasLimitsValidator}) — rejects if limits are
121
190
  * out of bounds.
122
- * 2. **Max fee per gas** — skips (not rejects) the tx if its maxFeesPerGas is below
123
- * the current block's gas fees. We skip rather than reject because the tx may
124
- * become eligible in a later block with lower fees.
191
+ * 2. **Max fee per gas** — rejects the tx if its maxFeesPerGas is below
192
+ * the current block's gas fees.
125
193
  * 3. **Fee payer balance** — reads the fee payer's FeeJuice balance from public state,
126
194
  * adds any pending claim from a setup-phase `_increase_public_balance` call, and
127
195
  * rejects if the total is less than the tx's fee limit (gasLimits * maxFeePerGas).
@@ -155,37 +223,15 @@ export class GasTxValidator implements TxValidator<Tx> {
155
223
  bindings: this.bindings,
156
224
  }).validateGasLimit(tx);
157
225
  if (gasLimitValidation.result === 'invalid') {
158
- return Promise.resolve(gasLimitValidation);
226
+ return gasLimitValidation;
159
227
  }
160
- if (this.#shouldSkip(tx)) {
161
- return Promise.resolve({ result: 'skipped', reason: [TX_ERROR_INSUFFICIENT_FEE_PER_GAS] });
228
+ const maxFeeValidation = new MaxFeePerGasValidator(this.#gasFees, this.bindings).validateMaxFeePerGas(tx);
229
+ if (maxFeeValidation.result === 'invalid') {
230
+ return maxFeeValidation;
162
231
  }
163
232
  return await this.validateTxFee(tx);
164
233
  }
165
234
 
166
- /**
167
- * Check whether the tx's max fees are valid for the current block, and skip if not.
168
- * We skip instead of invalidating since the tx may become eligible later.
169
- * Note that circuits check max fees even if fee payer is unset, so we
170
- * keep this validation even if the tx does not pay fees.
171
- */
172
- #shouldSkip(tx: Tx): boolean {
173
- const gasSettings = tx.data.constants.txContext.gasSettings;
174
-
175
- // Skip the tx if its max fees are not enough for the current block's gas fees.
176
- const maxFeesPerGas = gasSettings.maxFeesPerGas;
177
- const notEnoughMaxFees =
178
- maxFeesPerGas.feePerDaGas < this.#gasFees.feePerDaGas || maxFeesPerGas.feePerL2Gas < this.#gasFees.feePerL2Gas;
179
-
180
- if (notEnoughMaxFees) {
181
- this.#log.verbose(`Skipping transaction ${tx.getTxHash().toString()} due to insufficient fee per gas`, {
182
- txMaxFeesPerGas: maxFeesPerGas.toInspect(),
183
- currentGasFees: this.#gasFees.toInspect(),
184
- });
185
- }
186
- return notEnoughMaxFees;
187
- }
188
-
189
235
  /**
190
236
  * Checks the fee payer has enough FeeJuice balance to cover the tx's fee limit.
191
237
  * Accounts for any pending claim from a setup-phase `_increase_public_balance` call.
@@ -212,7 +258,10 @@ export class GasTxValidator implements TxValidator<Tx> {
212
258
  balance,
213
259
  feeLimit,
214
260
  });
215
- return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE] };
261
+ return {
262
+ result: 'invalid',
263
+ reason: [`${TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE} (required=${feeLimit}, available=${balance})`],
264
+ };
216
265
  }
217
266
  return { result: 'valid' };
218
267
  }
@@ -28,16 +28,24 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
28
28
  validateTx(tx: T): Promise<TxValidationResult> {
29
29
  const errors = [];
30
30
  if (!this.#hasCorrectL1ChainId(tx)) {
31
- errors.push(TX_ERROR_INCORRECT_L1_CHAIN_ID);
31
+ errors.push(
32
+ `${TX_ERROR_INCORRECT_L1_CHAIN_ID} (tx: ${tx.data.constants.txContext.chainId.toNumber()}, expected: ${this.values.l1ChainId.toNumber()})`,
33
+ );
32
34
  }
33
35
  if (!this.#hasCorrectRollupVersion(tx)) {
34
- errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
36
+ errors.push(
37
+ `${TX_ERROR_INCORRECT_ROLLUP_VERSION} (tx: ${tx.data.constants.txContext.version.toNumber()}, expected: ${this.values.rollupVersion.toNumber()})`,
38
+ );
35
39
  }
36
40
  if (!this.#hasCorrectVkTreeRoot(tx)) {
37
- errors.push(TX_ERROR_INCORRECT_VK_TREE_ROOT);
41
+ errors.push(
42
+ `${TX_ERROR_INCORRECT_VK_TREE_ROOT} (tx: ${tx.data.constants.vkTreeRoot.toString()}, expected: ${this.values.vkTreeRoot.toString()})`,
43
+ );
38
44
  }
39
45
  if (!this.#hasCorrectprotocolContractsHash(tx)) {
40
- errors.push(TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH);
46
+ errors.push(
47
+ `${TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH} (tx: ${tx.data.constants.protocolContractsHash.toString()}, expected: ${this.values.protocolContractsHash.toString()})`,
48
+ );
41
49
  }
42
50
  return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
43
51
  }
@@ -28,8 +28,6 @@ export class AztecDatastore implements Datastore {
28
28
  #memoryDatastore: Map<string, MemoryItem>;
29
29
  #dbDatastore: AztecAsyncMap<string, Uint8Array>;
30
30
 
31
- #batchOps: BatchOp[] = [];
32
-
33
31
  private maxMemoryItems: number;
34
32
 
35
33
  constructor(db: AztecAsyncKVStore, { maxMemoryItems } = { maxMemoryItems: 50 }) {
@@ -92,23 +90,17 @@ export class AztecDatastore implements Datastore {
92
90
  }
93
91
 
94
92
  batch(): Batch {
93
+ const ops: BatchOp[] = [];
95
94
  return {
96
95
  put: (key, value) => {
97
- this.#batchOps.push({
98
- type: 'put',
99
- key,
100
- value,
101
- });
96
+ ops.push({ type: 'put', key, value });
102
97
  },
103
98
  delete: key => {
104
- this.#batchOps.push({
105
- type: 'del',
106
- key,
107
- });
99
+ ops.push({ type: 'del', key });
108
100
  },
109
101
  commit: async () => {
110
102
  await this.#db.transactionAsync(async () => {
111
- for (const op of this.#batchOps) {
103
+ for (const op of ops) {
112
104
  if (op.type === 'put' && op.value) {
113
105
  await this.put(op.key, op.value);
114
106
  } else if (op.type === 'del') {
@@ -116,7 +108,7 @@ export class AztecDatastore implements Datastore {
116
108
  }
117
109
  }
118
110
  });
119
- this.#batchOps = []; // Clear operations after commit
111
+ ops.length = 0;
120
112
  },
121
113
  };
122
114
  }
@@ -1,6 +1,6 @@
1
1
  import type { EthAddress } from '@aztec/foundation/eth-address';
2
2
  import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
3
- import type { Gossipable, PeerErrorSeverity, TopicType } from '@aztec/stdlib/p2p';
3
+ import type { CheckpointProposalCore, Gossipable, PeerErrorSeverity, TopicType } from '@aztec/stdlib/p2p';
4
4
  import { Tx, TxHash } from '@aztec/stdlib/tx';
5
5
 
6
6
  import type { PeerId } from '@libp2p/interface';
@@ -86,7 +86,12 @@ export class DummyP2PService implements P2PService {
86
86
  /**
87
87
  * Register a callback into the validator client for when a checkpoint proposal is received
88
88
  */
89
- public registerCheckpointReceivedCallback(_callback: P2PCheckpointReceivedCallback) {}
89
+ public registerValidatorCheckpointReceivedCallback(_callback: P2PCheckpointReceivedCallback) {}
90
+ public registerAllNodesCheckpointReceivedCallback(_callback: P2PCheckpointReceivedCallback) {}
91
+
92
+ public notifyOwnCheckpointProposal(_checkpoint: CheckpointProposalCore): Promise<void> {
93
+ return Promise.resolve();
94
+ }
90
95
 
91
96
  /**
92
97
  * Register a callback for when a duplicate proposal is detected
@@ -282,6 +287,7 @@ export class DummyPeerManager implements PeerManagerInterface {
282
287
 
283
288
  export class DummyReqResp implements ReqRespInterface {
284
289
  updateConfig(_config: Partial<P2PReqRespConfig>): void {}
290
+ setShouldRejectPeer(): void {}
285
291
  start(
286
292
  _subProtocolHandlers: ReqRespSubProtocolHandlers,
287
293
  _subProtocolValidators: ReqRespSubProtocolValidators,