@aztec/p2p 0.0.1-commit.4d3c002 → 0.0.1-commit.4d9804df

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) 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 +33 -24
  8. package/dest/client/interface.d.ts +40 -10
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +32 -18
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +97 -51
  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/reqresp.error.d.ts +9 -16
  17. package/dest/errors/reqresp.error.d.ts.map +1 -1
  18. package/dest/errors/reqresp.error.js +10 -17
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +98 -56
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.js +270 -198
  22. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +218 -59
  25. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
  26. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/mocks.js +6 -4
  28. package/dest/mem_pools/instrumentation.d.ts +9 -4
  29. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  30. package/dest/mem_pools/instrumentation.js +28 -9
  31. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  32. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  33. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  34. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +3 -3
  35. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  36. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +6 -6
  37. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +1 -1
  38. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
  39. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
  41. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  42. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  43. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  44. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  45. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +33 -5
  46. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  48. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -2
  49. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +8 -5
  51. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +15 -1
  52. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +31 -0
  54. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -3
  55. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +19 -8
  57. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +17 -4
  58. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +208 -118
  60. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
  61. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  62. package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -16
  63. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  64. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  65. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  66. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +8 -3
  67. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  68. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +2 -2
  69. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +8 -3
  70. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  71. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +8 -2
  72. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +25 -3
  73. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  74. package/dest/msg_validators/proposal_validator/proposal_validator.js +85 -15
  75. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  76. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  77. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +8 -15
  78. package/dest/msg_validators/tx_validator/allowed_public_setup.js +3 -3
  79. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  80. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  81. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  82. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  83. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  84. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  85. package/dest/msg_validators/tx_validator/data_validator.js +1 -0
  86. package/dest/msg_validators/tx_validator/factory.d.ts +14 -15
  87. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  88. package/dest/msg_validators/tx_validator/factory.js +29 -16
  89. package/dest/msg_validators/tx_validator/gas_validator.d.ts +47 -10
  90. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/gas_validator.js +65 -48
  92. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  93. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  94. package/dest/msg_validators/tx_validator/index.js +2 -0
  95. package/dest/msg_validators/tx_validator/phases_validator.js +2 -2
  96. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  97. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  99. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  100. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  101. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  102. package/dest/services/data_store.d.ts +1 -1
  103. package/dest/services/data_store.d.ts.map +1 -1
  104. package/dest/services/data_store.js +5 -5
  105. package/dest/services/discv5/discV5_service.d.ts +13 -2
  106. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  107. package/dest/services/discv5/discV5_service.js +117 -24
  108. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  109. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  110. package/dest/services/discv5/persisted_enr_store.js +145 -0
  111. package/dest/services/dummy_service.d.ts +15 -17
  112. package/dest/services/dummy_service.d.ts.map +1 -1
  113. package/dest/services/dummy_service.js +13 -18
  114. package/dest/services/encoding.d.ts +19 -6
  115. package/dest/services/encoding.d.ts.map +1 -1
  116. package/dest/services/encoding.js +25 -15
  117. package/dest/services/gossipsub/topic_score_params.d.ts +6 -12
  118. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  119. package/dest/services/gossipsub/topic_score_params.js +4 -14
  120. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  121. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  122. package/dest/services/libp2p/instrumentation.js +14 -0
  123. package/dest/services/libp2p/libp2p_service.d.ts +31 -38
  124. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  125. package/dest/services/libp2p/libp2p_service.js +268 -248
  126. package/dest/services/peer-manager/peer_manager.d.ts +15 -2
  127. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  128. package/dest/services/peer-manager/peer_manager.js +59 -17
  129. package/dest/services/peer-manager/peer_scoring.d.ts +30 -1
  130. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  131. package/dest/services/peer-manager/peer_scoring.js +74 -3
  132. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -8
  133. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  134. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +35 -44
  135. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +8 -5
  136. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  137. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  138. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  139. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  140. package/dest/services/reqresp/config.d.ts +15 -3
  141. package/dest/services/reqresp/config.d.ts.map +1 -1
  142. package/dest/services/reqresp/config.js +11 -0
  143. package/dest/services/reqresp/interface.d.ts +16 -18
  144. package/dest/services/reqresp/interface.d.ts.map +1 -1
  145. package/dest/services/reqresp/interface.js +10 -20
  146. package/dest/services/reqresp/metrics.d.ts +1 -1
  147. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  148. package/dest/services/reqresp/metrics.js +0 -1
  149. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  150. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  151. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  152. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  153. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  154. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  155. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
  156. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  157. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
  158. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  159. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  160. package/dest/services/reqresp/protocols/index.js +0 -1
  161. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  162. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  163. package/dest/services/reqresp/protocols/tx.js +1 -3
  164. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  165. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  166. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  167. package/dest/services/reqresp/reqresp.d.ts +7 -29
  168. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  169. package/dest/services/reqresp/reqresp.js +59 -209
  170. package/dest/services/service.d.ts +21 -13
  171. package/dest/services/service.d.ts.map +1 -1
  172. package/dest/services/tx_collection/config.d.ts +2 -23
  173. package/dest/services/tx_collection/config.d.ts.map +1 -1
  174. package/dest/services/tx_collection/config.js +2 -55
  175. package/dest/services/tx_collection/file_store_tx_collection.d.ts +12 -28
  176. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  177. package/dest/services/tx_collection/file_store_tx_collection.js +43 -83
  178. package/dest/services/tx_collection/index.d.ts +2 -3
  179. package/dest/services/tx_collection/index.d.ts.map +1 -1
  180. package/dest/services/tx_collection/index.js +0 -1
  181. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  182. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  183. package/dest/services/tx_collection/instrumentation.js +0 -2
  184. package/dest/services/tx_collection/tx_collection.d.ts +35 -51
  185. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  186. package/dest/services/tx_collection/tx_collection.js +275 -119
  187. package/dest/services/tx_collection/tx_collection_sink.d.ts +1 -1
  188. package/dest/services/tx_collection/tx_collection_sink.js +2 -2
  189. package/dest/services/tx_collection/tx_source.d.ts +1 -1
  190. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  191. package/dest/services/tx_collection/tx_source.js +4 -1
  192. package/dest/services/tx_file_store/tx_file_store.d.ts +1 -3
  193. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  194. package/dest/services/tx_file_store/tx_file_store.js +4 -14
  195. package/dest/services/tx_provider.d.ts +3 -1
  196. package/dest/services/tx_provider.d.ts.map +1 -1
  197. package/dest/services/tx_provider.js +3 -0
  198. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  199. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  200. package/dest/test-helpers/make-test-p2p-clients.js +5 -2
  201. package/dest/test-helpers/mock-pubsub.d.ts +16 -9
  202. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  203. package/dest/test-helpers/mock-pubsub.js +36 -43
  204. package/dest/test-helpers/reqresp-nodes.d.ts +4 -5
  205. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  206. package/dest/test-helpers/reqresp-nodes.js +11 -17
  207. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  208. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  209. package/dest/test-helpers/test_tx_provider.js +3 -0
  210. package/dest/test-helpers/testbench-utils.d.ts +15 -14
  211. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  212. package/dest/test-helpers/testbench-utils.js +28 -13
  213. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  214. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  215. package/dest/testbench/p2p_client_testbench_worker.js +60 -27
  216. package/dest/testbench/worker_client_manager.d.ts +10 -6
  217. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  218. package/dest/testbench/worker_client_manager.js +51 -8
  219. package/dest/util.d.ts +7 -6
  220. package/dest/util.d.ts.map +1 -1
  221. package/dest/util.js +39 -10
  222. package/dest/versioning.d.ts +3 -6
  223. package/dest/versioning.d.ts.map +1 -1
  224. package/dest/versioning.js +3 -24
  225. package/package.json +16 -16
  226. package/src/bootstrap/bootstrap.ts +17 -3
  227. package/src/client/factory.ts +49 -25
  228. package/src/client/interface.ts +35 -16
  229. package/src/client/p2p_client.ts +116 -85
  230. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  231. package/src/config.ts +146 -34
  232. package/src/errors/reqresp.error.ts +13 -19
  233. package/src/mem_pools/attestation_pool/attestation_pool.ts +325 -242
  234. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +238 -63
  235. package/src/mem_pools/attestation_pool/mocks.ts +13 -8
  236. package/src/mem_pools/instrumentation.ts +18 -12
  237. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  238. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +7 -7
  239. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +1 -1
  240. package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
  241. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  242. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
  243. package/src/mem_pools/tx_pool_v2/interfaces.ts +31 -4
  244. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +13 -7
  245. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +35 -0
  246. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +22 -8
  247. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +233 -123
  248. package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -15
  249. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
  250. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +15 -3
  251. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +26 -3
  252. package/src/msg_validators/proposal_validator/proposal_validator.ts +94 -12
  253. package/src/msg_validators/tx_validator/README.md +13 -3
  254. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -12
  255. package/src/msg_validators/tx_validator/allowed_public_setup.ts +3 -3
  256. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  257. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  258. package/src/msg_validators/tx_validator/data_validator.ts +2 -0
  259. package/src/msg_validators/tx_validator/factory.ts +37 -20
  260. package/src/msg_validators/tx_validator/gas_validator.ts +99 -54
  261. package/src/msg_validators/tx_validator/index.ts +2 -0
  262. package/src/msg_validators/tx_validator/phases_validator.ts +2 -2
  263. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  264. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  265. package/src/services/data_store.ts +5 -13
  266. package/src/services/discv5/discV5_service.ts +124 -15
  267. package/src/services/discv5/persisted_enr_store.ts +158 -0
  268. package/src/services/dummy_service.ts +19 -43
  269. package/src/services/encoding.ts +28 -20
  270. package/src/services/gossipsub/README.md +33 -11
  271. package/src/services/gossipsub/topic_score_params.ts +9 -18
  272. package/src/services/libp2p/instrumentation.ts +14 -0
  273. package/src/services/libp2p/libp2p_service.ts +311 -271
  274. package/src/services/peer-manager/peer_manager.ts +63 -16
  275. package/src/services/peer-manager/peer_scoring.ts +81 -3
  276. package/src/services/reqresp/README.md +2 -37
  277. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +39 -52
  278. package/src/services/reqresp/batch-tx-requester/interface.ts +11 -4
  279. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  280. package/src/services/reqresp/config.ts +19 -2
  281. package/src/services/reqresp/interface.ts +21 -47
  282. package/src/services/reqresp/metrics.ts +0 -1
  283. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  284. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
  285. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
  286. package/src/services/reqresp/protocols/index.ts +0 -1
  287. package/src/services/reqresp/protocols/tx.ts +1 -3
  288. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  289. package/src/services/reqresp/reqresp.ts +69 -252
  290. package/src/services/service.ts +25 -30
  291. package/src/services/tx_collection/config.ts +3 -80
  292. package/src/services/tx_collection/file_store_tx_collection.ts +54 -103
  293. package/src/services/tx_collection/index.ts +1 -6
  294. package/src/services/tx_collection/instrumentation.ts +1 -7
  295. package/src/services/tx_collection/tx_collection.ts +330 -173
  296. package/src/services/tx_collection/tx_collection_sink.ts +2 -2
  297. package/src/services/tx_collection/tx_source.ts +2 -1
  298. package/src/services/tx_file_store/tx_file_store.ts +5 -17
  299. package/src/services/tx_provider.ts +5 -0
  300. package/src/test-helpers/make-test-p2p-clients.ts +3 -0
  301. package/src/test-helpers/mock-pubsub.ts +39 -60
  302. package/src/test-helpers/reqresp-nodes.ts +8 -22
  303. package/src/test-helpers/test_tx_provider.ts +5 -0
  304. package/src/test-helpers/testbench-utils.ts +35 -26
  305. package/src/testbench/p2p_client_testbench_worker.ts +68 -44
  306. package/src/testbench/worker_client_manager.ts +59 -19
  307. package/src/util.ts +34 -12
  308. package/src/versioning.ts +3 -33
  309. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  310. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  311. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -315
  312. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  313. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  314. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  315. package/dest/msg_validators/clock_tolerance.d.ts +0 -21
  316. package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
  317. package/dest/msg_validators/clock_tolerance.js +0 -38
  318. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  319. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  320. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  321. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  322. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  323. package/dest/services/reqresp/protocols/block.js +0 -32
  324. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -51
  325. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  326. package/dest/services/tx_collection/fast_tx_collection.js +0 -311
  327. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
  328. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  329. package/dest/services/tx_collection/proposal_tx_collector.js +0 -50
  330. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -57
  331. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  332. package/dest/services/tx_collection/slow_tx_collection.js +0 -211
  333. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -355
  334. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  335. package/src/msg_validators/clock_tolerance.ts +0 -52
  336. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  337. package/src/services/reqresp/protocols/block.ts +0 -37
  338. package/src/services/tx_collection/fast_tx_collection.ts +0 -361
  339. package/src/services/tx_collection/proposal_tx_collector.ts +0 -108
  340. package/src/services/tx_collection/slow_tx_collection.ts +0 -266
@@ -370,15 +370,17 @@ function applyDecs2203RFactory() {
370
370
  function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
371
371
  return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
372
372
  }
373
- var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _initProto;
373
+ var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _initProto;
374
374
  import { BlockNumber } from '@aztec/foundation/branded-types';
375
- import { maxBy } from '@aztec/foundation/collection';
375
+ import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
376
376
  import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
377
377
  import { RunningPromise } from '@aztec/foundation/running-promise';
378
378
  import { Timer } from '@aztec/foundation/timer';
379
379
  import { protocolContractsHash } from '@aztec/protocol-contracts';
380
- import { GasFees } from '@aztec/stdlib/gas';
380
+ import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
381
+ import { getNetworkTxGasLimits } from '@aztec/stdlib/gas';
381
382
  import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PMessage, PeerErrorSeverity, PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
383
+ import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
382
384
  import { MerkleTreeId } from '@aztec/stdlib/trees';
383
385
  import { Tx } from '@aztec/stdlib/tx';
384
386
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
@@ -399,20 +401,33 @@ import { createLibp2p } from 'libp2p';
399
401
  import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
400
402
  import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
401
403
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
402
- import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs, createTxValidatorForReqResponseReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
404
+ import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
403
405
  import { GossipSubEvent } from '../../types/index.js';
404
406
  import { convertToMultiaddr } from '../../util.js';
405
407
  import { getVersions } from '../../versioning.js';
406
408
  import { AztecDatastore } from '../data_store.js';
407
409
  import { DiscV5Service } from '../discv5/discV5_service.js';
408
- import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
410
+ import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
409
411
  import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
410
412
  import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
411
413
  import { PeerManager } from '../peer-manager/peer_manager.js';
412
414
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
413
- import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
415
+ import { YAMUX_MAX_MESSAGE_SIZE_BYTES } from '../reqresp/config.js';
416
+ import { ReqRespSubProtocol, ValidationError, pingHandler, reqGoodbyeHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
414
417
  import { ReqResp } from '../reqresp/reqresp.js';
415
418
  import { P2PInstrumentation } from './instrumentation.js';
419
+ /**
420
+ * Builds the {@link ConsensusTimetable} shared by the gossip validators for proposal/attestation receive-window
421
+ * bounds. Derived purely from protocol slot-timing constants plus the block sub-slot duration and the consensus
422
+ * materialization grace, so every node agrees on these bounds without depending on proposer operational budgets.
423
+ */ function buildConsensusTimetable(config, l1Constants) {
424
+ const blockDuration = config.blockDurationMs / 1000;
425
+ return new ConsensusTimetable({
426
+ l1Constants,
427
+ blockDuration,
428
+ checkpointProposalSyncGrace: config.checkpointProposalSyncGraceSeconds ?? getDefaultCheckpointProposalSyncGrace(blockDuration)
429
+ });
430
+ }
416
431
  _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
417
432
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString()
418
433
  })), _dec1 = trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block)=>({
@@ -428,12 +443,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
428
443
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
429
444
  [Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
430
445
  [Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then((i)=>i.toString())
431
- })), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxs', (request)=>({
446
+ })), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', (request)=>({
432
447
  [Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
433
- })), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
434
- [Attributes.TX_HASH]: requestedTxHash.toString()
435
- })), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
436
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
437
448
  }));
438
449
  /**
439
450
  * Lib P2P implementation of the P2PService interface.
@@ -448,6 +459,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
448
459
  epochCache;
449
460
  proofVerifier;
450
461
  worldStateSynchronizer;
462
+ blockMinFeesProvider;
463
+ txValidationCache;
451
464
  static{
452
465
  ({ e: [_initProto] } = _apply_decs_2203_r(this, [
453
466
  [
@@ -478,17 +491,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
478
491
  [
479
492
  _dec5,
480
493
  2,
481
- "validateRequestedBlockTxs"
482
- ],
483
- [
484
- _dec6,
485
- 2,
486
- "validateRequestedTxs"
487
- ],
488
- [
489
- _dec7,
490
- 2,
491
- "validateRequestedBlock"
494
+ "validateRequestedBlockTxsConsistency"
492
495
  ]
493
496
  ], []));
494
497
  }
@@ -500,9 +503,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
500
503
  checkpointAttestationValidator;
501
504
  protocolVersion;
502
505
  topicStrings;
503
- feesCache;
504
506
  /** Callback invoked when a duplicate proposal is detected (triggers slashing). */ duplicateProposalCallback;
507
+ /** Callback invoked when an oversized block proposal is stored as slashing evidence (triggers slashing). */ oversizedProposalCallback;
505
508
  /** Callback invoked when a duplicate attestation is detected (triggers slashing). */ duplicateAttestationCallback;
509
+ /** Callback invoked when a valid checkpoint attestation is accepted into the pool. */ checkpointAttestationCallback;
506
510
  /**
507
511
  * Callback for when a block is received from a peer.
508
512
  * @param block - The block received from the peer.
@@ -524,8 +528,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
524
528
  instrumentation;
525
529
  telemetry;
526
530
  logger;
527
- constructor(config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
528
- super(telemetry, 'LibP2PService'), this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.msgIdSeenValidators = (_initProto(this), {}), this.protocolVersion = '', this.topicStrings = {};
531
+ constructor(config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger = createLogger('p2p:libp2p_service'), txValidationCache){
532
+ super(telemetry, 'LibP2PService'), this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.blockMinFeesProvider = blockMinFeesProvider, this.txValidationCache = txValidationCache, this.msgIdSeenValidators = (_initProto(this), {}), this.protocolVersion = '', this.topicStrings = {};
529
533
  this.telemetry = telemetry;
530
534
  // Create child logger with fisherman prefix if in fisherman mode
531
535
  this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
@@ -541,13 +545,27 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
541
545
  this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
542
546
  this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
543
547
  this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
548
+ // Build the consensus timetable once from protocol slot-timing constants and inject it into every
549
+ // validator so they share one set of receive-window bounds, independent of proposer operational budgets.
550
+ const consensusTimetable = buildConsensusTimetable(config, epochCache.getL1Constants());
544
551
  const proposalValidatorOpts = {
545
552
  txsPermitted: !config.disableTransactions,
546
- maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint
553
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
554
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
555
+ skipSlotValidation: config.skipProposalSlotValidation,
556
+ signatureContext: {
557
+ chainId: config.l1ChainId,
558
+ rollupAddress: config.rollupAddress
559
+ },
560
+ clockDisparityMs: config.maxGossipClockDisparityMs
547
561
  };
548
- this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
549
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
550
- this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry) : new CheckpointAttestationValidator(epochCache);
562
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
563
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, consensusTimetable, proposalValidatorOpts);
564
+ const attestationValidatorOpts = {
565
+ signatureContext: proposalValidatorOpts.signatureContext,
566
+ clockDisparityMs: config.maxGossipClockDisparityMs
567
+ };
568
+ this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, consensusTimetable, mempools.attestationPool, telemetry, attestationValidatorOpts) : new CheckpointAttestationValidator(epochCache, consensusTimetable, attestationValidatorOpts);
551
569
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
552
570
  this.blockReceivedCallback = async (block)=>{
553
571
  this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
@@ -564,6 +582,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
564
582
  }
565
583
  updateConfig(config) {
566
584
  this.reqresp.updateConfig(config);
585
+ this.config = merge(this.config, config);
567
586
  }
568
587
  /**
569
588
  * Creates an instance of the LibP2P service.
@@ -571,12 +590,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
571
590
  * @param txPool - The transaction pool to be accessed by the service.
572
591
  * @returns The new service.
573
592
  */ static async new(config, peerId, deps) {
574
- const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, telemetry, logger, packageVersion } = deps;
593
+ const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, blockMinFeesProvider, telemetry, logger, packageVersion, txValidationCache } = deps;
575
594
  const { p2pPort, maxPeerCount, listenAddress } = config;
576
595
  const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
577
596
  const datastore = new AztecDatastore(peerStore);
578
597
  const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
579
- const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()));
598
+ const peerDiscoveryService = new DiscV5Service(peerId, config, packageVersion, telemetry, createLogger(`${logger.module}:discv5_service`, logger.getBindings()), peerStore);
580
599
  // Seed libp2p's bootstrap discovery with private and trusted peers
581
600
  const bootstrapNodes = [
582
601
  ...config.privatePeers,
@@ -591,31 +610,45 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
591
610
  const versions = getVersions(config);
592
611
  const protocolVersion = compressComponentVersions(versions);
593
612
  const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
594
- const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
595
- const peerId = await enr.peerId();
596
- const address = enr.getLocationMultiaddr('tcp');
597
- if (address === undefined) {
598
- throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
613
+ const directPeers = compactArray(await Promise.all(preferredPeersEnrs.map(async (enr)=>{
614
+ try {
615
+ const peerId = await enr.peerId();
616
+ const address = enr.getLocationMultiaddr('tcp');
617
+ if (address === undefined) {
618
+ throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
619
+ }
620
+ return {
621
+ id: peerId,
622
+ addrs: [
623
+ address
624
+ ]
625
+ };
626
+ } catch (err) {
627
+ // A malformed configured ENR shouldn't abort node setup — skip it and log.
628
+ logger.warn(`Skipping preferred peer with invalid ENR`, {
629
+ err
630
+ });
631
+ return undefined;
599
632
  }
600
- return {
601
- id: peerId,
602
- addrs: [
603
- address
604
- ]
605
- };
606
- }))).filter((peer)=>peer !== undefined);
633
+ })));
607
634
  const announceTcpMultiaddr = config.p2pIp ? [
608
635
  convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
609
636
  ] : [];
610
- // Create dynamic topic score params based on network configuration
637
+ // Create dynamic topic score params based on network configuration. Scoring uses the network-wide
638
+ // max-blocks-per-checkpoint config value directly to size expected per-slot message rates; these are
639
+ // peer-rate thresholds, not consensus deadlines, so they need no proposer operational budgets.
611
640
  const l1Constants = epochCache.getL1Constants();
612
641
  const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
613
642
  slotDurationMs: l1Constants.slotDuration * 1000,
614
643
  heartbeatIntervalMs: config.gossipsubInterval,
615
644
  targetCommitteeSize: l1Constants.targetCommitteeSize,
616
- blockDurationMs: config.blockDurationMs,
645
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
617
646
  expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
618
647
  });
648
+ // Restrict gossipsub to exactly the topics we subscribe to. Without this, an arbitrary-topic
649
+ // message is transformed, msg-id'd and inserted into the seenCache before the subscription check,
650
+ // so a crafted topic colliding on msg id can suppress a real message as a duplicate.
651
+ const allowedTopics = getTopicsForConfig(config.disableTransactions).map((topic)=>createTopicString(topic, protocolVersion));
619
652
  const node = await createLibp2p({
620
653
  start: false,
621
654
  peerId,
@@ -649,8 +682,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
649
682
  ],
650
683
  datastore,
651
684
  peerDiscovery,
685
+ // Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
652
686
  streamMuxers: [
653
- yamux(),
687
+ yamux({
688
+ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES
689
+ }),
654
690
  mplex()
655
691
  ],
656
692
  connectionEncryption: [
@@ -668,7 +704,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
668
704
  },
669
705
  connectionGater: {
670
706
  denyInboundConnection: (maConn)=>{
671
- const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
707
+ const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
672
708
  if (allowed) {
673
709
  return false;
674
710
  }
@@ -678,7 +714,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
678
714
  denyInboundEncryptedConnection: (peerId, _maConn)=>{
679
715
  //NOTE: it is not necessary to check address here because this was already done by
680
716
  // denyInboundConnection
681
- const allowed = peerManager.isNodeAllowedToConnect(peerId);
717
+ const allowed = peerManager.isPeerAllowedToConnect(peerId);
682
718
  if (allowed) {
683
719
  return false;
684
720
  }
@@ -705,9 +741,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
705
741
  mcacheLength: config.gossipsubMcacheLength,
706
742
  mcacheGossip: config.gossipsubMcacheGossip,
707
743
  seenTTL: config.gossipsubSeenTTL,
744
+ allowedTopics,
745
+ // No fastMsgIdFn: the fast-path dedup cache keys on a non-cryptographic 64-bit hash of the
746
+ // raw data only (no topic), so a collision — accidental or engineered via a weak seed — drops
747
+ // a different message with no fallback to the full id. Dedup instead rests solely on the
748
+ // cryptographic, topic-framed msgIdFn below.
708
749
  msgIdFn: getMsgIdFn,
709
750
  msgIdToStrFn: msgIdToStrFn,
710
- fastMsgIdFn: fastMsgIdFn,
711
751
  dataTransform: new SnappyTransform(),
712
752
  metricsRegister: otelMetricsAdapter,
713
753
  metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
@@ -729,6 +769,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
729
769
  const peerScoring = new PeerScoring(config, telemetry);
730
770
  const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
731
771
  const peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, reqresp, worldStateSynchronizer, protocolVersion, epochCache);
772
+ // Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
773
+ reqresp.setShouldRejectPeer((peerId)=>peerManager.shouldDisableP2PGossip(peerId));
732
774
  // Configure application-specific scoring for gossipsub.
733
775
  // The weight scales app score to align with gossipsub thresholds:
734
776
  // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
@@ -736,7 +778,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
736
778
  // Note: positive topic scores can offset penalties, so alignment is best-effort.
737
779
  node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
738
780
  node.services.pubsub.score.params.appSpecificScore = (peerId)=>peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
739
- return new LibP2PService(config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger);
781
+ return new LibP2PService(config, node, peerDiscoveryService, reqresp, peerManager, mempools, l2BlockSource, epochCache, proofVerifier, worldStateSynchronizer, blockMinFeesProvider, telemetry, logger, txValidationCache);
740
782
  }
741
783
  /**
742
784
  * Starts the LibP2P service.
@@ -754,13 +796,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
754
796
  // Create request response protocol handlers
755
797
  const txHandler = reqRespTxHandler(this.mempools);
756
798
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
757
- const blockHandler = reqRespBlockHandler(this.archiver);
758
799
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
759
800
  const requestResponseHandlers = {
760
801
  [ReqRespSubProtocol.PING]: pingHandler,
761
802
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
762
- [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
763
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
803
+ [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
764
804
  };
765
805
  if (!this.config.disableTransactions) {
766
806
  const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
@@ -769,15 +809,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
769
809
  if (!this.config.disableTransactions) {
770
810
  requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
771
811
  }
772
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
773
- const reqrespSubProtocolValidators = {
774
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
775
- [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
776
- [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
777
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
778
- };
779
812
  await this.peerManager.initializePeers();
780
- await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
813
+ await this.reqresp.start(requestResponseHandlers);
781
814
  await this.node.start();
782
815
  // Subscribe to standard GossipSub topics by default
783
816
  for (const topic of getTopicsForConfig(this.config.disableTransactions)){
@@ -791,19 +824,29 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
791
824
  }
792
825
  // Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
793
826
  if (this.config.queryForIp) {
827
+ this.discoveredP2pIp = this.config.p2pIp;
828
+ this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
794
829
  this.ipChangedHandler = (ip)=>{
795
830
  const addressManager = this.node.services.components.addressManager;
796
831
  const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
797
- if (this.discoveredP2pIp) {
798
- const oldAddr = multiaddr(convertToMultiaddr(this.discoveredP2pIp, this.config.p2pPort, 'tcp'));
832
+ const previousIp = this.discoveredP2pIp;
833
+ if (previousIp) {
834
+ const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
799
835
  addressManager.removeObservedAddr(oldAddr);
836
+ this.logger.info('Libp2p announce address updated due to IP change', {
837
+ previousIp,
838
+ newIp: ip,
839
+ newMultiaddr: newAddr.toString()
840
+ });
841
+ } else {
842
+ this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
843
+ ip,
844
+ multiaddr: newAddr.toString()
845
+ });
800
846
  }
801
847
  addressManager.addObservedAddr(newAddr);
802
848
  addressManager.confirmObservedAddr(newAddr);
803
849
  this.discoveredP2pIp = ip;
804
- this.logger.info('Public IP discovered via discv5', {
805
- ip
806
- });
807
850
  };
808
851
  this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
809
852
  }
@@ -841,8 +884,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
841
884
  await this.stopLibP2P();
842
885
  this.logger.info('LibP2P service stopped');
843
886
  }
844
- addReqRespSubProtocol(subProtocol, handler, validator) {
845
- return this.reqresp.addSubProtocol(subProtocol, handler, validator);
887
+ addReqRespSubProtocol(subProtocol, handler) {
888
+ return this.reqresp.addSubProtocol(subProtocol, handler);
846
889
  }
847
890
  registerThisValidatorAddresses(address) {
848
891
  this.peerManager.registerThisValidatorAddresses(address);
@@ -864,14 +907,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
864
907
  };
865
908
  setImmediate(()=>void safeJob());
866
909
  }
867
- /**
868
- * Send a batch of requests to peers, and return the responses
869
- * @param protocol - The request response protocol to use
870
- * @param requests - The requests to send to the peers
871
- * @returns The responses to the requests
872
- */ sendBatchRequest(protocol, requests, pinnedPeerId) {
873
- return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
874
- }
875
910
  sendRequestToPeer(peerId, subProtocol, payload, dialTimeout) {
876
911
  return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
877
912
  }
@@ -890,9 +925,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
890
925
  registerAllNodesCheckpointReceivedCallback(callback) {
891
926
  this.allNodesCheckpointReceivedCallback = callback;
892
927
  }
893
- async notifyOwnCheckpointProposal(checkpoint) {
894
- await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
895
- }
896
928
  /**
897
929
  * Registers a callback to be invoked when a duplicate proposal is detected.
898
930
  * This callback is triggered on the first duplicate (when count goes from 1 to 2).
@@ -900,12 +932,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
900
932
  this.duplicateProposalCallback = callback;
901
933
  }
902
934
  /**
935
+ * Registers a callback to be invoked when an oversized block proposal is stored as slashing evidence.
936
+ */ registerOversizedProposalCallback(callback) {
937
+ this.oversizedProposalCallback = callback;
938
+ }
939
+ /**
903
940
  * Registers a callback to be invoked when a duplicate attestation is detected.
904
941
  * A validator signing attestations for different proposals at the same slot.
905
942
  * This callback is triggered on the first duplicate (when count goes from 1 to 2).
906
943
  */ registerDuplicateAttestationCallback(callback) {
907
944
  this.duplicateAttestationCallback = callback;
908
945
  }
946
+ registerCheckpointAttestationCallback(callback) {
947
+ this.checkpointAttestationCallback = callback;
948
+ }
909
949
  /**
910
950
  * Subscribes to a topic.
911
951
  * @param topic - The topic to subscribe to.
@@ -1020,6 +1060,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1020
1060
  }
1021
1061
  // Process the message, optionally within a linked span for trace propagation
1022
1062
  const processMessage = async ()=>{
1063
+ if (this.config.skipIncomingProposals && (msg.topic === this.topicStrings[TopicType.block_proposal] || msg.topic === this.topicStrings[TopicType.checkpoint_proposal])) {
1064
+ this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, {
1065
+ topic: msg.topic
1066
+ });
1067
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
1068
+ return;
1069
+ }
1023
1070
  if (msg.topic === this.topicStrings[TopicType.tx]) {
1024
1071
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
1025
1072
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
@@ -1083,6 +1130,18 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1083
1130
  topicType
1084
1131
  });
1085
1132
  }
1133
+ const validationTimeMs = timer.ms();
1134
+ const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
1135
+ if (validationTimeMs > mcacheWindowMs * 0.75) {
1136
+ this.instrumentation.incSlowValidation(topicType);
1137
+ this.logger.warn(`Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` + `Message forwarding may be skipped if validation exceeds the window.`, {
1138
+ msgId,
1139
+ source: source.toString(),
1140
+ topicType,
1141
+ validationTimeMs,
1142
+ mcacheWindowMs
1143
+ });
1144
+ }
1086
1145
  if (resultAndObj.result === TopicValidatorResult.Accept) {
1087
1146
  this.logger.debug(`Message ${topicType} accepted by validator`, {
1088
1147
  msgId,
@@ -1317,15 +1376,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1317
1376
  }
1318
1377
  }
1319
1378
  // Attestation was added successfully - accept it so other nodes can also detect the equivocation
1379
+ this.checkpointAttestationCallback?.(attestation);
1320
1380
  return {
1321
1381
  result: TopicValidatorResult.Accept,
1322
1382
  obj: attestation
1323
1383
  };
1324
1384
  }
1325
1385
  async processBlockFromPeer(payloadData, msgId, source) {
1326
- const { result, obj: block, metadata: { isEquivocated } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
1327
- // If not accepted or equivocated, return
1328
- if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
1386
+ const { result, obj: block, metadata: { isEquivocated, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
1387
+ // If not accepted, equivocated, or oversized, return. Oversized proposals are re-broadcast as
1388
+ // slashing evidence but never attested or processed.
1389
+ if (result !== TopicValidatorResult.Accept || !block || isEquivocated || isOversized) {
1329
1390
  return;
1330
1391
  }
1331
1392
  await this.processValidBlockProposal(block, source);
@@ -1348,6 +1409,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1348
1409
  // Try to add the proposal: this handles existence check, cap check, and adding in one call
1349
1410
  const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1350
1411
  const isEquivocated = count !== undefined && count > 1;
1412
+ // An oversized proposal (index at or beyond the consensus per-checkpoint limit) is structurally valid
1413
+ // proposer misbehavior: it is stored and re-broadcast as slashing evidence but never processed or
1414
+ // attested to. No-ops when maxBlocksPerCheckpoint is unset (local/test).
1415
+ const isOversized = this.config.maxBlocksPerCheckpoint !== undefined && block.indexWithinCheckpoint >= this.config.maxBlocksPerCheckpoint;
1351
1416
  // Duplicate proposal received, no need to re-broadcast
1352
1417
  if (alreadyExists) {
1353
1418
  this.logger.debug(`Ignoring duplicate block proposal received`, {
@@ -1360,7 +1425,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1360
1425
  result: TopicValidatorResult.Ignore,
1361
1426
  obj: block,
1362
1427
  metadata: {
1363
- isEquivocated
1428
+ isEquivocated,
1429
+ isOversized
1364
1430
  }
1365
1431
  };
1366
1432
  }
@@ -1376,11 +1442,30 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1376
1442
  return {
1377
1443
  result: TopicValidatorResult.Reject,
1378
1444
  metadata: {
1379
- isEquivocated
1445
+ isEquivocated,
1446
+ isOversized
1380
1447
  },
1381
1448
  severity: PeerErrorSeverity.HighToleranceError
1382
1449
  };
1383
1450
  }
1451
+ // The proposal was stored: if oversized, invoke the oversized callback so the proposer can be
1452
+ // slashed. Fired alongside (not instead of) equivocation detection below.
1453
+ if (isOversized) {
1454
+ const proposer = block.getSender();
1455
+ if (proposer) {
1456
+ this.logger.warn(`Detected oversized block proposal at slot ${block.slotNumber}`, {
1457
+ ...block.toBlockInfo(),
1458
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
1459
+ maxBlocksPerCheckpoint: this.config.maxBlocksPerCheckpoint,
1460
+ source: peerId.toString(),
1461
+ proposer: proposer.toString()
1462
+ });
1463
+ this.oversizedProposalCallback?.({
1464
+ slot: block.slotNumber,
1465
+ proposer
1466
+ });
1467
+ }
1468
+ }
1384
1469
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
1385
1470
  // and do re-broadcast it so other nodes in the network know to slash the proposer
1386
1471
  if (isEquivocated) {
@@ -1402,14 +1487,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1402
1487
  result: TopicValidatorResult.Accept,
1403
1488
  obj: block,
1404
1489
  metadata: {
1405
- isEquivocated
1490
+ isEquivocated,
1491
+ isOversized
1406
1492
  }
1407
1493
  };
1408
1494
  }
1409
1495
  // Otherwise, we're good to go!
1410
1496
  return {
1411
1497
  result: TopicValidatorResult.Accept,
1412
- obj: block
1498
+ obj: block,
1499
+ metadata: {
1500
+ isEquivocated: false,
1501
+ isOversized
1502
+ }
1413
1503
  };
1414
1504
  }
1415
1505
  // REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
@@ -1428,22 +1518,35 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1428
1518
  const isValid = await this.blockReceivedCallback(block, sender);
1429
1519
  if (!isValid) {
1430
1520
  this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1521
+ // Release the protections this proposal created so its txs return to pending. Only entries still
1522
+ // keyed to this slot are cleared, so a tx referenced by a live proposal at another slot stays protected.
1523
+ await this.mempools.txPool.unprotectTxs(block.txHashes, slot);
1431
1524
  }
1432
1525
  }
1433
1526
  /**
1434
1527
  * Handle a gossiped checkpoint proposal.
1435
1528
  * Validates and processes the checkpoint proposal, then triggers the callback for attestation.
1436
1529
  */ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
1437
- const { result, obj: checkpoint, metadata: { isEquivocated, processBlock } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
1530
+ const { result, obj: checkpoint, metadata: { isEquivocated, processBlock, isOversized } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
1531
+ // An oversized checkpoint is re-broadcast as slashing evidence but never attested or processed.
1532
+ // Process checkpoint proposal if valid and neither equivocated nor oversized.
1533
+ const processCheckpointFn = ()=>result === TopicValidatorResult.Accept && checkpoint && !isEquivocated && !isOversized ? this.processValidCheckpointProposal(checkpoint.toCore(), source) : Promise.resolve();
1438
1534
  // If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
1439
1535
  // TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
1440
- if (processBlock && checkpoint?.getBlockProposal()) {
1441
- await this.processValidBlockProposal(checkpoint.getBlockProposal(), source);
1442
- }
1443
- if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
1536
+ const processBlockFn = ()=>processBlock && checkpoint && checkpoint.getBlockProposal() ? this.processValidBlockProposal(checkpoint.getBlockProposal(), source) : Promise.resolve();
1537
+ // A node that skips checkpoint validation attests without re-executing the embedded last block, so run
1538
+ // the checkpoint callback first: this creates and broadcasts the attestation before the block is
1539
+ // processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
1540
+ // waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
1541
+ // window, after which peers reject it as stale.
1542
+ if (this.config.skipCheckpointProposalValidation) {
1543
+ await processCheckpointFn();
1544
+ await processBlockFn();
1444
1545
  return;
1445
1546
  }
1446
- await this.processValidCheckpointProposal(checkpoint.toCore(), source);
1547
+ // Process the block first, since it's required for the checkpoint proposal validation.
1548
+ await processBlockFn();
1549
+ await processCheckpointFn();
1447
1550
  }
1448
1551
  /**
1449
1552
  * Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
@@ -1466,13 +1569,15 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1466
1569
  // Extract and try to add the block proposal first if present
1467
1570
  const blockProposal = checkpoint.getBlockProposal();
1468
1571
  let processBlock = false;
1572
+ let isOversized = false;
1469
1573
  if (blockProposal) {
1470
1574
  this.logger.debug(`Validating block proposal from propagated checkpoint`, {
1471
1575
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1472
1576
  [Attributes.P2P_ID]: peerId.toString()
1473
1577
  });
1474
1578
  const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1475
- const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1579
+ const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
1580
+ isOversized = blockIsOversized ?? false;
1476
1581
  if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1477
1582
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1478
1583
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
@@ -1484,7 +1589,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1484
1589
  result: TopicValidatorResult.Reject,
1485
1590
  severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
1486
1591
  };
1487
- } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1592
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated && !isOversized) {
1593
+ // An oversized terminal block is re-broadcast as slashing evidence but never processed.
1488
1594
  processBlock = true;
1489
1595
  }
1490
1596
  }
@@ -1504,11 +1610,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1504
1610
  obj: checkpoint,
1505
1611
  metadata: {
1506
1612
  isEquivocated,
1507
- processBlock
1613
+ processBlock,
1614
+ isOversized
1508
1615
  }
1509
1616
  };
1510
1617
  }
1511
- // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1618
+ // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast.
1512
1619
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1513
1620
  if (!added) {
1514
1621
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
@@ -1521,7 +1628,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1521
1628
  obj: checkpoint,
1522
1629
  metadata: {
1523
1630
  isEquivocated,
1524
- processBlock
1631
+ processBlock,
1632
+ isOversized
1525
1633
  },
1526
1634
  severity: PeerErrorSeverity.HighToleranceError
1527
1635
  };
@@ -1548,7 +1656,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1548
1656
  obj: checkpoint,
1549
1657
  metadata: {
1550
1658
  isEquivocated,
1551
- processBlock
1659
+ processBlock,
1660
+ isOversized
1552
1661
  }
1553
1662
  };
1554
1663
  }
@@ -1558,7 +1667,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1558
1667
  obj: checkpoint,
1559
1668
  metadata: {
1560
1669
  processBlock,
1561
- isEquivocated
1670
+ isEquivocated,
1671
+ isOversized
1562
1672
  }
1563
1673
  };
1564
1674
  }
@@ -1600,62 +1710,66 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1600
1710
  });
1601
1711
  }
1602
1712
  /**
1603
- * Validate the requested block transactions. Allow partial returns.
1713
+ * Validate the requested block transactions request-response consistency.
1714
+ * It does NOT validate the transactions themselves.
1604
1715
  * @param request - The block transactions request.
1605
1716
  * @param response - The block transactions response.
1606
1717
  * @param peerId - The ID of the peer that made the request.
1607
- * @returns True if the requested block transactions are valid, false otherwise.
1608
- */ async validateRequestedBlockTxs(request, response, peerId) {
1609
- const requestedTxValidator = this.createRequestedTxValidator();
1718
+ * @returns True if the request-response is consistent, false otherwise.
1719
+ */ async validateRequestedBlockTxsConsistency(request, response, peerId) {
1610
1720
  try {
1611
- if (!response.archiveRoot.equals(request.archiveRoot)) {
1612
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1613
- throw new ValidationError(`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`);
1614
- }
1615
- if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1616
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1617
- throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
1618
- }
1619
- // Check no duplicates and not exceeding returnable count
1620
- const requestedIndices = new Set(request.txIndices.getTrueIndices());
1621
- const availableIndices = new Set(response.txIndices.getTrueIndices());
1622
- const maxReturnable = [
1623
- ...requestedIndices
1624
- ].filter((i)=>availableIndices.has(i)).length;
1625
- const returnedHashes = await Promise.all(response.txs.map((tx)=>tx.getTxHash().toString()));
1721
+ // Check for duplicates txs (or hashes) in the response.
1722
+ const returnedHashes = response.txs.map((tx)=>tx.getTxHash().toString());
1626
1723
  const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
1627
1724
  if (uniqueReturned.size !== returnedHashes.length) {
1628
1725
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1629
1726
  throw new ValidationError(`Received duplicate txs in block txs response`);
1630
1727
  }
1631
- if (response.txs.length > maxReturnable) {
1728
+ // We get the block tx hashes from the proposal or the archiver.
1729
+ const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
1730
+ const blockTxHashes = proposal?.txHashes ?? (await this.archiver.getBlock({
1731
+ archive: request.archiveRoot
1732
+ }))?.body.txEffects.map((e)=>e.txHash);
1733
+ // If we don't have the block, we can't verify membership/order of the returned txs.
1734
+ if (!blockTxHashes) {
1735
+ // This shouldn't happen, since we asked for the block (proposal).
1736
+ // Neither a local proposal nor an archived block: we cannot verify membership/order of the
1737
+ // returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
1738
+ this.logger.warn(`Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`);
1739
+ // NOTE: We mark the response as invalid, given the limitations of a true/false return value.
1740
+ return false;
1741
+ }
1742
+ // Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
1743
+ const uniqueRequestedHashes = new Set([
1744
+ // tx hashes requested by index.
1745
+ ...request.txIndices.getTrueIndices().map((i)=>blockTxHashes[i].toString()),
1746
+ // explicitly requested tx hashes.
1747
+ ...request.txHashes.map((h)=>h.toString())
1748
+ ]);
1749
+ if (!returnedHashes.every((h)=>uniqueRequestedHashes.has(h))) {
1750
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1751
+ throw new ValidationError('Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)');
1752
+ }
1753
+ // Tx indices information is optional, but if present, we need to verify a few things.
1754
+ if (!response.peerHasBlock()) {
1755
+ this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
1756
+ return true;
1757
+ }
1758
+ // If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
1759
+ if (response.txIndices.getLength() !== blockTxHashes.length) {
1632
1760
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1633
- throw new ValidationError(`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`);
1761
+ throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`);
1634
1762
  }
1635
- // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1636
- const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
1637
- if (proposal) {
1638
- // Build intersected indices
1639
- const intersectIdx = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
1640
- // Enforce subset membership and preserve increasing order by index.
1641
- const hashToIndexInProposal = new Map(proposal.txHashes.map((h, i)=>[
1642
- h.toString(),
1643
- i
1644
- ]));
1645
- const allowedIndexSet = new Set(intersectIdx);
1646
- const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
1647
- const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
1648
- const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
1649
- if (!allAllowed || !strictlyIncreasing) {
1650
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1651
- throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1652
- }
1653
- } else {
1654
- // No local proposal, cannot check the membership/order of the returned txs
1655
- this.logger.warn(`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`);
1656
- return false;
1763
+ // For every index we requested that the peer claims to have (per its bitvector), the
1764
+ // corresponding tx must be present in the response. A peer advertising availability but
1765
+ // withholding the tx is inconsistent.
1766
+ const returnedHashSet = new Set(returnedHashes);
1767
+ const expectedIndices = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
1768
+ const missingExpected = expectedIndices.some((i)=>!returnedHashSet.has(blockTxHashes[i].toString()));
1769
+ if (missingExpected) {
1770
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1771
+ throw new ValidationError('Peer advertised requested txs via indices but did not return them');
1657
1772
  }
1658
- await Promise.all(response.txs.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator)));
1659
1773
  return true;
1660
1774
  } catch (e) {
1661
1775
  if (e instanceof ValidationError) {
@@ -1666,104 +1780,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1666
1780
  return false;
1667
1781
  }
1668
1782
  }
1669
- /**
1670
- * Validate a collection of txs that has been requested from a peer.
1671
- *
1672
- * The core component of this validator is that each tx hash MUST match the requested tx hash,
1673
- * In order to perform this check, the tx proof must be verified.
1674
- *
1675
- * Note: This function is called from within `ReqResp.sendRequest` as part of the
1676
- * ReqRespSubProtocol.TX subprotocol validation.
1677
- *
1678
- * @param requestedTxHash - The collection of the txs that was requested.
1679
- * @param responseTx - The collection of txs that was received as a response to the request.
1680
- * @param peerId - The peer ID of the peer that sent the tx.
1681
- * @returns True if the whole collection of txs is valid, false otherwise.
1682
- */ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
1683
- const requested = new Set(requestedTxHash.map((h)=>h.toString()));
1684
- const requestedTxValidator = this.createRequestedTxValidator();
1685
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
1686
- // I think we should still extract the valid txs and return them, so that we can still use the response.
1687
- try {
1688
- await Promise.all(responseTx.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
1689
- return true;
1690
- } catch (e) {
1691
- if (e instanceof ValidationError) {
1692
- this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
1693
- } else {
1694
- this.logger.error(`Error during validation of requested txs`, e);
1695
- }
1696
- return false;
1697
- }
1698
- }
1699
- /**
1700
- * Validates a BLOCK response.
1701
- *
1702
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1703
- * Penalizes on block number mismatch or hash mismatch.
1704
- *
1705
- * @param requestedBlockNumber - The requested block number.
1706
- * @param responseBlock - The block returned by the peer.
1707
- * @param peerId - The peer that returned the block.
1708
- * @returns True if the response is valid, false otherwise.
1709
- */ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
1710
- try {
1711
- const reqNum = Number(requestedBlockNumber.toString());
1712
- if (responseBlock.number !== reqNum) {
1713
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1714
- return false;
1715
- }
1716
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1717
- if (!local) {
1718
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1719
- // TODO: Consider extending this validator to accept an expected hash or
1720
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1721
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1722
- return false;
1723
- }
1724
- const [localHash, respHash] = await Promise.all([
1725
- local.hash(),
1726
- responseBlock.hash()
1727
- ]);
1728
- if (!localHash.equals(respHash)) {
1729
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1730
- return false;
1731
- }
1732
- return true;
1733
- } catch (e) {
1734
- this.logger.warn(`Error validating requested block`, e);
1735
- return false;
1736
- }
1737
- }
1738
- async validateRequestedTx(tx, peerId, txValidator, requested) {
1739
- const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
1740
- if (requested && !requested.has(tx.getTxHash().toString())) {
1741
- penalize(PeerErrorSeverity.MidToleranceError);
1742
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1743
- }
1744
- const { result } = await txValidator.validateTx(tx);
1745
- if (result === 'invalid') {
1746
- penalize(PeerErrorSeverity.LowToleranceError);
1747
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1748
- }
1749
- }
1750
- createRequestedTxValidator() {
1751
- return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
1752
- l1ChainId: this.config.l1ChainId,
1753
- rollupVersion: this.config.rollupVersion
1754
- });
1755
- }
1756
- async getGasFees(blockNumber) {
1757
- if (blockNumber === this.feesCache?.blockNumber) {
1758
- return this.feesCache.gasFees;
1759
- }
1760
- const header = await this.archiver.getBlockHeader(blockNumber);
1761
- const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
1762
- this.feesCache = {
1763
- blockNumber,
1764
- gasFees
1765
- };
1766
- return gasFees;
1783
+ getGasFees() {
1784
+ return this.blockMinFeesProvider.getCurrentMinFees();
1767
1785
  }
1768
1786
  /**
1769
1787
  * Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
@@ -1774,16 +1792,18 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1774
1792
  txValidatorConfig: {
1775
1793
  l1ChainId: this.config.l1ChainId,
1776
1794
  rollupVersion: this.config.rollupVersion,
1777
- proofVerifier: this.proofVerifier
1795
+ proofVerifier: this.proofVerifier,
1796
+ txValidationCache: this.txValidationCache
1778
1797
  },
1779
- peerScoring: this.peerManager
1798
+ peerScoring: this.peerManager,
1799
+ validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this)
1780
1800
  };
1781
1801
  }
1782
1802
  async validateTxsReceivedInBlockProposal(txs) {
1783
1803
  const validator = createTxValidatorForBlockProposalReceivedTxs(this.proofVerifier, {
1784
1804
  l1ChainId: this.config.l1ChainId,
1785
1805
  rollupVersion: this.config.rollupVersion
1786
- }, this.logger.getBindings());
1806
+ }, this.logger.getBindings(), this.txValidationCache);
1787
1807
  const results = await Promise.all(txs.map(async (tx)=>{
1788
1808
  const result = await validator.validateTx(tx);
1789
1809
  return result.result !== 'invalid';
@@ -1793,17 +1813,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1793
1813
  }
1794
1814
  }
1795
1815
  /** Creates the first stage (fast) validators for gossiped transactions. */ async createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp) {
1796
- const gasFees = await this.getGasFees(currentBlockNumber);
1816
+ const gasFees = await this.getGasFees();
1797
1817
  const allowedInSetup = [
1798
1818
  ...await getDefaultAllowedSetupFunctions(),
1799
1819
  ...this.config.txPublicSetupAllowListExtend ?? []
1800
1820
  ];
1801
1821
  const blockNumber = BlockNumber(currentBlockNumber + 1);
1802
1822
  const l1Constants = await this.archiver.getL1Constants();
1823
+ const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
1803
1824
  return createFirstStageTxValidationsForGossipedTransactions(nextSlotTimestamp, blockNumber, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), {
1804
- rollupManaLimit: l1Constants.rollupManaLimit,
1805
- maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1806
- maxBlockDAGas: this.config.validateMaxDABlockGas
1825
+ maxTxL2Gas: networkTxGasLimits.l2Gas,
1826
+ maxTxDAGas: networkTxGasLimits.daGas
1807
1827
  });
1808
1828
  }
1809
1829
  /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */ createSecondStageMessageValidators() {