@aztec/p2p 0.0.1-commit.e558bd1c → 0.0.1-commit.e57c76e

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 (521) hide show
  1. package/README.md +129 -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 +9 -1
  5. package/dest/client/factory.d.ts +11 -10
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +58 -16
  8. package/dest/client/interface.d.ts +51 -36
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +48 -57
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +219 -236
  13. package/dest/config.d.ts +161 -94
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +150 -41
  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 +1 -20
  20. package/dest/errors/reqresp.error.d.ts.map +1 -1
  21. package/dest/errors/reqresp.error.js +0 -21
  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 +2 -2
  26. package/dest/index.d.ts.map +1 -1
  27. package/dest/index.js +1 -1
  28. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +104 -55
  29. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool.js +295 -195
  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 +231 -115
  34. package/dest/mem_pools/attestation_pool/index.d.ts +2 -2
  35. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/index.js +1 -1
  37. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  38. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  39. package/dest/mem_pools/attestation_pool/mocks.js +7 -5
  40. package/dest/mem_pools/index.d.ts +2 -2
  41. package/dest/mem_pools/index.d.ts.map +1 -1
  42. package/dest/mem_pools/instrumentation.d.ts +4 -2
  43. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  44. package/dest/mem_pools/instrumentation.js +33 -15
  45. package/dest/mem_pools/interface.d.ts +3 -3
  46. package/dest/mem_pools/interface.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +1 -5
  48. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +1 -7
  50. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
  51. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
  52. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
  53. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  54. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  55. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  56. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  57. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  58. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +7 -3
  59. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  60. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  61. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  62. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
  63. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  64. package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
  65. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  66. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  67. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  68. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
  69. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  70. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  71. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
  72. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
  73. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  74. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  75. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
  76. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  77. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  78. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +16 -4
  79. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  80. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  81. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +3 -3
  82. package/dest/mem_pools/tx_pool_v2/index.d.ts +3 -2
  83. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  84. package/dest/mem_pools/tx_pool_v2/index.js +2 -1
  85. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  86. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  87. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  88. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +33 -12
  89. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  90. package/dest/mem_pools/tx_pool_v2/interfaces.js +5 -1
  91. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +81 -15
  92. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  93. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +147 -19
  94. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +12 -3
  95. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  96. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +50 -45
  97. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +12 -5
  98. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  99. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +17 -6
  100. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +14 -5
  101. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  102. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +407 -241
  103. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +9 -3
  104. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  105. package/dest/msg_validators/attestation_validator/attestation_validator.js +37 -12
  106. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
  107. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  108. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -5
  109. package/dest/msg_validators/clock_tolerance.d.ts +12 -1
  110. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  111. package/dest/msg_validators/clock_tolerance.js +56 -3
  112. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +10 -4
  113. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  114. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  115. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +10 -4
  116. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  117. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  118. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +21 -8
  119. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  120. package/dest/msg_validators/proposal_validator/proposal_validator.js +90 -44
  121. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
  122. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  123. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
  124. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  125. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  126. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
  127. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  128. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  129. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  130. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  131. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
  132. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  133. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  134. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  135. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  136. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  137. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  138. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  139. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  140. package/dest/msg_validators/tx_validator/data_validator.d.ts +2 -1
  141. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  142. package/dest/msg_validators/tx_validator/data_validator.js +36 -2
  143. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
  144. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  145. package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
  146. package/dest/msg_validators/tx_validator/factory.d.ts +135 -7
  147. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  148. package/dest/msg_validators/tx_validator/factory.js +252 -61
  149. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  150. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  151. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  152. package/dest/msg_validators/tx_validator/gas_validator.d.ts +99 -3
  153. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  154. package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
  155. package/dest/msg_validators/tx_validator/index.d.ts +5 -1
  156. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  157. package/dest/msg_validators/tx_validator/index.js +4 -0
  158. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  159. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  160. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  161. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  162. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  163. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  164. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  165. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  166. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  167. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
  168. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  169. package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
  170. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  171. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  172. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -0
  173. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  174. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  175. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  176. package/dest/services/data_store.d.ts +1 -1
  177. package/dest/services/data_store.d.ts.map +1 -1
  178. package/dest/services/data_store.js +5 -5
  179. package/dest/services/discv5/discV5_service.d.ts +2 -1
  180. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  181. package/dest/services/discv5/discV5_service.js +35 -8
  182. package/dest/services/dummy_service.d.ts +18 -18
  183. package/dest/services/dummy_service.d.ts.map +1 -1
  184. package/dest/services/dummy_service.js +19 -20
  185. package/dest/services/encoding.d.ts +7 -3
  186. package/dest/services/encoding.d.ts.map +1 -1
  187. package/dest/services/encoding.js +18 -11
  188. package/dest/services/gossipsub/index.d.ts +3 -0
  189. package/dest/services/gossipsub/index.d.ts.map +1 -0
  190. package/dest/services/gossipsub/index.js +2 -0
  191. package/dest/services/gossipsub/scoring.d.ts +21 -3
  192. package/dest/services/gossipsub/scoring.d.ts.map +1 -1
  193. package/dest/services/gossipsub/scoring.js +24 -7
  194. package/dest/services/gossipsub/topic_score_params.d.ts +184 -0
  195. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
  196. package/dest/services/gossipsub/topic_score_params.js +363 -0
  197. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  198. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  199. package/dest/services/libp2p/instrumentation.js +14 -0
  200. package/dest/services/libp2p/libp2p_service.d.ts +56 -55
  201. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  202. package/dest/services/libp2p/libp2p_service.js +449 -397
  203. package/dest/services/peer-manager/metrics.d.ts +3 -1
  204. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  205. package/dest/services/peer-manager/metrics.js +6 -0
  206. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  207. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  208. package/dest/services/peer-manager/peer_manager.js +40 -11
  209. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  210. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  211. package/dest/services/peer-manager/peer_scoring.js +57 -12
  212. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +5 -8
  213. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  214. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +95 -127
  215. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +11 -11
  216. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  217. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
  218. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  219. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
  220. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  221. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  222. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  223. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +5 -14
  224. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -1
  225. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +6 -20
  226. package/dest/services/reqresp/config.d.ts +3 -3
  227. package/dest/services/reqresp/config.d.ts.map +1 -1
  228. package/dest/services/reqresp/interface.d.ts +25 -18
  229. package/dest/services/reqresp/interface.d.ts.map +1 -1
  230. package/dest/services/reqresp/interface.js +23 -19
  231. package/dest/services/reqresp/metrics.d.ts +1 -1
  232. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  233. package/dest/services/reqresp/metrics.js +0 -1
  234. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +4 -3
  235. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  236. package/dest/services/reqresp/protocols/block_txs/bitvector.js +3 -2
  237. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +3 -3
  238. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  239. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +31 -28
  240. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +18 -7
  241. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  242. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +57 -24
  243. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  244. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  245. package/dest/services/reqresp/protocols/index.js +0 -1
  246. package/dest/services/reqresp/protocols/tx.d.ts +7 -1
  247. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  248. package/dest/services/reqresp/protocols/tx.js +21 -3
  249. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  250. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  251. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  252. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  253. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  254. package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
  255. package/dest/services/reqresp/reqresp.d.ts +7 -29
  256. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  257. package/dest/services/reqresp/reqresp.js +53 -218
  258. package/dest/services/service.d.ts +30 -14
  259. package/dest/services/service.d.ts.map +1 -1
  260. package/dest/services/tx_collection/config.d.ts +11 -14
  261. package/dest/services/tx_collection/config.d.ts.map +1 -1
  262. package/dest/services/tx_collection/config.js +26 -33
  263. package/dest/services/tx_collection/file_store_tx_collection.d.ts +37 -0
  264. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
  265. package/dest/services/tx_collection/file_store_tx_collection.js +127 -0
  266. package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
  267. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
  268. package/dest/services/tx_collection/file_store_tx_source.js +100 -0
  269. package/dest/services/tx_collection/index.d.ts +3 -3
  270. package/dest/services/tx_collection/index.d.ts.map +1 -1
  271. package/dest/services/tx_collection/index.js +1 -1
  272. package/dest/services/tx_collection/instrumentation.js +1 -2
  273. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  274. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  275. package/dest/services/tx_collection/request_tracker.js +84 -0
  276. package/dest/services/tx_collection/tx_collection.d.ts +45 -51
  277. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  278. package/dest/services/tx_collection/tx_collection.js +296 -68
  279. package/dest/services/tx_collection/tx_collection_sink.d.ts +19 -9
  280. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  281. package/dest/services/tx_collection/tx_collection_sink.js +28 -31
  282. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  283. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  284. package/dest/services/tx_collection/tx_source.js +26 -7
  285. package/dest/services/tx_file_store/config.d.ts +1 -3
  286. package/dest/services/tx_file_store/config.d.ts.map +1 -1
  287. package/dest/services/tx_file_store/config.js +0 -4
  288. package/dest/services/tx_file_store/tx_file_store.d.ts +4 -5
  289. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  290. package/dest/services/tx_file_store/tx_file_store.js +13 -20
  291. package/dest/services/tx_provider.d.ts +6 -4
  292. package/dest/services/tx_provider.d.ts.map +1 -1
  293. package/dest/services/tx_provider.js +12 -8
  294. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
  295. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  296. package/dest/test-helpers/make-test-p2p-clients.js +5 -3
  297. package/dest/test-helpers/mock-pubsub.d.ts +46 -6
  298. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  299. package/dest/test-helpers/mock-pubsub.js +115 -14
  300. package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
  301. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  302. package/dest/test-helpers/reqresp-nodes.js +19 -20
  303. package/dest/test-helpers/test_tx_provider.d.ts +3 -1
  304. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -1
  305. package/dest/test-helpers/test_tx_provider.js +3 -0
  306. package/dest/test-helpers/testbench-utils.d.ts +46 -37
  307. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  308. package/dest/test-helpers/testbench-utils.js +142 -50
  309. package/dest/testbench/p2p_client_testbench_worker.d.ts +3 -5
  310. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  311. package/dest/testbench/p2p_client_testbench_worker.js +93 -47
  312. package/dest/testbench/worker_client_manager.d.ts +12 -6
  313. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  314. package/dest/testbench/worker_client_manager.js +57 -11
  315. package/dest/util.d.ts +13 -8
  316. package/dest/util.d.ts.map +1 -1
  317. package/dest/util.js +35 -14
  318. package/dest/versioning.d.ts +3 -6
  319. package/dest/versioning.d.ts.map +1 -1
  320. package/dest/versioning.js +3 -24
  321. package/package.json +15 -14
  322. package/src/bootstrap/bootstrap.ts +9 -1
  323. package/src/client/factory.ts +124 -27
  324. package/src/client/interface.ts +58 -44
  325. package/src/client/p2p_client.ts +256 -299
  326. package/src/client/test/{tx_proposal_collector/README.md → p2p_client.batch_tx_requester.bench.README.md} +23 -53
  327. package/src/config.ts +260 -46
  328. package/src/errors/p2p-service.error.ts +11 -0
  329. package/src/errors/reqresp.error.ts +0 -25
  330. package/src/errors/tx-pool.error.ts +12 -0
  331. package/src/index.ts +1 -1
  332. package/src/mem_pools/attestation_pool/attestation_pool.ts +363 -236
  333. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +258 -118
  334. package/src/mem_pools/attestation_pool/index.ts +3 -3
  335. package/src/mem_pools/attestation_pool/mocks.ts +14 -8
  336. package/src/mem_pools/index.ts +1 -1
  337. package/src/mem_pools/instrumentation.ts +22 -14
  338. package/src/mem_pools/interface.ts +2 -2
  339. package/src/mem_pools/tx_pool_v2/README.md +85 -11
  340. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +1 -9
  341. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
  342. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  343. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +7 -3
  344. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  345. package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
  346. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  347. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
  348. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
  349. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
  350. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
  351. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
  352. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
  353. package/src/mem_pools/tx_pool_v2/index.ts +2 -1
  354. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  355. package/src/mem_pools/tx_pool_v2/interfaces.ts +35 -12
  356. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +215 -27
  357. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +58 -45
  358. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +34 -8
  359. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +448 -240
  360. package/src/msg_validators/attestation_validator/README.md +49 -0
  361. package/src/msg_validators/attestation_validator/attestation_validator.ts +41 -9
  362. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +14 -7
  363. package/src/msg_validators/clock_tolerance.ts +73 -3
  364. package/src/msg_validators/proposal_validator/README.md +123 -0
  365. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +24 -4
  366. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +35 -7
  367. package/src/msg_validators/proposal_validator/proposal_validator.ts +114 -47
  368. package/src/msg_validators/tx_validator/README.md +127 -0
  369. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +8 -17
  370. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  371. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  372. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  373. package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
  374. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  375. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  376. package/src/msg_validators/tx_validator/data_validator.ts +44 -1
  377. package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
  378. package/src/msg_validators/tx_validator/factory.ts +407 -80
  379. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  380. package/src/msg_validators/tx_validator/gas_validator.ts +199 -54
  381. package/src/msg_validators/tx_validator/index.ts +4 -0
  382. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  383. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  384. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  385. package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
  386. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -0
  387. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  388. package/src/services/data_store.ts +5 -13
  389. package/src/services/discv5/discV5_service.ts +38 -5
  390. package/src/services/dummy_service.ts +26 -45
  391. package/src/services/encoding.ts +18 -10
  392. package/src/services/gossipsub/README.md +641 -0
  393. package/src/services/gossipsub/index.ts +2 -0
  394. package/src/services/gossipsub/scoring.ts +29 -5
  395. package/src/services/gossipsub/topic_score_params.ts +519 -0
  396. package/src/services/libp2p/instrumentation.ts +14 -0
  397. package/src/services/libp2p/libp2p_service.ts +497 -453
  398. package/src/services/peer-manager/metrics.ts +7 -0
  399. package/src/services/peer-manager/peer_manager.ts +46 -11
  400. package/src/services/peer-manager/peer_scoring.ts +52 -5
  401. package/src/services/reqresp/README.md +215 -0
  402. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  403. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +92 -138
  404. package/src/services/reqresp/batch-tx-requester/interface.ts +14 -10
  405. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
  406. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  407. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +12 -25
  408. package/src/services/reqresp/config.ts +2 -2
  409. package/src/services/reqresp/interface.ts +45 -46
  410. package/src/services/reqresp/metrics.ts +0 -1
  411. package/src/services/reqresp/protocols/block_txs/bitvector.ts +3 -2
  412. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +36 -32
  413. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +64 -20
  414. package/src/services/reqresp/protocols/index.ts +0 -1
  415. package/src/services/reqresp/protocols/tx.ts +23 -3
  416. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  417. package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
  418. package/src/services/reqresp/reqresp.ts +61 -264
  419. package/src/services/service.ts +43 -30
  420. package/src/services/tx_collection/config.ts +40 -49
  421. package/src/services/tx_collection/file_store_tx_collection.ts +153 -0
  422. package/src/services/tx_collection/file_store_tx_source.ts +129 -0
  423. package/src/services/tx_collection/index.ts +2 -6
  424. package/src/services/tx_collection/instrumentation.ts +1 -1
  425. package/src/services/tx_collection/request_tracker.ts +127 -0
  426. package/src/services/tx_collection/tx_collection.ts +362 -110
  427. package/src/services/tx_collection/tx_collection_sink.ts +32 -36
  428. package/src/services/tx_collection/tx_source.ts +28 -8
  429. package/src/services/tx_file_store/config.ts +0 -6
  430. package/src/services/tx_file_store/tx_file_store.ts +15 -25
  431. package/src/services/tx_provider.ts +15 -9
  432. package/src/test-helpers/make-test-p2p-clients.ts +7 -6
  433. package/src/test-helpers/mock-pubsub.ts +137 -14
  434. package/src/test-helpers/reqresp-nodes.ts +17 -29
  435. package/src/test-helpers/test_tx_provider.ts +5 -0
  436. package/src/test-helpers/testbench-utils.ts +168 -68
  437. package/src/testbench/p2p_client_testbench_worker.ts +99 -62
  438. package/src/testbench/worker_client_manager.ts +72 -25
  439. package/src/util.ts +40 -19
  440. package/src/versioning.ts +3 -33
  441. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +0 -2
  442. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +0 -1
  443. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +0 -305
  444. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +0 -73
  445. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +0 -1
  446. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +0 -8
  447. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  448. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  449. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  450. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  451. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  452. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  453. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  454. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  455. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  456. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  457. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  458. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  459. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  460. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  461. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  462. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  463. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  464. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  465. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  466. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  467. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  468. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  469. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  470. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  471. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  472. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  473. package/dest/mem_pools/tx_pool/index.js +0 -2
  474. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  475. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  476. package/dest/mem_pools/tx_pool/priority.js +0 -15
  477. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  478. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  479. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  480. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  481. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  482. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  483. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  484. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  485. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  486. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -64
  487. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  488. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -151
  489. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  490. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  491. package/dest/services/reqresp/protocols/block.js +0 -32
  492. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -52
  493. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  494. package/dest/services/tx_collection/fast_tx_collection.js +0 -307
  495. package/dest/services/tx_collection/proposal_tx_collector.d.ts +0 -48
  496. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +0 -1
  497. package/dest/services/tx_collection/proposal_tx_collector.js +0 -49
  498. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -53
  499. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  500. package/dest/services/tx_collection/slow_tx_collection.js +0 -177
  501. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +0 -336
  502. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +0 -43
  503. package/src/mem_pools/tx_pool/README.md +0 -270
  504. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  505. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  506. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  507. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  508. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  509. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  510. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  511. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  512. package/src/mem_pools/tx_pool/index.ts +0 -2
  513. package/src/mem_pools/tx_pool/priority.ts +0 -20
  514. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  515. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  516. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
  517. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -161
  518. package/src/services/reqresp/protocols/block.ts +0 -37
  519. package/src/services/tx_collection/fast_tx_collection.ts +0 -354
  520. package/src/services/tx_collection/proposal_tx_collector.ts +0 -112
  521. package/src/services/tx_collection/slow_tx_collection.ts +0 -233
@@ -1,15 +1,14 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
- import { randomInt } from '@aztec/foundation/crypto/random';
4
- import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { maxBy, merge } from '@aztec/foundation/collection';
5
4
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
6
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
6
  import { Timer } from '@aztec/foundation/timer';
8
7
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
9
8
  import { protocolContractsHash } from '@aztec/protocol-contracts';
10
- import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
9
+ import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
11
10
  import type { ContractDataSource } from '@aztec/stdlib/contract';
12
- import { GasFees } from '@aztec/stdlib/gas';
11
+ import { type BlockMinFeesProvider, GasFees } from '@aztec/stdlib/gas';
13
12
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
14
13
  import {
15
14
  BlockProposal,
@@ -17,17 +16,16 @@ import {
17
16
  CheckpointProposal,
18
17
  type CheckpointProposalCore,
19
18
  type Gossipable,
20
- P2PClientType,
21
19
  P2PMessage,
22
- type ValidationResult as P2PValidationResult,
23
20
  PeerErrorSeverity,
21
+ PeerErrorSeverityByHarshness,
24
22
  TopicType,
25
23
  createTopicString,
26
- getTopicsForClientAndConfig,
24
+ getTopicsForConfig,
27
25
  metricsTopicStrToLabels,
28
26
  } from '@aztec/stdlib/p2p';
29
27
  import { MerkleTreeId } from '@aztec/stdlib/trees';
30
- import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
28
+ import { Tx, type TxValidationResult } from '@aztec/stdlib/tx';
31
29
  import type { UInt64 } from '@aztec/stdlib/types';
32
30
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
33
31
  import {
@@ -45,20 +43,22 @@ import {
45
43
  type GossipsubMessage,
46
44
  gossipsub,
47
45
  } from '@chainsafe/libp2p-gossipsub';
48
- import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p-gossipsub/score';
46
+ import { createPeerScoreParams } from '@chainsafe/libp2p-gossipsub/score';
49
47
  import { SignaturePolicy } from '@chainsafe/libp2p-gossipsub/types';
50
48
  import { noise } from '@chainsafe/libp2p-noise';
51
49
  import { yamux } from '@chainsafe/libp2p-yamux';
52
50
  import { bootstrap } from '@libp2p/bootstrap';
53
51
  import { identify } from '@libp2p/identify';
54
52
  import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
55
- import type { ConnectionManager } from '@libp2p/interface-internal';
53
+ import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
56
54
  import { mplex } from '@libp2p/mplex';
57
55
  import { tcp } from '@libp2p/tcp';
56
+ import { multiaddr } from '@multiformats/multiaddr';
58
57
  import { ENR } from '@nethermindeth/enr';
59
58
  import { createLibp2p } from 'libp2p';
60
59
 
61
60
  import type { P2PConfig } from '../../config.js';
61
+ import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
62
62
  import type { MemPools } from '../../mem_pools/interface.js';
63
63
  import {
64
64
  BlockProposalValidator,
@@ -70,41 +70,38 @@ import {
70
70
  } from '../../msg_validators/index.js';
71
71
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
72
72
  import {
73
- type MessageValidator,
74
- createTxMessageValidators,
75
- createTxReqRespValidator,
73
+ type TransactionValidator,
74
+ createFirstStageTxValidationsForGossipedTransactions,
75
+ createSecondStageTxValidationsForGossipedTransactions,
76
+ createTxValidatorForBlockProposalReceivedTxs,
76
77
  } from '../../msg_validators/tx_validator/factory.js';
78
+ import { TxValidationCache } from '../../msg_validators/tx_validator/tx_validation_cache.js';
77
79
  import { GossipSubEvent } from '../../types/index.js';
78
80
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
79
81
  import { getVersions } from '../../versioning.js';
80
82
  import { AztecDatastore } from '../data_store.js';
81
83
  import { DiscV5Service } from '../discv5/discV5_service.js';
82
84
  import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
83
- import { gossipScoreThresholds } from '../gossipsub/scoring.js';
85
+ import { APP_SPECIFIC_WEIGHT, gossipScoreThresholds } from '../gossipsub/scoring.js';
86
+ import { createAllTopicScoreParams } from '../gossipsub/topic_score_params.js';
84
87
  import type { PeerManagerInterface } from '../peer-manager/interface.js';
85
88
  import { PeerManager } from '../peer-manager/peer_manager.js';
86
89
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
87
90
  import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
88
91
  import type { P2PReqRespConfig } from '../reqresp/config.js';
89
92
  import {
90
- DEFAULT_SUB_PROTOCOL_VALIDATORS,
93
+ AuthRequest,
94
+ BlockTxsRequest,
95
+ BlockTxsResponse,
91
96
  type ReqRespInterface,
92
97
  type ReqRespResponse,
93
98
  ReqRespSubProtocol,
94
99
  type ReqRespSubProtocolHandler,
95
100
  type ReqRespSubProtocolHandlers,
96
- type ReqRespSubProtocolValidators,
97
- type SubProtocolMap,
98
- ValidationError,
99
- } from '../reqresp/index.js';
100
- import {
101
- AuthRequest,
102
- BlockTxsRequest,
103
- BlockTxsResponse,
104
101
  StatusMessage,
102
+ ValidationError,
105
103
  pingHandler,
106
104
  reqGoodbyeHandler,
107
- reqRespBlockHandler,
108
105
  reqRespBlockTxsHandler,
109
106
  reqRespStatusHandler,
110
107
  reqRespTxHandler,
@@ -112,7 +109,9 @@ import {
112
109
  import { ReqResp } from '../reqresp/reqresp.js';
113
110
  import type {
114
111
  P2PBlockReceivedCallback,
112
+ P2PCheckpointAttestationCallback,
115
113
  P2PCheckpointReceivedCallback,
114
+ P2PDuplicateAttestationCallback,
116
115
  P2PService,
117
116
  PeerDiscoveryService,
118
117
  } from '../service.js';
@@ -129,12 +128,12 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
129
128
  // REFACTOR: Unify with the type above
130
129
  type ReceivedMessageValidationResult<T, M = undefined> =
131
130
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
132
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
131
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
133
132
 
134
133
  /**
135
134
  * Lib P2P implementation of the P2PService interface.
136
135
  */
137
- export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
136
+ export class LibP2PService extends WithTracer implements P2PService {
138
137
  private discoveryRunningPromise?: RunningPromise;
139
138
  private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
140
139
 
@@ -146,8 +145,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
146
145
  private protocolVersion = '';
147
146
  private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
148
147
 
149
- private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
150
-
151
148
  /** Callback invoked when a duplicate proposal is detected (triggers slashing). */
152
149
  private duplicateProposalCallback?: (info: {
153
150
  slot: SlotNumber;
@@ -155,6 +152,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
155
152
  type: 'checkpoint' | 'block';
156
153
  }) => void;
157
154
 
155
+ /** Callback invoked when a duplicate attestation is detected (triggers slashing). */
156
+ private duplicateAttestationCallback?: P2PDuplicateAttestationCallback;
157
+
158
+ /** Callback invoked when a valid checkpoint attestation is accepted into the pool. */
159
+ private checkpointAttestationCallback?: P2PCheckpointAttestationCallback;
160
+
158
161
  /**
159
162
  * Callback for when a block is received from a peer.
160
163
  * @param block - The block received from the peer.
@@ -167,10 +170,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
167
170
  * @param checkpoint - The checkpoint proposal received from the peer.
168
171
  * @returns The attestations for the checkpoint, if any.
169
172
  */
170
- private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
173
+ private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
174
+ /**
175
+ * Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
176
+ * @param checkpoint - The checkpoint proposal received from the peer.
177
+ * @returns The attestations for the checkpoint, if any.
178
+ */
179
+ private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
171
180
 
172
181
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
173
182
 
183
+ private ipChangedHandler?: (ip: string) => void;
184
+ private discoveredP2pIp?: string;
185
+
174
186
  private instrumentation: P2PInstrumentation;
175
187
 
176
188
  private telemetry: TelemetryClient;
@@ -178,7 +190,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
178
190
  protected logger: Logger;
179
191
 
180
192
  constructor(
181
- private clientType: T,
182
193
  private config: P2PConfig,
183
194
  protected node: PubSubLibp2p,
184
195
  private peerDiscoveryService: PeerDiscoveryService,
@@ -189,8 +200,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
189
200
  private epochCache: EpochCacheInterface,
190
201
  private proofVerifier: ClientProtocolCircuitVerifier,
191
202
  private worldStateSynchronizer: WorldStateSynchronizer,
203
+ private blockMinFeesProvider: BlockMinFeesProvider,
192
204
  telemetry: TelemetryClient,
193
205
  logger: Logger = createLogger('p2p:libp2p_service'),
206
+ private txValidationCache?: TxValidationCache,
194
207
  ) {
195
208
  super(telemetry, 'LibP2PService');
196
209
  this.telemetry = telemetry;
@@ -220,36 +233,55 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
220
233
  this.protocolVersion,
221
234
  );
222
235
 
223
- this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
224
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
236
+ const p2pPropagationTime = config.attestationPropagationTime;
237
+ const proposalValidatorOpts = {
225
238
  txsPermitted: !config.disableTransactions,
226
- });
239
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
240
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
241
+ p2pPropagationTime,
242
+ skipSlotValidation: config.skipProposalSlotValidation,
243
+ signatureContext: {
244
+ chainId: config.l1ChainId,
245
+ rollupAddress: config.rollupAddress,
246
+ },
247
+ };
248
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
249
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
250
+ const attestationValidatorOpts = {
251
+ l1PublishingTime: config.l1PublishingTime,
252
+ p2pPropagationTime,
253
+ signatureContext: proposalValidatorOpts.signatureContext,
254
+ };
227
255
  this.checkpointAttestationValidator = config.fishermanMode
228
- ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
229
- : new CheckpointAttestationValidator(epochCache);
256
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, attestationValidatorOpts)
257
+ : new CheckpointAttestationValidator(epochCache, attestationValidatorOpts);
230
258
 
231
259
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
232
260
 
233
261
  this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
234
- this.logger.debug(
235
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
262
+ this.logger.warn(
263
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
236
264
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
237
265
  );
238
- return false;
266
+ return true;
239
267
  };
240
268
 
241
- this.checkpointReceivedCallback = (
242
- checkpoint: CheckpointProposalCore,
269
+ this.allNodesCheckpointReceivedCallback = (
270
+ _checkpoint: CheckpointProposalCore,
271
+ ): Promise<CheckpointAttestation[] | undefined> => {
272
+ throw new CheckpointProposalReceivedCallbackNotRegisteredError();
273
+ };
274
+
275
+ this.validatorCheckpointReceivedCallback = (
276
+ _checkpoint: CheckpointProposalCore,
243
277
  ): Promise<CheckpointAttestation[] | undefined> => {
244
- this.logger.debug(
245
- `Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
246
- );
247
278
  return Promise.resolve(undefined);
248
279
  };
249
280
  }
250
281
 
251
- public updateConfig(config: Partial<P2PReqRespConfig>) {
282
+ public updateConfig(config: Partial<P2PReqRespConfig & Pick<P2PConfig, 'skipIncomingProposals'>>) {
252
283
  this.reqresp.updateConfig(config);
284
+ this.config = merge(this.config, config);
253
285
  }
254
286
 
255
287
  /**
@@ -258,8 +290,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
258
290
  * @param txPool - The transaction pool to be accessed by the service.
259
291
  * @returns The new service.
260
292
  */
261
- public static async new<T extends P2PClientType>(
262
- clientType: T,
293
+ public static async new(
263
294
  config: P2PConfig,
264
295
  peerId: PeerId,
265
296
  deps: {
@@ -269,9 +300,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
269
300
  proofVerifier: ClientProtocolCircuitVerifier;
270
301
  worldStateSynchronizer: WorldStateSynchronizer;
271
302
  peerStore: AztecAsyncKVStore;
303
+ blockMinFeesProvider: BlockMinFeesProvider;
272
304
  telemetry: TelemetryClient;
273
305
  logger: Logger;
274
306
  packageVersion: string;
307
+ txValidationCache?: TxValidationCache;
275
308
  },
276
309
  ) {
277
310
  const {
@@ -281,9 +314,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
281
314
  mempools,
282
315
  proofVerifier,
283
316
  peerStore,
317
+ blockMinFeesProvider,
284
318
  telemetry,
285
319
  logger,
286
320
  packageVersion,
321
+ txValidationCache,
287
322
  } = deps;
288
323
  const { p2pPort, maxPeerCount, listenAddress } = config;
289
324
  const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
@@ -311,11 +346,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
311
346
  const versions = getVersions(config);
312
347
  const protocolVersion = compressComponentVersions(versions);
313
348
 
314
- const txTopic = createTopicString(TopicType.tx, protocolVersion);
315
- const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
316
- const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
317
- const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
318
-
319
349
  const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
320
350
  const directPeers = (
321
351
  await Promise.all(
@@ -335,6 +365,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
335
365
 
336
366
  const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
337
367
 
368
+ // Create dynamic topic score params based on network configuration
369
+ const l1Constants = epochCache.getL1Constants();
370
+ const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
371
+ slotDurationMs: l1Constants.slotDuration * 1000,
372
+ ethereumSlotDuration: l1Constants.ethereumSlotDuration,
373
+ heartbeatIntervalMs: config.gossipsubInterval,
374
+ targetCommitteeSize: l1Constants.targetCommitteeSize,
375
+ blockDurationMs: config.blockDurationMs,
376
+ l1PublishingTime: config.l1PublishingTime,
377
+ p2pPropagationTime: config.attestationPropagationTime,
378
+ expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
379
+ });
380
+
338
381
  const node = await createLibp2p({
339
382
  start: false,
340
383
  peerId,
@@ -430,32 +473,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
430
473
  scoreParams: createPeerScoreParams({
431
474
  // IPColocation factor can be disabled for local testing - default to -5
432
475
  IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
433
- topics: {
434
- [txTopic]: createTopicScoreParams({
435
- topicWeight: 1,
436
- invalidMessageDeliveriesWeight: -20,
437
- invalidMessageDeliveriesDecay: 0.5,
438
- }),
439
- [blockProposalTopic]: createTopicScoreParams({
440
- topicWeight: 1,
441
- invalidMessageDeliveriesWeight: -20,
442
- invalidMessageDeliveriesDecay: 0.5,
443
- }),
444
- [checkpointProposalTopic]: createTopicScoreParams({
445
- topicWeight: 1,
446
- invalidMessageDeliveriesWeight: -20,
447
- invalidMessageDeliveriesDecay: 0.5,
448
- }),
449
- [checkpointAttestationTopic]: createTopicScoreParams({
450
- topicWeight: 1,
451
- invalidMessageDeliveriesWeight: -20,
452
- invalidMessageDeliveriesDecay: 0.5,
453
- }),
454
- },
476
+ topics: topicScoreParams,
455
477
  }),
456
478
  }) as (components: GossipSubComponents) => GossipSub,
457
- components: (components: { connectionManager: ConnectionManager }) => ({
479
+ components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
458
480
  connectionManager: components.connectionManager,
481
+ addressManager: components.addressManager,
459
482
  }),
460
483
  },
461
484
  logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
@@ -477,13 +500,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
477
500
  epochCache,
478
501
  );
479
502
 
480
- // Update gossipsub score params
481
- node.services.pubsub.score.params.appSpecificWeight = 10;
503
+ // Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
504
+ reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
505
+
506
+ // Configure application-specific scoring for gossipsub.
507
+ // The weight scales app score to align with gossipsub thresholds:
508
+ // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
509
+ // - Ban (-100) × 10 = -1000 = publishThreshold (cannot publish)
510
+ // Note: positive topic scores can offset penalties, so alignment is best-effort.
511
+ node.services.pubsub.score.params.appSpecificWeight = APP_SPECIFIC_WEIGHT;
482
512
  node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
483
513
  peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
484
514
 
485
515
  return new LibP2PService(
486
- clientType,
487
516
  config,
488
517
  node,
489
518
  peerDiscoveryService,
@@ -494,8 +523,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
494
523
  epochCache,
495
524
  proofVerifier,
496
525
  worldStateSynchronizer,
526
+ blockMinFeesProvider,
497
527
  telemetry,
498
528
  logger,
529
+ txValidationCache,
499
530
  );
500
531
  }
501
532
 
@@ -509,24 +540,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
509
540
  throw new Error('P2P service already started');
510
541
  }
511
542
 
512
- // Get listen & announce addresses for logging
513
543
  const { p2pIp, p2pPort } = this.config;
514
- if (!p2pIp) {
515
- throw new Error('Announce address not provided.');
544
+ if (!p2pIp && !this.config.queryForIp) {
545
+ throw new Error('Announce address not provided and queryForIp is not enabled.');
516
546
  }
517
- const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
547
+ const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
518
548
 
519
549
  // Create request response protocol handlers
520
550
  const txHandler = reqRespTxHandler(this.mempools);
521
551
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
522
- const blockHandler = reqRespBlockHandler(this.archiver);
523
552
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
524
553
 
525
554
  const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
526
555
  [ReqRespSubProtocol.PING]: pingHandler,
527
556
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
528
557
  [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
529
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
530
558
  };
531
559
 
532
560
  if (!this.config.disableTransactions) {
@@ -542,22 +570,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
542
570
  requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
543
571
  }
544
572
 
545
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
546
- const reqrespSubProtocolValidators = {
547
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
548
- [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
549
- [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
550
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
551
- };
552
-
553
573
  await this.peerManager.initializePeers();
554
574
 
555
- await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
575
+ await this.reqresp.start(requestResponseHandlers);
556
576
 
557
577
  await this.node.start();
558
578
 
559
579
  // Subscribe to standard GossipSub topics by default
560
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
580
+ for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
561
581
  this.subscribeToTopic(this.topicStrings[topic]);
562
582
  }
563
583
 
@@ -568,6 +588,38 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
568
588
  if (!this.config.p2pDiscoveryDisabled) {
569
589
  await this.peerDiscoveryService.start();
570
590
  }
591
+
592
+ // Bridge discv5 IP changes to libp2p's AddressManager so peers see the updated address
593
+ if (this.config.queryForIp) {
594
+ this.discoveredP2pIp = this.config.p2pIp;
595
+ this.logger.info('IP change tracking enabled, bridging discv5 IP updates to libp2p AddressManager');
596
+ this.ipChangedHandler = (ip: string) => {
597
+ const addressManager = this.node.services.components.addressManager;
598
+ const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
599
+ const previousIp = this.discoveredP2pIp;
600
+
601
+ if (previousIp) {
602
+ const oldAddr = multiaddr(convertToMultiaddr(previousIp, this.config.p2pPort, 'tcp'));
603
+ addressManager.removeObservedAddr(oldAddr);
604
+ this.logger.info('Libp2p announce address updated due to IP change', {
605
+ previousIp,
606
+ newIp: ip,
607
+ newMultiaddr: newAddr.toString(),
608
+ });
609
+ } else {
610
+ this.logger.info('Libp2p announce address set from initial discv5 IP discovery', {
611
+ ip,
612
+ multiaddr: newAddr.toString(),
613
+ });
614
+ }
615
+
616
+ addressManager.addObservedAddr(newAddr);
617
+ addressManager.confirmObservedAddr(newAddr);
618
+ this.discoveredP2pIp = ip;
619
+ };
620
+ this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
621
+ }
622
+
571
623
  this.discoveryRunningPromise = new RunningPromise(
572
624
  async () => {
573
625
  await this.peerManager.heartbeat();
@@ -593,6 +645,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
593
645
  // Remove gossip sub listener
594
646
  this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
595
647
 
648
+ if (this.ipChangedHandler) {
649
+ this.peerDiscoveryService.removeListener('ip:changed', this.ipChangedHandler);
650
+ this.ipChangedHandler = undefined;
651
+ }
652
+
596
653
  // Stop peer manager
597
654
  this.logger.debug('Stopping peer manager...');
598
655
  await this.peerManager.stop();
@@ -607,12 +664,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
607
664
  this.logger.info('LibP2P service stopped');
608
665
  }
609
666
 
610
- addReqRespSubProtocol(
611
- subProtocol: ReqRespSubProtocol,
612
- handler: ReqRespSubProtocolHandler,
613
- validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
614
- ): Promise<void> {
615
- return this.reqresp.addSubProtocol(subProtocol, handler, validator);
667
+ addReqRespSubProtocol(subProtocol: ReqRespSubProtocol, handler: ReqRespSubProtocolHandler): Promise<void> {
668
+ return this.reqresp.addSubProtocol(subProtocol, handler);
616
669
  }
617
670
 
618
671
  public registerThisValidatorAddresses(address: EthAddress[]): void {
@@ -623,6 +676,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
623
676
  return this.peerManager.getPeers(includePending);
624
677
  }
625
678
 
679
+ public getGossipMeshPeerCount(topicType: TopicType): number {
680
+ return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
681
+ }
682
+
626
683
  private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
627
684
  this.logger.trace(`Received PUBSUB message.`);
628
685
 
@@ -636,20 +693,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
636
693
  setImmediate(() => void safeJob());
637
694
  }
638
695
 
639
- /**
640
- * Send a batch of requests to peers, and return the responses
641
- * @param protocol - The request response protocol to use
642
- * @param requests - The requests to send to the peers
643
- * @returns The responses to the requests
644
- */
645
- sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
646
- protocol: SubProtocol,
647
- requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
648
- pinnedPeerId: PeerId | undefined,
649
- ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
650
- return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
651
- }
652
-
653
696
  public sendRequestToPeer(
654
697
  peerId: PeerId,
655
698
  subProtocol: ReqRespSubProtocol,
@@ -671,8 +714,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
671
714
  this.blockReceivedCallback = callback;
672
715
  }
673
716
 
674
- public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
675
- this.checkpointReceivedCallback = callback;
717
+ public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
718
+ this.validatorCheckpointReceivedCallback = callback;
719
+ }
720
+
721
+ public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
722
+ this.allNodesCheckpointReceivedCallback = callback;
676
723
  }
677
724
 
678
725
  /**
@@ -685,6 +732,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
685
732
  this.duplicateProposalCallback = callback;
686
733
  }
687
734
 
735
+ /**
736
+ * Registers a callback to be invoked when a duplicate attestation is detected.
737
+ * A validator signing attestations for different proposals at the same slot.
738
+ * This callback is triggered on the first duplicate (when count goes from 1 to 2).
739
+ */
740
+ public registerDuplicateAttestationCallback(callback: P2PDuplicateAttestationCallback): void {
741
+ this.duplicateAttestationCallback = callback;
742
+ }
743
+
744
+ public registerCheckpointAttestationCallback(callback: P2PCheckpointAttestationCallback): void {
745
+ this.checkpointAttestationCallback = callback;
746
+ }
747
+
688
748
  /**
689
749
  * Subscribes to a topic.
690
750
  * @param topic - The topic to subscribe to.
@@ -749,6 +809,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
749
809
  if (!validator || !validator.addMessage(msgId)) {
750
810
  this.instrumentation.incMessagePrevalidationStatus(false, topicType);
751
811
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
812
+ if (topicType === TopicType.tx) {
813
+ this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
814
+ }
752
815
  return { result: false, topicType };
753
816
  }
754
817
 
@@ -810,12 +873,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
810
873
 
811
874
  // Process the message, optionally within a linked span for trace propagation
812
875
  const processMessage = async () => {
876
+ if (
877
+ this.config.skipIncomingProposals &&
878
+ (msg.topic === this.topicStrings[TopicType.block_proposal] ||
879
+ msg.topic === this.topicStrings[TopicType.checkpoint_proposal])
880
+ ) {
881
+ this.logger.warn(`Ignoring incoming proposal (skipIncomingProposals is set)`, { topic: msg.topic });
882
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
883
+ return;
884
+ }
813
885
  if (msg.topic === this.topicStrings[TopicType.tx]) {
814
886
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
815
887
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
816
- if (this.clientType === P2PClientType.Full) {
817
- await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
818
- }
888
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
819
889
  } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
820
890
  await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
821
891
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
@@ -877,45 +947,139 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
877
947
  source: PeerId,
878
948
  topicType: TopicType,
879
949
  ): Promise<ReceivedMessageValidationResult<T, M>> {
880
- let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
950
+ // Default to reject result with a penalty if validation function throws an error
951
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
952
+ result: TopicValidatorResult.Reject,
953
+ severity: PeerErrorSeverity.MidToleranceError,
954
+ };
881
955
  const timer = new Timer();
882
956
  try {
883
957
  resultAndObj = await validationFunc();
884
958
  } catch (err) {
885
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
886
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
887
- msgId,
888
- source: source.toString(),
889
- topicType,
890
- });
959
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
960
+ }
961
+
962
+ const validationTimeMs = timer.ms();
963
+ const mcacheWindowMs = this.config.gossipsubMcacheLength * this.config.gossipsubInterval;
964
+ if (validationTimeMs > mcacheWindowMs * 0.75) {
965
+ this.instrumentation.incSlowValidation(topicType);
966
+ this.logger.warn(
967
+ `Gossip validation for ${topicType} took ${validationTimeMs}ms, approaching mcache eviction window of ${mcacheWindowMs}ms. ` +
968
+ `Message forwarding may be skipped if validation exceeds the window.`,
969
+ { msgId, source: source.toString(), topicType, validationTimeMs, mcacheWindowMs },
970
+ );
891
971
  }
892
972
 
893
973
  if (resultAndObj.result === TopicValidatorResult.Accept) {
974
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
894
975
  this.instrumentation.recordMessageValidation(topicType, timer);
976
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
977
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
978
+ msgId,
979
+ source: source.toString(),
980
+ topicType,
981
+ severity: resultAndObj.severity,
982
+ });
983
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
984
+ } else {
985
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
895
986
  }
896
987
 
897
988
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
898
989
  return resultAndObj;
899
990
  }
900
991
 
992
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
993
+ try {
994
+ return deserializeFunc();
995
+ } catch (err) {
996
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
997
+ err,
998
+ msgId,
999
+ source: source.toString(),
1000
+ });
1001
+ return undefined;
1002
+ }
1003
+ }
1004
+
901
1005
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
902
1006
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
903
- const tx = Tx.fromBuffer(payloadData);
904
- const isValid = await this.validatePropagatedTx(tx, source);
905
- const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
1007
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
1008
+ if (!tx) {
1009
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
1010
+ }
1011
+
1012
+ const currentBlockNumber = await this.archiver.getBlockNumber();
1013
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1014
+
1015
+ // Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
1016
+ const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
1017
+ const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
1018
+ if (!firstStageOutcome.allPassed) {
1019
+ const { name } = firstStageOutcome.failure;
1020
+ let { severity } = firstStageOutcome.failure;
1021
+
1022
+ // Double spend validator has a special case handler. We perform more detailed examination
1023
+ // as to how recently the nullifier was entered into the tree and if the transaction should
1024
+ // have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
1025
+ if (name === 'doubleSpendValidator') {
1026
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1);
1027
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1028
+ }
1029
+
1030
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
1031
+ validator: name,
1032
+ severity,
1033
+ source: source.toString(),
1034
+ });
1035
+ return { result: TopicValidatorResult.Reject, severity };
1036
+ }
1037
+
1038
+ // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
1039
+ const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
1040
+ if (canAdd === 'ignored') {
1041
+ this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
1042
+ source: source.toString(),
1043
+ });
1044
+ return { result: TopicValidatorResult.Ignore, obj: tx };
1045
+ }
1046
+
1047
+ // Stage 2: expensive proof verification
1048
+ const secondStageValidators = this.createSecondStageMessageValidators();
1049
+ const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
1050
+ if (!secondStageOutcome.allPassed) {
1051
+ const { severity, name } = secondStageOutcome.failure;
1052
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
1053
+ validator: name,
1054
+ severity,
1055
+ source: source.toString(),
1056
+ });
1057
+ return { result: TopicValidatorResult.Reject, severity };
1058
+ }
906
1059
 
907
- this.logger.trace(`Validate propagated tx`, {
908
- isValid,
909
- exists,
1060
+ // Pool add: persist the tx
1061
+ const txHash = tx.getTxHash();
1062
+ const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
1063
+
1064
+ const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
1065
+ const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
1066
+
1067
+ this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
1068
+ wasAccepted,
1069
+ wasIgnored,
910
1070
  [Attributes.P2P_ID]: source.toString(),
911
1071
  });
912
1072
 
913
- if (!isValid) {
914
- return { result: TopicValidatorResult.Reject };
915
- } else if (exists) {
1073
+ if (wasAccepted) {
1074
+ return { result: TopicValidatorResult.Accept, obj: tx };
1075
+ } else if (wasIgnored) {
916
1076
  return { result: TopicValidatorResult.Ignore, obj: tx };
917
1077
  } else {
918
- return { result: TopicValidatorResult.Accept, obj: tx };
1078
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
1079
+ source: source.toString(),
1080
+ txHash: txHash.toString(),
1081
+ });
1082
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
919
1083
  }
920
1084
  };
921
1085
 
@@ -924,6 +1088,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
924
1088
  return;
925
1089
  }
926
1090
 
1091
+ // Tx was accepted into pool and will be propagated - just log and record metrics
927
1092
  const txHash = tx.getTxHash();
928
1093
  const txHashString = txHash.toString();
929
1094
  this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
@@ -931,13 +1096,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
931
1096
  txHash: txHashString,
932
1097
  });
933
1098
 
934
- if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
935
- this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
936
- return;
937
- }
938
-
939
1099
  this.instrumentation.incrementTxReceived(1);
940
- await this.mempools.txPool.addTxs([tx]);
941
1100
  }
942
1101
 
943
1102
  /**
@@ -950,7 +1109,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
950
1109
  source: PeerId,
951
1110
  ): Promise<void> {
952
1111
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
953
- () => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
1112
+ () => {
1113
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1114
+ if (!attestation) {
1115
+ return Promise.resolve({
1116
+ result: TopicValidatorResult.Reject,
1117
+ severity: PeerErrorSeverity.LowToleranceError,
1118
+ });
1119
+ }
1120
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1121
+ },
954
1122
  msgId,
955
1123
  source,
956
1124
  TopicType.checkpoint_attestation,
@@ -983,48 +1151,61 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
983
1151
 
984
1152
  if (validationResult.result === 'reject') {
985
1153
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
986
- this.peerManager.penalizePeer(peerId, validationResult.severity);
987
- return { result: TopicValidatorResult.Reject };
1154
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
988
1155
  }
989
1156
 
990
1157
  if (validationResult.result === 'ignore') {
991
1158
  return { result: TopicValidatorResult.Ignore, obj: attestation };
992
1159
  }
993
1160
 
994
- // Get committee size for the attestation's slot
995
- const slot = attestation.payload.header.slotNumber;
996
- const { committee } = await this.epochCache.getCommittee(slot);
997
- const committeeSize = committee?.length ?? 0;
998
-
999
1161
  // Try to add the attestation: this handles existence check, cap check, and adding in one call
1000
- const { added, alreadyExists } = await this.mempools.attestationPool.tryAddCheckpointAttestation(
1001
- attestation,
1002
- committeeSize,
1003
- );
1162
+ // count is the number of attestations by this signer for this slot (for duplicate detection)
1163
+ const slot = attestation.payload.header.slotNumber;
1164
+ const { added, alreadyExists, count } =
1165
+ await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation);
1004
1166
 
1005
1167
  this.logger.trace(`Validate propagated checkpoint attestation`, {
1006
1168
  added,
1007
1169
  alreadyExists,
1170
+ count,
1008
1171
  [Attributes.SLOT_NUMBER]: slot.toString(),
1009
1172
  [Attributes.P2P_ID]: peerId.toString(),
1010
1173
  });
1011
1174
 
1012
- // Duplicate attestation received, no need to re-broadcast
1175
+ // Exact same attestation received, no need to re-broadcast
1013
1176
  if (alreadyExists) {
1014
1177
  return { result: TopicValidatorResult.Ignore, obj: attestation };
1015
1178
  }
1016
1179
 
1017
- // Could not add (cap reached), no need to re-broadcast
1180
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1018
1181
  if (!added) {
1019
- this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
1182
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1020
1183
  slot: slot.toString(),
1021
1184
  archive: attestation.archive.toString(),
1022
1185
  source: peerId.toString(),
1186
+ attester: attestation.getSender()?.toString(),
1187
+ count,
1023
1188
  });
1024
- return { result: TopicValidatorResult.Ignore, obj: attestation };
1189
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1190
+ }
1191
+
1192
+ // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
1193
+ // count is the number of attestations by this signer for this slot
1194
+ if (count === 2) {
1195
+ const attester = attestation.getSender();
1196
+ if (attester) {
1197
+ this.logger.warn(`Detected duplicate attestation (equivocation) at slot ${slot}`, {
1198
+ slot: slot.toString(),
1199
+ archive: attestation.archive.toString(),
1200
+ source: peerId.toString(),
1201
+ attester: attester.toString(),
1202
+ });
1203
+ this.duplicateAttestationCallback?.({ slot, attester });
1204
+ }
1025
1205
  }
1026
1206
 
1027
- // Attestation was added successfully
1207
+ // Attestation was added successfully - accept it so other nodes can also detect the equivocation
1208
+ this.checkpointAttestationCallback?.(attestation);
1028
1209
  return { result: TopicValidatorResult.Accept, obj: attestation };
1029
1210
  }
1030
1211
 
@@ -1061,8 +1242,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1061
1242
 
1062
1243
  if (validationResult.result === 'reject') {
1063
1244
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1064
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1065
- return { result: TopicValidatorResult.Reject };
1245
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1066
1246
  }
1067
1247
 
1068
1248
  if (validationResult.result === 'ignore') {
@@ -1070,8 +1250,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1070
1250
  }
1071
1251
 
1072
1252
  // Try to add the proposal: this handles existence check, cap check, and adding in one call
1073
- const { added, alreadyExists, totalForPosition } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1074
- const isEquivocated = totalForPosition !== undefined && totalForPosition > 1;
1253
+ const { added, alreadyExists, count } = await this.mempools.attestationPool.tryAddBlockProposal(block);
1254
+ const isEquivocated = count !== undefined && count > 1;
1075
1255
 
1076
1256
  // Duplicate proposal received, no need to re-broadcast
1077
1257
  if (alreadyExists) {
@@ -1086,15 +1266,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1086
1266
 
1087
1267
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1088
1268
  if (!added) {
1089
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1090
1269
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1091
1270
  ...block.toBlockInfo(),
1092
1271
  indexWithinCheckpoint: block.indexWithinCheckpoint,
1093
- totalForPosition,
1272
+ count,
1094
1273
  proposer: block.getSender()?.toString(),
1095
1274
  source: peerId.toString(),
1096
1275
  });
1097
- return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
1276
+ return {
1277
+ result: TopicValidatorResult.Reject,
1278
+ metadata: { isEquivocated },
1279
+ severity: PeerErrorSeverity.HighToleranceError,
1280
+ };
1098
1281
  }
1099
1282
 
1100
1283
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1107,7 +1290,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1107
1290
  proposer: proposer?.toString(),
1108
1291
  });
1109
1292
  // Invoke the duplicate callback on the first duplicate spotted only
1110
- if (proposer && totalForPosition === 2) {
1293
+ if (proposer && count === 2) {
1111
1294
  this.duplicateProposalCallback?.({ slot: block.slotNumber, proposer, type: 'block' });
1112
1295
  }
1113
1296
  return { result: TopicValidatorResult.Accept, obj: block, metadata: { isEquivocated } };
@@ -1132,14 +1315,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1132
1315
  ...block.toBlockInfo(),
1133
1316
  });
1134
1317
 
1135
- // Mark the txs in this proposal as non-evictable
1136
- await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
1318
+ // Mark the txs in this proposal as protected
1319
+ await this.mempools.txPool.protectTxs(block.txHashes, block.blockHeader);
1137
1320
 
1138
1321
  // Call the block received callback to validate the proposal.
1139
1322
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1140
1323
  const isValid = await this.blockReceivedCallback(block, sender);
1141
1324
  if (!isValid) {
1142
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1325
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1143
1326
  }
1144
1327
  }
1145
1328
 
@@ -1159,17 +1342,33 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1159
1342
  TopicType.checkpoint_proposal,
1160
1343
  );
1161
1344
 
1345
+ // Process checkpoint proposal if valid and not equivocated.
1346
+ const processCheckpointFn = () =>
1347
+ result === TopicValidatorResult.Accept && checkpoint && !isEquivocated
1348
+ ? this.processValidCheckpointProposal(checkpoint.toCore(), source)
1349
+ : Promise.resolve();
1350
+
1162
1351
  // If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
1163
1352
  // TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
1164
- if (processBlock && checkpoint?.getBlockProposal()) {
1165
- await this.processValidBlockProposal(checkpoint.getBlockProposal()!, source);
1166
- }
1167
-
1168
- if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
1353
+ const processBlockFn = () =>
1354
+ processBlock && checkpoint && checkpoint.getBlockProposal()
1355
+ ? this.processValidBlockProposal(checkpoint.getBlockProposal()!, source)
1356
+ : Promise.resolve();
1357
+
1358
+ // A node that skips checkpoint validation attests without re-executing the embedded last block, so run
1359
+ // the checkpoint callback first: this creates and broadcasts the attestation before the block is
1360
+ // processed. Otherwise the block's re-execution — which can stall until the re-execution deadline
1361
+ // waiting for a parent that may never arrive — would delay the attestation past the slot's attestation
1362
+ // window, after which peers reject it as stale.
1363
+ if (this.config.skipCheckpointProposalValidation) {
1364
+ await processCheckpointFn();
1365
+ await processBlockFn();
1169
1366
  return;
1170
1367
  }
1171
1368
 
1172
- await this.processValidCheckpointProposal(checkpoint.toCore(), source);
1369
+ // Process the block first, since it's required for the checkpoint proposal validation.
1370
+ await processBlockFn();
1371
+ await processCheckpointFn();
1173
1372
  }
1174
1373
 
1175
1374
  /**
@@ -1187,8 +1386,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1187
1386
 
1188
1387
  if (validationResult.result === 'reject') {
1189
1388
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1190
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1191
- return { result: TopicValidatorResult.Reject };
1389
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1192
1390
  }
1193
1391
 
1194
1392
  if (validationResult.result === 'ignore') {
@@ -1203,20 +1401,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1203
1401
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1204
1402
  [Attributes.P2P_ID]: peerId.toString(),
1205
1403
  });
1206
- const {
1207
- result,
1208
- obj,
1209
- metadata: { isEquivocated } = {},
1210
- } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1211
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1404
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1405
+ const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1406
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1212
1407
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1213
1408
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1214
1409
  [Attributes.P2P_ID]: peerId.toString(),
1215
1410
  isEquivocated,
1216
- result,
1411
+ result: blockProposalResult.result,
1217
1412
  });
1218
- return { result: TopicValidatorResult.Reject };
1219
- } else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1413
+ return {
1414
+ result: TopicValidatorResult.Reject,
1415
+ severity:
1416
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1417
+ };
1418
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1220
1419
  processBlock = true;
1221
1420
  }
1222
1421
  }
@@ -1224,8 +1423,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1224
1423
  // Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
1225
1424
  const checkpointCore = checkpoint.toCore();
1226
1425
  const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
1227
- const { added, alreadyExists, totalForPosition } = tryAddResult;
1228
- const isEquivocated = totalForPosition !== undefined && totalForPosition > 1;
1426
+ const { added, alreadyExists, count } = tryAddResult;
1427
+ const isEquivocated = count !== undefined && count > 1;
1229
1428
 
1230
1429
  // Duplicate proposal received, do not re-broadcast
1231
1430
  if (alreadyExists) {
@@ -1243,13 +1442,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1243
1442
  // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1244
1443
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1245
1444
  if (!added) {
1246
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1247
1445
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1248
1446
  ...checkpoint.toCheckpointInfo(),
1249
- totalForPosition,
1447
+ count,
1250
1448
  source: peerId.toString(),
1251
1449
  });
1252
- return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
1450
+ return {
1451
+ result: TopicValidatorResult.Reject,
1452
+ obj: checkpoint,
1453
+ metadata: { isEquivocated, processBlock },
1454
+ severity: PeerErrorSeverity.HighToleranceError,
1455
+ };
1253
1456
  }
1254
1457
 
1255
1458
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1262,7 +1465,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1262
1465
  proposer: proposer?.toString(),
1263
1466
  });
1264
1467
  // Invoke the duplicate callback on the first duplicate spotted only
1265
- if (proposer && totalForPosition === 2) {
1468
+ if (proposer && count === 2) {
1266
1469
  this.duplicateProposalCallback?.({ slot: checkpoint.slotNumber, proposer, type: 'checkpoint' });
1267
1470
  }
1268
1471
  return {
@@ -1294,9 +1497,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1294
1497
  source: sender.toString(),
1295
1498
  });
1296
1499
 
1500
+ await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
1501
+
1297
1502
  // Call the checkpoint received callback with the core version (without lastBlock)
1298
1503
  // to validate and potentially generate attestations
1299
- const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
1504
+ const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
1300
1505
  if (attestations && attestations.length > 0) {
1301
1506
  // If the callback returned attestations, add them to the pool and propagate them
1302
1507
  await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
@@ -1319,82 +1524,87 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1319
1524
  }
1320
1525
 
1321
1526
  /**
1322
- * Validate the requested block transactions. Allow partial returns.
1527
+ * Validate the requested block transactions request-response consistency.
1528
+ * It does NOT validate the transactions themselves.
1323
1529
  * @param request - The block transactions request.
1324
1530
  * @param response - The block transactions response.
1325
1531
  * @param peerId - The ID of the peer that made the request.
1326
- * @returns True if the requested block transactions are valid, false otherwise.
1532
+ * @returns True if the request-response is consistent, false otherwise.
1327
1533
  */
1328
- @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
1534
+ @trackSpan('Libp2pService.validateRequestedBlockTxsConsistency', request => ({
1329
1535
  [Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
1330
1536
  }))
1331
- protected async validateRequestedBlockTxs(
1537
+ protected async validateRequestedBlockTxsConsistency(
1332
1538
  request: BlockTxsRequest,
1333
1539
  response: BlockTxsResponse,
1334
1540
  peerId: PeerId,
1335
1541
  ): Promise<boolean> {
1336
- const requestedTxValidator = this.createRequestedTxValidator();
1337
-
1338
1542
  try {
1339
- if (!response.archiveRoot.equals(request.archiveRoot)) {
1543
+ // Check for duplicates txs (or hashes) in the response.
1544
+ const returnedHashes = response.txs.map(tx => tx.getTxHash().toString());
1545
+ const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1546
+ if (uniqueReturned.size !== returnedHashes.length) {
1340
1547
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1341
- throw new ValidationError(
1342
- `Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
1548
+ throw new ValidationError(`Received duplicate txs in block txs response`);
1549
+ }
1550
+
1551
+ // We get the block tx hashes from the proposal or the archiver.
1552
+ const proposal = await this.mempools.attestationPool.getBlockProposalByArchive(request.archiveRoot.toString());
1553
+ const blockTxHashes =
1554
+ proposal?.txHashes ??
1555
+ (await this.archiver.getBlock({ archive: request.archiveRoot }))?.body.txEffects.map(e => e.txHash);
1556
+
1557
+ // If we don't have the block, we can't verify membership/order of the returned txs.
1558
+ if (!blockTxHashes) {
1559
+ // This shouldn't happen, since we asked for the block (proposal).
1560
+ // Neither a local proposal nor an archived block: we cannot verify membership/order of the
1561
+ // returned txs. This is a local-state gap, not a peer fault, so we do not penalize.
1562
+ this.logger.warn(
1563
+ `Block ${request.archiveRoot.toString()} not found in attestation pool or archiver; cannot validate membership/order of returned txs`,
1343
1564
  );
1565
+ // NOTE: We mark the response as invalid, given the limitations of a true/false return value.
1566
+ return false;
1344
1567
  }
1345
1568
 
1346
- if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1347
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1569
+ // Verify that the returned tx hashes are a subset of (tx hashes by index) U (explicitly requested tx hashes).
1570
+ const uniqueRequestedHashes = new Set([
1571
+ // tx hashes requested by index.
1572
+ ...request.txIndices.getTrueIndices().map(i => blockTxHashes[i].toString()),
1573
+ // explicitly requested tx hashes.
1574
+ ...request.txHashes.map(h => h.toString()),
1575
+ ]);
1576
+ if (!returnedHashes.every(h => uniqueRequestedHashes.has(h))) {
1577
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1348
1578
  throw new ValidationError(
1349
- `Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
1579
+ 'Returned txs should be a subset of (tx hashes by index) U (explicitly requested tx hashes)',
1350
1580
  );
1351
1581
  }
1352
1582
 
1353
- // Check no duplicates and not exceeding returnable count
1354
- const requestedIndices = new Set(request.txIndices.getTrueIndices());
1355
- const availableIndices = new Set(response.txIndices.getTrueIndices());
1356
- const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
1357
-
1358
- const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
1359
- const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1360
- if (uniqueReturned.size !== returnedHashes.length) {
1361
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1362
- throw new ValidationError(`Received duplicate txs in block txs response`);
1583
+ // Tx indices information is optional, but if present, we need to verify a few things.
1584
+ if (!response.peerHasBlock()) {
1585
+ this.logger.debug(`Peer ${peerId.toString()} signalled missing block`);
1586
+ return true;
1363
1587
  }
1364
- if (response.txs.length > maxReturnable) {
1588
+
1589
+ // If the response has a non-empty bitvector, it needs to be consistent with the number of txs in the block.
1590
+ if (response.txIndices.getLength() !== blockTxHashes.length) {
1365
1591
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1366
1592
  throw new ValidationError(
1367
- `Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
1593
+ `Received block txs with mismatched bitvector length: expected ${blockTxHashes.length}, got ${response.txIndices.getLength()}`,
1368
1594
  );
1369
1595
  }
1370
1596
 
1371
- // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1372
- const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
1373
- if (proposal) {
1374
- // Build intersected indices
1375
- const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1376
-
1377
- // Enforce subset membership and preserve increasing order by index.
1378
- const hashToIndexInProposal = new Map<string, number>(
1379
- proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
1380
- );
1381
- const allowedIndexSet = new Set(intersectIdx);
1382
- const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
1383
- const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
1384
- const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
1385
- if (!allAllowed || !strictlyIncreasing) {
1386
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1387
- throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1388
- }
1389
- } else {
1390
- // No local proposal, cannot check the membership/order of the returned txs
1391
- this.logger.warn(
1392
- `Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
1393
- );
1394
- return false;
1597
+ // For every index we requested that the peer claims to have (per its bitvector), the
1598
+ // corresponding tx must be present in the response. A peer advertising availability but
1599
+ // withholding the tx is inconsistent.
1600
+ const returnedHashSet = new Set(returnedHashes);
1601
+ const expectedIndices = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1602
+ const missingExpected = expectedIndices.some(i => !returnedHashSet.has(blockTxHashes[i].toString()));
1603
+ if (missingExpected) {
1604
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1605
+ throw new ValidationError('Peer advertised requested txs via indices but did not return them');
1395
1606
  }
1396
1607
 
1397
- await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
1398
1608
  return true;
1399
1609
  } catch (e: any) {
1400
1610
  if (e instanceof ValidationError) {
@@ -1407,156 +1617,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1407
1617
  }
1408
1618
  }
1409
1619
 
1410
- /**
1411
- * Validate a collection of txs that has been requested from a peer.
1412
- *
1413
- * The core component of this validator is that each tx hash MUST match the requested tx hash,
1414
- * In order to perform this check, the tx proof must be verified.
1415
- *
1416
- * Note: This function is called from within `ReqResp.sendRequest` as part of the
1417
- * ReqRespSubProtocol.TX subprotocol validation.
1418
- *
1419
- * @param requestedTxHash - The collection of the txs that was requested.
1420
- * @param responseTx - The collection of txs that was received as a response to the request.
1421
- * @param peerId - The peer ID of the peer that sent the tx.
1422
- * @returns True if the whole collection of txs is valid, false otherwise.
1423
- */
1424
- @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
1425
- [Attributes.TX_HASH]: requestedTxHash.toString(),
1426
- }))
1427
- private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
1428
- const requested = new Set(requestedTxHash.map(h => h.toString()));
1429
- const requestedTxValidator = this.createRequestedTxValidator();
1430
-
1431
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
1432
- // I think we should still extract the valid txs and return them, so that we can still use the response.
1433
- try {
1434
- await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
1435
- return true;
1436
- } catch (e: any) {
1437
- if (e instanceof ValidationError) {
1438
- this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
1439
- } else {
1440
- this.logger.error(`Error during validation of requested txs`, e);
1441
- }
1442
-
1443
- return false;
1444
- }
1445
- }
1446
-
1447
- /**
1448
- * Validates a BLOCK response.
1449
- *
1450
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1451
- * Penalizes on block number mismatch or hash mismatch.
1452
- *
1453
- * @param requestedBlockNumber - The requested block number.
1454
- * @param responseBlock - The block returned by the peer.
1455
- * @param peerId - The peer that returned the block.
1456
- * @returns True if the response is valid, false otherwise.
1457
- */
1458
- @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1459
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1460
- }))
1461
- protected async validateRequestedBlock(
1462
- requestedBlockNumber: Fr,
1463
- responseBlock: L2Block,
1464
- peerId: PeerId,
1465
- ): Promise<boolean> {
1466
- try {
1467
- const reqNum = Number(requestedBlockNumber.toString());
1468
- if (responseBlock.number !== reqNum) {
1469
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1470
- return false;
1471
- }
1472
-
1473
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1474
- if (!local) {
1475
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1476
- // TODO: Consider extending this validator to accept an expected hash or
1477
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1478
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1479
- return false;
1480
- }
1481
- const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1482
- if (!localHash.equals(respHash)) {
1483
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1484
- return false;
1485
- }
1486
-
1487
- return true;
1488
- } catch (e) {
1489
- this.logger.warn(`Error validating requested block`, e);
1490
- return false;
1491
- }
1492
- }
1493
-
1494
- protected async validateRequestedTx(
1495
- tx: Tx,
1496
- peerId: PeerId,
1497
- txValidator: TxValidator,
1498
- requested?: Set<`0x${string}`>,
1499
- ) {
1500
- const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
1501
- if (requested && !requested.has(tx.getTxHash().toString())) {
1502
- penalize(PeerErrorSeverity.MidToleranceError);
1503
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1504
- }
1505
-
1506
- const { result } = await txValidator.validateTx(tx);
1507
- if (result === 'invalid') {
1508
- penalize(PeerErrorSeverity.LowToleranceError);
1509
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1510
- }
1511
- }
1512
-
1513
- protected createRequestedTxValidator(): TxValidator {
1514
- return createTxReqRespValidator(this.proofVerifier, {
1515
- l1ChainId: this.config.l1ChainId,
1516
- rollupVersion: this.config.rollupVersion,
1517
- });
1518
- }
1519
-
1520
- @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
1521
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
1522
- }))
1523
- private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
1524
- const currentBlockNumber = await this.archiver.getBlockNumber();
1525
-
1526
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1527
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1528
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1529
-
1530
- for (const validator of messageValidators) {
1531
- const outcome = await this.runValidations(tx, validator);
1532
-
1533
- if (outcome.allPassed) {
1534
- continue;
1535
- }
1536
- const { name } = outcome.failure;
1537
- let { severity } = outcome.failure;
1538
-
1539
- // Double spend validator has a special case handler
1540
- if (name === 'doubleSpendValidator') {
1541
- const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1542
- severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1543
- }
1544
-
1545
- this.peerManager.penalizePeer(peerId, severity);
1546
- return false;
1547
- }
1548
- return true;
1549
- }
1550
-
1551
- private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
1552
- if (blockNumber === this.feesCache?.blockNumber) {
1553
- return this.feesCache.gasFees;
1554
- }
1555
-
1556
- const header = await this.archiver.getBlockHeader(blockNumber);
1557
- const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
1558
- this.feesCache = { blockNumber, gasFees };
1559
- return gasFees;
1620
+ private getGasFees(): Promise<GasFees> {
1621
+ return this.blockMinFeesProvider.getCurrentMinFees();
1560
1622
  }
1561
1623
 
1562
1624
  /**
@@ -1570,65 +1632,70 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1570
1632
  l1ChainId: this.config.l1ChainId,
1571
1633
  rollupVersion: this.config.rollupVersion,
1572
1634
  proofVerifier: this.proofVerifier,
1635
+ txValidationCache: this.txValidationCache,
1573
1636
  },
1574
1637
  peerScoring: this.peerManager,
1638
+ validateRequestedBlockTxsConsistency: this.validateRequestedBlockTxsConsistency.bind(this),
1575
1639
  };
1576
1640
  }
1577
1641
 
1578
- public async validate(txs: Tx[]): Promise<void> {
1579
- const currentBlockNumber = await this.archiver.getBlockNumber();
1580
-
1581
- // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1582
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1583
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1642
+ public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
1643
+ const validator = createTxValidatorForBlockProposalReceivedTxs(
1644
+ this.proofVerifier,
1645
+ { l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
1646
+ this.logger.getBindings(),
1647
+ this.txValidationCache,
1648
+ );
1584
1649
 
1585
- await Promise.all(
1650
+ const results = await Promise.all(
1586
1651
  txs.map(async tx => {
1587
- for (const validator of messageValidators) {
1588
- const outcome = await this.runValidations(tx, validator);
1589
- if (!outcome.allPassed) {
1590
- throw new Error('Invalid tx detected', { cause: { outcome } });
1591
- }
1592
- }
1652
+ const result = await validator.validateTx(tx);
1653
+ return result.result !== 'invalid';
1593
1654
  }),
1594
1655
  );
1656
+ if (results.some(value => value === false)) {
1657
+ throw new Error('Invalid tx detected');
1658
+ }
1595
1659
  }
1596
1660
 
1597
- /**
1598
- * Create message validators for the given block number and timestamp.
1599
- *
1600
- * Each validator is a pair of a validator and a severity.
1601
- * If a validator fails, the peer is penalized with the severity of the validator.
1602
- *
1603
- * @param currentBlockNumber - The current synced block number.
1604
- * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
1605
- * @returns The message validators.
1606
- */
1607
- private async createMessageValidators(
1661
+ /** Creates the first stage (fast) validators for gossiped transactions. */
1662
+ protected async createFirstStageMessageValidators(
1608
1663
  currentBlockNumber: BlockNumber,
1609
1664
  nextSlotTimestamp: UInt64,
1610
- ): Promise<Record<string, MessageValidator>[]> {
1611
- const gasFees = await this.getGasFees(currentBlockNumber);
1612
- const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1613
-
1614
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1615
-
1616
- return createTxMessageValidators(
1665
+ ): Promise<Record<string, TransactionValidator>> {
1666
+ const gasFees = await this.getGasFees();
1667
+ const allowedInSetup = [
1668
+ ...(await getDefaultAllowedSetupFunctions()),
1669
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
1670
+ ];
1671
+ const blockNumber = BlockNumber(currentBlockNumber + 1);
1672
+ const l1Constants = await this.archiver.getL1Constants();
1673
+
1674
+ return createFirstStageTxValidationsForGossipedTransactions(
1617
1675
  nextSlotTimestamp,
1618
- blockNumberInWhichTheTxIsConsideredToBeIncluded,
1676
+ blockNumber,
1619
1677
  this.worldStateSynchronizer,
1620
1678
  gasFees,
1621
1679
  this.config.l1ChainId,
1622
1680
  this.config.rollupVersion,
1623
1681
  protocolContractsHash,
1624
1682
  this.archiver,
1625
- this.proofVerifier,
1626
1683
  !this.config.disableTransactions,
1627
1684
  allowedInSetup,
1628
1685
  this.logger.getBindings(),
1686
+ {
1687
+ rollupManaLimit: l1Constants.rollupManaLimit,
1688
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1689
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1690
+ },
1629
1691
  );
1630
1692
  }
1631
1693
 
1694
+ /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
1695
+ protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
1696
+ return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
1697
+ }
1698
+
1632
1699
  /**
1633
1700
  * Run validations on a tx.
1634
1701
  * @param tx - The tx to validate.
@@ -1637,7 +1704,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1637
1704
  */
1638
1705
  private async runValidations(
1639
1706
  tx: Tx,
1640
- messageValidators: Record<string, MessageValidator>,
1707
+ messageValidators: Record<string, TransactionValidator>,
1641
1708
  ): Promise<ValidationOutcome> {
1642
1709
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
1643
1710
  const { result } = await validator.validateTx(tx);
@@ -1646,8 +1713,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1646
1713
 
1647
1714
  // A promise that resolves when all validations have been run
1648
1715
  const allValidations = await Promise.all(validationPromises);
1649
- const failed = allValidations.find(x => !x.isValid);
1650
- if (failed) {
1716
+ const failures = allValidations.filter(x => !x.isValid);
1717
+ if (failures.length > 0) {
1718
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1719
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1651
1720
  return {
1652
1721
  allPassed: false,
1653
1722
  failure: {
@@ -1700,31 +1769,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1700
1769
  return PeerErrorSeverity.HighToleranceError;
1701
1770
  }
1702
1771
 
1703
- /**
1704
- * Validate a checkpoint attestation.
1705
- *
1706
- * @param attestation - The checkpoint attestation to validate.
1707
- * @returns True if the checkpoint attestation is valid, false otherwise.
1708
- */
1709
- @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1710
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1711
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1712
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1713
- }))
1714
- public async validateCheckpointAttestation(
1715
- peerId: PeerId,
1716
- attestation: CheckpointAttestation,
1717
- ): Promise<P2PValidationResult> {
1718
- const result = await this.checkpointAttestationValidator.validate(attestation);
1719
-
1720
- if (result.result === 'reject') {
1721
- this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1722
- this.peerManager.penalizePeer(peerId, result.severity);
1723
- }
1724
-
1725
- return result;
1726
- }
1727
-
1728
1772
  public getPeerScore(peerId: PeerId): number {
1729
1773
  return this.node.services.pubsub.score.score(peerId.toString());
1730
1774
  }