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

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