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

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