@aztec/p2p 0.0.1-commit.3469e52 → 0.0.1-commit.35158ae7e

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