@aztec/p2p 0.0.0-test.0 → 0.0.1-commit.001888fc

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