@aztec/p2p 0.0.1-commit.b6e433891 → 0.0.1-commit.b8a057fa

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 (413) hide show
  1. package/README.md +7 -6
  2. package/dest/bootstrap/bootstrap.d.ts +1 -1
  3. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  4. package/dest/bootstrap/bootstrap.js +22 -6
  5. package/dest/client/factory.d.ts +4 -3
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +35 -25
  8. package/dest/client/interface.d.ts +48 -11
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +34 -19
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +105 -46
  13. package/dest/config.d.ts +143 -107
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +72 -26
  16. package/dest/errors/p2p-service.error.d.ts +9 -0
  17. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  18. package/dest/errors/p2p-service.error.js +10 -0
  19. package/dest/errors/reqresp.error.d.ts +9 -16
  20. package/dest/errors/reqresp.error.d.ts.map +1 -1
  21. package/dest/errors/reqresp.error.js +10 -17
  22. package/dest/index.d.ts +1 -2
  23. package/dest/index.d.ts.map +1 -1
  24. package/dest/index.js +0 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +98 -56
  26. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/attestation_pool.js +269 -196
  28. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  29. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +218 -59
  31. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
  32. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/mocks.js +6 -4
  34. package/dest/mem_pools/index.d.ts +1 -2
  35. package/dest/mem_pools/index.d.ts.map +1 -1
  36. package/dest/mem_pools/instrumentation.d.ts +9 -4
  37. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  38. package/dest/mem_pools/instrumentation.js +28 -9
  39. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  40. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  41. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  42. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -3
  43. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +6 -6
  45. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +1 -1
  46. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
  47. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  48. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
  49. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  50. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  51. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  52. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  53. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +33 -5
  54. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  55. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  56. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -2
  57. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  58. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +13 -6
  59. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +15 -1
  60. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  61. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +31 -0
  62. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -3
  63. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  64. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +19 -8
  65. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +17 -4
  66. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  67. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +208 -118
  68. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
  69. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  70. package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -16
  71. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  72. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  73. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  74. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +8 -3
  75. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  76. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +2 -2
  77. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +8 -3
  78. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  79. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +8 -2
  80. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +25 -3
  81. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  82. package/dest/msg_validators/proposal_validator/proposal_validator.js +85 -15
  83. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  84. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  85. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +8 -15
  86. package/dest/msg_validators/tx_validator/allowed_public_setup.js +3 -3
  87. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  88. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  89. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  90. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  91. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  92. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  93. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  94. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  95. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  96. package/dest/msg_validators/tx_validator/data_validator.js +36 -2
  97. package/dest/msg_validators/tx_validator/factory.d.ts +14 -15
  98. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  99. package/dest/msg_validators/tx_validator/factory.js +36 -17
  100. package/dest/msg_validators/tx_validator/gas_validator.d.ts +47 -10
  101. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  102. package/dest/msg_validators/tx_validator/gas_validator.js +65 -48
  103. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  104. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  105. package/dest/msg_validators/tx_validator/index.js +2 -0
  106. package/dest/msg_validators/tx_validator/phases_validator.js +3 -3
  107. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  108. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  109. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  110. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  111. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  112. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  113. package/dest/services/data_store.d.ts +1 -1
  114. package/dest/services/data_store.d.ts.map +1 -1
  115. package/dest/services/data_store.js +5 -5
  116. package/dest/services/discv5/discV5_service.d.ts +13 -2
  117. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  118. package/dest/services/discv5/discV5_service.js +119 -23
  119. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  120. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  121. package/dest/services/discv5/persisted_enr_store.js +145 -0
  122. package/dest/services/dummy_service.d.ts +15 -15
  123. package/dest/services/dummy_service.d.ts.map +1 -1
  124. package/dest/services/dummy_service.js +15 -16
  125. package/dest/services/encoding.d.ts +19 -6
  126. package/dest/services/encoding.d.ts.map +1 -1
  127. package/dest/services/encoding.js +25 -15
  128. package/dest/services/gossipsub/topic_score_params.d.ts +6 -12
  129. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  130. package/dest/services/gossipsub/topic_score_params.js +4 -14
  131. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  132. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  133. package/dest/services/libp2p/instrumentation.js +14 -0
  134. package/dest/services/libp2p/libp2p_service.d.ts +45 -40
  135. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  136. package/dest/services/libp2p/libp2p_service.js +388 -279
  137. package/dest/services/peer-manager/peer_manager.d.ts +20 -3
  138. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  139. package/dest/services/peer-manager/peer_manager.js +79 -23
  140. package/dest/services/peer-manager/peer_scoring.d.ts +34 -2
  141. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  142. package/dest/services/peer-manager/peer_scoring.js +102 -13
  143. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -8
  144. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  145. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +38 -44
  146. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +8 -5
  147. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  148. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  149. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  150. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  151. package/dest/services/reqresp/config.d.ts +15 -3
  152. package/dest/services/reqresp/config.d.ts.map +1 -1
  153. package/dest/services/reqresp/config.js +11 -0
  154. package/dest/services/reqresp/interface.d.ts +16 -18
  155. package/dest/services/reqresp/interface.d.ts.map +1 -1
  156. package/dest/services/reqresp/interface.js +10 -20
  157. package/dest/services/reqresp/metrics.d.ts +1 -1
  158. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  159. package/dest/services/reqresp/metrics.js +0 -1
  160. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  161. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  162. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  163. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  164. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  165. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  166. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
  167. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  168. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
  169. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  170. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  171. package/dest/services/reqresp/protocols/index.js +0 -1
  172. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  173. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  174. package/dest/services/reqresp/protocols/tx.js +1 -3
  175. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  176. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  177. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  178. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  179. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  180. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  181. package/dest/services/reqresp/reqresp.d.ts +7 -29
  182. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  183. package/dest/services/reqresp/reqresp.js +59 -209
  184. package/dest/services/service.d.ts +25 -12
  185. package/dest/services/service.d.ts.map +1 -1
  186. package/dest/services/tx_collection/config.d.ts +2 -23
  187. package/dest/services/tx_collection/config.d.ts.map +1 -1
  188. package/dest/services/tx_collection/config.js +2 -55
  189. package/dest/services/tx_collection/file_store_tx_collection.d.ts +12 -28
  190. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  191. package/dest/services/tx_collection/file_store_tx_collection.js +43 -83
  192. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  193. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  194. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  195. package/dest/services/tx_collection/index.d.ts +2 -3
  196. package/dest/services/tx_collection/index.d.ts.map +1 -1
  197. package/dest/services/tx_collection/index.js +0 -1
  198. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  199. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  200. package/dest/services/tx_collection/instrumentation.js +0 -2
  201. package/dest/services/tx_collection/tx_collection.d.ts +35 -51
  202. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  203. package/dest/services/tx_collection/tx_collection.js +275 -119
  204. package/dest/services/tx_collection/tx_collection_sink.d.ts +1 -1
  205. package/dest/services/tx_collection/tx_collection_sink.js +2 -2
  206. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  207. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  208. package/dest/services/tx_collection/tx_source.js +13 -8
  209. package/dest/services/tx_file_store/tx_file_store.d.ts +1 -3
  210. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  211. package/dest/services/tx_file_store/tx_file_store.js +4 -14
  212. package/dest/services/tx_provider.d.ts +3 -1
  213. package/dest/services/tx_provider.d.ts.map +1 -1
  214. package/dest/services/tx_provider.js +3 -0
  215. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  216. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  217. package/dest/test-helpers/make-test-p2p-clients.js +5 -2
  218. package/dest/test-helpers/mock-pubsub.d.ts +23 -9
  219. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  220. package/dest/test-helpers/mock-pubsub.js +44 -44
  221. package/dest/test-helpers/reqresp-nodes.d.ts +4 -5
  222. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  223. package/dest/test-helpers/reqresp-nodes.js +16 -18
  224. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  225. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  226. package/dest/test-helpers/test_tx_provider.js +3 -0
  227. package/dest/test-helpers/testbench-utils.d.ts +15 -14
  228. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  229. package/dest/test-helpers/testbench-utils.js +28 -13
  230. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  231. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  232. package/dest/testbench/p2p_client_testbench_worker.js +102 -41
  233. package/dest/testbench/worker_client_manager.d.ts +10 -6
  234. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  235. package/dest/testbench/worker_client_manager.js +51 -9
  236. package/dest/util.d.ts +11 -6
  237. package/dest/util.d.ts.map +1 -1
  238. package/dest/util.js +35 -14
  239. package/dest/versioning.d.ts +3 -6
  240. package/dest/versioning.d.ts.map +1 -1
  241. package/dest/versioning.js +3 -24
  242. package/package.json +16 -16
  243. package/src/bootstrap/bootstrap.ts +17 -3
  244. package/src/client/factory.ts +53 -24
  245. package/src/client/interface.ts +44 -17
  246. package/src/client/p2p_client.ts +125 -79
  247. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  248. package/src/config.ts +146 -34
  249. package/src/errors/p2p-service.error.ts +11 -0
  250. package/src/errors/reqresp.error.ts +13 -19
  251. package/src/index.ts +0 -1
  252. package/src/mem_pools/attestation_pool/attestation_pool.ts +324 -239
  253. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +238 -63
  254. package/src/mem_pools/attestation_pool/mocks.ts +13 -8
  255. package/src/mem_pools/index.ts +0 -3
  256. package/src/mem_pools/instrumentation.ts +18 -12
  257. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  258. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +7 -7
  259. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +1 -1
  260. package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
  261. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  262. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
  263. package/src/mem_pools/tx_pool_v2/interfaces.ts +31 -4
  264. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +20 -8
  265. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +35 -0
  266. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +22 -8
  267. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +233 -123
  268. package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -15
  269. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
  270. package/src/msg_validators/proposal_validator/README.md +1 -1
  271. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +15 -3
  272. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +26 -3
  273. package/src/msg_validators/proposal_validator/proposal_validator.ts +94 -12
  274. package/src/msg_validators/tx_validator/README.md +13 -3
  275. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -12
  276. package/src/msg_validators/tx_validator/allowed_public_setup.ts +3 -3
  277. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  278. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  279. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  280. package/src/msg_validators/tx_validator/data_validator.ts +44 -1
  281. package/src/msg_validators/tx_validator/factory.ts +44 -20
  282. package/src/msg_validators/tx_validator/gas_validator.ts +99 -54
  283. package/src/msg_validators/tx_validator/index.ts +2 -0
  284. package/src/msg_validators/tx_validator/phases_validator.ts +3 -3
  285. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  286. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  287. package/src/services/data_store.ts +5 -13
  288. package/src/services/discv5/discV5_service.ts +126 -14
  289. package/src/services/discv5/persisted_enr_store.ts +158 -0
  290. package/src/services/dummy_service.ts +20 -39
  291. package/src/services/encoding.ts +28 -20
  292. package/src/services/gossipsub/README.md +33 -11
  293. package/src/services/gossipsub/topic_score_params.ts +9 -18
  294. package/src/services/libp2p/instrumentation.ts +14 -0
  295. package/src/services/libp2p/libp2p_service.ts +439 -313
  296. package/src/services/peer-manager/peer_manager.ts +86 -22
  297. package/src/services/peer-manager/peer_scoring.ts +102 -8
  298. package/src/services/reqresp/README.md +2 -37
  299. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +42 -52
  300. package/src/services/reqresp/batch-tx-requester/interface.ts +11 -4
  301. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  302. package/src/services/reqresp/config.ts +19 -2
  303. package/src/services/reqresp/interface.ts +21 -47
  304. package/src/services/reqresp/metrics.ts +0 -1
  305. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  306. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
  307. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
  308. package/src/services/reqresp/protocols/index.ts +0 -1
  309. package/src/services/reqresp/protocols/tx.ts +1 -3
  310. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  311. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  312. package/src/services/reqresp/reqresp.ts +69 -252
  313. package/src/services/service.ts +31 -28
  314. package/src/services/tx_collection/config.ts +3 -80
  315. package/src/services/tx_collection/file_store_tx_collection.ts +54 -103
  316. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  317. package/src/services/tx_collection/index.ts +1 -6
  318. package/src/services/tx_collection/instrumentation.ts +1 -7
  319. package/src/services/tx_collection/tx_collection.ts +330 -173
  320. package/src/services/tx_collection/tx_collection_sink.ts +2 -2
  321. package/src/services/tx_collection/tx_source.ts +10 -8
  322. package/src/services/tx_file_store/tx_file_store.ts +5 -17
  323. package/src/services/tx_provider.ts +5 -0
  324. package/src/test-helpers/make-test-p2p-clients.ts +3 -0
  325. package/src/test-helpers/mock-pubsub.ts +46 -60
  326. package/src/test-helpers/reqresp-nodes.ts +12 -22
  327. package/src/test-helpers/test_tx_provider.ts +5 -0
  328. package/src/test-helpers/testbench-utils.ts +35 -26
  329. package/src/testbench/p2p_client_testbench_worker.ts +110 -55
  330. package/src/testbench/worker_client_manager.ts +59 -20
  331. package/src/util.ts +32 -17
  332. package/src/versioning.ts +3 -33
  333. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  334. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  335. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
  336. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  337. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  338. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  339. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  340. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  341. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  342. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  343. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  344. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  345. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  346. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  347. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  348. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  349. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  350. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
  351. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  352. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  353. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  354. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  355. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  356. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  357. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  358. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  359. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  360. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  361. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  362. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  363. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  364. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  365. package/dest/mem_pools/tx_pool/index.js +0 -2
  366. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  367. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  368. package/dest/mem_pools/tx_pool/priority.js +0 -15
  369. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  370. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  371. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  372. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  373. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  374. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
  375. package/dest/msg_validators/clock_tolerance.d.ts +0 -21
  376. package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
  377. package/dest/msg_validators/clock_tolerance.js +0 -38
  378. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  379. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  380. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  381. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  382. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  383. package/dest/services/reqresp/protocols/block.js +0 -32
  384. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -51
  385. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  386. package/dest/services/tx_collection/fast_tx_collection.js +0 -311
  387. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
  388. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  389. package/dest/services/tx_collection/proposal_tx_collector.js +0 -50
  390. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -57
  391. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  392. package/dest/services/tx_collection/slow_tx_collection.js +0 -211
  393. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -344
  394. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  395. package/src/mem_pools/tx_pool/README.md +0 -270
  396. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  397. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  398. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  399. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
  400. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  401. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  402. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  403. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  404. package/src/mem_pools/tx_pool/index.ts +0 -2
  405. package/src/mem_pools/tx_pool/priority.ts +0 -20
  406. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  407. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
  408. package/src/msg_validators/clock_tolerance.ts +0 -52
  409. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  410. package/src/services/reqresp/protocols/block.ts +0 -37
  411. package/src/services/tx_collection/fast_tx_collection.ts +0 -361
  412. package/src/services/tx_collection/proposal_tx_collector.ts +0 -108
  413. package/src/services/tx_collection/slow_tx_collection.ts +0 -266
@@ -1,15 +1,15 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
- import { maxBy } from '@aztec/foundation/collection';
4
- import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { compactArray, maxBy, merge } 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
8
  import { protocolContractsHash } from '@aztec/protocol-contracts';
10
- import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
9
+ import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
10
+ import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
11
11
  import type { ContractDataSource } from '@aztec/stdlib/contract';
12
- import { GasFees } from '@aztec/stdlib/gas';
12
+ import { type BlockMinFeesProvider, GasFees, getNetworkTxGasLimits } from '@aztec/stdlib/gas';
13
13
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
14
14
  import {
15
15
  BlockProposal,
@@ -25,8 +25,9 @@ import {
25
25
  getTopicsForConfig,
26
26
  metricsTopicStrToLabels,
27
27
  } from '@aztec/stdlib/p2p';
28
+ import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
28
29
  import { MerkleTreeId } from '@aztec/stdlib/trees';
29
- import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
30
+ import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
30
31
  import type { UInt64 } from '@aztec/stdlib/types';
31
32
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
32
33
  import {
@@ -51,13 +52,15 @@ import { yamux } from '@chainsafe/libp2p-yamux';
51
52
  import { bootstrap } from '@libp2p/bootstrap';
52
53
  import { identify } from '@libp2p/identify';
53
54
  import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
54
- import type { ConnectionManager } from '@libp2p/interface-internal';
55
+ import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
55
56
  import { mplex } from '@libp2p/mplex';
56
57
  import { tcp } from '@libp2p/tcp';
58
+ import { multiaddr } from '@multiformats/multiaddr';
57
59
  import { ENR } from '@nethermindeth/enr';
58
60
  import { createLibp2p } from 'libp2p';
59
61
 
60
62
  import type { P2PConfig } from '../../config.js';
63
+ import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
61
64
  import type { MemPools } from '../../mem_pools/interface.js';
62
65
  import {
63
66
  BlockProposalValidator,
@@ -73,38 +76,34 @@ import {
73
76
  createFirstStageTxValidationsForGossipedTransactions,
74
77
  createSecondStageTxValidationsForGossipedTransactions,
75
78
  createTxValidatorForBlockProposalReceivedTxs,
76
- createTxValidatorForReqResponseReceivedTxs,
77
79
  } from '../../msg_validators/tx_validator/factory.js';
80
+ import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
78
81
  import { GossipSubEvent } from '../../types/index.js';
79
82
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
80
83
  import { getVersions } from '../../versioning.js';
81
84
  import { AztecDatastore } from '../data_store.js';
82
85
  import { DiscV5Service } from '../discv5/discV5_service.js';
83
- import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
86
+ import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
84
87
  import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
85
88
  import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
86
89
  import type { PeerManagerInterface } from '../peer-manager/interface.js';
87
90
  import { PeerManager } from '../peer-manager/peer_manager.js';
88
91
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
89
92
  import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
90
- import type { P2PReqRespConfig } from '../reqresp/config.js';
93
+ import { type P2PReqRespConfig, YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
91
94
  import {
92
95
  AuthRequest,
93
96
  BlockTxsRequest,
94
97
  BlockTxsResponse,
95
- DEFAULT_SUB_PROTOCOL_VALIDATORS,
96
98
  type ReqRespInterface,
97
99
  type ReqRespResponse,
98
100
  ReqRespSubProtocol,
99
101
  type ReqRespSubProtocolHandler,
100
102
  type ReqRespSubProtocolHandlers,
101
- type ReqRespSubProtocolValidators,
102
103
  StatusMessage,
103
- type SubProtocolMap,
104
104
  ValidationError,
105
105
  pingHandler,
106
106
  reqGoodbyeHandler,
107
- reqRespBlockHandler,
108
107
  reqRespBlockTxsHandler,
109
108
  reqRespStatusHandler,
110
109
  reqRespTxHandler,
@@ -112,13 +111,33 @@ import {
112
111
  import { ReqResp } from '../reqresp/reqresp.js';
113
112
  import type {
114
113
  P2PBlockReceivedCallback,
114
+ P2PCheckpointAttestationCallback,
115
115
  P2PCheckpointReceivedCallback,
116
116
  P2PDuplicateAttestationCallback,
117
+ P2POversizedProposalCallback,
117
118
  P2PService,
118
119
  PeerDiscoveryService,
119
120
  } from '../service.js';
120
121
  import { P2PInstrumentation } from './instrumentation.js';
121
122
 
123
+ /**
124
+ * Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
125
+ * bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
126
+ * materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
127
+ */
128
+ function buildConsensusTimetable(
129
+ config: P2PConfig,
130
+ l1Constants: ReturnType<EpochCacheInterface['getL1Constants']>,
131
+ ): ConsensusTimetable {
132
+ const blockDuration = config.blockDurationMs / 1000;
133
+ return new ConsensusTimetable({
134
+ l1Constants,
135
+ blockDuration,
136
+ checkpointProposalSyncGrace:
137
+ config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration),
138
+ });
139
+ }
140
+
122
141
  interface ValidationResult {
123
142
  name: string;
124
143
  isValid: TxValidationResult;
@@ -130,7 +149,7 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
130
149
  // REFACTOR: Unify with the type above
131
150
  type ReceivedMessageValidationResult<T, M = undefined> =
132
151
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
133
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
152
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
134
153
 
135
154
  /**
136
155
  * Lib P2P implementation of the P2PService interface.
@@ -147,8 +166,6 @@ export class LibP2PService extends WithTracer implements P2PService {
147
166
  private protocolVersion = '';
148
167
  private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
149
168
 
150
- private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
151
-
152
169
  /** Callback invoked when a duplicate proposal is detected (triggers slashing). */
153
170
  private duplicateProposalCallback?: (info: {
154
171
  slot: SlotNumber;
@@ -156,9 +173,15 @@ export class LibP2PService extends WithTracer implements P2PService {
156
173
  type: 'checkpoint' | 'block';
157
174
  }) => void;
158
175
 
176
+ /** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */
177
+ private oversizedProposalCallback?: P2POversizedProposalCallback;
178
+
159
179
  /** Callback invoked when a duplicate attestation is detected (triggers slashing). */
160
180
  private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
161
181
 
182
+ /** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
183
+ private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
184
+
162
185
  /**
163
186
  * Callback for when a block is received from a peer.
164
187
  * @param block - The block received from the peer.
@@ -171,10 +194,19 @@ export class LibP2PService extends WithTracer implements P2PService {
171
194
  * @param checkpoint - The checkpoint proposal received from the peer.
172
195
  * @returns The attestations for the checkpoint, if any.
173
196
  */
174
- private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
197
+ private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
198
+ /**
199
+ * Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
200
+ * @param checkpoint - The checkpoint proposal received from the peer.
201
+ * @returns The attestations for the checkpoint, if any.
202
+ */
203
+ private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
175
204
 
176
205
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
177
206
 
207
+ private ipChangedHandler?: (ip: string) => void;
208
+ private discoveredP2pIp?: string;
209
+
178
210
  private instrumentation: P2PInstrumentation;
179
211
 
180
212
  private telemetry: TelemetryClient;
@@ -192,8 +224,10 @@ export class LibP2PService extends WithTracer implements P2PService {
192
224
  private epochCache: EpochCacheInterface,
193
225
  private proofVerifier: ClientProtocolCircuitVerifier,
194
226
  private worldStateSynchronizer: WorldStateSynchronizer,
227
+ private blockMinFeesProvider: BlockMinFeesProvider,
195
228
  telemetry: TelemetryClient,
196
229
  logger: Logger = createLogger('p2p:libp2p_service'),
230
+ private txValidationCache?: TxValidationCache,
197
231
  ) {
198
232
  super(telemetry, 'LibP2PService');
199
233
  this.telemetry = telemetry;
@@ -223,15 +257,39 @@ export class LibP2PService extends WithTracer implements P2PService {
223
257
  this.protocolVersion,
224
258
  );
225
259
 
260
+ // Build the consensus timetable once from protocol slot-timing constants and inject it into every
261
+ // validator so they share one set of receive-window bounds, independent of proposer operational budgets.
262
+ const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
226
263
  const proposalValidatorOpts = {
227
264
  txsPermitted: !config.disableTransactions,
228
265
  maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
266
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
267
+ skipSlotValidation: config.skipProposalSlotValidation,
268
+ signatureContext: {
269
+ chainId: config.l1ChainId,
270
+ rollupAddress: config.rollupAddress,
271
+ },
272
+ clockDisparityMs: config.maxGossipClockDisparityMs,
273
+ };
274
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
275
+ this.checkpointProposalValidator = new CheckpointProposalValidator(
276
+ epochCache,
277
+ consensusTimetable,
278
+ proposalValidatorOpts,
279
+ );
280
+ const attestationValidatorOpts = {
281
+ signatureContext: proposalValidatorOpts.signatureContext,
282
+ clockDisparityMs: config.maxGossipClockDisparityMs,
229
283
  };
230
- this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
231
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
232
284
  this.checkpointAttestationValidator = config.fishermanMode
233
- ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
234
- : new CheckpointAttestationValidator(epochCache);
285
+ ? new FishermanAttestationValidator(
286
+ epochCache,
287
+ consensusTimetable,
288
+ mempools.attestationPool,
289
+ telemetry,
290
+ attestationValidatorOpts,
291
+ )
292
+ : new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
235
293
 
236
294
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
237
295
 
@@ -243,18 +301,22 @@ export class LibP2PService extends WithTracer implements P2PService {
243
301
  return true;
244
302
  };
245
303
 
246
- this.checkpointReceivedCallback = (
247
- checkpoint: CheckpointProposalCore,
304
+ this.allNodesCheckpointReceivedCallback = (
305
+ _checkpoint: CheckpointProposalCore,
306
+ ): Promise<CheckpointAttestation[] | undefined> => {
307
+ throw new CheckpointProposalReceivedCallbackNotRegisteredError();
308
+ };
309
+
310
+ this.validatorCheckpointReceivedCallback = (
311
+ _checkpoint: CheckpointProposalCore,
248
312
  ): Promise<CheckpointAttestation[] | undefined> => {
249
- this.logger.debug(
250
- `Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
251
- );
252
313
  return Promise.resolve(undefined);
253
314
  };
254
315
  }
255
316
 
256
- public updateConfig(config: Partial<P2PReqRespConfig>) {
317
+ public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
257
318
  this.reqresp.updateConfig(config);
319
+ this.config = merge(this.config, config);
258
320
  }
259
321
 
260
322
  /**
@@ -273,9 +335,11 @@ export class LibP2PService extends WithTracer implements P2PService {
273
335
  proofVerifier: ClientProtocolCircuitVerifier;
274
336
  worldStateSynchronizer: WorldStateSynchronizer;
275
337
  peerStore: AztecAsyncKVStore;
338
+ blockMinFeesProvider: BlockMinFeesProvider;
276
339
  telemetry: TelemetryClient;
277
340
  logger: Logger;
278
341
  packageVersion: string;
342
+ txValidationCache?: TxValidationCache;
279
343
  },
280
344
  ) {
281
345
  const {
@@ -285,9 +349,11 @@ export class LibP2PService extends WithTracer implements P2PService {
285
349
  mempools,
286
350
  proofVerifier,
287
351
  peerStore,
352
+ blockMinFeesProvider,
288
353
  telemetry,
289
354
  logger,
290
355
  packageVersion,
356
+ txValidationCache,
291
357
  } = deps;
292
358
  const { p2pPort, maxPeerCount, listenAddress } = config;
293
359
  const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
@@ -302,6 +368,7 @@ export class LibP2PService extends WithTracer implements P2PService {
302
368
  packageVersion,
303
369
  telemetry,
304
370
  createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
371
+ peerStore,
305
372
  );
306
373
 
307
374
  // Seed libp2p's bootstrap discovery with private and trusted peers
@@ -316,34 +383,49 @@ export class LibP2PService extends WithTracer implements P2PService {
316
383
  const protocolVersion = compressComponentVersions(versions);
317
384
 
318
385
  const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
319
- const directPeers = (
386
+ const directPeers = compactArray(
320
387
  await Promise.all(
321
388
  preferredPeersEnrs.map(async enr => {
322
- const peerId = await enr.peerId();
323
- const address = enr.getLocationMultiaddr('tcp');
324
- if (address === undefined) {
325
- throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
389
+ try {
390
+ const peerId = await enr.peerId();
391
+ const address = enr.getLocationMultiaddr('tcp');
392
+ if (address === undefined) {
393
+ throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
394
+ }
395
+ return {
396
+ id: peerId,
397
+ addrs: [address],
398
+ };
399
+ } catch (err) {
400
+ // A malformed configured ENR shouldn't abort node setup — skip it and log.
401
+ logger.warn(`Skipping preferred peer with invalid ENR`, { err });
402
+ return undefined;
326
403
  }
327
- return {
328
- id: peerId,
329
- addrs: [address],
330
- };
331
404
  }),
332
- )
333
- ).filter(peer => peer !== undefined);
405
+ ),
406
+ );
334
407
 
335
408
  const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
336
409
 
337
- // Create dynamic topic score params based on network configuration
410
+ // Create dynamic topic score params based on network configuration. Scoring uses the network-wide
411
+ // max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
412
+ // peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
338
413
  const l1Constants = epochCache.getL1Constants();
339
414
  const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
340
415
  slotDurationMs: l1Constants.slotDuration * 1000,
341
416
  heartbeatIntervalMs: config.gossipsubInterval,
342
417
  targetCommitteeSize: l1Constants.targetCommitteeSize,
343
- blockDurationMs: config.blockDurationMs,
418
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
344
419
  expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
345
420
  });
346
421
 
422
+ // Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
423
+ // message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
424
+ // so a crafted topic colliding on msg id can suppress a real message as a duplicate.
425
+ const allowedTopics = getTopicsForConfig(config.disableTransactions).map(topic =>
426
+ createTopicString(topic, protocolVersion),
427
+ );
428
+
347
429
  const node = await createLibp2p({
348
430
  start: false,
349
431
  peerId,
@@ -375,7 +457,8 @@ export class LibP2PService extends WithTracer implements P2PService {
375
457
  ],
376
458
  datastore,
377
459
  peerDiscovery,
378
- streamMuxers: [yamux(), mplex()],
460
+ // Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
461
+ streamMuxers: [yamux({ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES }), mplex()],
379
462
  connectionEncryption: [noise()],
380
463
  connectionManager: {
381
464
  minConnections: 0, // Disable libp2p peer dialing, we do it manually
@@ -389,7 +472,7 @@ export class LibP2PService extends WithTracer implements P2PService {
389
472
  },
390
473
  connectionGater: {
391
474
  denyInboundConnection: (maConn: MultiaddrConnection) => {
392
- const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
475
+ const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
393
476
  if (allowed) {
394
477
  return false;
395
478
  }
@@ -400,7 +483,7 @@ export class LibP2PService extends WithTracer implements P2PService {
400
483
  denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
401
484
  //NOTE: it is not necessary to check address here because this was already done by
402
485
  // denyInboundConnection
403
- const allowed = peerManager.isNodeAllowedToConnect(peerId);
486
+ const allowed = peerManager.isPeerAllowedToConnect(peerId);
404
487
  if (allowed) {
405
488
  return false;
406
489
  }
@@ -428,9 +511,13 @@ export class LibP2PService extends WithTracer implements P2PService {
428
511
  mcacheLength: config.gossipsubMcacheLength,
429
512
  mcacheGossip: config.gossipsubMcacheGossip,
430
513
  seenTTL: config.gossipsubSeenTTL,
514
+ allowedTopics,
515
+ // No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
516
+ // raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
517
+ // a different message with no fallback to the full id. Dedup instead rests solely on the
518
+ // cryptographic, topic-framed msgIdFn below.
431
519
  msgIdFn: getMsgIdFn,
432
520
  msgIdToStrFn: msgIdToStrFn,
433
- fastMsgIdFn: fastMsgIdFn,
434
521
  dataTransform: new SnappyTransform(),
435
522
  metricsRegister: otelMetricsAdapter,
436
523
  metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
@@ -442,8 +529,9 @@ export class LibP2PService extends WithTracer implements P2PService {
442
529
  topics: topicScoreParams,
443
530
  }),
444
531
  }) as (components: GossipSubComponents) => GossipSub,
445
- components: (components: { connectionManager: ConnectionManager }) => ({
532
+ components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
446
533
  connectionManager: components.connectionManager,
534
+ addressManager: components.addressManager,
447
535
  }),
448
536
  },
449
537
  logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
@@ -465,6 +553,9 @@ export class LibP2PService extends WithTracer implements P2PService {
465
553
  epochCache,
466
554
  );
467
555
 
556
+ // Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
557
+ reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
558
+
468
559
  // Configure application-specific scoring for gossipsub.
469
560
  // The weight scales app score to align with gossipsub thresholds:
470
561
  // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
@@ -485,8 +576,10 @@ export class LibP2PService extends WithTracer implements P2PService {
485
576
  epochCache,
486
577
  proofVerifier,
487
578
  worldStateSynchronizer,
579
+ blockMinFeesProvider,
488
580
  telemetry,
489
581
  logger,
582
+ txValidationCache,
490
583
  );
491
584
  }
492
585
 
@@ -500,24 +593,21 @@ export class LibP2PService extends WithTracer implements P2PService {
500
593
  throw new Error('P2P service already started');
501
594
  }
502
595
 
503
- // Get listen & announce addresses for logging
504
596
  const { p2pIp, p2pPort } = this.config;
505
- if (!p2pIp) {
506
- throw new Error('Announce address not provided.');
597
+ if (!p2pIp && !this.config.queryForIp) {
598
+ throw new Error('Announce address not provided and queryForIp is not enabled.');
507
599
  }
508
- const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
600
+ const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
509
601
 
510
602
  // Create request response protocol handlers
511
603
  const txHandler = reqRespTxHandler(this.mempools);
512
604
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
513
- const blockHandler = reqRespBlockHandler(this.archiver);
514
605
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
515
606
 
516
607
  const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
517
608
  [ReqRespSubProtocol.PING]: pingHandler,
518
609
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
519
610
  [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
520
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
521
611
  };
522
612
 
523
613
  if (!this.config.disableTransactions) {
@@ -533,17 +623,9 @@ export class LibP2PService extends WithTracer implements P2PService {
533
623
  requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
534
624
  }
535
625
 
536
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
537
- const reqrespSubProtocolValidators = {
538
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
539
- [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
540
- [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
541
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
542
- };
543
-
544
626
  await this.peerManager.initializePeers();
545
627
 
546
- await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
628
+ await this.reqresp.start(requestResponseHandlers);
547
629
 
548
630
  await this.node.start();
549
631
 
@@ -559,6 +641,38 @@ export class LibP2PService extends WithTracer implements P2PService {
559
641
  if (!this.config.p2pDiscoveryDisabled) {
560
642
  await this.peerDiscoveryService.start();
561
643
  }
644
+
645
+ // Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
646
+ if (this.config.queryForIp) {
647
+ this.discoveredP2pIp = this.config.p2pIp;
648
+ this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
649
+ this.ipChangedHandler = (ip: string) => {
650
+ const addressManager = this.node.services.components.addressManager;
651
+ const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
652
+ const previousIp = this.discoveredP2pIp;
653
+
654
+ if (previousIp) {
655
+ const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
656
+ addressManager.removeObservedAddr(oldAddr);
657
+ this.logger.info('Libp2p announce address updated due to IP change', {
658
+ previousIp,
659
+ newIp: ip,
660
+ newMultiaddr: newAddr.toString(),
661
+ });
662
+ } else {
663
+ this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
664
+ ip,
665
+ multiaddr: newAddr.toString(),
666
+ });
667
+ }
668
+
669
+ addressManager.addObservedAddr(newAddr);
670
+ addressManager.confirmObservedAddr(newAddr);
671
+ this.discoveredP2pIp = ip;
672
+ };
673
+ this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
674
+ }
675
+
562
676
  this.discoveryRunningPromise = new RunningPromise(
563
677
  async () => {
564
678
  await this.peerManager.heartbeat();
@@ -584,6 +698,11 @@ export class LibP2PService extends WithTracer implements P2PService {
584
698
  // Remove gossip sub listener
585
699
  this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
586
700
 
701
+ if (this.ipChangedHandler) {
702
+ this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
703
+ this.ipChangedHandler = undefined;
704
+ }
705
+
587
706
  // Stop peer manager
588
707
  this.logger.debug('Stopping peer manager...');
589
708
  await this.peerManager.stop();
@@ -598,12 +717,8 @@ export class LibP2PService extends WithTracer implements P2PService {
598
717
  this.logger.info('LibP2P service stopped');
599
718
  }
600
719
 
601
- addReqRespSubProtocol(
602
- subProtocol: ReqRespSubProtocol,
603
- handler: ReqRespSubProtocolHandler,
604
- validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
605
- ): Promise<void> {
606
- return this.reqresp.addSubProtocol(subProtocol, handler, validator);
720
+ addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
721
+ return this.reqresp.addSubProtocol(subProtocol, handler);
607
722
  }
608
723
 
609
724
  public registerThisValidatorAddresses(address: EthAddress[]): void {
@@ -631,20 +746,6 @@ export class LibP2PService extends WithTracer implements P2PService {
631
746
  setImmediate(() => void safeJob());
632
747
  }
633
748
 
634
- /**
635
- * Send a batch of requests to peers, and return the responses
636
- * @param protocol - The request response protocol to use
637
- * @param requests - The requests to send to the peers
638
- * @returns The responses to the requests
639
- */
640
- sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
641
- protocol: SubProtocol,
642
- requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
643
- pinnedPeerId: PeerId | undefined,
644
- ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
645
- return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
646
- }
647
-
648
749
  public sendRequestToPeer(
649
750
  peerId: PeerId,
650
751
  subProtocol: ReqRespSubProtocol,
@@ -666,8 +767,12 @@ export class LibP2PService extends WithTracer implements P2PService {
666
767
  this.blockReceivedCallback = callback;
667
768
  }
668
769
 
669
- public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
670
- this.checkpointReceivedCallback = callback;
770
+ public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
771
+ this.validatorCheckpointReceivedCallback = callback;
772
+ }
773
+
774
+ public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
775
+ this.allNodesCheckpointReceivedCallback = callback;
671
776
  }
672
777
 
673
778
  /**
@@ -680,6 +785,13 @@ export class LibP2PService extends WithTracer implements P2PService {
680
785
  this.duplicateProposalCallback = callback;
681
786
  }
682
787
 
788
+ /**
789
+ * Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
790
+ */
791
+ public registerOversizedProposalCallback(callback: P2POversizedProposalCallback): void {
792
+ this.oversizedProposalCallback = callback;
793
+ }
794
+
683
795
  /**
684
796
  * Registers a callback to be invoked when a duplicate attestation is detected.
685
797
  * A validator signing attestations for different proposals at the same slot.
@@ -689,6 +801,10 @@ export class LibP2PService extends WithTracer implements P2PService {
689
801
  this.duplicateAttestationCallback = callback;
690
802
  }
691
803
 
804
+ public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
805
+ this.checkpointAttestationCallback = callback;
806
+ }
807
+
692
808
  /**
693
809
  * Subscribes to a topic.
694
810
  * @param topic - The topic to subscribe to.
@@ -817,6 +933,15 @@ export class LibP2PService extends WithTracer implements P2PService {
817
933
 
818
934
  // Process the message, optionally within a linked span for trace propagation
819
935
  const processMessage = async () => {
936
+ if (
937
+ this.config.skipIncomingProposals &&
938
+ (msg.topic === this.topicStrings[TopicType.block_proposal] ||
939
+ msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
940
+ ) {
941
+ this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
942
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
943
+ return;
944
+ }
820
945
  if (msg.topic === this.topicStrings[TopicType.tx]) {
821
946
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
822
947
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
@@ -882,30 +1007,67 @@ export class LibP2PService extends WithTracer implements P2PService {
882
1007
  source: PeerId,
883
1008
  topicType: TopicType,
884
1009
  ): Promise<ReceivedMessageValidationResult<T, M>> {
885
- let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
1010
+ // Default to reject result with a penalty if validation function throws an error
1011
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
1012
+ result: TopicValidatorResult.Reject,
1013
+ severity: PeerErrorSeverity.MidToleranceError,
1014
+ };
886
1015
  const timer = new Timer();
887
1016
  try {
888
1017
  resultAndObj = await validationFunc();
889
1018
  } catch (err) {
890
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
891
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
892
- msgId,
893
- source: source.toString(),
894
- topicType,
895
- });
1019
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
1020
+ }
1021
+
1022
+ const validationTimeMs = timer.ms();
1023
+ const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
1024
+ if (validationTimeMs > mcacheWindowMs * 0.75) {
1025
+ this.instrumentation.incSlowValidation(topicType);
1026
+ this.logger.warn(
1027
+ `Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
1028
+ `Message forwarding may be skipped if validation exceeds the window.`,
1029
+ { msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
1030
+ );
896
1031
  }
897
1032
 
898
1033
  if (resultAndObj.result === TopicValidatorResult.Accept) {
1034
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
899
1035
  this.instrumentation.recordMessageValidation(topicType, timer);
1036
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
1037
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
1038
+ msgId,
1039
+ source: source.toString(),
1040
+ topicType,
1041
+ severity: resultAndObj.severity,
1042
+ });
1043
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
1044
+ } else {
1045
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
900
1046
  }
901
1047
 
902
1048
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
903
1049
  return resultAndObj;
904
1050
  }
905
1051
 
1052
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
1053
+ try {
1054
+ return deserializeFunc();
1055
+ } catch (err) {
1056
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
1057
+ err,
1058
+ msgId,
1059
+ source: source.toString(),
1060
+ });
1061
+ return undefined;
1062
+ }
1063
+ }
1064
+
906
1065
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
907
1066
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
908
- const tx = Tx.fromBuffer(payloadData);
1067
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
1068
+ if (!tx) {
1069
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
1070
+ }
909
1071
 
910
1072
  const currentBlockNumber = await this.archiver.getBlockNumber();
911
1073
  const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
@@ -930,8 +1092,7 @@ export class LibP2PService extends WithTracer implements P2PService {
930
1092
  severity,
931
1093
  source: source.toString(),
932
1094
  });
933
- this.peerManager.penalizePeer(source, severity);
934
- return { result: TopicValidatorResult.Reject };
1095
+ return { result: TopicValidatorResult.Reject, severity };
935
1096
  }
936
1097
 
937
1098
  // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
@@ -953,8 +1114,7 @@ export class LibP2PService extends WithTracer implements P2PService {
953
1114
  severity,
954
1115
  source: source.toString(),
955
1116
  });
956
- this.peerManager.penalizePeer(source, severity);
957
- return { result: TopicValidatorResult.Reject };
1117
+ return { result: TopicValidatorResult.Reject, severity };
958
1118
  }
959
1119
 
960
1120
  // Pool add: persist the tx
@@ -979,8 +1139,7 @@ export class LibP2PService extends WithTracer implements P2PService {
979
1139
  source: source.toString(),
980
1140
  txHash: txHash.toString(),
981
1141
  });
982
- this.peerManager.penalizePeer(source, PeerErrorSeverity.HighToleranceError);
983
- return { result: TopicValidatorResult.Reject };
1142
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
984
1143
  }
985
1144
  };
986
1145
 
@@ -1010,7 +1169,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1010
1169
  source: PeerId,
1011
1170
  ): Promise<void> {
1012
1171
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
1013
- () => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
1172
+ () => {
1173
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1174
+ if (!attestation) {
1175
+ return Promise.resolve({
1176
+ result: TopicValidatorResult.Reject,
1177
+ severity: PeerErrorSeverity.LowToleranceError,
1178
+ });
1179
+ }
1180
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1181
+ },
1014
1182
  msgId,
1015
1183
  source,
1016
1184
  TopicType.checkpoint_attestation,
@@ -1043,8 +1211,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1043
1211
 
1044
1212
  if (validationResult.result === 'reject') {
1045
1213
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1046
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1047
- return { result: TopicValidatorResult.Reject };
1214
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1048
1215
  }
1049
1216
 
1050
1217
  if (validationResult.result === 'ignore') {
@@ -1070,16 +1237,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1070
1237
  return { result: TopicValidatorResult.Ignore, obj: attestation };
1071
1238
  }
1072
1239
 
1073
- // Could not add (cap reached for signer), no need to re-broadcast
1240
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1074
1241
  if (!added) {
1075
- this.logger.warn(`Dropping checkpoint attestation due to cap`, {
1242
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1076
1243
  slot: slot.toString(),
1077
1244
  archive: attestation.archive.toString(),
1078
1245
  source: peerId.toString(),
1079
1246
  attester: attestation.getSender()?.toString(),
1080
1247
  count,
1081
1248
  });
1082
- return { result: TopicValidatorResult.Ignore, obj: attestation };
1249
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1083
1250
  }
1084
1251
 
1085
1252
  // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
@@ -1098,6 +1265,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1098
1265
  }
1099
1266
 
1100
1267
  // Attestation was added successfully - accept it so other nodes can also detect the equivocation
1268
+ this.checkpointAttestationCallback?.(attestation);
1101
1269
  return { result: TopicValidatorResult.Accept, obj: attestation };
1102
1270
  }
1103
1271
 
@@ -1105,16 +1273,17 @@ export class LibP2PService extends WithTracer implements P2PService {
1105
1273
  const {
1106
1274
  result,
1107
1275
  obj: block,
1108
- metadata: { isEquivocated } = {},
1109
- } = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean }>(
1276
+ metadata: { isEquivocated, isOversized } = {},
1277
+ } = await this.validateReceivedMessage<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>(
1110
1278
  () => this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)),
1111
1279
  msgId,
1112
1280
  source,
1113
1281
  TopicType.block_proposal,
1114
1282
  );
1115
1283
 
1116
- // If not accepted or equivocated, return
1117
- if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
1284
+ // If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
1285
+ // slashing evidence but never attested or processed.
1286
+ if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
1118
1287
  return;
1119
1288
  }
1120
1289
 
@@ -1129,13 +1298,12 @@ export class LibP2PService extends WithTracer implements P2PService {
1129
1298
  protected async validateAndStoreBlockProposal(
1130
1299
  peerId: PeerId,
1131
1300
  block: BlockProposal,
1132
- ): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean }>> {
1301
+ ): Promise<ReceivedMessageValidationResult<BlockProposal, { isEquivocated: boolean; isOversized: boolean }>> {
1133
1302
  const validationResult = await this.blockProposalValidator.validate(block);
1134
1303
 
1135
1304
  if (validationResult.result === 'reject') {
1136
1305
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1137
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1138
- return { result: TopicValidatorResult.Reject };
1306
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1139
1307
  }
1140
1308
 
1141
1309
  if (validationResult.result === 'ignore') {
@@ -1145,6 +1313,12 @@ export class LibP2PService extends WithTracer implements P2PService {
1145
1313
  // Try to add the proposal: this handles existence check, cap check, and adding in one call
1146
1314
  const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1147
1315
  const isEquivocated = count !== undefined && count > 1;
1316
+ // An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
1317
+ // proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
1318
+ // attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
1319
+ const isOversized =
1320
+ this.config.maxBlocksPerCheckpoint !== undefined &&
1321
+ block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
1148
1322
 
1149
1323
  // Duplicate proposal received, no need to re-broadcast
1150
1324
  if (alreadyExists) {
@@ -1154,12 +1328,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1154
1328
  proposer: block.getSender()?.toString(),
1155
1329
  source: peerId.toString(),
1156
1330
  });
1157
- return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated } };
1331
+ return { result: TopicValidatorResult.Ignore, obj: block, metadata: { isEquivocated, isOversized } };
1158
1332
  }
1159
1333
 
1160
1334
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1161
1335
  if (!added) {
1162
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1163
1336
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1164
1337
  ...block.toBlockInfo(),
1165
1338
  indexWithinCheckpoint: block.indexWithinCheckpoint,
@@ -1167,7 +1340,27 @@ export class LibP2PService extends WithTracer implements P2PService {
1167
1340
  proposer: block.getSender()?.toString(),
1168
1341
  source: peerId.toString(),
1169
1342
  });
1170
- return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
1343
+ return {
1344
+ result: TopicValidatorResult.Reject,
1345
+ metadata: { isEquivocated, isOversized },
1346
+ severity: PeerErrorSeverity.HighToleranceError,
1347
+ };
1348
+ }
1349
+
1350
+ // The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
1351
+ // slashed. Fired alongside (not instead of) equivocation detection below.
1352
+ if (isOversized) {
1353
+ const proposer = block.getSender();
1354
+ if (proposer) {
1355
+ this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
1356
+ ...block.toBlockInfo(),
1357
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
1358
+ maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
1359
+ source: peerId.toString(),
1360
+ proposer: proposer.toString(),
1361
+ });
1362
+ this.oversizedProposalCallback?.({ slot: block.slotNumber, proposer });
1363
+ }
1171
1364
  }
1172
1365
 
1173
1366
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1183,11 +1376,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1183
1376
  if (proposer && count === 2) {
1184
1377
  this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
1185
1378
  }
1186
- return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
1379
+ return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated, isOversized } };
1187
1380
  }
1188
1381
 
1189
1382
  // Otherwise, we're good to go!
1190
- return { result: TopicValidatorResult.Accept, obj: block };
1383
+ return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated: false, isOversized } };
1191
1384
  }
1192
1385
 
1193
1386
  // REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
@@ -1213,6 +1406,9 @@ export class LibP2PService extends WithTracer implements P2PService {
1213
1406
  const isValid = await this.blockReceivedCallback(block, sender);
1214
1407
  if (!isValid) {
1215
1408
  this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1409
+ // Release the protections this proposal created so its txs return to pending. Only entries still
1410
+ // keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
1411
+ await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
1216
1412
  }
1217
1413
  }
1218
1414
 
@@ -1224,25 +1420,45 @@ export class LibP2PService extends WithTracer implements P2PService {
1224
1420
  const {
1225
1421
  result,
1226
1422
  obj: checkpoint,
1227
- metadata: { isEquivocated, processBlock } = {},
1228
- } = await this.validateReceivedMessage<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>(
1423
+ metadata: { isEquivocated, processBlock, isOversized } = {},
1424
+ } = await this.validateReceivedMessage<
1425
+ CheckpointProposal,
1426
+ { isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
1427
+ >(
1229
1428
  () => this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)),
1230
1429
  msgId,
1231
1430
  source,
1232
1431
  TopicType.checkpoint_proposal,
1233
1432
  );
1234
1433
 
1434
+ // An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
1435
+ // Process checkpoint proposal if valid and neither equivocated nor oversized.
1436
+ const processCheckpointFn = () =>
1437
+ result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized
1438
+ ? this.processValidCheckpointProposal(checkpoint.toCore(), source)
1439
+ : Promise.resolve();
1440
+
1235
1441
  // If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
1236
1442
  // TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
1237
- if (processBlock && checkpoint?.getBlockProposal()) {
1238
- await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
1239
- }
1240
-
1241
- if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
1443
+ const processBlockFn = () =>
1444
+ processBlock && checkpoint && checkpoint.getBlockProposal()
1445
+ ? this.processValidBlockProposal(checkpoint.getBlockProposal()!, source)
1446
+ : Promise.resolve();
1447
+
1448
+ // A node that skips checkpoint validation attests without re-executing the embedded last block, so run
1449
+ // the checkpoint callback first: this creates and broadcasts the attestation before the block is
1450
+ // processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
1451
+ // waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
1452
+ // window, after which peers reject it as stale.
1453
+ if (this.config.skipCheckpointProposalValidation) {
1454
+ await processCheckpointFn();
1455
+ await processBlockFn();
1242
1456
  return;
1243
1457
  }
1244
1458
 
1245
- await this.processValidCheckpointProposal(checkpoint.toCore(), source);
1459
+ // Process the block first, since it's required for the checkpoint proposal validation.
1460
+ await processBlockFn();
1461
+ await processCheckpointFn();
1246
1462
  }
1247
1463
 
1248
1464
  /**
@@ -1255,13 +1471,17 @@ export class LibP2PService extends WithTracer implements P2PService {
1255
1471
  protected async validateAndStoreCheckpointProposal(
1256
1472
  peerId: PeerId,
1257
1473
  checkpoint: CheckpointProposal,
1258
- ): Promise<ReceivedMessageValidationResult<CheckpointProposal, { isEquivocated: boolean; processBlock: boolean }>> {
1474
+ ): Promise<
1475
+ ReceivedMessageValidationResult<
1476
+ CheckpointProposal,
1477
+ { isEquivocated: boolean; processBlock: boolean; isOversized: boolean }
1478
+ >
1479
+ > {
1259
1480
  const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
1260
1481
 
1261
1482
  if (validationResult.result === 'reject') {
1262
1483
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1263
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1264
- return { result: TopicValidatorResult.Reject };
1484
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1265
1485
  }
1266
1486
 
1267
1487
  if (validationResult.result === 'ignore') {
@@ -1271,25 +1491,30 @@ export class LibP2PService extends WithTracer implements P2PService {
1271
1491
  // Extract and try to add the block proposal first if present
1272
1492
  const blockProposal = checkpoint.getBlockProposal();
1273
1493
  let processBlock = false;
1494
+ let isOversized = false;
1274
1495
  if (blockProposal) {
1275
1496
  this.logger.debug(`Validating block proposal from propagated checkpoint`, {
1276
1497
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1277
1498
  [Attributes.P2P_ID]: peerId.toString(),
1278
1499
  });
1279
- const {
1280
- result,
1281
- obj,
1282
- metadata: { isEquivocated } = {},
1283
- } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1284
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1500
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1501
+ const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
1502
+ isOversized = blockIsOversized ?? false;
1503
+
1504
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1285
1505
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1286
1506
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1287
1507
  [Attributes.P2P_ID]: peerId.toString(),
1288
1508
  isEquivocated,
1289
- result,
1509
+ result: blockProposalResult.result,
1290
1510
  });
1291
- return { result: TopicValidatorResult.Reject };
1292
- } else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1511
+ return {
1512
+ result: TopicValidatorResult.Reject,
1513
+ severity:
1514
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1515
+ };
1516
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
1517
+ // An oversized terminal block is re-broadcast as slashing evidence but never processed.
1293
1518
  processBlock = true;
1294
1519
  }
1295
1520
  }
@@ -1309,20 +1534,24 @@ export class LibP2PService extends WithTracer implements P2PService {
1309
1534
  return {
1310
1535
  result: TopicValidatorResult.Ignore,
1311
1536
  obj: checkpoint,
1312
- metadata: { isEquivocated, processBlock },
1537
+ metadata: { isEquivocated, processBlock, isOversized },
1313
1538
  };
1314
1539
  }
1315
1540
 
1316
- // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1541
+ // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
1317
1542
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1318
1543
  if (!added) {
1319
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1320
1544
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1321
1545
  ...checkpoint.toCheckpointInfo(),
1322
1546
  count,
1323
1547
  source: peerId.toString(),
1324
1548
  });
1325
- return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
1549
+ return {
1550
+ result: TopicValidatorResult.Reject,
1551
+ obj: checkpoint,
1552
+ metadata: { isEquivocated, processBlock, isOversized },
1553
+ severity: PeerErrorSeverity.HighToleranceError,
1554
+ };
1326
1555
  }
1327
1556
 
1328
1557
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1341,12 +1570,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1341
1570
  return {
1342
1571
  result: TopicValidatorResult.Accept,
1343
1572
  obj: checkpoint,
1344
- metadata: { isEquivocated, processBlock },
1573
+ metadata: { isEquivocated, processBlock, isOversized },
1345
1574
  };
1346
1575
  }
1347
1576
 
1348
1577
  // Otherwise, we're good to go!
1349
- return { result: TopicValidatorResult.Accept, obj: checkpoint, metadata: { processBlock, isEquivocated } };
1578
+ return {
1579
+ result: TopicValidatorResult.Accept,
1580
+ obj: checkpoint,
1581
+ metadata: { processBlock, isEquivocated, isOversized },
1582
+ };
1350
1583
  }
1351
1584
 
1352
1585
  /**
@@ -1367,9 +1600,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1367
1600
  source: sender.toString(),
1368
1601
  });
1369
1602
 
1603
+ await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
1604
+
1370
1605
  // Call the checkpoint received callback with the core version (without lastBlock)
1371
1606
  // to validate and potentially generate attestations
1372
- const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
1607
+ const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
1373
1608
  if (attestations && attestations.length > 0) {
1374
1609
  // If the callback returned attestations, add them to the pool and propagate them
1375
1610
  await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
@@ -1392,82 +1627,87 @@ export class LibP2PService extends WithTracer implements P2PService {
1392
1627
  }
1393
1628
 
1394
1629
  /**
1395
- * Validate the requested block transactions. Allow partial returns.
1630
+ * Validate the requested block transactions request-response consistency.
1631
+ * It does NOT validate the transactions themselves.
1396
1632
  * @param request - The block transactions request.
1397
1633
  * @param response - The block transactions response.
1398
1634
  * @param peerId - The ID of the peer that made the request.
1399
- * @returns True if the requested block transactions are valid, false otherwise.
1635
+ * @returns True if the request-response is consistent, false otherwise.
1400
1636
  */
1401
- @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
1637
+ @trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
1402
1638
  [Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
1403
1639
  }))
1404
- protected async validateRequestedBlockTxs(
1640
+ protected async validateRequestedBlockTxsConsistency(
1405
1641
  request: BlockTxsRequest,
1406
1642
  response: BlockTxsResponse,
1407
1643
  peerId: PeerId,
1408
1644
  ): Promise<boolean> {
1409
- const requestedTxValidator = this.createRequestedTxValidator();
1410
-
1411
1645
  try {
1412
- if (!response.archiveRoot.equals(request.archiveRoot)) {
1646
+ // Check for duplicates txs (or hashes) in the response.
1647
+ const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
1648
+ const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1649
+ if (uniqueReturned.size !== returnedHashes.length) {
1413
1650
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1414
- throw new ValidationError(
1415
- `Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
1651
+ throw new ValidationError(`Received duplicate txs in block txs response`);
1652
+ }
1653
+
1654
+ // We get the block tx hashes from the proposal or the archiver.
1655
+ const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
1656
+ const blockTxHashes =
1657
+ proposal?.txHashes ??
1658
+ (await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
1659
+
1660
+ // If we don't have the block, we can't verify membership/order of the returned txs.
1661
+ if (!blockTxHashes) {
1662
+ // This shouldn't happen, since we asked for the block (proposal).
1663
+ // Neither a local proposal nor an archived block: we cannot verify membership/order of the
1664
+ // returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
1665
+ this.logger.warn(
1666
+ `Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
1416
1667
  );
1668
+ // NOTE: We mark the response as invalid, given the limitations of a true/false return value.
1669
+ return false;
1417
1670
  }
1418
1671
 
1419
- if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1420
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1672
+ // Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
1673
+ const uniqueRequestedHashes = new Set([
1674
+ // tx hashes requested by index.
1675
+ ...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
1676
+ // explicitly requested tx hashes.
1677
+ ...request.txHashes.map(h => h.toString()),
1678
+ ]);
1679
+ if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
1680
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1421
1681
  throw new ValidationError(
1422
- `Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
1682
+ 'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
1423
1683
  );
1424
1684
  }
1425
1685
 
1426
- // Check no duplicates and not exceeding returnable count
1427
- const requestedIndices = new Set(request.txIndices.getTrueIndices());
1428
- const availableIndices = new Set(response.txIndices.getTrueIndices());
1429
- const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
1430
-
1431
- const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
1432
- const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1433
- if (uniqueReturned.size !== returnedHashes.length) {
1434
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1435
- throw new ValidationError(`Received duplicate txs in block txs response`);
1686
+ // Tx indices information is optional, but if present, we need to verify a few things.
1687
+ if (!response.peerHasBlock()) {
1688
+ this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
1689
+ return true;
1436
1690
  }
1437
- if (response.txs.length > maxReturnable) {
1691
+
1692
+ // If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
1693
+ if (response.txIndices.getLength() !== blockTxHashes.length) {
1438
1694
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1439
1695
  throw new ValidationError(
1440
- `Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
1696
+ `Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
1441
1697
  );
1442
1698
  }
1443
1699
 
1444
- // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1445
- const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
1446
- if (proposal) {
1447
- // Build intersected indices
1448
- const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1449
-
1450
- // Enforce subset membership and preserve increasing order by index.
1451
- const hashToIndexInProposal = new Map<string, number>(
1452
- proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
1453
- );
1454
- const allowedIndexSet = new Set(intersectIdx);
1455
- const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
1456
- const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
1457
- const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
1458
- if (!allAllowed || !strictlyIncreasing) {
1459
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1460
- throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1461
- }
1462
- } else {
1463
- // No local proposal, cannot check the membership/order of the returned txs
1464
- this.logger.warn(
1465
- `Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
1466
- );
1467
- return false;
1700
+ // For every index we requested that the peer claims to have (per its bitvector), the
1701
+ // corresponding tx must be present in the response. A peer advertising availability but
1702
+ // withholding the tx is inconsistent.
1703
+ const returnedHashSet = new Set(returnedHashes);
1704
+ const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1705
+ const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
1706
+ if (missingExpected) {
1707
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1708
+ throw new ValidationError('Peer advertised requested txs via indices but did not return them');
1468
1709
  }
1469
1710
 
1470
- await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
1471
1711
  return true;
1472
1712
  } catch (e: any) {
1473
1713
  if (e instanceof ValidationError) {
@@ -1480,125 +1720,8 @@ export class LibP2PService extends WithTracer implements P2PService {
1480
1720
  }
1481
1721
  }
1482
1722
 
1483
- /**
1484
- * Validate a collection of txs that has been requested from a peer.
1485
- *
1486
- * The core component of this validator is that each tx hash MUST match the requested tx hash,
1487
- * In order to perform this check, the tx proof must be verified.
1488
- *
1489
- * Note: This function is called from within `ReqResp.sendRequest` as part of the
1490
- * ReqRespSubProtocol.TX subprotocol validation.
1491
- *
1492
- * @param requestedTxHash - The collection of the txs that was requested.
1493
- * @param responseTx - The collection of txs that was received as a response to the request.
1494
- * @param peerId - The peer ID of the peer that sent the tx.
1495
- * @returns True if the whole collection of txs is valid, false otherwise.
1496
- */
1497
- @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
1498
- [Attributes.TX_HASH]: requestedTxHash.toString(),
1499
- }))
1500
- private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
1501
- const requested = new Set(requestedTxHash.map(h => h.toString()));
1502
- const requestedTxValidator = this.createRequestedTxValidator();
1503
-
1504
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
1505
- // I think we should still extract the valid txs and return them, so that we can still use the response.
1506
- try {
1507
- await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
1508
- return true;
1509
- } catch (e: any) {
1510
- if (e instanceof ValidationError) {
1511
- this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
1512
- } else {
1513
- this.logger.error(`Error during validation of requested txs`, e);
1514
- }
1515
-
1516
- return false;
1517
- }
1518
- }
1519
-
1520
- /**
1521
- * Validates a BLOCK response.
1522
- *
1523
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1524
- * Penalizes on block number mismatch or hash mismatch.
1525
- *
1526
- * @param requestedBlockNumber - The requested block number.
1527
- * @param responseBlock - The block returned by the peer.
1528
- * @param peerId - The peer that returned the block.
1529
- * @returns True if the response is valid, false otherwise.
1530
- */
1531
- @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1532
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1533
- }))
1534
- protected async validateRequestedBlock(
1535
- requestedBlockNumber: Fr,
1536
- responseBlock: L2Block,
1537
- peerId: PeerId,
1538
- ): Promise<boolean> {
1539
- try {
1540
- const reqNum = Number(requestedBlockNumber.toString());
1541
- if (responseBlock.number !== reqNum) {
1542
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1543
- return false;
1544
- }
1545
-
1546
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1547
- if (!local) {
1548
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1549
- // TODO: Consider extending this validator to accept an expected hash or
1550
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1551
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1552
- return false;
1553
- }
1554
- const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1555
- if (!localHash.equals(respHash)) {
1556
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1557
- return false;
1558
- }
1559
-
1560
- return true;
1561
- } catch (e) {
1562
- this.logger.warn(`Error validating requested block`, e);
1563
- return false;
1564
- }
1565
- }
1566
-
1567
- protected async validateRequestedTx(
1568
- tx: Tx,
1569
- peerId: PeerId,
1570
- txValidator: TxValidator,
1571
- requested?: Set<`0x${string}`>,
1572
- ) {
1573
- const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
1574
- if (requested && !requested.has(tx.getTxHash().toString())) {
1575
- penalize(PeerErrorSeverity.MidToleranceError);
1576
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1577
- }
1578
-
1579
- const { result } = await txValidator.validateTx(tx);
1580
- if (result === 'invalid') {
1581
- penalize(PeerErrorSeverity.LowToleranceError);
1582
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1583
- }
1584
- }
1585
-
1586
- protected createRequestedTxValidator(): TxValidator {
1587
- return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
1588
- l1ChainId: this.config.l1ChainId,
1589
- rollupVersion: this.config.rollupVersion,
1590
- });
1591
- }
1592
-
1593
- private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
1594
- if (blockNumber === this.feesCache?.blockNumber) {
1595
- return this.feesCache.gasFees;
1596
- }
1597
-
1598
- const header = await this.archiver.getBlockHeader(blockNumber);
1599
- const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
1600
- this.feesCache = { blockNumber, gasFees };
1601
- return gasFees;
1723
+ private getGasFees(): Promise<GasFees> {
1724
+ return this.blockMinFeesProvider.getCurrentMinFees();
1602
1725
  }
1603
1726
 
1604
1727
  /**
@@ -1612,8 +1735,10 @@ export class LibP2PService extends WithTracer implements P2PService {
1612
1735
  l1ChainId: this.config.l1ChainId,
1613
1736
  rollupVersion: this.config.rollupVersion,
1614
1737
  proofVerifier: this.proofVerifier,
1738
+ txValidationCache: this.txValidationCache,
1615
1739
  },
1616
1740
  peerScoring: this.peerManager,
1741
+ validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
1617
1742
  };
1618
1743
  }
1619
1744
 
@@ -1622,6 +1747,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1622
1747
  this.proofVerifier,
1623
1748
  { l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
1624
1749
  this.logger.getBindings(),
1750
+ this.txValidationCache,
1625
1751
  );
1626
1752
 
1627
1753
  const results = await Promise.all(
@@ -1640,13 +1766,14 @@ export class LibP2PService extends WithTracer implements P2PService {
1640
1766
  currentBlockNumber: BlockNumber,
1641
1767
  nextSlotTimestamp: UInt64,
1642
1768
  ): Promise<Record<string, TransactionValidator>> {
1643
- const gasFees = await this.getGasFees(currentBlockNumber);
1769
+ const gasFees = await this.getGasFees();
1644
1770
  const allowedInSetup = [
1645
1771
  ...(await getDefaultAllowedSetupFunctions()),
1646
1772
  ...(this.config.txPublicSetupAllowListExtend ?? []),
1647
1773
  ];
1648
1774
  const blockNumber = BlockNumber(currentBlockNumber + 1);
1649
1775
  const l1Constants = await this.archiver.getL1Constants();
1776
+ const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
1650
1777
 
1651
1778
  return createFirstStageTxValidationsForGossipedTransactions(
1652
1779
  nextSlotTimestamp,
@@ -1661,9 +1788,8 @@ export class LibP2PService extends WithTracer implements P2PService {
1661
1788
  allowedInSetup,
1662
1789
  this.logger.getBindings(),
1663
1790
  {
1664
- rollupManaLimit: l1Constants.rollupManaLimit,
1665
- maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1666
- maxBlockDAGas: this.config.validateMaxDABlockGas,
1791
+ maxTxL2Gas: networkTxGasLimits.l2Gas,
1792
+ maxTxDAGas: networkTxGasLimits.daGas,
1667
1793
  },
1668
1794
  );
1669
1795
  }