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

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