@aztec-labs/p2p 6.0.0-nightly.20260829

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