@aztec/p2p 0.0.0-test.1 → 0.0.1-commit.017a351

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