@aztec/p2p 0.0.1-commit.d431d1c → 0.0.1-commit.d939eb5aa

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 (558) hide show
  1. package/README.md +129 -3
  2. package/dest/bootstrap/bootstrap.d.ts +4 -3
  3. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  4. package/dest/bootstrap/bootstrap.js +4 -4
  5. package/dest/client/factory.d.ts +11 -11
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +60 -19
  8. package/dest/client/interface.d.ts +54 -34
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +43 -52
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +190 -226
  13. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +2 -0
  14. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +1 -0
  15. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +315 -0
  16. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +73 -0
  17. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +1 -0
  18. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +8 -0
  19. package/dest/config.d.ts +135 -82
  20. package/dest/config.d.ts.map +1 -1
  21. package/dest/config.js +113 -40
  22. package/dest/errors/p2p-service.error.d.ts +9 -0
  23. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  24. package/dest/errors/p2p-service.error.js +10 -0
  25. package/dest/errors/tx-pool.error.d.ts +8 -0
  26. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  27. package/dest/errors/tx-pool.error.js +9 -0
  28. package/dest/index.d.ts +2 -2
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +1 -1
  31. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +106 -88
  32. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/attestation_pool.js +448 -3
  34. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
  35. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +353 -87
  37. package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
  38. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
  39. package/dest/mem_pools/attestation_pool/index.js +1 -2
  40. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  41. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  42. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  43. package/dest/mem_pools/index.d.ts +3 -3
  44. package/dest/mem_pools/index.d.ts.map +1 -1
  45. package/dest/mem_pools/index.js +1 -1
  46. package/dest/mem_pools/instrumentation.d.ts +4 -2
  47. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  48. package/dest/mem_pools/instrumentation.js +18 -16
  49. package/dest/mem_pools/interface.d.ts +5 -5
  50. package/dest/mem_pools/interface.d.ts.map +1 -1
  51. package/dest/mem_pools/tx_pool_v2/archive/index.d.ts +2 -0
  52. package/dest/mem_pools/tx_pool_v2/archive/index.d.ts.map +1 -0
  53. package/dest/mem_pools/tx_pool_v2/archive/index.js +1 -0
  54. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +43 -0
  55. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -0
  56. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +103 -0
  57. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
  58. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
  59. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
  60. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +47 -0
  61. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -0
  62. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +128 -0
  63. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +17 -0
  64. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
  65. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +94 -0
  66. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +19 -0
  67. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -0
  68. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +97 -0
  69. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +10 -0
  70. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -0
  71. package/dest/mem_pools/tx_pool_v2/eviction/index.js +11 -0
  72. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +180 -0
  73. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -0
  74. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +25 -0
  75. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +15 -0
  76. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  77. package/dest/mem_pools/{tx_pool → tx_pool_v2}/eviction/invalid_txs_after_mining_rule.js +16 -35
  78. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +17 -0
  79. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  80. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +93 -0
  81. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +16 -0
  82. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  83. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +78 -0
  84. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +20 -0
  85. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -0
  86. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +75 -0
  87. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +15 -0
  88. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -0
  89. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +19 -0
  90. package/dest/mem_pools/tx_pool_v2/index.d.ts +6 -0
  91. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -0
  92. package/dest/mem_pools/tx_pool_v2/index.js +5 -0
  93. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  94. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  95. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  96. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +215 -0
  97. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
  98. package/dest/mem_pools/tx_pool_v2/interfaces.js +10 -0
  99. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +134 -0
  100. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -0
  101. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +220 -0
  102. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts +26 -0
  103. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts.map +1 -0
  104. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.js +70 -0
  105. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +108 -0
  106. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
  107. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +337 -0
  108. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +62 -0
  109. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -0
  110. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +167 -0
  111. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +78 -0
  112. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -0
  113. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +923 -0
  114. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +7 -4
  115. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  116. package/dest/msg_validators/attestation_validator/attestation_validator.js +52 -12
  117. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -5
  118. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  119. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +20 -8
  120. package/dest/msg_validators/clock_tolerance.d.ts +32 -0
  121. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -0
  122. package/dest/msg_validators/clock_tolerance.js +88 -0
  123. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +7 -4
  124. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  125. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  126. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +7 -4
  127. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  128. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  129. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +15 -8
  130. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  131. package/dest/msg_validators/proposal_validator/proposal_validator.js +92 -41
  132. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
  133. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  134. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  135. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  136. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  137. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  138. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  139. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  140. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  141. package/dest/msg_validators/tx_validator/archive_cache.d.ts +3 -3
  142. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  143. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +20 -6
  144. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  145. package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
  146. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  147. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  148. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  149. package/dest/msg_validators/tx_validator/data_validator.d.ts +3 -1
  150. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  151. package/dest/msg_validators/tx_validator/data_validator.js +39 -3
  152. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +15 -4
  153. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  154. package/dest/msg_validators/tx_validator/double_spend_validator.js +7 -6
  155. package/dest/msg_validators/tx_validator/factory.d.ts +137 -5
  156. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  157. package/dest/msg_validators/tx_validator/factory.js +255 -58
  158. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  159. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  160. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  161. package/dest/msg_validators/tx_validator/gas_validator.d.ts +68 -3
  162. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  163. package/dest/msg_validators/tx_validator/gas_validator.js +114 -44
  164. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  165. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  166. package/dest/msg_validators/tx_validator/index.js +2 -0
  167. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -2
  168. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  169. package/dest/msg_validators/tx_validator/metadata_validator.js +6 -6
  170. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  171. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  172. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  173. package/dest/msg_validators/tx_validator/phases_validator.d.ts +24 -3
  174. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  175. package/dest/msg_validators/tx_validator/phases_validator.js +75 -27
  176. package/dest/msg_validators/tx_validator/size_validator.d.ts +3 -1
  177. package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -1
  178. package/dest/msg_validators/tx_validator/size_validator.js +4 -1
  179. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +22 -5
  180. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  181. package/dest/msg_validators/tx_validator/timestamp_validator.js +8 -8
  182. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
  183. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  184. package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
  185. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +3 -2
  186. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  187. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
  188. package/dest/services/data_store.d.ts +1 -1
  189. package/dest/services/data_store.d.ts.map +1 -1
  190. package/dest/services/data_store.js +14 -10
  191. package/dest/services/discv5/discV5_service.js +1 -1
  192. package/dest/services/dummy_service.d.ts +28 -5
  193. package/dest/services/dummy_service.d.ts.map +1 -1
  194. package/dest/services/dummy_service.js +52 -2
  195. package/dest/services/encoding.d.ts +7 -3
  196. package/dest/services/encoding.d.ts.map +1 -1
  197. package/dest/services/encoding.js +18 -11
  198. package/dest/services/gossipsub/index.d.ts +3 -0
  199. package/dest/services/gossipsub/index.d.ts.map +1 -0
  200. package/dest/services/gossipsub/index.js +2 -0
  201. package/dest/services/gossipsub/scoring.d.ts +21 -3
  202. package/dest/services/gossipsub/scoring.d.ts.map +1 -1
  203. package/dest/services/gossipsub/scoring.js +24 -7
  204. package/dest/services/gossipsub/topic_score_params.d.ts +184 -0
  205. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
  206. package/dest/services/gossipsub/topic_score_params.js +363 -0
  207. package/dest/services/index.d.ts +2 -1
  208. package/dest/services/index.d.ts.map +1 -1
  209. package/dest/services/index.js +1 -0
  210. package/dest/services/libp2p/instrumentation.d.ts +1 -1
  211. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  212. package/dest/services/libp2p/instrumentation.js +14 -3
  213. package/dest/services/libp2p/libp2p_service.d.ts +98 -50
  214. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  215. package/dest/services/libp2p/libp2p_service.js +580 -449
  216. package/dest/services/peer-manager/metrics.d.ts +4 -2
  217. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  218. package/dest/services/peer-manager/metrics.js +26 -5
  219. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  220. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  221. package/dest/services/peer-manager/peer_manager.js +39 -11
  222. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  223. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  224. package/dest/services/peer-manager/peer_scoring.js +65 -14
  225. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +51 -0
  226. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -0
  227. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +543 -0
  228. package/dest/services/reqresp/batch-tx-requester/config.d.ts +17 -0
  229. package/dest/services/reqresp/batch-tx-requester/config.d.ts.map +1 -0
  230. package/dest/services/reqresp/batch-tx-requester/config.js +27 -0
  231. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +47 -0
  232. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -0
  233. package/dest/services/reqresp/batch-tx-requester/interface.js +1 -0
  234. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +35 -0
  235. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -0
  236. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +136 -0
  237. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +62 -0
  238. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -0
  239. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +176 -0
  240. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +20 -0
  241. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -0
  242. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +21 -0
  243. package/dest/services/reqresp/config.d.ts +3 -3
  244. package/dest/services/reqresp/config.d.ts.map +1 -1
  245. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +22 -3
  246. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  247. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +63 -4
  248. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -1
  249. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  250. package/dest/services/reqresp/connection-sampler/connection_sampler.js +12 -0
  251. package/dest/services/reqresp/interface.d.ts +25 -9
  252. package/dest/services/reqresp/interface.d.ts.map +1 -1
  253. package/dest/services/reqresp/interface.js +23 -10
  254. package/dest/services/reqresp/metrics.d.ts +6 -5
  255. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  256. package/dest/services/reqresp/metrics.js +16 -5
  257. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +5 -1
  258. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  259. package/dest/services/reqresp/protocols/block_txs/bitvector.js +5 -0
  260. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +7 -5
  261. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  262. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +27 -9
  263. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +29 -6
  264. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  265. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +59 -13
  266. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  267. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  268. package/dest/services/reqresp/protocols/index.js +0 -1
  269. package/dest/services/reqresp/protocols/tx.d.ts +7 -1
  270. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  271. package/dest/services/reqresp/protocols/tx.js +21 -3
  272. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  273. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  274. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  275. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  276. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  277. package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
  278. package/dest/services/reqresp/reqresp.d.ts +9 -2
  279. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  280. package/dest/services/reqresp/reqresp.js +95 -34
  281. package/dest/services/service.d.ts +46 -4
  282. package/dest/services/service.d.ts.map +1 -1
  283. package/dest/services/tx_collection/config.d.ts +22 -1
  284. package/dest/services/tx_collection/config.d.ts.map +1 -1
  285. package/dest/services/tx_collection/config.js +55 -1
  286. package/dest/services/tx_collection/fast_tx_collection.d.ts +7 -7
  287. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  288. package/dest/services/tx_collection/fast_tx_collection.js +95 -84
  289. package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -0
  290. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
  291. package/dest/services/tx_collection/file_store_tx_collection.js +167 -0
  292. package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
  293. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
  294. package/dest/services/tx_collection/file_store_tx_source.js +100 -0
  295. package/dest/services/tx_collection/index.d.ts +3 -1
  296. package/dest/services/tx_collection/index.d.ts.map +1 -1
  297. package/dest/services/tx_collection/index.js +2 -0
  298. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  299. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  300. package/dest/services/tx_collection/instrumentation.js +10 -2
  301. package/dest/services/tx_collection/proposal_tx_collector.d.ts +48 -0
  302. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -0
  303. package/dest/services/tx_collection/proposal_tx_collector.js +50 -0
  304. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  305. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  306. package/dest/services/tx_collection/request_tracker.js +84 -0
  307. package/dest/services/tx_collection/slow_tx_collection.d.ts +9 -5
  308. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  309. package/dest/services/tx_collection/slow_tx_collection.js +60 -26
  310. package/dest/services/tx_collection/tx_collection.d.ts +29 -19
  311. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  312. package/dest/services/tx_collection/tx_collection.js +79 -7
  313. package/dest/services/tx_collection/tx_collection_sink.d.ts +18 -8
  314. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  315. package/dest/services/tx_collection/tx_collection_sink.js +26 -29
  316. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  317. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  318. package/dest/services/tx_collection/tx_source.js +26 -7
  319. package/dest/services/tx_file_store/config.d.ts +16 -0
  320. package/dest/services/tx_file_store/config.d.ts.map +1 -0
  321. package/dest/services/tx_file_store/config.js +22 -0
  322. package/dest/services/tx_file_store/index.d.ts +4 -0
  323. package/dest/services/tx_file_store/index.d.ts.map +1 -0
  324. package/dest/services/tx_file_store/index.js +3 -0
  325. package/dest/services/tx_file_store/instrumentation.d.ts +15 -0
  326. package/dest/services/tx_file_store/instrumentation.d.ts.map +1 -0
  327. package/dest/services/tx_file_store/instrumentation.js +29 -0
  328. package/dest/services/tx_file_store/tx_file_store.d.ts +48 -0
  329. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -0
  330. package/dest/services/tx_file_store/tx_file_store.js +152 -0
  331. package/dest/services/tx_provider.d.ts +6 -6
  332. package/dest/services/tx_provider.d.ts.map +1 -1
  333. package/dest/services/tx_provider.js +9 -8
  334. package/dest/services/tx_provider_instrumentation.d.ts +1 -1
  335. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  336. package/dest/services/tx_provider_instrumentation.js +5 -5
  337. package/dest/test-helpers/index.d.ts +3 -1
  338. package/dest/test-helpers/index.d.ts.map +1 -1
  339. package/dest/test-helpers/index.js +2 -0
  340. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
  341. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  342. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  343. package/dest/test-helpers/mock-pubsub.d.ts +40 -6
  344. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  345. package/dest/test-helpers/mock-pubsub.js +139 -13
  346. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  347. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  348. package/dest/test-helpers/reqresp-nodes.js +5 -5
  349. package/dest/test-helpers/test_tx_provider.d.ts +40 -0
  350. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
  351. package/dest/test-helpers/test_tx_provider.js +41 -0
  352. package/dest/test-helpers/testbench-utils.d.ts +163 -0
  353. package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
  354. package/dest/test-helpers/testbench-utils.js +386 -0
  355. package/dest/testbench/p2p_client_testbench_worker.d.ts +28 -2
  356. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  357. package/dest/testbench/p2p_client_testbench_worker.js +276 -142
  358. package/dest/testbench/worker_client_manager.d.ts +60 -6
  359. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  360. package/dest/testbench/worker_client_manager.js +280 -46
  361. package/dest/util.d.ts +3 -3
  362. package/dest/util.d.ts.map +1 -1
  363. package/package.json +14 -14
  364. package/src/bootstrap/bootstrap.ts +7 -4
  365. package/src/client/factory.ts +114 -38
  366. package/src/client/interface.ts +65 -35
  367. package/src/client/p2p_client.ts +232 -276
  368. package/src/client/test/tx_proposal_collector/README.md +227 -0
  369. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +355 -0
  370. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
  371. package/src/config.ts +183 -45
  372. package/src/errors/p2p-service.error.ts +11 -0
  373. package/src/errors/tx-pool.error.ts +12 -0
  374. package/src/index.ts +1 -1
  375. package/src/mem_pools/attestation_pool/attestation_pool.ts +501 -91
  376. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +442 -102
  377. package/src/mem_pools/attestation_pool/index.ts +9 -2
  378. package/src/mem_pools/attestation_pool/mocks.ts +2 -1
  379. package/src/mem_pools/index.ts +2 -2
  380. package/src/mem_pools/instrumentation.ts +19 -14
  381. package/src/mem_pools/interface.ts +4 -4
  382. package/src/mem_pools/tx_pool_v2/README.md +283 -0
  383. package/src/mem_pools/tx_pool_v2/archive/index.ts +1 -0
  384. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +120 -0
  385. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
  386. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +160 -0
  387. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +122 -0
  388. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +125 -0
  389. package/src/mem_pools/tx_pool_v2/eviction/index.ts +27 -0
  390. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +219 -0
  391. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +74 -0
  392. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +101 -0
  393. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +91 -0
  394. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +99 -0
  395. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +32 -0
  396. package/src/mem_pools/tx_pool_v2/index.ts +12 -0
  397. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  398. package/src/mem_pools/tx_pool_v2/interfaces.ts +247 -0
  399. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +343 -0
  400. package/src/mem_pools/tx_pool_v2/tx_pool_bench_metrics.ts +77 -0
  401. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +430 -0
  402. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +238 -0
  403. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1105 -0
  404. package/src/msg_validators/attestation_validator/README.md +49 -0
  405. package/src/msg_validators/attestation_validator/attestation_validator.ts +40 -16
  406. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +20 -11
  407. package/src/msg_validators/clock_tolerance.ts +120 -0
  408. package/src/msg_validators/proposal_validator/README.md +123 -0
  409. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +17 -4
  410. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +23 -7
  411. package/src/msg_validators/proposal_validator/proposal_validator.ts +88 -51
  412. package/src/msg_validators/tx_validator/README.md +119 -0
  413. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
  414. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  415. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  416. package/src/msg_validators/tx_validator/archive_cache.ts +2 -2
  417. package/src/msg_validators/tx_validator/block_header_validator.ts +21 -8
  418. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  419. package/src/msg_validators/tx_validator/data_validator.ts +48 -3
  420. package/src/msg_validators/tx_validator/double_spend_validator.ts +15 -9
  421. package/src/msg_validators/tx_validator/factory.ts +413 -56
  422. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  423. package/src/msg_validators/tx_validator/gas_validator.ts +154 -36
  424. package/src/msg_validators/tx_validator/index.ts +2 -0
  425. package/src/msg_validators/tx_validator/metadata_validator.ts +18 -7
  426. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  427. package/src/msg_validators/tx_validator/phases_validator.ts +87 -30
  428. package/src/msg_validators/tx_validator/size_validator.ts +6 -2
  429. package/src/msg_validators/tx_validator/timestamp_validator.ts +29 -21
  430. package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
  431. package/src/msg_validators/tx_validator/tx_proof_validator.ts +8 -3
  432. package/src/services/data_store.ts +14 -19
  433. package/src/services/discv5/discV5_service.ts +1 -1
  434. package/src/services/dummy_service.ts +66 -3
  435. package/src/services/encoding.ts +18 -10
  436. package/src/services/gossipsub/README.md +641 -0
  437. package/src/services/gossipsub/index.ts +2 -0
  438. package/src/services/gossipsub/scoring.ts +29 -5
  439. package/src/services/gossipsub/topic_score_params.ts +519 -0
  440. package/src/services/index.ts +1 -0
  441. package/src/services/libp2p/instrumentation.ts +15 -2
  442. package/src/services/libp2p/libp2p_service.ts +624 -490
  443. package/src/services/peer-manager/metrics.ts +28 -4
  444. package/src/services/peer-manager/peer_manager.ts +45 -11
  445. package/src/services/peer-manager/peer_scoring.ts +56 -6
  446. package/src/services/reqresp/README.md +229 -0
  447. package/src/services/reqresp/batch-tx-requester/README.md +344 -0
  448. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +673 -0
  449. package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
  450. package/src/services/reqresp/batch-tx-requester/interface.ts +54 -0
  451. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +168 -0
  452. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +249 -0
  453. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
  454. package/src/services/reqresp/config.ts +2 -2
  455. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +65 -4
  456. package/src/services/reqresp/connection-sampler/connection_sampler.ts +16 -0
  457. package/src/services/reqresp/interface.ts +48 -10
  458. package/src/services/reqresp/metrics.ts +33 -9
  459. package/src/services/reqresp/protocols/block_txs/bitvector.ts +7 -0
  460. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +35 -12
  461. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +74 -9
  462. package/src/services/reqresp/protocols/index.ts +0 -1
  463. package/src/services/reqresp/protocols/tx.ts +23 -3
  464. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  465. package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
  466. package/src/services/reqresp/reqresp.ts +116 -32
  467. package/src/services/service.ts +61 -3
  468. package/src/services/tx_collection/config.ts +83 -1
  469. package/src/services/tx_collection/fast_tx_collection.ts +111 -91
  470. package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
  471. package/src/services/tx_collection/file_store_tx_source.ts +129 -0
  472. package/src/services/tx_collection/index.ts +6 -0
  473. package/src/services/tx_collection/instrumentation.ts +17 -2
  474. package/src/services/tx_collection/proposal_tx_collector.ts +108 -0
  475. package/src/services/tx_collection/request_tracker.ts +127 -0
  476. package/src/services/tx_collection/slow_tx_collection.ts +68 -35
  477. package/src/services/tx_collection/tx_collection.ts +122 -27
  478. package/src/services/tx_collection/tx_collection_sink.ts +30 -34
  479. package/src/services/tx_collection/tx_source.ts +28 -8
  480. package/src/services/tx_file_store/config.ts +37 -0
  481. package/src/services/tx_file_store/index.ts +3 -0
  482. package/src/services/tx_file_store/instrumentation.ts +36 -0
  483. package/src/services/tx_file_store/tx_file_store.ts +175 -0
  484. package/src/services/tx_provider.ts +12 -11
  485. package/src/services/tx_provider_instrumentation.ts +11 -5
  486. package/src/test-helpers/index.ts +2 -0
  487. package/src/test-helpers/make-test-p2p-clients.ts +4 -6
  488. package/src/test-helpers/mock-pubsub.ts +177 -14
  489. package/src/test-helpers/reqresp-nodes.ts +7 -9
  490. package/src/test-helpers/test_tx_provider.ts +64 -0
  491. package/src/test-helpers/testbench-utils.ts +457 -0
  492. package/src/testbench/p2p_client_testbench_worker.ts +393 -134
  493. package/src/testbench/worker_client_manager.ts +367 -48
  494. package/src/util.ts +8 -2
  495. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
  496. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
  497. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -218
  498. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
  499. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
  500. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -180
  501. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  502. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  503. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  504. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -31
  505. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  506. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  507. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -156
  508. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  509. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  510. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  511. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  512. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -115
  513. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  514. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  515. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  516. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  517. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -76
  518. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  519. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  520. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  521. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  522. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  523. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  524. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  525. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  526. package/dest/mem_pools/tx_pool/index.js +0 -2
  527. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  528. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  529. package/dest/mem_pools/tx_pool/priority.js +0 -15
  530. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  531. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  532. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  533. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  534. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  535. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  536. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  537. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  538. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -157
  539. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  540. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  541. package/dest/services/reqresp/protocols/block.js +0 -32
  542. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
  543. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
  544. package/src/mem_pools/tx_pool/README.md +0 -270
  545. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  546. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -131
  547. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -207
  548. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -159
  549. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  550. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -91
  551. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  552. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  553. package/src/mem_pools/tx_pool/index.ts +0 -2
  554. package/src/mem_pools/tx_pool/priority.ts +0 -20
  555. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  556. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  557. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -191
  558. package/src/services/reqresp/protocols/block.ts +0 -37
@@ -1,14 +1,12 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import { BlockNumber } from '@aztec/foundation/branded-types';
3
- import { randomInt } from '@aztec/foundation/crypto/random';
4
- import { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { maxBy } from '@aztec/foundation/collection';
5
4
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
6
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
6
  import { Timer } from '@aztec/foundation/timer';
8
7
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
9
- import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
10
8
  import { protocolContractsHash } from '@aztec/protocol-contracts';
11
- import type { EthAddress, L2BlockNew, L2BlockSource } from '@aztec/stdlib/block';
9
+ import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
12
10
  import type { ContractDataSource } from '@aztec/stdlib/contract';
13
11
  import { GasFees } from '@aztec/stdlib/gas';
14
12
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
@@ -18,12 +16,12 @@ import {
18
16
  CheckpointProposal,
19
17
  type CheckpointProposalCore,
20
18
  type Gossipable,
21
- P2PClientType,
22
19
  P2PMessage,
23
20
  PeerErrorSeverity,
21
+ PeerErrorSeverityByHarshness,
24
22
  TopicType,
25
23
  createTopicString,
26
- getTopicsForClientAndConfig,
24
+ getTopicsForConfig,
27
25
  metricsTopicStrToLabels,
28
26
  } from '@aztec/stdlib/p2p';
29
27
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -45,7 +43,7 @@ import {
45
43
  type GossipsubMessage,
46
44
  gossipsub,
47
45
  } from '@chainsafe/libp2p-gossipsub';
48
- import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p-gossipsub/score';
46
+ import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
49
47
  import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
50
48
  import { noise } from '@chainsafe/libp2p-noise';
51
49
  import { yamux } from '@chainsafe/libp2p-yamux';
@@ -59,62 +57,62 @@ import { ENR } from '@nethermindeth/enr';
59
57
  import { createLibp2p } from 'libp2p';
60
58
 
61
59
  import type { P2PConfig } from '../../config.js';
62
- import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
60
+ import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
63
61
  import type { MemPools } from '../../mem_pools/interface.js';
64
62
  import {
65
63
  BlockProposalValidator,
66
64
  CheckpointAttestationValidator,
67
65
  CheckpointProposalValidator,
66
+ DoubleSpendTxValidator,
68
67
  FishermanAttestationValidator,
69
- SizeTxValidator,
68
+ getDefaultAllowedSetupFunctions,
70
69
  } from '../../msg_validators/index.js';
71
70
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
72
- import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
73
- import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
74
71
  import {
75
- AggregateTxValidator,
76
- DataTxValidator,
77
- DoubleSpendTxValidator,
78
- MetadataTxValidator,
79
- TxProofValidator,
80
- } from '../../msg_validators/tx_validator/index.js';
72
+ type TransactionValidator,
73
+ createFirstStageTxValidationsForGossipedTransactions,
74
+ createSecondStageTxValidationsForGossipedTransactions,
75
+ createTxValidatorForBlockProposalReceivedTxs,
76
+ createTxValidatorForReqResponseReceivedTxs,
77
+ } from '../../msg_validators/tx_validator/factory.js';
81
78
  import { GossipSubEvent } from '../../types/index.js';
82
79
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
83
80
  import { getVersions } from '../../versioning.js';
84
81
  import { AztecDatastore } from '../data_store.js';
85
82
  import { DiscV5Service } from '../discv5/discV5_service.js';
86
83
  import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
87
- import { gossipScoreThresholds } from '../gossipsub/scoring.js';
84
+ import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
85
+ import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
88
86
  import type { PeerManagerInterface } from '../peer-manager/interface.js';
89
87
  import { PeerManager } from '../peer-manager/peer_manager.js';
90
88
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
89
+ import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
91
90
  import type { P2PReqRespConfig } from '../reqresp/config.js';
92
91
  import {
92
+ AuthRequest,
93
+ BlockTxsRequest,
94
+ BlockTxsResponse,
93
95
  DEFAULT_SUB_PROTOCOL_VALIDATORS,
94
96
  type ReqRespInterface,
97
+ type ReqRespResponse,
95
98
  ReqRespSubProtocol,
96
99
  type ReqRespSubProtocolHandler,
97
100
  type ReqRespSubProtocolHandlers,
98
101
  type ReqRespSubProtocolValidators,
102
+ StatusMessage,
99
103
  type SubProtocolMap,
100
104
  ValidationError,
101
- } from '../reqresp/interface.js';
102
- import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
103
- import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
104
- import {
105
- AuthRequest,
106
- BlockTxsRequest,
107
- BlockTxsResponse,
108
- StatusMessage,
109
105
  pingHandler,
110
- reqRespBlockHandler,
106
+ reqGoodbyeHandler,
107
+ reqRespBlockTxsHandler,
111
108
  reqRespStatusHandler,
112
109
  reqRespTxHandler,
113
- } from '../reqresp/protocols/index.js';
110
+ } from '../reqresp/index.js';
114
111
  import { ReqResp } from '../reqresp/reqresp.js';
115
112
  import type {
116
113
  P2PBlockReceivedCallback,
117
114
  P2PCheckpointReceivedCallback,
115
+ P2PDuplicateAttestationCallback,
118
116
  P2PService,
119
117
  PeerDiscoveryService,
120
118
  } from '../service.js';
@@ -129,14 +127,14 @@ interface ValidationResult {
129
127
  type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
130
128
 
131
129
  // REFACTOR: Unify with the type above
132
- type ReceivedMessageValidationResult<T> =
133
- | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
134
- | { obj?: undefined; result: TopicValidatorResult.Reject };
130
+ type ReceivedMessageValidationResult<T, M = undefined> =
131
+ | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
132
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
135
133
 
136
134
  /**
137
135
  * Lib P2P implementation of the P2PService interface.
138
136
  */
139
- export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
137
+ export class LibP2PService extends WithTracer implements P2PService {
140
138
  private discoveryRunningPromise?: RunningPromise;
141
139
  private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
142
140
 
@@ -150,6 +148,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
150
148
 
151
149
  private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
152
150
 
151
+ /** Callback invoked when a duplicate proposal is detected (triggers slashing). */
152
+ private duplicateProposalCallback?: (info: {
153
+ slot: SlotNumber;
154
+ proposer: EthAddress;
155
+ type: 'checkpoint' | 'block';
156
+ }) => void;
157
+
158
+ /** Callback invoked when a duplicate attestation is detected (triggers slashing). */
159
+ private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
160
+
153
161
  /**
154
162
  * Callback for when a block is received from a peer.
155
163
  * @param block - The block received from the peer.
@@ -162,7 +170,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
162
170
  * @param checkpoint - The checkpoint proposal received from the peer.
163
171
  * @returns The attestations for the checkpoint, if any.
164
172
  */
165
- private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
173
+ private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
174
+ /**
175
+ * Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
176
+ * @param checkpoint - The checkpoint proposal received from the peer.
177
+ * @returns The attestations for the checkpoint, if any.
178
+ */
179
+ private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
166
180
 
167
181
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
168
182
 
@@ -173,14 +187,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
173
187
  protected logger: Logger;
174
188
 
175
189
  constructor(
176
- private clientType: T,
177
190
  private config: P2PConfig,
178
191
  protected node: PubSubLibp2p,
179
192
  private peerDiscoveryService: PeerDiscoveryService,
180
193
  private reqresp: ReqRespInterface,
181
- private peerManager: PeerManagerInterface,
194
+ protected peerManager: PeerManagerInterface,
182
195
  protected mempools: MemPools,
183
- private archiver: L2BlockSource & ContractDataSource,
196
+ protected archiver: L2BlockSource & ContractDataSource,
184
197
  private epochCache: EpochCacheInterface,
185
198
  private proofVerifier: ClientProtocolCircuitVerifier,
186
199
  private worldStateSynchronizer: WorldStateSynchronizer,
@@ -215,30 +228,39 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
215
228
  this.protocolVersion,
216
229
  );
217
230
 
218
- this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
219
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
231
+ const p2pPropagationTime = config.attestationPropagationTime;
232
+ const proposalValidatorOpts = {
220
233
  txsPermitted: !config.disableTransactions,
221
- });
234
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
235
+ p2pPropagationTime,
236
+ };
237
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
238
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
222
239
  this.checkpointAttestationValidator = config.fishermanMode
223
- ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
224
- : new CheckpointAttestationValidator(epochCache);
240
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, {
241
+ l1PublishingTime: config.l1PublishingTime,
242
+ })
243
+ : new CheckpointAttestationValidator(epochCache, { l1PublishingTime: config.l1PublishingTime });
225
244
 
226
245
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
227
246
 
228
247
  this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
229
- this.logger.debug(
230
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
248
+ this.logger.warn(
249
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
231
250
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
232
251
  );
233
- return false;
252
+ return true;
234
253
  };
235
254
 
236
- this.checkpointReceivedCallback = (
237
- checkpoint: CheckpointProposalCore,
255
+ this.allNodesCheckpointReceivedCallback = (
256
+ _checkpoint: CheckpointProposalCore,
257
+ ): Promise<CheckpointAttestation[] | undefined> => {
258
+ throw new CheckpointProposalReceivedCallbackNotRegisteredError();
259
+ };
260
+
261
+ this.validatorCheckpointReceivedCallback = (
262
+ _checkpoint: CheckpointProposalCore,
238
263
  ): Promise<CheckpointAttestation[] | undefined> => {
239
- this.logger.debug(
240
- `Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
241
- );
242
264
  return Promise.resolve(undefined);
243
265
  };
244
266
  }
@@ -253,8 +275,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
253
275
  * @param txPool - The transaction pool to be accessed by the service.
254
276
  * @returns The new service.
255
277
  */
256
- public static async new<T extends P2PClientType>(
257
- clientType: T,
278
+ public static async new(
258
279
  config: P2PConfig,
259
280
  peerId: PeerId,
260
281
  deps: {
@@ -285,14 +306,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
285
306
 
286
307
  const datastore = new AztecDatastore(peerStore);
287
308
 
288
- const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
309
+ const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
289
310
 
290
311
  const peerDiscoveryService = new DiscV5Service(
291
312
  peerId,
292
313
  config,
293
314
  packageVersion,
294
315
  telemetry,
295
- createLogger(`${logger.module}:discv5_service`),
316
+ createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
296
317
  );
297
318
 
298
319
  // Seed libp2p's bootstrap discovery with private and trusted peers
@@ -306,11 +327,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
306
327
  const versions = getVersions(config);
307
328
  const protocolVersion = compressComponentVersions(versions);
308
329
 
309
- const txTopic = createTopicString(TopicType.tx, protocolVersion);
310
- const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
311
- const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
312
- const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
313
-
314
330
  const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
315
331
  const directPeers = (
316
332
  await Promise.all(
@@ -330,6 +346,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
330
346
 
331
347
  const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
332
348
 
349
+ // Create dynamic topic score params based on network configuration
350
+ const l1Constants = epochCache.getL1Constants();
351
+ const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
352
+ slotDurationMs: l1Constants.slotDuration * 1000,
353
+ ethereumSlotDuration: l1Constants.ethereumSlotDuration,
354
+ heartbeatIntervalMs: config.gossipsubInterval,
355
+ targetCommitteeSize: l1Constants.targetCommitteeSize,
356
+ blockDurationMs: config.blockDurationMs,
357
+ l1PublishingTime: config.l1PublishingTime,
358
+ p2pPropagationTime: config.attestationPropagationTime,
359
+ expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
360
+ });
361
+
333
362
  const node = await createLibp2p({
334
363
  start: false,
335
364
  peerId,
@@ -425,35 +454,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
425
454
  scoreParams: createPeerScoreParams({
426
455
  // IPColocation factor can be disabled for local testing - default to -5
427
456
  IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
428
- topics: {
429
- [txTopic]: createTopicScoreParams({
430
- topicWeight: 1,
431
- invalidMessageDeliveriesWeight: -20,
432
- invalidMessageDeliveriesDecay: 0.5,
433
- }),
434
- [blockProposalTopic]: createTopicScoreParams({
435
- topicWeight: 1,
436
- invalidMessageDeliveriesWeight: -20,
437
- invalidMessageDeliveriesDecay: 0.5,
438
- }),
439
- [checkpointProposalTopic]: createTopicScoreParams({
440
- topicWeight: 1,
441
- invalidMessageDeliveriesWeight: -20,
442
- invalidMessageDeliveriesDecay: 0.5,
443
- }),
444
- [checkpointAttestationTopic]: createTopicScoreParams({
445
- topicWeight: 1,
446
- invalidMessageDeliveriesWeight: -20,
447
- invalidMessageDeliveriesDecay: 0.5,
448
- }),
449
- },
457
+ topics: topicScoreParams,
450
458
  }),
451
459
  }) as (components: GossipSubComponents) => GossipSub,
452
460
  components: (components: { connectionManager: ConnectionManager }) => ({
453
461
  connectionManager: components.connectionManager,
454
462
  }),
455
463
  },
456
- logger: createLibp2pComponentLogger(logger.module),
464
+ logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
457
465
  });
458
466
 
459
467
  const peerScoring = new PeerScoring(config, telemetry);
@@ -472,13 +480,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
472
480
  epochCache,
473
481
  );
474
482
 
475
- // Update gossipsub score params
476
- node.services.pubsub.score.params.appSpecificWeight = 10;
483
+ // Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
484
+ reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
485
+
486
+ // Configure application-specific scoring for gossipsub.
487
+ // The weight scales app score to align with gossipsub thresholds:
488
+ // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
489
+ // - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
490
+ // Note: positive topic scores can offset penalties, so alignment is best-effort.
491
+ node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
477
492
  node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
478
493
  peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
479
494
 
480
495
  return new LibP2PService(
481
- clientType,
482
496
  config,
483
497
  node,
484
498
  peerDiscoveryService,
@@ -514,18 +528,20 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
514
528
  // Create request response protocol handlers
515
529
  const txHandler = reqRespTxHandler(this.mempools);
516
530
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
517
- const blockHandler = reqRespBlockHandler(this.archiver);
518
531
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
519
532
 
520
533
  const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
521
534
  [ReqRespSubProtocol.PING]: pingHandler,
522
535
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
523
536
  [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
524
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
525
537
  };
526
538
 
527
539
  if (!this.config.disableTransactions) {
528
- const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
540
+ const blockTxsHandler = reqRespBlockTxsHandler(
541
+ this.mempools.attestationPool,
542
+ this.archiver,
543
+ this.mempools.txPool,
544
+ );
529
545
  requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
530
546
  }
531
547
 
@@ -538,7 +554,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
538
554
  ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
539
555
  [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
540
556
  [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
541
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
542
557
  };
543
558
 
544
559
  await this.peerManager.initializePeers();
@@ -548,7 +563,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
548
563
  await this.node.start();
549
564
 
550
565
  // Subscribe to standard GossipSub topics by default
551
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
566
+ for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
552
567
  this.subscribeToTopic(this.topicStrings[topic]);
553
568
  }
554
569
 
@@ -614,6 +629,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
614
629
  return this.peerManager.getPeers(includePending);
615
630
  }
616
631
 
632
+ public getGossipMeshPeerCount(topicType: TopicType): number {
633
+ return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
634
+ }
635
+
617
636
  private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
618
637
  this.logger.trace(`Received PUBSUB message.`);
619
638
 
@@ -641,6 +660,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
641
660
  return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
642
661
  }
643
662
 
663
+ public sendRequestToPeer(
664
+ peerId: PeerId,
665
+ subProtocol: ReqRespSubProtocol,
666
+ payload: Buffer,
667
+ dialTimeout?: number,
668
+ ): Promise<ReqRespResponse> {
669
+ return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
670
+ }
671
+
644
672
  /**
645
673
  * Get the ENR of the node
646
674
  * @returns The ENR of the node
@@ -653,8 +681,35 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
653
681
  this.blockReceivedCallback = callback;
654
682
  }
655
683
 
656
- public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
657
- this.checkpointReceivedCallback = callback;
684
+ public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
685
+ this.validatorCheckpointReceivedCallback = callback;
686
+ }
687
+
688
+ public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
689
+ this.allNodesCheckpointReceivedCallback = callback;
690
+ }
691
+
692
+ public async notifyOwnCheckpointProposal(checkpoint: CheckpointProposalCore): Promise<void> {
693
+ await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
694
+ }
695
+
696
+ /**
697
+ * Registers a callback to be invoked when a duplicate proposal is detected.
698
+ * This callback is triggered on the first duplicate (when count goes from 1 to 2).
699
+ */
700
+ public registerDuplicateProposalCallback(
701
+ callback: (info: { slot: SlotNumber; proposer: EthAddress; type: 'checkpoint' | 'block' }) => void,
702
+ ): void {
703
+ this.duplicateProposalCallback = callback;
704
+ }
705
+
706
+ /**
707
+ * Registers a callback to be invoked when a duplicate attestation is detected.
708
+ * A validator signing attestations for different proposals at the same slot.
709
+ * This callback is triggered on the first duplicate (when count goes from 1 to 2).
710
+ */
711
+ public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
712
+ this.duplicateAttestationCallback = callback;
658
713
  }
659
714
 
660
715
  /**
@@ -721,6 +776,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
721
776
  if (!validator || !validator.addMessage(msgId)) {
722
777
  this.instrumentation.incMessagePrevalidationStatus(false, topicType);
723
778
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
779
+ if (topicType === TopicType.tx) {
780
+ this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
781
+ }
724
782
  return { result: false, topicType };
725
783
  }
726
784
 
@@ -785,9 +843,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
785
843
  if (msg.topic === this.topicStrings[TopicType.tx]) {
786
844
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
787
845
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
788
- if (this.clientType === P2PClientType.Full) {
789
- await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
790
- }
846
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
791
847
  } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
792
848
  await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
793
849
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
@@ -843,51 +899,134 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
843
899
  return;
844
900
  }
845
901
 
846
- protected async validateReceivedMessage<T>(
847
- validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
902
+ protected async validateReceivedMessage<T, M = undefined>(
903
+ validationFunc: () => Promise<ReceivedMessageValidationResult<T, M>>,
848
904
  msgId: string,
849
905
  source: PeerId,
850
906
  topicType: TopicType,
851
- ): Promise<ReceivedMessageValidationResult<T>> {
852
- let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
907
+ ): Promise<ReceivedMessageValidationResult<T, M>> {
908
+ // Default to reject result with a penalty if validation function throws an error
909
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
910
+ result: TopicValidatorResult.Reject,
911
+ severity: PeerErrorSeverity.MidToleranceError,
912
+ };
853
913
  const timer = new Timer();
854
914
  try {
855
915
  resultAndObj = await validationFunc();
856
916
  } catch (err) {
857
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
858
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
859
- msgId,
860
- source: source.toString(),
861
- topicType,
862
- });
917
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
863
918
  }
864
919
 
865
920
  if (resultAndObj.result === TopicValidatorResult.Accept) {
921
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
866
922
  this.instrumentation.recordMessageValidation(topicType, timer);
923
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
924
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
925
+ msgId,
926
+ source: source.toString(),
927
+ topicType,
928
+ severity: resultAndObj.severity,
929
+ });
930
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
931
+ } else {
932
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
867
933
  }
868
934
 
869
935
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
870
936
  return resultAndObj;
871
937
  }
872
938
 
939
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
940
+ try {
941
+ return deserializeFunc();
942
+ } catch (err) {
943
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
944
+ err,
945
+ msgId,
946
+ source: source.toString(),
947
+ });
948
+ return undefined;
949
+ }
950
+ }
951
+
873
952
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
874
953
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
875
- const tx = Tx.fromBuffer(payloadData);
876
- const isValid = await this.validatePropagatedTx(tx, source);
877
- const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
954
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
955
+ if (!tx) {
956
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
957
+ }
958
+
959
+ const currentBlockNumber = await this.archiver.getBlockNumber();
960
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
961
+
962
+ // Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
963
+ const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
964
+ const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
965
+ if (!firstStageOutcome.allPassed) {
966
+ const { name } = firstStageOutcome.failure;
967
+ let { severity } = firstStageOutcome.failure;
968
+
969
+ // Double spend validator has a special case handler. We perform more detailed examination
970
+ // as to how recently the nullifier was entered into the tree and if the transaction should
971
+ // have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
972
+ if (name === 'doubleSpendValidator') {
973
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1);
974
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
975
+ }
878
976
 
879
- this.logger.trace(`Validate propagated tx`, {
880
- isValid,
881
- exists,
977
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
978
+ validator: name,
979
+ severity,
980
+ source: source.toString(),
981
+ });
982
+ return { result: TopicValidatorResult.Reject, severity };
983
+ }
984
+
985
+ // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
986
+ const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
987
+ if (canAdd === 'ignored') {
988
+ this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
989
+ source: source.toString(),
990
+ });
991
+ return { result: TopicValidatorResult.Ignore, obj: tx };
992
+ }
993
+
994
+ // Stage 2: expensive proof verification
995
+ const secondStageValidators = this.createSecondStageMessageValidators();
996
+ const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
997
+ if (!secondStageOutcome.allPassed) {
998
+ const { severity, name } = secondStageOutcome.failure;
999
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
1000
+ validator: name,
1001
+ severity,
1002
+ source: source.toString(),
1003
+ });
1004
+ return { result: TopicValidatorResult.Reject, severity };
1005
+ }
1006
+
1007
+ // Pool add: persist the tx
1008
+ const txHash = tx.getTxHash();
1009
+ const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
1010
+
1011
+ const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
1012
+ const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
1013
+
1014
+ this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
1015
+ wasAccepted,
1016
+ wasIgnored,
882
1017
  [Attributes.P2P_ID]: source.toString(),
883
1018
  });
884
1019
 
885
- if (!isValid) {
886
- return { result: TopicValidatorResult.Reject };
887
- } else if (exists) {
1020
+ if (wasAccepted) {
1021
+ return { result: TopicValidatorResult.Accept, obj: tx };
1022
+ } else if (wasIgnored) {
888
1023
  return { result: TopicValidatorResult.Ignore, obj: tx };
889
1024
  } else {
890
- return { result: TopicValidatorResult.Accept, obj: tx };
1025
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
1026
+ source: source.toString(),
1027
+ txHash: txHash.toString(),
1028
+ });
1029
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
891
1030
  }
892
1031
  };
893
1032
 
@@ -896,6 +1035,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
896
1035
  return;
897
1036
  }
898
1037
 
1038
+ // Tx was accepted into pool and will be propagated - just log and record metrics
899
1039
  const txHash = tx.getTxHash();
900
1040
  const txHashString = txHash.toString();
901
1041
  this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
@@ -903,13 +1043,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
903
1043
  txHash: txHashString,
904
1044
  });
905
1045
 
906
- if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
907
- this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
908
- return;
909
- }
910
-
911
1046
  this.instrumentation.incrementTxReceived(1);
912
- await this.mempools.txPool.addTxs([tx]);
913
1047
  }
914
1048
 
915
1049
  /**
@@ -921,46 +1055,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
921
1055
  msgId: string,
922
1056
  source: PeerId,
923
1057
  ): Promise<void> {
924
- const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointAttestation>> = async () => {
925
- const attestation = CheckpointAttestation.fromBuffer(payloadData);
926
- const pool = this.mempools.attestationPool;
927
- const isValid = await this.validateCheckpointAttestation(source, attestation);
928
- const exists = isValid && (await pool.hasCheckpointAttestation(attestation));
929
-
930
- let canAdd = true;
931
- if (isValid && !exists) {
932
- const slot = attestation.payload.header.slotNumber;
933
- const { committee } = await this.epochCache.getCommittee(slot);
934
- const committeeSize = committee?.length ?? 0;
935
- canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
936
- }
937
-
938
- this.logger.trace(`Validate propagated checkpoint attestation`, {
939
- isValid,
940
- exists,
941
- canAdd,
942
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
943
- [Attributes.P2P_ID]: source.toString(),
944
- });
945
-
946
- if (!isValid) {
947
- return { result: TopicValidatorResult.Reject };
948
- } else if (exists) {
949
- return { result: TopicValidatorResult.Ignore, obj: attestation };
950
- } else if (!canAdd) {
951
- this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
952
- slot: attestation.payload.header.slotNumber.toString(),
953
- archive: attestation.archive.toString(),
954
- source: source.toString(),
955
- });
956
- return { result: TopicValidatorResult.Ignore, obj: attestation };
957
- } else {
958
- return { result: TopicValidatorResult.Accept, obj: attestation };
959
- }
960
- };
961
-
962
1058
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
963
- validationFunc,
1059
+ () => {
1060
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1061
+ if (!attestation) {
1062
+ return Promise.resolve({
1063
+ result: TopicValidatorResult.Reject,
1064
+ severity: PeerErrorSeverity.LowToleranceError,
1065
+ });
1066
+ }
1067
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1068
+ },
964
1069
  msgId,
965
1070
  source,
966
1071
  TopicType.checkpoint_attestation,
@@ -970,8 +1075,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
970
1075
  return;
971
1076
  }
972
1077
 
973
- this.logger.debug(
974
- `Received checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
1078
+ this.logger.verbose(
1079
+ `Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
975
1080
  {
976
1081
  p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
977
1082
  slot: attestation.slotNumber,
@@ -979,59 +1084,168 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
979
1084
  source: source.toString(),
980
1085
  },
981
1086
  );
982
-
983
- await this.mempools.attestationPool.addCheckpointAttestations([attestation]);
984
1087
  }
985
1088
 
986
- private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
987
- const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
988
- const block = BlockProposal.fromBuffer(payloadData);
989
- const isValid = await this.validateBlockProposal(source, block);
990
- const pool = this.mempools.attestationPool;
1089
+ /** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */
1090
+ @trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation) => ({
1091
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
1092
+ }))
1093
+ protected async validateAndStoreCheckpointAttestation(
1094
+ peerId: PeerId,
1095
+ attestation: CheckpointAttestation,
1096
+ ): Promise<ReceivedMessageValidationResult<CheckpointAttestation>> {
1097
+ const validationResult = await this.checkpointAttestationValidator.validate(attestation);
991
1098
 
992
- const exists = isValid && (await pool.hasBlockProposal(block));
993
- const canAdd = isValid && (await pool.canAddProposal(block));
1099
+ if (validationResult.result === 'reject') {
1100
+ this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1101
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1102
+ }
994
1103
 
995
- this.logger.trace(`Validate propagated block proposal`, {
996
- isValid,
997
- exists,
998
- canAdd,
999
- [Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
1000
- [Attributes.P2P_ID]: source.toString(),
1104
+ if (validationResult.result === 'ignore') {
1105
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
1106
+ }
1107
+
1108
+ // Try to add the attestation: this handles existence check, cap check, and adding in one call
1109
+ // count is the number of attestations by this signer for this slot (for duplicate detection)
1110
+ const slot = attestation.payload.header.slotNumber;
1111
+ const { added, alreadyExists, count } =
1112
+ await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
1113
+
1114
+ this.logger.trace(`Validate propagated checkpoint attestation`, {
1115
+ added,
1116
+ alreadyExists,
1117
+ count,
1118
+ [Attributes.SLOT_NUMBER]: slot.toString(),
1119
+ [Attributes.P2P_ID]: peerId.toString(),
1120
+ });
1121
+
1122
+ // Exact same attestation received, no need to re-broadcast
1123
+ if (alreadyExists) {
1124
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
1125
+ }
1126
+
1127
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1128
+ if (!added) {
1129
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1130
+ slot: slot.toString(),
1131
+ archive: attestation.archive.toString(),
1132
+ source: peerId.toString(),
1133
+ attester: attestation.getSender()?.toString(),
1134
+ count,
1001
1135
  });
1136
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1137
+ }
1002
1138
 
1003
- if (!isValid) {
1004
- return { result: TopicValidatorResult.Reject };
1005
- } else if (exists) {
1006
- return { result: TopicValidatorResult.Ignore, obj: block };
1007
- } else if (!canAdd) {
1008
- this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
1009
- this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
1010
- slot: block.slotNumber.toString(),
1011
- archive: block.archive.toString(),
1012
- source: source.toString(),
1139
+ // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
1140
+ // count is the number of attestations by this signer for this slot
1141
+ if (count === 2) {
1142
+ const attester = attestation.getSender();
1143
+ if (attester) {
1144
+ this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
1145
+ slot: slot.toString(),
1146
+ archive: attestation.archive.toString(),
1147
+ source: peerId.toString(),
1148
+ attester: attester.toString(),
1013
1149
  });
1014
- return { result: TopicValidatorResult.Reject };
1015
- } else {
1016
- return { result: TopicValidatorResult.Accept, obj: block };
1150
+ this.duplicateAttestationCallback?.({ slot, attester });
1017
1151
  }
1018
- };
1152
+ }
1019
1153
 
1020
- const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
1021
- validationFunc,
1154
+ // Attestation was added successfully - accept it so other nodes can also detect the equivocation
1155
+ return { result: TopicValidatorResult.Accept, obj: attestation };
1156
+ }
1157
+
1158
+ protected async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
1159
+ const {
1160
+ result,
1161
+ obj: block,
1162
+ metadata: { isEquivocated } = {},
1163
+ } = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
1164
+ () => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
1022
1165
  msgId,
1023
1166
  source,
1024
1167
  TopicType.block_proposal,
1025
1168
  );
1026
1169
 
1027
- if (!result || !block) {
1170
+ // If not accepted or equivocated, return
1171
+ if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
1028
1172
  return;
1029
1173
  }
1030
1174
 
1031
1175
  await this.processValidBlockProposal(block, source);
1032
1176
  }
1033
1177
 
1034
- // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
1178
+ /** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */
1179
+ @trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block) => ({
1180
+ [Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
1181
+ [Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
1182
+ }))
1183
+ protected async validateAndStoreBlockProposal(
1184
+ peerId: PeerId,
1185
+ block: BlockProposal,
1186
+ ): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
1187
+ const validationResult = await this.blockProposalValidator.validate(block);
1188
+
1189
+ if (validationResult.result === 'reject') {
1190
+ this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1191
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1192
+ }
1193
+
1194
+ if (validationResult.result === 'ignore') {
1195
+ return { result: TopicValidatorResult.Ignore, obj: block };
1196
+ }
1197
+
1198
+ // Try to add the proposal: this handles existence check, cap check, and adding in one call
1199
+ const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1200
+ const isEquivocated = count !== undefined && count > 1;
1201
+
1202
+ // Duplicate proposal received, no need to re-broadcast
1203
+ if (alreadyExists) {
1204
+ this.logger.debug(`Ignoring duplicate block proposal received`, {
1205
+ ...block.toBlockInfo(),
1206
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
1207
+ proposer: block.getSender()?.toString(),
1208
+ source: peerId.toString(),
1209
+ });
1210
+ return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
1211
+ }
1212
+
1213
+ // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1214
+ if (!added) {
1215
+ this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1216
+ ...block.toBlockInfo(),
1217
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
1218
+ count,
1219
+ proposer: block.getSender()?.toString(),
1220
+ source: peerId.toString(),
1221
+ });
1222
+ return {
1223
+ result: TopicValidatorResult.Reject,
1224
+ metadata: { isEquivocated },
1225
+ severity: PeerErrorSeverity.HighToleranceError,
1226
+ };
1227
+ }
1228
+
1229
+ // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
1230
+ // and do re-broadcast it so other nodes in the network know to slash the proposer
1231
+ if (isEquivocated) {
1232
+ const proposer = block.getSender();
1233
+ this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
1234
+ ...block.toBlockInfo(),
1235
+ source: peerId.toString(),
1236
+ proposer: proposer?.toString(),
1237
+ });
1238
+ // Invoke the duplicate callback on the first duplicate spotted only
1239
+ if (proposer && count === 2) {
1240
+ this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
1241
+ }
1242
+ return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
1243
+ }
1244
+
1245
+ // Otherwise, we're good to go!
1246
+ return { result: TopicValidatorResult.Accept, obj: block };
1247
+ }
1248
+
1035
1249
  // REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
1036
1250
  // should not be here as it does not deal with p2p networking.
1037
1251
  @trackSpan('Libp2pService.processValidBlockProposal', async block => ({
@@ -1039,7 +1253,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1039
1253
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
1040
1254
  [Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
1041
1255
  }))
1042
- private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
1256
+ protected async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
1043
1257
  const slot = block.slotNumber;
1044
1258
  this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
1045
1259
  p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
@@ -1047,30 +1261,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1047
1261
  ...block.toBlockInfo(),
1048
1262
  });
1049
1263
 
1050
- // Attempt to add proposal
1051
- try {
1052
- await this.mempools.attestationPool.addBlockProposal(block);
1053
- } catch (err: unknown) {
1054
- // Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
1055
- if (err instanceof ProposalSlotCapExceededError) {
1056
- this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
1057
- slot: String(slot),
1058
- archive: block.archive.toString(),
1059
- error: (err as Error).message,
1060
- });
1061
- return;
1062
- }
1063
- throw err;
1064
- }
1065
-
1066
- // Mark the txs in this proposal as non-evictable
1067
- await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
1264
+ // Mark the txs in this proposal as protected
1265
+ await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
1068
1266
 
1069
1267
  // Call the block received callback to validate the proposal.
1070
1268
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1071
1269
  const isValid = await this.blockReceivedCallback(block, sender);
1072
1270
  if (!isValid) {
1073
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1271
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1074
1272
  }
1075
1273
  }
1076
1274
 
@@ -1078,66 +1276,149 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1078
1276
  * Handle a gossiped checkpoint proposal.
1079
1277
  * Validates and processes the checkpoint proposal, then triggers the callback for attestation.
1080
1278
  */
1081
- private async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
1082
- // TODO(palla/mbps): This pattern is repeated across multiple message handlers, consider abstracting it.
1083
- const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointProposal>> = async () => {
1084
- const checkpoint = CheckpointProposal.fromBuffer(payloadData);
1085
- const isValid = await this.validateCheckpointProposal(source, checkpoint);
1086
- const pool = this.mempools.attestationPool;
1087
-
1088
- const exists = isValid && (await pool.hasCheckpointProposal(checkpoint));
1089
- const canAdd = isValid && (await pool.canAddCheckpointProposal(checkpoint));
1090
-
1091
- this.logger.trace(`Validate propagated checkpoint proposal`, {
1092
- isValid,
1093
- exists,
1094
- canAdd,
1095
- [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1096
- [Attributes.P2P_ID]: source.toString(),
1097
- });
1098
-
1099
- if (!isValid) {
1100
- return { result: TopicValidatorResult.Reject };
1101
- } else if (exists) {
1102
- return { result: TopicValidatorResult.Ignore, obj: checkpoint };
1103
- } else if (!canAdd) {
1104
- this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
1105
- this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1106
- slot: checkpoint.slotNumber.toString(),
1107
- archive: checkpoint.archive.toString(),
1108
- source: source.toString(),
1109
- });
1110
- return { result: TopicValidatorResult.Reject };
1111
- } else {
1112
- return { result: TopicValidatorResult.Accept, obj: checkpoint };
1113
- }
1114
- };
1115
-
1116
- const { result, obj: checkpoint } = await this.validateReceivedMessage<CheckpointProposal>(
1117
- validationFunc,
1279
+ protected async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
1280
+ const {
1281
+ result,
1282
+ obj: checkpoint,
1283
+ metadata: { isEquivocated, processBlock } = {},
1284
+ } = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
1285
+ () => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
1118
1286
  msgId,
1119
1287
  source,
1120
1288
  TopicType.checkpoint_proposal,
1121
1289
  );
1122
1290
 
1123
- if (result !== TopicValidatorResult.Accept || !checkpoint) {
1291
+ // If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
1292
+ // TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
1293
+ if (processBlock && checkpoint?.getBlockProposal()) {
1294
+ await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
1295
+ }
1296
+
1297
+ if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
1124
1298
  return;
1125
1299
  }
1126
1300
 
1127
- await this.processValidCheckpointProposal(checkpoint, source);
1301
+ await this.processValidCheckpointProposal(checkpoint.toCore(), source);
1302
+ }
1303
+
1304
+ /**
1305
+ * Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
1306
+ * its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
1307
+ */
1308
+ @trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint) => ({
1309
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1310
+ }))
1311
+ protected async validateAndStoreCheckpointProposal(
1312
+ peerId: PeerId,
1313
+ checkpoint: CheckpointProposal,
1314
+ ): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
1315
+ const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
1316
+
1317
+ if (validationResult.result === 'reject') {
1318
+ this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1319
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1320
+ }
1321
+
1322
+ if (validationResult.result === 'ignore') {
1323
+ return { result: TopicValidatorResult.Ignore, obj: checkpoint };
1324
+ }
1325
+
1326
+ // Extract and try to add the block proposal first if present
1327
+ const blockProposal = checkpoint.getBlockProposal();
1328
+ let processBlock = false;
1329
+ if (blockProposal) {
1330
+ this.logger.debug(`Validating block proposal from propagated checkpoint`, {
1331
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1332
+ [Attributes.P2P_ID]: peerId.toString(),
1333
+ });
1334
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1335
+ const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1336
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1337
+ this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1338
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1339
+ [Attributes.P2P_ID]: peerId.toString(),
1340
+ isEquivocated,
1341
+ result: blockProposalResult.result,
1342
+ });
1343
+ return {
1344
+ result: TopicValidatorResult.Reject,
1345
+ severity:
1346
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1347
+ };
1348
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1349
+ processBlock = true;
1350
+ }
1351
+ }
1352
+
1353
+ // Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
1354
+ const checkpointCore = checkpoint.toCore();
1355
+ const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
1356
+ const { added, alreadyExists, count } = tryAddResult;
1357
+ const isEquivocated = count !== undefined && count > 1;
1358
+
1359
+ // Duplicate proposal received, do not re-broadcast
1360
+ if (alreadyExists) {
1361
+ this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
1362
+ ...checkpoint.toCheckpointInfo(),
1363
+ source: peerId.toString(),
1364
+ });
1365
+ return {
1366
+ result: TopicValidatorResult.Ignore,
1367
+ obj: checkpoint,
1368
+ metadata: { isEquivocated, processBlock },
1369
+ };
1370
+ }
1371
+
1372
+ // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1373
+ // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1374
+ if (!added) {
1375
+ this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1376
+ ...checkpoint.toCheckpointInfo(),
1377
+ count,
1378
+ source: peerId.toString(),
1379
+ });
1380
+ return {
1381
+ result: TopicValidatorResult.Reject,
1382
+ obj: checkpoint,
1383
+ metadata: { isEquivocated, processBlock },
1384
+ severity: PeerErrorSeverity.HighToleranceError,
1385
+ };
1386
+ }
1387
+
1388
+ // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
1389
+ // and do re-broadcast it so other nodes in the network know to slash the proposer
1390
+ if (isEquivocated) {
1391
+ const proposer = checkpoint.getSender();
1392
+ this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
1393
+ ...checkpoint.toCheckpointInfo(),
1394
+ source: peerId.toString(),
1395
+ proposer: proposer?.toString(),
1396
+ });
1397
+ // Invoke the duplicate callback on the first duplicate spotted only
1398
+ if (proposer && count === 2) {
1399
+ this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
1400
+ }
1401
+ return {
1402
+ result: TopicValidatorResult.Accept,
1403
+ obj: checkpoint,
1404
+ metadata: { isEquivocated, processBlock },
1405
+ };
1406
+ }
1407
+
1408
+ // Otherwise, we're good to go!
1409
+ return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
1128
1410
  }
1129
1411
 
1130
1412
  /**
1131
1413
  * Process a validated checkpoint proposal.
1132
- * Extracts and processes the last block proposal (if present) first, then processes the checkpoint.
1133
- * The block callback is invoked before the checkpoint callback.
1414
+ * Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
1134
1415
  */
1135
1416
  @trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
1136
1417
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
1137
1418
  [Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
1138
1419
  [Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
1139
1420
  }))
1140
- private async processValidCheckpointProposal(checkpoint: CheckpointProposal, sender: PeerId) {
1421
+ protected async processValidCheckpointProposal(checkpoint: CheckpointProposalCore, sender: PeerId) {
1141
1422
  const slot = checkpoint.slotNumber;
1142
1423
  this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
1143
1424
  p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
@@ -1146,37 +1427,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1146
1427
  source: sender.toString(),
1147
1428
  });
1148
1429
 
1149
- // Extract block proposal before adding to pool (pool stores them separately)
1150
- const blockProposal = checkpoint.getBlockProposal();
1151
-
1152
- // Add proposal to the pool (this extracts and stores block proposal separately)
1153
- await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
1154
-
1155
- // Mark txs as non-evictable if present (from the last block)
1156
- if (checkpoint.txHashes.length > 0) {
1157
- await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
1158
- }
1159
-
1160
- // If there was a last block proposal, invoke the block callback first for validation.
1161
- // Note: The block proposal is already stored in the pool by addCheckpointProposal.
1162
- if (blockProposal) {
1163
- const isValid = await this.blockReceivedCallback(blockProposal, sender);
1164
- if (!isValid) {
1165
- this.logger.warn(`Block proposal from checkpoint failed validation`, {
1166
- slot: slot.toString(),
1167
- archive: checkpoint.archive.toString(),
1168
- blockNumber: blockProposal.blockNumber.toString(),
1169
- });
1170
- return;
1171
- }
1172
- }
1430
+ await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
1173
1431
 
1174
1432
  // Call the checkpoint received callback with the core version (without lastBlock)
1175
1433
  // to validate and potentially generate attestations
1176
- const attestations = await this.checkpointReceivedCallback(checkpoint.toCore(), sender);
1434
+ const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
1177
1435
  if (attestations && attestations.length > 0) {
1178
1436
  // If the callback returned attestations, add them to the pool and propagate them
1179
- await this.mempools.attestationPool.addCheckpointAttestations(attestations);
1437
+ await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
1180
1438
  for (const attestation of attestations) {
1181
1439
  await this.propagate(attestation);
1182
1440
  }
@@ -1203,9 +1461,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1203
1461
  * @returns True if the requested block transactions are valid, false otherwise.
1204
1462
  */
1205
1463
  @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
1206
- [Attributes.BLOCK_HASH]: request.blockHash.toString(),
1464
+ [Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
1207
1465
  }))
1208
- private async validateRequestedBlockTxs(
1466
+ protected async validateRequestedBlockTxs(
1209
1467
  request: BlockTxsRequest,
1210
1468
  response: BlockTxsResponse,
1211
1469
  peerId: PeerId,
@@ -1213,10 +1471,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1213
1471
  const requestedTxValidator = this.createRequestedTxValidator();
1214
1472
 
1215
1473
  try {
1216
- if (!response.blockHash.equals(request.blockHash)) {
1474
+ if (!response.archiveRoot.equals(request.archiveRoot)) {
1217
1475
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1218
1476
  throw new ValidationError(
1219
- `Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
1477
+ `Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
1220
1478
  );
1221
1479
  }
1222
1480
 
@@ -1246,7 +1504,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1246
1504
  }
1247
1505
 
1248
1506
  // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1249
- const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
1507
+ const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
1250
1508
  if (proposal) {
1251
1509
  // Build intersected indices
1252
1510
  const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
@@ -1266,7 +1524,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1266
1524
  } else {
1267
1525
  // No local proposal, cannot check the membership/order of the returned txs
1268
1526
  this.logger.warn(
1269
- `Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
1527
+ `Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
1270
1528
  );
1271
1529
  return false;
1272
1530
  }
@@ -1305,7 +1563,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1305
1563
  const requested = new Set(requestedTxHash.map(h => h.toString()));
1306
1564
  const requestedTxValidator = this.createRequestedTxValidator();
1307
1565
 
1308
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
1566
+ //TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
1309
1567
  // I think we should still extract the valid txs and return them, so that we can still use the response.
1310
1568
  try {
1311
1569
  await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
@@ -1321,75 +1579,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1321
1579
  }
1322
1580
  }
1323
1581
 
1324
- /**
1325
- * Validates a BLOCK response.
1326
- *
1327
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1328
- * Penalizes on block number mismatch or hash mismatch.
1329
- *
1330
- * @param requestedBlockNumber - The requested block number.
1331
- * @param responseBlock - The block returned by the peer.
1332
- * @param peerId - The peer that returned the block.
1333
- * @returns True if the response is valid, false otherwise.
1334
- */
1335
- @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1336
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1337
- }))
1338
- private async validateRequestedBlock(
1339
- requestedBlockNumber: Fr,
1340
- responseBlock: L2BlockNew,
1582
+ protected async validateRequestedTx(
1583
+ tx: Tx,
1341
1584
  peerId: PeerId,
1342
- ): Promise<boolean> {
1343
- try {
1344
- const reqNum = Number(requestedBlockNumber.toString());
1345
- if (responseBlock.number !== reqNum) {
1346
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1347
- return false;
1348
- }
1349
-
1350
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1351
- if (!local) {
1352
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1353
- // TODO: Consider extending this validator to accept an expected hash or
1354
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1355
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1356
- return false;
1357
- }
1358
- const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1359
- if (!localHash.equals(respHash)) {
1360
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1361
- return false;
1362
- }
1363
-
1364
- return true;
1365
- } catch (e) {
1366
- this.logger.warn(`Error validating requested block`, e);
1367
- return false;
1368
- }
1369
- }
1370
-
1371
- private createRequestedTxValidator(): TxValidator {
1372
- return new AggregateTxValidator(
1373
- new DataTxValidator(),
1374
- new SizeTxValidator(),
1375
- new MetadataTxValidator({
1376
- l1ChainId: new Fr(this.config.l1ChainId),
1377
- rollupVersion: new Fr(this.config.rollupVersion),
1378
- protocolContractsHash,
1379
- vkTreeRoot: getVKTreeRoot(),
1380
- }),
1381
- new TxProofValidator(this.proofVerifier),
1382
- );
1383
- }
1384
-
1385
- private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
1585
+ txValidator: TxValidator,
1586
+ requested?: Set<`0x${string}`>,
1587
+ ) {
1386
1588
  const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
1387
-
1388
- if (!(await tx.validateTxHash())) {
1389
- penalize(PeerErrorSeverity.MidToleranceError);
1390
- throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
1391
- }
1392
-
1393
1589
  if (requested && !requested.has(tx.getTxHash().toString())) {
1394
1590
  penalize(PeerErrorSeverity.MidToleranceError);
1395
1591
  throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
@@ -1402,35 +1598,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1402
1598
  }
1403
1599
  }
1404
1600
 
1405
- @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
1406
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
1407
- }))
1408
- private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
1409
- const currentBlockNumber = await this.archiver.getBlockNumber();
1410
-
1411
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1412
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1413
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1414
-
1415
- for (const validator of messageValidators) {
1416
- const outcome = await this.runValidations(tx, validator);
1417
-
1418
- if (outcome.allPassed) {
1419
- continue;
1420
- }
1421
- const { name } = outcome.failure;
1422
- let { severity } = outcome.failure;
1423
-
1424
- // Double spend validator has a special case handler
1425
- if (name === 'doubleSpendValidator') {
1426
- const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1427
- severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1428
- }
1429
-
1430
- this.peerManager.penalizePeer(peerId, severity);
1431
- return false;
1432
- }
1433
- return true;
1601
+ protected createRequestedTxValidator(): TxValidator {
1602
+ return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
1603
+ l1ChainId: this.config.l1ChainId,
1604
+ rollupVersion: this.config.rollupVersion,
1605
+ });
1434
1606
  }
1435
1607
 
1436
1608
  private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
@@ -1444,59 +1616,78 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1444
1616
  return gasFees;
1445
1617
  }
1446
1618
 
1447
- public async validate(txs: Tx[]): Promise<void> {
1448
- const currentBlockNumber = await this.archiver.getBlockNumber();
1619
+ /**
1620
+ * Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
1621
+ */
1622
+ public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
1623
+ return {
1624
+ reqResp: this.reqresp,
1625
+ connectionSampler: this.reqresp.getConnectionSampler(),
1626
+ txValidatorConfig: {
1627
+ l1ChainId: this.config.l1ChainId,
1628
+ rollupVersion: this.config.rollupVersion,
1629
+ proofVerifier: this.proofVerifier,
1630
+ },
1631
+ peerScoring: this.peerManager,
1632
+ };
1633
+ }
1449
1634
 
1450
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1451
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1452
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1635
+ public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
1636
+ const validator = createTxValidatorForBlockProposalReceivedTxs(
1637
+ this.proofVerifier,
1638
+ { l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
1639
+ this.logger.getBindings(),
1640
+ );
1453
1641
 
1454
- await Promise.all(
1642
+ const results = await Promise.all(
1455
1643
  txs.map(async tx => {
1456
- for (const validator of messageValidators) {
1457
- const outcome = await this.runValidations(tx, validator);
1458
- if (!outcome.allPassed) {
1459
- throw new Error('Invalid tx detected', { cause: { outcome } });
1460
- }
1461
- }
1644
+ const result = await validator.validateTx(tx);
1645
+ return result.result !== 'invalid';
1462
1646
  }),
1463
1647
  );
1648
+ if (results.some(value => value === false)) {
1649
+ throw new Error('Invalid tx detected');
1650
+ }
1464
1651
  }
1465
1652
 
1466
- /**
1467
- * Create message validators for the given block number and timestamp.
1468
- *
1469
- * Each validator is a pair of a validator and a severity.
1470
- * If a validator fails, the peer is penalized with the severity of the validator.
1471
- *
1472
- * @param currentBlockNumber - The current synced block number.
1473
- * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
1474
- * @returns The message validators.
1475
- */
1476
- private async createMessageValidators(
1653
+ /** Creates the first stage (fast) validators for gossiped transactions. */
1654
+ protected async createFirstStageMessageValidators(
1477
1655
  currentBlockNumber: BlockNumber,
1478
1656
  nextSlotTimestamp: UInt64,
1479
- ): Promise<Record<string, MessageValidator>[]> {
1657
+ ): Promise<Record<string, TransactionValidator>> {
1480
1658
  const gasFees = await this.getGasFees(currentBlockNumber);
1481
- const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1482
-
1483
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1484
-
1485
- return createTxMessageValidators(
1659
+ const allowedInSetup = [
1660
+ ...(await getDefaultAllowedSetupFunctions()),
1661
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
1662
+ ];
1663
+ const blockNumber = BlockNumber(currentBlockNumber + 1);
1664
+ const l1Constants = await this.archiver.getL1Constants();
1665
+
1666
+ return createFirstStageTxValidationsForGossipedTransactions(
1486
1667
  nextSlotTimestamp,
1487
- blockNumberInWhichTheTxIsConsideredToBeIncluded,
1668
+ blockNumber,
1488
1669
  this.worldStateSynchronizer,
1489
1670
  gasFees,
1490
1671
  this.config.l1ChainId,
1491
1672
  this.config.rollupVersion,
1492
1673
  protocolContractsHash,
1493
1674
  this.archiver,
1494
- this.proofVerifier,
1495
1675
  !this.config.disableTransactions,
1496
1676
  allowedInSetup,
1677
+ this.logger.getBindings(),
1678
+ {
1679
+ rollupManaLimit: l1Constants.rollupManaLimit,
1680
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1681
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1682
+ },
1497
1683
  );
1498
1684
  }
1499
1685
 
1686
+ /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
1687
+ protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
1688
+ return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
1689
+ }
1690
+
1500
1691
  /**
1501
1692
  * Run validations on a tx.
1502
1693
  * @param tx - The tx to validate.
@@ -1505,7 +1696,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1505
1696
  */
1506
1697
  private async runValidations(
1507
1698
  tx: Tx,
1508
- messageValidators: Record<string, MessageValidator>,
1699
+ messageValidators: Record<string, TransactionValidator>,
1509
1700
  ): Promise<ValidationOutcome> {
1510
1701
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
1511
1702
  const { result } = await validator.validateTx(tx);
@@ -1514,8 +1705,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1514
1705
 
1515
1706
  // A promise that resolves when all validations have been run
1516
1707
  const allValidations = await Promise.all(validationPromises);
1517
- const failed = allValidations.find(x => !x.isValid);
1518
- if (failed) {
1708
+ const failures = allValidations.filter(x => !x.isValid);
1709
+ if (failures.length > 0) {
1710
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1711
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1519
1712
  return {
1520
1713
  allPassed: false,
1521
1714
  failure: {
@@ -1547,15 +1740,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1547
1740
  return PeerErrorSeverity.HighToleranceError;
1548
1741
  }
1549
1742
 
1550
- const snapshotValidator = new DoubleSpendTxValidator({
1551
- nullifiersExist: async (nullifiers: Buffer[]) => {
1552
- const merkleTree = this.worldStateSynchronizer.getSnapshot(
1553
- BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
1554
- );
1555
- const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
1556
- return indices.map(index => index !== undefined);
1743
+ const snapshotValidator = new DoubleSpendTxValidator(
1744
+ {
1745
+ nullifiersExist: async (nullifiers: Buffer[]) => {
1746
+ const merkleTree = this.worldStateSynchronizer.getSnapshot(
1747
+ BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
1748
+ );
1749
+ const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
1750
+ return indices.map(index => index !== undefined);
1751
+ },
1557
1752
  },
1558
- });
1753
+ this.logger.getBindings(),
1754
+ );
1559
1755
 
1560
1756
  const validSnapshot = await snapshotValidator.validateTx(tx);
1561
1757
  if (validSnapshot.result !== 'valid') {
@@ -1565,68 +1761,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1565
1761
  return PeerErrorSeverity.HighToleranceError;
1566
1762
  }
1567
1763
 
1568
- /**
1569
- * Validate a checkpoint attestation.
1570
- *
1571
- * @param attestation - The checkpoint attestation to validate.
1572
- * @returns True if the checkpoint attestation is valid, false otherwise.
1573
- */
1574
- @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1575
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1576
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1577
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1578
- }))
1579
- public async validateCheckpointAttestation(peerId: PeerId, attestation: CheckpointAttestation): Promise<boolean> {
1580
- const severity = await this.checkpointAttestationValidator.validate(attestation);
1581
- if (severity) {
1582
- this.logger.debug(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1583
- this.peerManager.penalizePeer(peerId, severity);
1584
- return false;
1585
- }
1586
-
1587
- return true;
1588
- }
1589
-
1590
- /**
1591
- * Validate a block proposal.
1592
- *
1593
- * @param block - The block proposal to validate.
1594
- * @returns True if the block proposal is valid, false otherwise.
1595
- */
1596
- @trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
1597
- [Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
1598
- }))
1599
- public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
1600
- const severity = await this.blockProposalValidator.validate(block);
1601
- if (severity) {
1602
- this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
1603
- this.peerManager.penalizePeer(peerId, severity);
1604
- return false;
1605
- }
1606
-
1607
- return true;
1608
- }
1609
-
1610
- /**
1611
- * Validate a checkpoint proposal.
1612
- *
1613
- * @param checkpoint - The checkpoint proposal to validate.
1614
- * @returns True if the checkpoint proposal is valid, false otherwise.
1615
- */
1616
- @trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint) => ({
1617
- [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1618
- }))
1619
- public async validateCheckpointProposal(peerId: PeerId, checkpoint: CheckpointProposal): Promise<boolean> {
1620
- const severity = await this.checkpointProposalValidator.validate(checkpoint);
1621
- if (severity) {
1622
- this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1623
- this.peerManager.penalizePeer(peerId, severity);
1624
- return false;
1625
- }
1626
-
1627
- return true;
1628
- }
1629
-
1630
1764
  public getPeerScore(peerId: PeerId): number {
1631
1765
  return this.node.services.pubsub.score.score(peerId.toString());
1632
1766
  }