@aztec/p2p 0.0.1-commit.4d79d1f2d → 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 (499) hide show
  1. package/README.md +130 -3
  2. package/dest/bootstrap/bootstrap.d.ts +1 -1
  3. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  4. package/dest/bootstrap/bootstrap.js +22 -6
  5. package/dest/client/factory.d.ts +9 -8
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +50 -34
  8. package/dest/client/interface.d.ts +59 -27
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +40 -34
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +162 -135
  13. package/dest/config.d.ts +164 -100
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +149 -49
  16. package/dest/errors/p2p-service.error.d.ts +9 -0
  17. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  18. package/dest/errors/p2p-service.error.js +10 -0
  19. package/dest/errors/reqresp.error.d.ts +9 -16
  20. package/dest/errors/reqresp.error.d.ts.map +1 -1
  21. package/dest/errors/reqresp.error.js +10 -17
  22. package/dest/errors/tx-pool.error.d.ts +8 -0
  23. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  24. package/dest/errors/tx-pool.error.js +9 -0
  25. package/dest/index.d.ts +1 -2
  26. package/dest/index.d.ts.map +1 -1
  27. package/dest/index.js +0 -1
  28. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +103 -59
  29. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool.js +278 -196
  31. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  32. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +224 -65
  34. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  35. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/mocks.js +7 -5
  37. package/dest/mem_pools/index.d.ts +1 -2
  38. package/dest/mem_pools/index.d.ts.map +1 -1
  39. package/dest/mem_pools/instrumentation.d.ts +12 -5
  40. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  41. package/dest/mem_pools/instrumentation.js +38 -17
  42. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  43. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  45. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +32 -15
  46. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +95 -24
  48. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  49. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  51. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  52. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +8 -4
  54. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  55. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  57. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
  58. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
  60. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  61. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  62. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  63. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
  64. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  65. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  66. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
  67. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
  68. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  69. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  70. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
  71. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  72. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  73. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
  74. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  75. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  76. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
  77. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  78. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  79. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  80. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  81. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  82. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  83. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +60 -14
  84. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  85. package/dest/mem_pools/tx_pool_v2/interfaces.js +6 -1
  86. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +59 -15
  87. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  88. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +116 -20
  89. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +26 -3
  90. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  91. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +79 -43
  92. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +20 -7
  93. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  94. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +34 -12
  95. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +29 -7
  96. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  97. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +473 -211
  98. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +10 -3
  99. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  100. package/dest/msg_validators/attestation_validator/attestation_validator.js +38 -15
  101. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  102. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  103. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  104. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +12 -5
  105. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  106. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +11 -3
  107. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +12 -5
  108. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  109. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +23 -3
  110. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +36 -9
  111. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  112. package/dest/msg_validators/proposal_validator/proposal_validator.js +130 -48
  113. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  114. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  115. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
  116. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  117. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  118. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
  119. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  120. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  121. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  122. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  123. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  124. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  125. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  126. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  127. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  128. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  129. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  130. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  131. package/dest/msg_validators/tx_validator/data_validator.js +36 -2
  132. package/dest/msg_validators/tx_validator/factory.d.ts +133 -7
  133. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  134. package/dest/msg_validators/tx_validator/factory.js +261 -61
  135. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  136. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  137. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  138. package/dest/msg_validators/tx_validator/gas_validator.d.ts +104 -3
  139. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  140. package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
  141. package/dest/msg_validators/tx_validator/index.d.ts +5 -1
  142. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  143. package/dest/msg_validators/tx_validator/index.js +4 -0
  144. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  145. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  146. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  147. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  148. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  149. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  150. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  151. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  152. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  153. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +2 -2
  154. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  155. package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
  156. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  157. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  158. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  159. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  160. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  161. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  162. package/dest/services/data_store.d.ts +1 -1
  163. package/dest/services/data_store.d.ts.map +1 -1
  164. package/dest/services/data_store.js +5 -5
  165. package/dest/services/discv5/discV5_service.d.ts +13 -2
  166. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  167. package/dest/services/discv5/discV5_service.js +119 -23
  168. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  169. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  170. package/dest/services/discv5/persisted_enr_store.js +145 -0
  171. package/dest/services/dummy_service.d.ts +18 -18
  172. package/dest/services/dummy_service.d.ts.map +1 -1
  173. package/dest/services/dummy_service.js +19 -20
  174. package/dest/services/encoding.d.ts +23 -6
  175. package/dest/services/encoding.d.ts.map +1 -1
  176. package/dest/services/encoding.js +41 -24
  177. package/dest/services/gossipsub/topic_score_params.d.ts +23 -17
  178. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  179. package/dest/services/gossipsub/topic_score_params.js +36 -24
  180. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  181. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  182. package/dest/services/libp2p/instrumentation.js +14 -0
  183. package/dest/services/libp2p/libp2p_service.d.ts +57 -56
  184. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  185. package/dest/services/libp2p/libp2p_service.js +483 -373
  186. package/dest/services/peer-manager/metrics.d.ts +3 -1
  187. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  188. package/dest/services/peer-manager/metrics.js +6 -0
  189. package/dest/services/peer-manager/peer_manager.d.ts +20 -3
  190. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  191. package/dest/services/peer-manager/peer_manager.js +83 -26
  192. package/dest/services/peer-manager/peer_scoring.d.ts +34 -2
  193. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  194. package/dest/services/peer-manager/peer_scoring.js +102 -13
  195. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +5 -8
  196. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  197. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +95 -127
  198. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +11 -11
  199. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  200. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
  201. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  202. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
  203. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  204. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  205. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  206. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  207. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  208. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  209. package/dest/services/reqresp/config.d.ts +15 -3
  210. package/dest/services/reqresp/config.d.ts.map +1 -1
  211. package/dest/services/reqresp/config.js +11 -0
  212. package/dest/services/reqresp/interface.d.ts +16 -18
  213. package/dest/services/reqresp/interface.d.ts.map +1 -1
  214. package/dest/services/reqresp/interface.js +10 -20
  215. package/dest/services/reqresp/metrics.d.ts +1 -1
  216. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  217. package/dest/services/reqresp/metrics.js +0 -1
  218. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  219. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  220. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  221. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  222. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  223. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  224. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +12 -7
  225. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  226. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +42 -24
  227. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  228. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  229. package/dest/services/reqresp/protocols/index.js +0 -1
  230. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  231. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  232. package/dest/services/reqresp/protocols/tx.js +1 -3
  233. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  234. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  235. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  236. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  237. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  238. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  239. package/dest/services/reqresp/reqresp.d.ts +7 -29
  240. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  241. package/dest/services/reqresp/reqresp.js +75 -216
  242. package/dest/services/service.d.ts +29 -14
  243. package/dest/services/service.d.ts.map +1 -1
  244. package/dest/services/tx_collection/config.d.ts +8 -17
  245. package/dest/services/tx_collection/config.d.ts.map +1 -1
  246. package/dest/services/tx_collection/config.js +17 -40
  247. package/dest/services/tx_collection/file_store_tx_collection.d.ts +25 -32
  248. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
  249. package/dest/services/tx_collection/file_store_tx_collection.js +96 -87
  250. package/dest/services/tx_collection/file_store_tx_source.d.ts +17 -6
  251. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  252. package/dest/services/tx_collection/file_store_tx_source.js +53 -10
  253. package/dest/services/tx_collection/index.d.ts +2 -3
  254. package/dest/services/tx_collection/index.d.ts.map +1 -1
  255. package/dest/services/tx_collection/index.js +0 -1
  256. package/dest/services/tx_collection/instrumentation.js +1 -2
  257. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  258. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  259. package/dest/services/tx_collection/request_tracker.js +84 -0
  260. package/dest/services/tx_collection/tx_collection.d.ts +39 -55
  261. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  262. package/dest/services/tx_collection/tx_collection.js +280 -108
  263. package/dest/services/tx_collection/tx_collection_sink.d.ts +7 -6
  264. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  265. package/dest/services/tx_collection/tx_collection_sink.js +15 -24
  266. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  267. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  268. package/dest/services/tx_collection/tx_source.js +29 -7
  269. package/dest/services/tx_file_store/tx_file_store.d.ts +3 -4
  270. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  271. package/dest/services/tx_file_store/tx_file_store.js +13 -20
  272. package/dest/services/tx_provider.d.ts +5 -3
  273. package/dest/services/tx_provider.d.ts.map +1 -1
  274. package/dest/services/tx_provider.js +7 -4
  275. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  276. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  277. package/dest/test-helpers/make-test-p2p-clients.js +5 -3
  278. package/dest/test-helpers/mock-pubsub.d.ts +26 -12
  279. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  280. package/dest/test-helpers/mock-pubsub.js +51 -45
  281. package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
  282. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  283. package/dest/test-helpers/reqresp-nodes.js +17 -19
  284. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  285. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  286. package/dest/test-helpers/test_tx_provider.js +3 -0
  287. package/dest/test-helpers/testbench-utils.d.ts +22 -16
  288. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  289. package/dest/test-helpers/testbench-utils.js +56 -16
  290. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  291. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  292. package/dest/testbench/p2p_client_testbench_worker.js +111 -48
  293. package/dest/testbench/worker_client_manager.d.ts +12 -6
  294. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  295. package/dest/testbench/worker_client_manager.js +57 -11
  296. package/dest/util.d.ts +13 -8
  297. package/dest/util.d.ts.map +1 -1
  298. package/dest/util.js +35 -14
  299. package/dest/versioning.d.ts +3 -6
  300. package/dest/versioning.d.ts.map +1 -1
  301. package/dest/versioning.js +3 -24
  302. package/package.json +16 -16
  303. package/src/bootstrap/bootstrap.ts +17 -3
  304. package/src/client/factory.ts +95 -51
  305. package/src/client/interface.ts +59 -35
  306. package/src/client/p2p_client.ts +186 -196
  307. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  308. package/src/config.ts +259 -57
  309. package/src/errors/p2p-service.error.ts +11 -0
  310. package/src/errors/reqresp.error.ts +13 -19
  311. package/src/errors/tx-pool.error.ts +12 -0
  312. package/src/index.ts +0 -1
  313. package/src/mem_pools/attestation_pool/attestation_pool.ts +336 -242
  314. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +244 -69
  315. package/src/mem_pools/attestation_pool/mocks.ts +14 -8
  316. package/src/mem_pools/index.ts +0 -3
  317. package/src/mem_pools/instrumentation.ts +27 -17
  318. package/src/mem_pools/tx_pool_v2/README.md +52 -28
  319. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  320. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +114 -27
  321. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  322. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +8 -4
  323. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  324. package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
  325. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  326. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
  327. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
  328. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
  329. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
  330. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
  331. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
  332. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  333. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  334. package/src/mem_pools/tx_pool_v2/interfaces.ts +61 -14
  335. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +170 -28
  336. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +91 -43
  337. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +54 -14
  338. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +527 -207
  339. package/src/msg_validators/attestation_validator/README.md +49 -0
  340. package/src/msg_validators/attestation_validator/attestation_validator.ts +46 -14
  341. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +15 -7
  342. package/src/msg_validators/proposal_validator/README.md +123 -0
  343. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +26 -4
  344. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +43 -7
  345. package/src/msg_validators/proposal_validator/proposal_validator.ts +155 -49
  346. package/src/msg_validators/tx_validator/README.md +129 -0
  347. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +6 -15
  348. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  349. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  350. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  351. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  352. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  353. package/src/msg_validators/tx_validator/data_validator.ts +44 -1
  354. package/src/msg_validators/tx_validator/factory.ts +413 -80
  355. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  356. package/src/msg_validators/tx_validator/gas_validator.ts +195 -54
  357. package/src/msg_validators/tx_validator/index.ts +4 -0
  358. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  359. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  360. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  361. package/src/msg_validators/tx_validator/timestamp_validator.ts +7 -7
  362. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  363. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  364. package/src/services/data_store.ts +5 -13
  365. package/src/services/discv5/discV5_service.ts +126 -14
  366. package/src/services/discv5/persisted_enr_store.ts +158 -0
  367. package/src/services/dummy_service.ts +26 -45
  368. package/src/services/encoding.ts +40 -24
  369. package/src/services/gossipsub/README.md +59 -22
  370. package/src/services/gossipsub/topic_score_params.ts +58 -31
  371. package/src/services/libp2p/instrumentation.ts +14 -0
  372. package/src/services/libp2p/libp2p_service.ts +554 -428
  373. package/src/services/peer-manager/metrics.ts +7 -0
  374. package/src/services/peer-manager/peer_manager.ts +91 -25
  375. package/src/services/peer-manager/peer_scoring.ts +102 -8
  376. package/src/services/reqresp/README.md +194 -0
  377. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  378. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +92 -138
  379. package/src/services/reqresp/batch-tx-requester/interface.ts +14 -10
  380. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
  381. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  382. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  383. package/src/services/reqresp/config.ts +19 -2
  384. package/src/services/reqresp/interface.ts +21 -47
  385. package/src/services/reqresp/metrics.ts +0 -1
  386. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  387. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +34 -30
  388. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +47 -20
  389. package/src/services/reqresp/protocols/index.ts +0 -1
  390. package/src/services/reqresp/protocols/tx.ts +1 -3
  391. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  392. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  393. package/src/services/reqresp/reqresp.ts +87 -260
  394. package/src/services/service.ts +42 -30
  395. package/src/services/tx_collection/config.ts +24 -59
  396. package/src/services/tx_collection/file_store_tx_collection.ts +108 -107
  397. package/src/services/tx_collection/file_store_tx_source.ts +69 -10
  398. package/src/services/tx_collection/index.ts +1 -6
  399. package/src/services/tx_collection/instrumentation.ts +1 -1
  400. package/src/services/tx_collection/request_tracker.ts +127 -0
  401. package/src/services/tx_collection/tx_collection.ts +342 -156
  402. package/src/services/tx_collection/tx_collection_sink.ts +17 -31
  403. package/src/services/tx_collection/tx_source.ts +29 -8
  404. package/src/services/tx_file_store/tx_file_store.ts +11 -21
  405. package/src/services/tx_provider.ts +7 -2
  406. package/src/test-helpers/make-test-p2p-clients.ts +4 -3
  407. package/src/test-helpers/mock-pubsub.ts +59 -66
  408. package/src/test-helpers/reqresp-nodes.ts +15 -28
  409. package/src/test-helpers/test_tx_provider.ts +5 -0
  410. package/src/test-helpers/testbench-utils.ts +74 -31
  411. package/src/testbench/p2p_client_testbench_worker.ts +120 -63
  412. package/src/testbench/worker_client_manager.ts +72 -25
  413. package/src/util.ts +40 -19
  414. package/src/versioning.ts +3 -33
  415. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  416. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  417. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
  418. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  419. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  420. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  421. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  422. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  423. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  424. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  425. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  426. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  427. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  428. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  429. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  430. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  431. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  432. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  433. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  434. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  435. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  436. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  437. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  438. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  439. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  440. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  441. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  442. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  443. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  444. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  445. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  446. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  447. package/dest/mem_pools/tx_pool/index.js +0 -2
  448. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  449. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  450. package/dest/mem_pools/tx_pool/priority.js +0 -15
  451. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  452. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  453. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  454. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  455. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  456. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  457. package/dest/msg_validators/clock_tolerance.d.ts +0 -21
  458. package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
  459. package/dest/msg_validators/clock_tolerance.js +0 -37
  460. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  461. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  462. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  463. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  464. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  465. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  466. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  467. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  468. package/dest/services/reqresp/protocols/block.js +0 -32
  469. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -54
  470. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  471. package/dest/services/tx_collection/fast_tx_collection.js +0 -321
  472. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
  473. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  474. package/dest/services/tx_collection/proposal_tx_collector.js +0 -49
  475. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -55
  476. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  477. package/dest/services/tx_collection/slow_tx_collection.js +0 -206
  478. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -336
  479. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  480. package/src/mem_pools/tx_pool/README.md +0 -270
  481. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  482. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  483. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  484. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  485. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  486. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  487. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  488. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  489. package/src/mem_pools/tx_pool/index.ts +0 -2
  490. package/src/mem_pools/tx_pool/priority.ts +0 -20
  491. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  492. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  493. package/src/msg_validators/clock_tolerance.ts +0 -51
  494. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
  495. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  496. package/src/services/reqresp/protocols/block.ts +0 -37
  497. package/src/services/tx_collection/fast_tx_collection.ts +0 -366
  498. package/src/services/tx_collection/proposal_tx_collector.ts +0 -112
  499. package/src/services/tx_collection/slow_tx_collection.ts +0 -262
@@ -370,14 +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, _dec8, _dec9, _initProto;
373
+ var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _initProto;
374
374
  import { BlockNumber } from '@aztec/foundation/branded-types';
375
+ import { compactArray, maxBy, merge } from '@aztec/foundation/collection';
375
376
  import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
376
377
  import { RunningPromise } from '@aztec/foundation/running-promise';
377
378
  import { Timer } from '@aztec/foundation/timer';
378
379
  import { protocolContractsHash } from '@aztec/protocol-contracts';
379
- import { GasFees } from '@aztec/stdlib/gas';
380
- import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PClientType, P2PMessage, PeerErrorSeverity, TopicType, createTopicString, getTopicsForClientAndConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
380
+ import { DEFAULT_MAX_BLOCKS_PER_CHECKPOINT } from '@aztec/stdlib/config';
381
+ import { getNetworkTxGasLimits } from '@aztec/stdlib/gas';
382
+ import { BlockProposal, CheckpointAttestation, CheckpointProposal, P2PMessage, PeerErrorSeverity, PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
383
+ import { ConsensusTimetable, getDefaultCheckpointProposalSyncGrace } from '@aztec/stdlib/timetable';
381
384
  import { MerkleTreeId } from '@aztec/stdlib/trees';
382
385
  import { Tx } from '@aztec/stdlib/tx';
383
386
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
@@ -392,25 +395,39 @@ import { identify } from '@libp2p/identify';
392
395
  import { TopicValidatorResult } from '@libp2p/interface';
393
396
  import { mplex } from '@libp2p/mplex';
394
397
  import { tcp } from '@libp2p/tcp';
398
+ import { multiaddr } from '@multiformats/multiaddr';
395
399
  import { ENR } from '@nethermindeth/enr';
396
400
  import { createLibp2p } from 'libp2p';
401
+ import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
397
402
  import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
398
403
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
399
- import { createTxMessageValidators, createTxReqRespValidator } from '../../msg_validators/tx_validator/factory.js';
404
+ import { createFirstStageTxValidationsForGossipedTransactions, createSecondStageTxValidationsForGossipedTransactions, createTxValidatorForBlockProposalReceivedTxs } from '../../msg_validators/tx_validator/factory.js';
400
405
  import { GossipSubEvent } from '../../types/index.js';
401
406
  import { convertToMultiaddr } from '../../util.js';
402
407
  import { getVersions } from '../../versioning.js';
403
408
  import { AztecDatastore } from '../data_store.js';
404
409
  import { DiscV5Service } from '../discv5/discV5_service.js';
405
- import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
410
+ import { SnappyTransform, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
406
411
  import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
407
412
  import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
408
413
  import { PeerManager } from '../peer-manager/peer_manager.js';
409
414
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
410
- import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError } from '../reqresp/index.js';
411
- import { 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';
412
417
  import { ReqResp } from '../reqresp/reqresp.js';
413
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
+ }
414
431
  _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
415
432
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString()
416
433
  })), _dec1 = trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block)=>({
@@ -426,23 +443,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
426
443
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
427
444
  [Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
428
445
  [Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then((i)=>i.toString())
429
- })), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxs', (request)=>({
446
+ })), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', (request)=>({
430
447
  [Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
431
- })), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
432
- [Attributes.TX_HASH]: requestedTxHash.toString()
433
- })), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
434
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
435
- })), _dec8 = trackSpan('Libp2pService.validatePropagatedTx', (tx)=>({
436
- [Attributes.TX_HASH]: tx.getTxHash().toString()
437
- })), _dec9 = trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation)=>({
438
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
439
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
440
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
441
448
  }));
442
449
  /**
443
450
  * Lib P2P implementation of the P2PService interface.
444
451
  */ export class LibP2PService extends WithTracer {
445
- clientType;
446
452
  config;
447
453
  node;
448
454
  peerDiscoveryService;
@@ -453,6 +459,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
453
459
  epochCache;
454
460
  proofVerifier;
455
461
  worldStateSynchronizer;
462
+ blockMinFeesProvider;
463
+ txValidationCache;
456
464
  static{
457
465
  ({ e: [_initProto] } = _apply_decs_2203_r(this, [
458
466
  [
@@ -483,27 +491,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
483
491
  [
484
492
  _dec5,
485
493
  2,
486
- "validateRequestedBlockTxs"
487
- ],
488
- [
489
- _dec6,
490
- 2,
491
- "validateRequestedTxs"
492
- ],
493
- [
494
- _dec7,
495
- 2,
496
- "validateRequestedBlock"
497
- ],
498
- [
499
- _dec8,
500
- 2,
501
- "validatePropagatedTx"
502
- ],
503
- [
504
- _dec9,
505
- 2,
506
- "validateCheckpointAttestation"
494
+ "validateRequestedBlockTxsConsistency"
507
495
  ]
508
496
  ], []));
509
497
  }
@@ -515,9 +503,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
515
503
  checkpointAttestationValidator;
516
504
  protocolVersion;
517
505
  topicStrings;
518
- feesCache;
519
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;
520
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;
521
510
  /**
522
511
  * Callback for when a block is received from a peer.
523
512
  * @param block - The block received from the peer.
@@ -527,13 +516,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
527
516
  * Callback for when a checkpoint proposal is received from a peer.
528
517
  * @param checkpoint - The checkpoint proposal received from the peer.
529
518
  * @returns The attestations for the checkpoint, if any.
530
- */ checkpointReceivedCallback;
519
+ */ allNodesCheckpointReceivedCallback;
520
+ /**
521
+ * Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
522
+ * @param checkpoint - The checkpoint proposal received from the peer.
523
+ * @returns The attestations for the checkpoint, if any.
524
+ */ validatorCheckpointReceivedCallback;
531
525
  gossipSubEventHandler;
526
+ ipChangedHandler;
527
+ discoveredP2pIp;
532
528
  instrumentation;
533
529
  telemetry;
534
530
  logger;
535
- constructor(clientType, config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
536
- super(telemetry, 'LibP2PService'), this.clientType = clientType, 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 = {};
537
533
  this.telemetry = telemetry;
538
534
  // Create child logger with fisherman prefix if in fisherman mode
539
535
  this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
@@ -549,40 +545,57 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
549
545
  this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
550
546
  this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(TopicType.checkpoint_proposal, this.protocolVersion);
551
547
  this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(TopicType.checkpoint_attestation, this.protocolVersion);
552
- this.blockProposalValidator = new BlockProposalValidator(epochCache, {
553
- txsPermitted: !config.disableTransactions
554
- });
555
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
556
- txsPermitted: !config.disableTransactions
557
- });
558
- this.checkpointAttestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry) : new CheckpointAttestationValidator(epochCache);
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());
551
+ const proposalValidatorOpts = {
552
+ txsPermitted: !config.disableTransactions,
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
561
+ };
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);
559
569
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
560
570
  this.blockReceivedCallback = async (block)=>{
561
- this.logger.debug(`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`, {
571
+ this.logger.warn(`Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, {
562
572
  p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier()
563
573
  });
564
- return false;
574
+ return true;
575
+ };
576
+ this.allNodesCheckpointReceivedCallback = (_checkpoint)=>{
577
+ throw new CheckpointProposalReceivedCallbackNotRegisteredError();
565
578
  };
566
- this.checkpointReceivedCallback = (checkpoint)=>{
567
- this.logger.debug(`Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`);
579
+ this.validatorCheckpointReceivedCallback = (_checkpoint)=>{
568
580
  return Promise.resolve(undefined);
569
581
  };
570
582
  }
571
583
  updateConfig(config) {
572
584
  this.reqresp.updateConfig(config);
585
+ this.config = merge(this.config, config);
573
586
  }
574
587
  /**
575
588
  * Creates an instance of the LibP2P service.
576
589
  * @param config - The configuration to use when creating the service.
577
590
  * @param txPool - The transaction pool to be accessed by the service.
578
591
  * @returns The new service.
579
- */ static async new(clientType, config, peerId, deps) {
580
- const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, telemetry, logger, packageVersion } = deps;
592
+ */ static async new(config, peerId, deps) {
593
+ const { worldStateSynchronizer, epochCache, l2BlockSource, mempools, proofVerifier, peerStore, blockMinFeesProvider, telemetry, logger, packageVersion, txValidationCache } = deps;
581
594
  const { p2pPort, maxPeerCount, listenAddress } = config;
582
595
  const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
583
596
  const datastore = new AztecDatastore(peerStore);
584
597
  const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
585
- 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);
586
599
  // Seed libp2p's bootstrap discovery with private and trusted peers
587
600
  const bootstrapNodes = [
588
601
  ...config.privatePeers,
@@ -597,30 +610,45 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
597
610
  const versions = getVersions(config);
598
611
  const protocolVersion = compressComponentVersions(versions);
599
612
  const preferredPeersEnrs = config.preferredPeers.map((enr)=>ENR.decodeTxt(enr));
600
- const directPeers = (await Promise.all(preferredPeersEnrs.map(async (enr)=>{
601
- const peerId = await enr.peerId();
602
- const address = enr.getLocationMultiaddr('tcp');
603
- if (address === undefined) {
604
- 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;
605
632
  }
606
- return {
607
- id: peerId,
608
- addrs: [
609
- address
610
- ]
611
- };
612
- }))).filter((peer)=>peer !== undefined);
633
+ })));
613
634
  const announceTcpMultiaddr = config.p2pIp ? [
614
635
  convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')
615
636
  ] : [];
616
- // 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.
617
640
  const l1Constants = epochCache.getL1Constants();
618
641
  const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
619
642
  slotDurationMs: l1Constants.slotDuration * 1000,
620
643
  heartbeatIntervalMs: config.gossipsubInterval,
621
644
  targetCommitteeSize: l1Constants.targetCommitteeSize,
622
- blockDurationMs: config.blockDurationMs
645
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint ?? DEFAULT_MAX_BLOCKS_PER_CHECKPOINT,
646
+ expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot
623
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));
624
652
  const node = await createLibp2p({
625
653
  start: false,
626
654
  peerId,
@@ -654,8 +682,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
654
682
  ],
655
683
  datastore,
656
684
  peerDiscovery,
685
+ // Pin the yamux frame size: MAX_REQRESP_REQUEST_SIZE_BYTES relies on a reqresp request fitting in one frame.
657
686
  streamMuxers: [
658
- yamux(),
687
+ yamux({
688
+ maxMessageSize: YAMUX_MAX_MESSAGE_SIZE_BYTES
689
+ }),
659
690
  mplex()
660
691
  ],
661
692
  connectionEncryption: [
@@ -673,7 +704,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
673
704
  },
674
705
  connectionGater: {
675
706
  denyInboundConnection: (maConn)=>{
676
- const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
707
+ const allowed = peerManager.isAddressAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
677
708
  if (allowed) {
678
709
  return false;
679
710
  }
@@ -683,7 +714,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
683
714
  denyInboundEncryptedConnection: (peerId, _maConn)=>{
684
715
  //NOTE: it is not necessary to check address here because this was already done by
685
716
  // denyInboundConnection
686
- const allowed = peerManager.isNodeAllowedToConnect(peerId);
717
+ const allowed = peerManager.isPeerAllowedToConnect(peerId);
687
718
  if (allowed) {
688
719
  return false;
689
720
  }
@@ -710,9 +741,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
710
741
  mcacheLength: config.gossipsubMcacheLength,
711
742
  mcacheGossip: config.gossipsubMcacheGossip,
712
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.
713
749
  msgIdFn: getMsgIdFn,
714
750
  msgIdToStrFn: msgIdToStrFn,
715
- fastMsgIdFn: fastMsgIdFn,
716
751
  dataTransform: new SnappyTransform(),
717
752
  metricsRegister: otelMetricsAdapter,
718
753
  metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
@@ -725,7 +760,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
725
760
  })
726
761
  }),
727
762
  components: (components)=>({
728
- connectionManager: components.connectionManager
763
+ connectionManager: components.connectionManager,
764
+ addressManager: components.addressManager
729
765
  })
730
766
  },
731
767
  logger: createLibp2pComponentLogger(logger.module, logger.getBindings())
@@ -733,6 +769,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
733
769
  const peerScoring = new PeerScoring(config, telemetry);
734
770
  const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
735
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));
736
774
  // Configure application-specific scoring for gossipsub.
737
775
  // The weight scales app score to align with gossipsub thresholds:
738
776
  // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
@@ -740,7 +778,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
740
778
  // Note: positive topic scores can offset penalties, so alignment is best-effort.
741
779
  node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
742
780
  node.services.pubsub.score.params.appSpecificScore = (peerId)=>peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
743
- return new LibP2PService(clientType, 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);
744
782
  }
745
783
  /**
746
784
  * Starts the LibP2P service.
@@ -750,22 +788,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
750
788
  if (this.node.status === 'started') {
751
789
  throw new Error('P2P service already started');
752
790
  }
753
- // Get listen & announce addresses for logging
754
791
  const { p2pIp, p2pPort } = this.config;
755
- if (!p2pIp) {
756
- throw new Error('Announce address not provided.');
792
+ if (!p2pIp && !this.config.queryForIp) {
793
+ throw new Error('Announce address not provided and queryForIp is not enabled.');
757
794
  }
758
- const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
795
+ const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
759
796
  // Create request response protocol handlers
760
797
  const txHandler = reqRespTxHandler(this.mempools);
761
798
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
762
- const blockHandler = reqRespBlockHandler(this.archiver);
763
799
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
764
800
  const requestResponseHandlers = {
765
801
  [ReqRespSubProtocol.PING]: pingHandler,
766
802
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
767
- [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
768
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
803
+ [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this)
769
804
  };
770
805
  if (!this.config.disableTransactions) {
771
806
  const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
@@ -774,18 +809,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
774
809
  if (!this.config.disableTransactions) {
775
810
  requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
776
811
  }
777
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
778
- const reqrespSubProtocolValidators = {
779
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
780
- [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
781
- [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
782
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this)
783
- };
784
812
  await this.peerManager.initializePeers();
785
- await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
813
+ await this.reqresp.start(requestResponseHandlers);
786
814
  await this.node.start();
787
815
  // Subscribe to standard GossipSub topics by default
788
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)){
816
+ for (const topic of getTopicsForConfig(this.config.disableTransactions)){
789
817
  this.subscribeToTopic(this.topicStrings[topic]);
790
818
  }
791
819
  // add GossipSub listener
@@ -794,6 +822,34 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
794
822
  if (!this.config.p2pDiscoveryDisabled) {
795
823
  await this.peerDiscoveryService.start();
796
824
  }
825
+ // Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
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');
829
+ this.ipChangedHandler = (ip)=>{
830
+ const addressManager = this.node.services.components.addressManager;
831
+ const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
832
+ const previousIp = this.discoveredP2pIp;
833
+ if (previousIp) {
834
+ const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
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
+ });
846
+ }
847
+ addressManager.addObservedAddr(newAddr);
848
+ addressManager.confirmObservedAddr(newAddr);
849
+ this.discoveredP2pIp = ip;
850
+ };
851
+ this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
852
+ }
797
853
  this.discoveryRunningPromise = new RunningPromise(async ()=>{
798
854
  await this.peerManager.heartbeat();
799
855
  }, this.logger, this.config.peerCheckIntervalMS);
@@ -811,6 +867,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
811
867
  */ async stop() {
812
868
  // Remove gossip sub listener
813
869
  this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
870
+ if (this.ipChangedHandler) {
871
+ this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
872
+ this.ipChangedHandler = undefined;
873
+ }
814
874
  // Stop peer manager
815
875
  this.logger.debug('Stopping peer manager...');
816
876
  await this.peerManager.stop();
@@ -824,8 +884,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
824
884
  await this.stopLibP2P();
825
885
  this.logger.info('LibP2P service stopped');
826
886
  }
827
- addReqRespSubProtocol(subProtocol, handler, validator) {
828
- return this.reqresp.addSubProtocol(subProtocol, handler, validator);
887
+ addReqRespSubProtocol(subProtocol, handler) {
888
+ return this.reqresp.addSubProtocol(subProtocol, handler);
829
889
  }
830
890
  registerThisValidatorAddresses(address) {
831
891
  this.peerManager.registerThisValidatorAddresses(address);
@@ -833,6 +893,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
833
893
  getPeers(includePending) {
834
894
  return this.peerManager.getPeers(includePending);
835
895
  }
896
+ getGossipMeshPeerCount(topicType) {
897
+ return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
898
+ }
836
899
  handleGossipSubEvent(e) {
837
900
  this.logger.trace(`Received PUBSUB message.`);
838
901
  const safeJob = async ()=>{
@@ -844,14 +907,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
844
907
  };
845
908
  setImmediate(()=>void safeJob());
846
909
  }
847
- /**
848
- * Send a batch of requests to peers, and return the responses
849
- * @param protocol - The request response protocol to use
850
- * @param requests - The requests to send to the peers
851
- * @returns The responses to the requests
852
- */ sendBatchRequest(protocol, requests, pinnedPeerId) {
853
- return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
854
- }
855
910
  sendRequestToPeer(peerId, subProtocol, payload, dialTimeout) {
856
911
  return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
857
912
  }
@@ -864,8 +919,11 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
864
919
  registerBlockReceivedCallback(callback) {
865
920
  this.blockReceivedCallback = callback;
866
921
  }
867
- registerCheckpointReceivedCallback(callback) {
868
- this.checkpointReceivedCallback = callback;
922
+ registerValidatorCheckpointReceivedCallback(callback) {
923
+ this.validatorCheckpointReceivedCallback = callback;
924
+ }
925
+ registerAllNodesCheckpointReceivedCallback(callback) {
926
+ this.allNodesCheckpointReceivedCallback = callback;
869
927
  }
870
928
  /**
871
929
  * Registers a callback to be invoked when a duplicate proposal is detected.
@@ -874,12 +932,20 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
874
932
  this.duplicateProposalCallback = callback;
875
933
  }
876
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
+ /**
877
940
  * Registers a callback to be invoked when a duplicate attestation is detected.
878
941
  * A validator signing attestations for different proposals at the same slot.
879
942
  * This callback is triggered on the first duplicate (when count goes from 1 to 2).
880
943
  */ registerDuplicateAttestationCallback(callback) {
881
944
  this.duplicateAttestationCallback = callback;
882
945
  }
946
+ registerCheckpointAttestationCallback(callback) {
947
+ this.checkpointAttestationCallback = callback;
948
+ }
883
949
  /**
884
950
  * Subscribes to a topic.
885
951
  * @param topic - The topic to subscribe to.
@@ -931,6 +997,12 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
931
997
  if (!validator || !validator.addMessage(msgId)) {
932
998
  this.instrumentation.incMessagePrevalidationStatus(false, topicType);
933
999
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
1000
+ if (topicType === TopicType.tx) {
1001
+ this.logger.verbose(`Ignoring already-seen tx gossip message`, {
1002
+ msgId,
1003
+ source: source.toString()
1004
+ });
1005
+ }
934
1006
  return {
935
1007
  result: false,
936
1008
  topicType
@@ -988,12 +1060,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
988
1060
  }
989
1061
  // Process the message, optionally within a linked span for trace propagation
990
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
+ }
991
1070
  if (msg.topic === this.topicStrings[TopicType.tx]) {
992
1071
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
993
1072
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
994
- if (this.clientType === P2PClientType.Full) {
995
- await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
996
- }
1073
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
997
1074
  } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
998
1075
  await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
999
1076
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
@@ -1038,39 +1115,131 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1038
1115
  return;
1039
1116
  }
1040
1117
  async validateReceivedMessage(validationFunc, msgId, source, topicType) {
1118
+ // Default to reject result with a penalty if validation function throws an error
1041
1119
  let resultAndObj = {
1042
- result: TopicValidatorResult.Reject
1120
+ result: TopicValidatorResult.Reject,
1121
+ severity: PeerErrorSeverity.MidToleranceError
1043
1122
  };
1044
1123
  const timer = new Timer();
1045
1124
  try {
1046
1125
  resultAndObj = await validationFunc();
1047
1126
  } catch (err) {
1048
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
1049
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
1127
+ this.logger.error(`Error validating gossipsub message`, err, {
1050
1128
  msgId,
1051
1129
  source: source.toString(),
1052
1130
  topicType
1053
1131
  });
1054
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
+ }
1055
1145
  if (resultAndObj.result === TopicValidatorResult.Accept) {
1146
+ this.logger.debug(`Message ${topicType} accepted by validator`, {
1147
+ msgId,
1148
+ source: source.toString(),
1149
+ topicType
1150
+ });
1056
1151
  this.instrumentation.recordMessageValidation(topicType, timer);
1152
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
1153
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
1154
+ msgId,
1155
+ source: source.toString(),
1156
+ topicType,
1157
+ severity: resultAndObj.severity
1158
+ });
1159
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
1160
+ } else {
1161
+ this.logger.trace(`Message ${topicType} ignored by validator`, {
1162
+ msgId,
1163
+ source: source.toString(),
1164
+ topicType
1165
+ });
1057
1166
  }
1058
1167
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
1059
1168
  return resultAndObj;
1060
1169
  }
1170
+ tryDeserialize(deserializeFunc, msgId, source) {
1171
+ try {
1172
+ return deserializeFunc();
1173
+ } catch (err) {
1174
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
1175
+ err,
1176
+ msgId,
1177
+ source: source.toString()
1178
+ });
1179
+ return undefined;
1180
+ }
1181
+ }
1061
1182
  async handleGossipedTx(payloadData, msgId, source) {
1062
1183
  const validationFunc = async ()=>{
1063
- const tx = Tx.fromBuffer(payloadData);
1064
- const isValid = await this.validatePropagatedTx(tx, source);
1065
- if (!isValid) {
1066
- this.logger.trace(`Rejecting invalid propagated tx`, {
1067
- [Attributes.P2P_ID]: source.toString()
1184
+ const tx = this.tryDeserialize(()=>Tx.fromBuffer(payloadData), msgId, source);
1185
+ if (!tx) {
1186
+ return {
1187
+ result: TopicValidatorResult.Reject,
1188
+ severity: PeerErrorSeverity.LowToleranceError
1189
+ };
1190
+ }
1191
+ const currentBlockNumber = await this.archiver.getBlockNumber();
1192
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1193
+ // Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
1194
+ const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
1195
+ const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
1196
+ if (!firstStageOutcome.allPassed) {
1197
+ const { name } = firstStageOutcome.failure;
1198
+ let { severity } = firstStageOutcome.failure;
1199
+ // Double spend validator has a special case handler. We perform more detailed examination
1200
+ // as to how recently the nullifier was entered into the tree and if the transaction should
1201
+ // have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
1202
+ if (name === 'doubleSpendValidator') {
1203
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1);
1204
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1205
+ }
1206
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
1207
+ validator: name,
1208
+ severity,
1209
+ source: source.toString()
1210
+ });
1211
+ return {
1212
+ result: TopicValidatorResult.Reject,
1213
+ severity
1214
+ };
1215
+ }
1216
+ // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
1217
+ const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
1218
+ if (canAdd === 'ignored') {
1219
+ this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
1220
+ source: source.toString()
1221
+ });
1222
+ return {
1223
+ result: TopicValidatorResult.Ignore,
1224
+ obj: tx
1225
+ };
1226
+ }
1227
+ // Stage 2: expensive proof verification
1228
+ const secondStageValidators = this.createSecondStageMessageValidators();
1229
+ const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
1230
+ if (!secondStageOutcome.allPassed) {
1231
+ const { severity, name } = secondStageOutcome.failure;
1232
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
1233
+ validator: name,
1234
+ severity,
1235
+ source: source.toString()
1068
1236
  });
1069
1237
  return {
1070
- result: TopicValidatorResult.Reject
1238
+ result: TopicValidatorResult.Reject,
1239
+ severity
1071
1240
  };
1072
1241
  }
1073
- // Propagate only on pool acceptance
1242
+ // Pool add: persist the tx
1074
1243
  const txHash = tx.getTxHash();
1075
1244
  const addResult = await this.mempools.txPool.addPendingTxs([
1076
1245
  tx
@@ -1079,8 +1248,7 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1079
1248
  });
1080
1249
  const wasAccepted = addResult.accepted.some((h)=>h.equals(txHash));
1081
1250
  const wasIgnored = addResult.ignored.some((h)=>h.equals(txHash));
1082
- this.logger.trace(`Validate propagated tx`, {
1083
- isValid,
1251
+ this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
1084
1252
  wasAccepted,
1085
1253
  wasIgnored,
1086
1254
  [Attributes.P2P_ID]: source.toString()
@@ -1096,8 +1264,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1096
1264
  obj: tx
1097
1265
  };
1098
1266
  } else {
1267
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
1268
+ source: source.toString(),
1269
+ txHash: txHash.toString()
1270
+ });
1099
1271
  return {
1100
- result: TopicValidatorResult.Reject
1272
+ result: TopicValidatorResult.Reject,
1273
+ severity: PeerErrorSeverity.HighToleranceError
1101
1274
  };
1102
1275
  }
1103
1276
  };
@@ -1118,7 +1291,16 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1118
1291
  * Process a checkpoint attestation from a peer.
1119
1292
  * Validates the attestation and adds it to the pool.
1120
1293
  */ async processCheckpointAttestationFromPeer(payloadData, msgId, source) {
1121
- const { result, obj: attestation } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_attestation);
1294
+ const { result, obj: attestation } = await this.validateReceivedMessage(()=>{
1295
+ const attestation = this.tryDeserialize(()=>CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1296
+ if (!attestation) {
1297
+ return Promise.resolve({
1298
+ result: TopicValidatorResult.Reject,
1299
+ severity: PeerErrorSeverity.LowToleranceError
1300
+ });
1301
+ }
1302
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1303
+ }, msgId, source, TopicType.checkpoint_attestation);
1122
1304
  if (result !== TopicValidatorResult.Accept || !attestation) {
1123
1305
  return;
1124
1306
  }
@@ -1133,9 +1315,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1133
1315
  const validationResult = await this.checkpointAttestationValidator.validate(attestation);
1134
1316
  if (validationResult.result === 'reject') {
1135
1317
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1136
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1137
1318
  return {
1138
- result: TopicValidatorResult.Reject
1319
+ result: TopicValidatorResult.Reject,
1320
+ severity: validationResult.severity
1139
1321
  };
1140
1322
  }
1141
1323
  if (validationResult.result === 'ignore') {
@@ -1162,9 +1344,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1162
1344
  obj: attestation
1163
1345
  };
1164
1346
  }
1165
- // Could not add (cap reached for signer), no need to re-broadcast
1347
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1166
1348
  if (!added) {
1167
- this.logger.warn(`Dropping checkpoint attestation due to cap`, {
1349
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1168
1350
  slot: slot.toString(),
1169
1351
  archive: attestation.archive.toString(),
1170
1352
  source: peerId.toString(),
@@ -1172,8 +1354,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1172
1354
  count
1173
1355
  });
1174
1356
  return {
1175
- result: TopicValidatorResult.Ignore,
1176
- obj: attestation
1357
+ result: TopicValidatorResult.Reject,
1358
+ severity: PeerErrorSeverity.HighToleranceError
1177
1359
  };
1178
1360
  }
1179
1361
  // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
@@ -1194,15 +1376,17 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1194
1376
  }
1195
1377
  }
1196
1378
  // Attestation was added successfully - accept it so other nodes can also detect the equivocation
1379
+ this.checkpointAttestationCallback?.(attestation);
1197
1380
  return {
1198
1381
  result: TopicValidatorResult.Accept,
1199
1382
  obj: attestation
1200
1383
  };
1201
1384
  }
1202
1385
  async processBlockFromPeer(payloadData, msgId, source) {
1203
- const { result, obj: block, metadata: { isEquivocated } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
1204
- // If not accepted or equivocated, return
1205
- 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) {
1206
1390
  return;
1207
1391
  }
1208
1392
  await this.processValidBlockProposal(block, source);
@@ -1211,9 +1395,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1211
1395
  const validationResult = await this.blockProposalValidator.validate(block);
1212
1396
  if (validationResult.result === 'reject') {
1213
1397
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1214
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1215
1398
  return {
1216
- result: TopicValidatorResult.Reject
1399
+ result: TopicValidatorResult.Reject,
1400
+ severity: validationResult.severity
1217
1401
  };
1218
1402
  }
1219
1403
  if (validationResult.result === 'ignore') {
@@ -1225,6 +1409,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1225
1409
  // Try to add the proposal: this handles existence check, cap check, and adding in one call
1226
1410
  const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1227
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;
1228
1416
  // Duplicate proposal received, no need to re-broadcast
1229
1417
  if (alreadyExists) {
1230
1418
  this.logger.debug(`Ignoring duplicate block proposal received`, {
@@ -1237,13 +1425,13 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1237
1425
  result: TopicValidatorResult.Ignore,
1238
1426
  obj: block,
1239
1427
  metadata: {
1240
- isEquivocated
1428
+ isEquivocated,
1429
+ isOversized
1241
1430
  }
1242
1431
  };
1243
1432
  }
1244
1433
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1245
1434
  if (!added) {
1246
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1247
1435
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1248
1436
  ...block.toBlockInfo(),
1249
1437
  indexWithinCheckpoint: block.indexWithinCheckpoint,
@@ -1254,10 +1442,30 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1254
1442
  return {
1255
1443
  result: TopicValidatorResult.Reject,
1256
1444
  metadata: {
1257
- isEquivocated
1258
- }
1445
+ isEquivocated,
1446
+ isOversized
1447
+ },
1448
+ severity: PeerErrorSeverity.HighToleranceError
1259
1449
  };
1260
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
+ }
1261
1469
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
1262
1470
  // and do re-broadcast it so other nodes in the network know to slash the proposer
1263
1471
  if (isEquivocated) {
@@ -1279,14 +1487,19 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1279
1487
  result: TopicValidatorResult.Accept,
1280
1488
  obj: block,
1281
1489
  metadata: {
1282
- isEquivocated
1490
+ isEquivocated,
1491
+ isOversized
1283
1492
  }
1284
1493
  };
1285
1494
  }
1286
1495
  // Otherwise, we're good to go!
1287
1496
  return {
1288
1497
  result: TopicValidatorResult.Accept,
1289
- obj: block
1498
+ obj: block,
1499
+ metadata: {
1500
+ isEquivocated: false,
1501
+ isOversized
1502
+ }
1290
1503
  };
1291
1504
  }
1292
1505
  // REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
@@ -1304,23 +1517,36 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1304
1517
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1305
1518
  const isValid = await this.blockReceivedCallback(block, sender);
1306
1519
  if (!isValid) {
1307
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
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);
1308
1524
  }
1309
1525
  }
1310
1526
  /**
1311
1527
  * Handle a gossiped checkpoint proposal.
1312
1528
  * Validates and processes the checkpoint proposal, then triggers the callback for attestation.
1313
1529
  */ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
1314
- 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();
1315
1534
  // If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
1316
1535
  // TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
1317
- if (processBlock && checkpoint?.getBlockProposal()) {
1318
- await this.processValidBlockProposal(checkpoint.getBlockProposal(), source);
1319
- }
1320
- 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();
1321
1545
  return;
1322
1546
  }
1323
- 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();
1324
1550
  }
1325
1551
  /**
1326
1552
  * Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
@@ -1329,9 +1555,9 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1329
1555
  const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
1330
1556
  if (validationResult.result === 'reject') {
1331
1557
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1332
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1333
1558
  return {
1334
- result: TopicValidatorResult.Reject
1559
+ result: TopicValidatorResult.Reject,
1560
+ severity: validationResult.severity
1335
1561
  };
1336
1562
  }
1337
1563
  if (validationResult.result === 'ignore') {
@@ -1343,23 +1569,28 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1343
1569
  // Extract and try to add the block proposal first if present
1344
1570
  const blockProposal = checkpoint.getBlockProposal();
1345
1571
  let processBlock = false;
1572
+ let isOversized = false;
1346
1573
  if (blockProposal) {
1347
1574
  this.logger.debug(`Validating block proposal from propagated checkpoint`, {
1348
1575
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1349
1576
  [Attributes.P2P_ID]: peerId.toString()
1350
1577
  });
1351
- const { result, obj, metadata: { isEquivocated } = {} } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1352
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1578
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1579
+ const { obj, metadata: { isEquivocated, isOversized: blockIsOversized } = {} } = blockProposalResult;
1580
+ isOversized = blockIsOversized ?? false;
1581
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1353
1582
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1354
1583
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1355
1584
  [Attributes.P2P_ID]: peerId.toString(),
1356
1585
  isEquivocated,
1357
- result
1586
+ result: blockProposalResult.result
1358
1587
  });
1359
1588
  return {
1360
- result: TopicValidatorResult.Reject
1589
+ result: TopicValidatorResult.Reject,
1590
+ severity: 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError
1361
1591
  };
1362
- } else if (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.
1363
1594
  processBlock = true;
1364
1595
  }
1365
1596
  }
@@ -1379,14 +1610,14 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1379
1610
  obj: checkpoint,
1380
1611
  metadata: {
1381
1612
  isEquivocated,
1382
- processBlock
1613
+ processBlock,
1614
+ isOversized
1383
1615
  }
1384
1616
  };
1385
1617
  }
1386
- // 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.
1387
1619
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1388
1620
  if (!added) {
1389
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1390
1621
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1391
1622
  ...checkpoint.toCheckpointInfo(),
1392
1623
  count,
@@ -1397,8 +1628,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1397
1628
  obj: checkpoint,
1398
1629
  metadata: {
1399
1630
  isEquivocated,
1400
- processBlock
1401
- }
1631
+ processBlock,
1632
+ isOversized
1633
+ },
1634
+ severity: PeerErrorSeverity.HighToleranceError
1402
1635
  };
1403
1636
  }
1404
1637
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1423,7 +1656,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1423
1656
  obj: checkpoint,
1424
1657
  metadata: {
1425
1658
  isEquivocated,
1426
- processBlock
1659
+ processBlock,
1660
+ isOversized
1427
1661
  }
1428
1662
  };
1429
1663
  }
@@ -1433,7 +1667,8 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1433
1667
  obj: checkpoint,
1434
1668
  metadata: {
1435
1669
  processBlock,
1436
- isEquivocated
1670
+ isEquivocated,
1671
+ isOversized
1437
1672
  }
1438
1673
  };
1439
1674
  }
@@ -1448,9 +1683,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1448
1683
  archive: checkpoint.archive.toString(),
1449
1684
  source: sender.toString()
1450
1685
  });
1686
+ await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
1451
1687
  // Call the checkpoint received callback with the core version (without lastBlock)
1452
1688
  // to validate and potentially generate attestations
1453
- const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
1689
+ const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
1454
1690
  if (attestations && attestations.length > 0) {
1455
1691
  // If the callback returned attestations, add them to the pool and propagate them
1456
1692
  await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
@@ -1474,192 +1710,78 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1474
1710
  });
1475
1711
  }
1476
1712
  /**
1477
- * 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.
1478
1715
  * @param request - The block transactions request.
1479
1716
  * @param response - The block transactions response.
1480
1717
  * @param peerId - The ID of the peer that made the request.
1481
- * @returns True if the requested block transactions are valid, false otherwise.
1482
- */ async validateRequestedBlockTxs(request, response, peerId) {
1483
- const requestedTxValidator = this.createRequestedTxValidator();
1718
+ * @returns True if the request-response is consistent, false otherwise.
1719
+ */ async validateRequestedBlockTxsConsistency(request, response, peerId) {
1484
1720
  try {
1485
- if (!response.archiveRoot.equals(request.archiveRoot)) {
1486
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1487
- throw new ValidationError(`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`);
1488
- }
1489
- if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1490
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1491
- throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`);
1492
- }
1493
- // Check no duplicates and not exceeding returnable count
1494
- const requestedIndices = new Set(request.txIndices.getTrueIndices());
1495
- const availableIndices = new Set(response.txIndices.getTrueIndices());
1496
- const maxReturnable = [
1497
- ...requestedIndices
1498
- ].filter((i)=>availableIndices.has(i)).length;
1499
- 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());
1500
1723
  const uniqueReturned = new Set(returnedHashes.map((h)=>h.toString()));
1501
1724
  if (uniqueReturned.size !== returnedHashes.length) {
1502
1725
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1503
1726
  throw new ValidationError(`Received duplicate txs in block txs response`);
1504
1727
  }
1505
- if (response.txs.length > maxReturnable) {
1506
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1507
- throw new ValidationError(`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`);
1508
- }
1509
- // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1510
- const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
1511
- if (proposal) {
1512
- // Build intersected indices
1513
- const intersectIdx = request.txIndices.getTrueIndices().filter((i)=>response.txIndices.isSet(i));
1514
- // Enforce subset membership and preserve increasing order by index.
1515
- const hashToIndexInProposal = new Map(proposal.txHashes.map((h, i)=>[
1516
- h.toString(),
1517
- i
1518
- ]));
1519
- const allowedIndexSet = new Set(intersectIdx);
1520
- const indices = returnedHashes.map((h)=>hashToIndexInProposal.get(h));
1521
- const allAllowed = indices.every((idx)=>idx !== undefined && allowedIndexSet.has(idx));
1522
- const strictlyIncreasing = indices.every((idx, i)=>i === 0 ? idx !== undefined : idx > indices[i - 1]);
1523
- if (!allAllowed || !strictlyIncreasing) {
1524
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1525
- throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1526
- }
1527
- } else {
1528
- // No local proposal, cannot check the membership/order of the returned txs
1529
- this.logger.warn(`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`);
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.
1530
1740
  return false;
1531
1741
  }
1532
- await Promise.all(response.txs.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator)));
1533
- return true;
1534
- } catch (e) {
1535
- if (e instanceof ValidationError) {
1536
- this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
1537
- } else {
1538
- this.logger.error(`Error during validation of requested block txs`, e);
1539
- }
1540
- return false;
1541
- }
1542
- }
1543
- /**
1544
- * Validate a collection of txs that has been requested from a peer.
1545
- *
1546
- * The core component of this validator is that each tx hash MUST match the requested tx hash,
1547
- * In order to perform this check, the tx proof must be verified.
1548
- *
1549
- * Note: This function is called from within `ReqResp.sendRequest` as part of the
1550
- * ReqRespSubProtocol.TX subprotocol validation.
1551
- *
1552
- * @param requestedTxHash - The collection of the txs that was requested.
1553
- * @param responseTx - The collection of txs that was received as a response to the request.
1554
- * @param peerId - The peer ID of the peer that sent the tx.
1555
- * @returns True if the whole collection of txs is valid, false otherwise.
1556
- */ async validateRequestedTxs(requestedTxHash, responseTx, peerId) {
1557
- const requested = new Set(requestedTxHash.map((h)=>h.toString()));
1558
- const requestedTxValidator = this.createRequestedTxValidator();
1559
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
1560
- // I think we should still extract the valid txs and return them, so that we can still use the response.
1561
- try {
1562
- await Promise.all(responseTx.map((tx)=>this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
1563
- return true;
1564
- } catch (e) {
1565
- if (e instanceof ValidationError) {
1566
- this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
1567
- } else {
1568
- this.logger.error(`Error during validation of requested txs`, e);
1569
- }
1570
- return false;
1571
- }
1572
- }
1573
- /**
1574
- * Validates a BLOCK response.
1575
- *
1576
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1577
- * Penalizes on block number mismatch or hash mismatch.
1578
- *
1579
- * @param requestedBlockNumber - The requested block number.
1580
- * @param responseBlock - The block returned by the peer.
1581
- * @param peerId - The peer that returned the block.
1582
- * @returns True if the response is valid, false otherwise.
1583
- */ async validateRequestedBlock(requestedBlockNumber, responseBlock, peerId) {
1584
- try {
1585
- const reqNum = Number(requestedBlockNumber.toString());
1586
- if (responseBlock.number !== reqNum) {
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))) {
1587
1750
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1588
- return false;
1751
+ throw new ValidationError('Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)');
1589
1752
  }
1590
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1591
- if (!local) {
1592
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1593
- // TODO: Consider extending this validator to accept an expected hash or
1594
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1595
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1596
- return false;
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;
1597
1757
  }
1598
- const [localHash, respHash] = await Promise.all([
1599
- local.hash(),
1600
- responseBlock.hash()
1601
- ]);
1602
- if (!localHash.equals(respHash)) {
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) {
1603
1760
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1604
- return false;
1761
+ throw new ValidationError(`Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`);
1762
+ }
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');
1605
1772
  }
1606
1773
  return true;
1607
1774
  } catch (e) {
1608
- this.logger.warn(`Error validating requested block`, e);
1609
- return false;
1610
- }
1611
- }
1612
- async validateRequestedTx(tx, peerId, txValidator, requested) {
1613
- const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
1614
- if (requested && !requested.has(tx.getTxHash().toString())) {
1615
- penalize(PeerErrorSeverity.MidToleranceError);
1616
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1617
- }
1618
- const { result } = await txValidator.validateTx(tx);
1619
- if (result === 'invalid') {
1620
- penalize(PeerErrorSeverity.LowToleranceError);
1621
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1622
- }
1623
- }
1624
- createRequestedTxValidator() {
1625
- return createTxReqRespValidator(this.proofVerifier, {
1626
- l1ChainId: this.config.l1ChainId,
1627
- rollupVersion: this.config.rollupVersion
1628
- });
1629
- }
1630
- async validatePropagatedTx(tx, peerId) {
1631
- const currentBlockNumber = await this.archiver.getBlockNumber();
1632
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1633
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1634
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1635
- for (const validator of messageValidators){
1636
- const outcome = await this.runValidations(tx, validator);
1637
- if (outcome.allPassed) {
1638
- continue;
1639
- }
1640
- const { name } = outcome.failure;
1641
- let { severity } = outcome.failure;
1642
- // Double spend validator has a special case handler
1643
- if (name === 'doubleSpendValidator') {
1644
- const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1645
- severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1775
+ if (e instanceof ValidationError) {
1776
+ this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
1777
+ } else {
1778
+ this.logger.error(`Error during validation of requested block txs`, e);
1646
1779
  }
1647
- this.peerManager.penalizePeer(peerId, severity);
1648
1780
  return false;
1649
1781
  }
1650
- return true;
1651
1782
  }
1652
- async getGasFees(blockNumber) {
1653
- if (blockNumber === this.feesCache?.blockNumber) {
1654
- return this.feesCache.gasFees;
1655
- }
1656
- const header = await this.archiver.getBlockHeader(blockNumber);
1657
- const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
1658
- this.feesCache = {
1659
- blockNumber,
1660
- gasFees
1661
- };
1662
- return gasFees;
1783
+ getGasFees() {
1784
+ return this.blockMinFeesProvider.getCurrentMinFees();
1663
1785
  }
1664
1786
  /**
1665
1787
  * Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
@@ -1670,43 +1792,42 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1670
1792
  txValidatorConfig: {
1671
1793
  l1ChainId: this.config.l1ChainId,
1672
1794
  rollupVersion: this.config.rollupVersion,
1673
- proofVerifier: this.proofVerifier
1795
+ proofVerifier: this.proofVerifier,
1796
+ txValidationCache: this.txValidationCache
1674
1797
  },
1675
- peerScoring: this.peerManager
1798
+ peerScoring: this.peerManager,
1799
+ validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this)
1676
1800
  };
1677
1801
  }
1678
- async validate(txs) {
1679
- const currentBlockNumber = await this.archiver.getBlockNumber();
1680
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1681
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1682
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1683
- await Promise.all(txs.map(async (tx)=>{
1684
- for (const validator of messageValidators){
1685
- const outcome = await this.runValidations(tx, validator);
1686
- if (!outcome.allPassed) {
1687
- throw new Error('Invalid tx detected', {
1688
- cause: {
1689
- outcome
1690
- }
1691
- });
1692
- }
1693
- }
1802
+ async validateTxsReceivedInBlockProposal(txs) {
1803
+ const validator = createTxValidatorForBlockProposalReceivedTxs(this.proofVerifier, {
1804
+ l1ChainId: this.config.l1ChainId,
1805
+ rollupVersion: this.config.rollupVersion
1806
+ }, this.logger.getBindings(), this.txValidationCache);
1807
+ const results = await Promise.all(txs.map(async (tx)=>{
1808
+ const result = await validator.validateTx(tx);
1809
+ return result.result !== 'invalid';
1694
1810
  }));
1811
+ if (results.some((value)=>value === false)) {
1812
+ throw new Error('Invalid tx detected');
1813
+ }
1695
1814
  }
1696
- /**
1697
- * Create message validators for the given block number and timestamp.
1698
- *
1699
- * Each validator is a pair of a validator and a severity.
1700
- * If a validator fails, the peer is penalized with the severity of the validator.
1701
- *
1702
- * @param currentBlockNumber - The current synced block number.
1703
- * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
1704
- * @returns The message validators.
1705
- */ async createMessageValidators(currentBlockNumber, nextSlotTimestamp) {
1706
- const gasFees = await this.getGasFees(currentBlockNumber);
1707
- const allowedInSetup = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
1708
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1709
- return createTxMessageValidators(nextSlotTimestamp, blockNumberInWhichTheTxIsConsideredToBeIncluded, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, this.proofVerifier, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings());
1815
+ /** Creates the first stage (fast) validators for gossiped transactions. */ async createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp) {
1816
+ const gasFees = await this.getGasFees();
1817
+ const allowedInSetup = [
1818
+ ...await getDefaultAllowedSetupFunctions(),
1819
+ ...this.config.txPublicSetupAllowListExtend ?? []
1820
+ ];
1821
+ const blockNumber = BlockNumber(currentBlockNumber + 1);
1822
+ const l1Constants = await this.archiver.getL1Constants();
1823
+ const networkTxGasLimits = getNetworkTxGasLimits(this.config, l1Constants);
1824
+ return createFirstStageTxValidationsForGossipedTransactions(nextSlotTimestamp, blockNumber, this.worldStateSynchronizer, gasFees, this.config.l1ChainId, this.config.rollupVersion, protocolContractsHash, this.archiver, !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), {
1825
+ maxTxL2Gas: networkTxGasLimits.l2Gas,
1826
+ maxTxDAGas: networkTxGasLimits.daGas
1827
+ });
1828
+ }
1829
+ /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */ createSecondStageMessageValidators() {
1830
+ return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
1710
1831
  }
1711
1832
  /**
1712
1833
  * Run validations on a tx.
@@ -1724,8 +1845,10 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1724
1845
  });
1725
1846
  // A promise that resolves when all validations have been run
1726
1847
  const allValidations = await Promise.all(validationPromises);
1727
- const failed = allValidations.find((x)=>!x.isValid);
1728
- if (failed) {
1848
+ const failures = allValidations.filter((x)=>!x.isValid);
1849
+ if (failures.length > 0) {
1850
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1851
+ const failed = maxBy(failures, (f)=>PeerErrorSeverityByHarshness.indexOf(f.severity));
1729
1852
  return {
1730
1853
  allPassed: false,
1731
1854
  failure: {
@@ -1772,19 +1895,6 @@ _dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId
1772
1895
  }
1773
1896
  return PeerErrorSeverity.HighToleranceError;
1774
1897
  }
1775
- /**
1776
- * Validate a checkpoint attestation.
1777
- *
1778
- * @param attestation - The checkpoint attestation to validate.
1779
- * @returns True if the checkpoint attestation is valid, false otherwise.
1780
- */ async validateCheckpointAttestation(peerId, attestation) {
1781
- const result = await this.checkpointAttestationValidator.validate(attestation);
1782
- if (result.result === 'reject') {
1783
- this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1784
- this.peerManager.penalizePeer(peerId, result.severity);
1785
- }
1786
- return result;
1787
- }
1788
1898
  getPeerScore(peerId) {
1789
1899
  return this.node.services.pubsub.score.score(peerId.toString());
1790
1900
  }