@aztec/p2p 0.0.1-commit.24de95ac → 0.0.1-commit.3469e52

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 (362) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +1 -1
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/client/factory.d.ts +2 -2
  4. package/dest/client/factory.d.ts.map +1 -1
  5. package/dest/client/factory.js +2 -3
  6. package/dest/client/index.d.ts +1 -1
  7. package/dest/client/interface.d.ts +18 -3
  8. package/dest/client/interface.d.ts.map +1 -1
  9. package/dest/client/p2p_client.d.ts +16 -37
  10. package/dest/client/p2p_client.d.ts.map +1 -1
  11. package/dest/client/p2p_client.js +464 -126
  12. package/dest/config.d.ts +62 -59
  13. package/dest/config.d.ts.map +1 -1
  14. package/dest/config.js +21 -14
  15. package/dest/enr/generate-enr.d.ts +1 -1
  16. package/dest/enr/index.d.ts +1 -1
  17. package/dest/errors/attestation-pool.error.d.ts +7 -0
  18. package/dest/errors/attestation-pool.error.d.ts.map +1 -0
  19. package/dest/errors/attestation-pool.error.js +12 -0
  20. package/dest/errors/reqresp.error.d.ts +1 -1
  21. package/dest/errors/reqresp.error.d.ts.map +1 -1
  22. package/dest/index.d.ts +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +77 -36
  24. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  26. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +241 -266
  28. package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
  29. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +24 -14
  30. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  31. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +123 -95
  32. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +18 -12
  33. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  34. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +91 -108
  35. package/dest/mem_pools/attestation_pool/mocks.d.ts +234 -10
  36. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  37. package/dest/mem_pools/attestation_pool/mocks.js +17 -13
  38. package/dest/mem_pools/index.d.ts +1 -1
  39. package/dest/mem_pools/instrumentation.d.ts +9 -1
  40. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  41. package/dest/mem_pools/instrumentation.js +36 -9
  42. package/dest/mem_pools/interface.d.ts +3 -4
  43. package/dest/mem_pools/interface.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +34 -59
  45. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +314 -335
  47. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +31 -0
  48. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
  49. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +112 -0
  50. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +156 -0
  51. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
  52. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +52 -0
  53. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +16 -0
  54. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
  55. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +115 -0
  56. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
  57. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  58. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
  59. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
  60. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  61. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
  62. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
  63. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  64. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
  65. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +25 -0
  66. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +1 -0
  67. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +57 -0
  68. package/dest/mem_pools/tx_pool/index.d.ts +1 -2
  69. package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
  70. package/dest/mem_pools/tx_pool/index.js +0 -1
  71. package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
  72. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  73. package/dest/mem_pools/tx_pool/priority.js +6 -1
  74. package/dest/mem_pools/tx_pool/tx_pool.d.ts +11 -6
  75. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  76. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  77. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  78. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +30 -24
  79. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +7 -6
  80. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  81. package/dest/msg_validators/attestation_validator/attestation_validator.js +18 -16
  82. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
  83. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
  84. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +64 -0
  85. package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
  86. package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
  87. package/dest/msg_validators/attestation_validator/index.js +1 -0
  88. package/dest/msg_validators/index.d.ts +2 -2
  89. package/dest/msg_validators/index.d.ts.map +1 -1
  90. package/dest/msg_validators/index.js +1 -1
  91. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
  92. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
  93. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +9 -0
  94. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
  95. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +6 -0
  96. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +9 -0
  97. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
  98. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +6 -0
  99. package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
  100. package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
  101. package/dest/msg_validators/proposal_validator/index.js +3 -0
  102. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -0
  103. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
  104. package/dest/msg_validators/proposal_validator/proposal_validator.js +73 -0
  105. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +23 -0
  106. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -0
  107. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +157 -0
  108. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  109. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  110. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  111. package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
  112. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  113. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
  114. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  115. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  116. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  117. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
  118. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  119. package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
  120. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  121. package/dest/msg_validators/tx_validator/factory.js +1 -1
  122. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +10 -0
  123. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -0
  124. package/dest/msg_validators/tx_validator/fee_payer_balance.js +20 -0
  125. package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
  126. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  127. package/dest/msg_validators/tx_validator/gas_validator.js +8 -14
  128. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  129. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  130. package/dest/msg_validators/tx_validator/index.js +1 -0
  131. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
  132. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  133. package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
  134. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  135. package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
  136. package/dest/msg_validators/tx_validator/size_validator.d.ts +6 -0
  137. package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -0
  138. package/dest/msg_validators/tx_validator/size_validator.js +20 -0
  139. package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
  140. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
  141. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
  142. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  143. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
  144. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  145. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
  146. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  147. package/dest/services/data_store.d.ts +1 -1
  148. package/dest/services/data_store.d.ts.map +1 -1
  149. package/dest/services/discv5/discV5_service.d.ts +1 -1
  150. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  151. package/dest/services/dummy_service.d.ts +6 -2
  152. package/dest/services/dummy_service.d.ts.map +1 -1
  153. package/dest/services/dummy_service.js +3 -0
  154. package/dest/services/encoding.d.ts +1 -1
  155. package/dest/services/encoding.d.ts.map +1 -1
  156. package/dest/services/encoding.js +7 -6
  157. package/dest/services/gossipsub/scoring.d.ts +1 -1
  158. package/dest/services/index.d.ts +1 -1
  159. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  160. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  161. package/dest/services/libp2p/instrumentation.js +26 -72
  162. package/dest/services/libp2p/libp2p_service.d.ts +40 -79
  163. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  164. package/dest/services/libp2p/libp2p_service.js +885 -161
  165. package/dest/services/peer-manager/interface.d.ts +1 -1
  166. package/dest/services/peer-manager/metrics.d.ts +8 -1
  167. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  168. package/dest/services/peer-manager/metrics.js +24 -16
  169. package/dest/services/peer-manager/peer_manager.d.ts +2 -33
  170. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  171. package/dest/services/peer-manager/peer_manager.js +6 -12
  172. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  173. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  174. package/dest/services/peer-manager/peer_scoring.js +37 -2
  175. package/dest/services/reqresp/config.d.ts +1 -1
  176. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
  177. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  178. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
  179. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  180. package/dest/services/reqresp/constants.d.ts +12 -0
  181. package/dest/services/reqresp/constants.d.ts.map +1 -0
  182. package/dest/services/reqresp/constants.js +7 -0
  183. package/dest/services/reqresp/index.d.ts +1 -1
  184. package/dest/services/reqresp/interface.d.ts +4 -4
  185. package/dest/services/reqresp/interface.d.ts.map +1 -1
  186. package/dest/services/reqresp/interface.js +3 -3
  187. package/dest/services/reqresp/metrics.d.ts +1 -1
  188. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  189. package/dest/services/reqresp/metrics.js +5 -21
  190. package/dest/services/reqresp/protocols/auth.d.ts +2 -2
  191. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
  192. package/dest/services/reqresp/protocols/auth.js +2 -2
  193. package/dest/services/reqresp/protocols/block.d.ts +1 -1
  194. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  195. package/dest/services/reqresp/protocols/block.js +3 -2
  196. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
  197. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  198. package/dest/services/reqresp/protocols/block_txs/bitvector.js +7 -0
  199. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  200. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
  201. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  202. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +1 -1
  203. package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
  204. package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
  205. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  206. package/dest/services/reqresp/protocols/index.d.ts +1 -1
  207. package/dest/services/reqresp/protocols/ping.d.ts +1 -1
  208. package/dest/services/reqresp/protocols/status.d.ts +6 -5
  209. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  210. package/dest/services/reqresp/protocols/status.js +7 -3
  211. package/dest/services/reqresp/protocols/tx.d.ts +2 -3
  212. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  213. package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
  214. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
  215. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  216. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  217. package/dest/services/reqresp/reqresp.d.ts +1 -41
  218. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  219. package/dest/services/reqresp/reqresp.js +402 -24
  220. package/dest/services/reqresp/status.d.ts +2 -2
  221. package/dest/services/reqresp/status.d.ts.map +1 -1
  222. package/dest/services/service.d.ts +16 -3
  223. package/dest/services/service.d.ts.map +1 -1
  224. package/dest/services/tx_collection/config.d.ts +1 -1
  225. package/dest/services/tx_collection/config.js +1 -1
  226. package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
  227. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  228. package/dest/services/tx_collection/index.d.ts +1 -1
  229. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  230. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  231. package/dest/services/tx_collection/instrumentation.js +4 -14
  232. package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -7
  233. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  234. package/dest/services/tx_collection/slow_tx_collection.js +2 -1
  235. package/dest/services/tx_collection/tx_collection.d.ts +11 -11
  236. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  237. package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
  238. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  239. package/dest/services/tx_collection/tx_source.d.ts +1 -1
  240. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  241. package/dest/services/tx_provider.d.ts +6 -4
  242. package/dest/services/tx_provider.d.ts.map +1 -1
  243. package/dest/services/tx_provider.js +11 -2
  244. package/dest/services/tx_provider_instrumentation.d.ts +5 -2
  245. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  246. package/dest/services/tx_provider_instrumentation.js +13 -13
  247. package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
  248. package/dest/test-helpers/get-ports.d.ts +1 -1
  249. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  250. package/dest/test-helpers/index.d.ts +1 -1
  251. package/dest/test-helpers/make-enrs.d.ts +1 -1
  252. package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
  253. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  254. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  255. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  256. package/dest/test-helpers/mock-tx-helpers.d.ts +2 -2
  257. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
  258. package/dest/test-helpers/mock-tx-helpers.js +1 -1
  259. package/dest/test-helpers/reqresp-nodes.d.ts +2 -2
  260. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  261. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  262. package/dest/testbench/p2p_client_testbench_worker.js +37 -21
  263. package/dest/testbench/parse_log_file.d.ts +1 -1
  264. package/dest/testbench/testbench.d.ts +1 -1
  265. package/dest/testbench/worker_client_manager.d.ts +1 -1
  266. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  267. package/dest/testbench/worker_client_manager.js +6 -1
  268. package/dest/types/index.d.ts +1 -1
  269. package/dest/util.d.ts +2 -1
  270. package/dest/util.d.ts.map +1 -1
  271. package/dest/util.js +11 -2
  272. package/dest/versioning.d.ts +1 -1
  273. package/package.json +19 -18
  274. package/src/client/factory.ts +5 -10
  275. package/src/client/interface.ts +20 -2
  276. package/src/client/p2p_client.ts +111 -158
  277. package/src/config.ts +30 -19
  278. package/src/errors/attestation-pool.error.ts +13 -0
  279. package/src/mem_pools/attestation_pool/attestation_pool.ts +86 -35
  280. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +243 -278
  281. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +175 -111
  282. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +147 -136
  283. package/src/mem_pools/attestation_pool/mocks.ts +21 -15
  284. package/src/mem_pools/instrumentation.ts +47 -10
  285. package/src/mem_pools/interface.ts +2 -4
  286. package/src/mem_pools/tx_pool/README.md +270 -0
  287. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +368 -372
  288. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +131 -0
  289. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +207 -0
  290. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +159 -0
  291. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
  292. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
  293. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
  294. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +75 -0
  295. package/src/mem_pools/tx_pool/index.ts +0 -1
  296. package/src/mem_pools/tx_pool/priority.ts +8 -1
  297. package/src/mem_pools/tx_pool/tx_pool.ts +11 -5
  298. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +23 -17
  299. package/src/msg_validators/attestation_validator/attestation_validator.ts +23 -22
  300. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +88 -0
  301. package/src/msg_validators/attestation_validator/index.ts +1 -0
  302. package/src/msg_validators/index.ts +1 -1
  303. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +10 -0
  304. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +13 -0
  305. package/src/msg_validators/proposal_validator/index.ts +3 -0
  306. package/src/msg_validators/proposal_validator/proposal_validator.ts +85 -0
  307. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +191 -0
  308. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  309. package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
  310. package/src/msg_validators/tx_validator/data_validator.ts +12 -4
  311. package/src/msg_validators/tx_validator/factory.ts +3 -2
  312. package/src/msg_validators/tx_validator/fee_payer_balance.ts +40 -0
  313. package/src/msg_validators/tx_validator/gas_validator.ts +8 -25
  314. package/src/msg_validators/tx_validator/index.ts +1 -0
  315. package/src/msg_validators/tx_validator/metadata_validator.ts +13 -5
  316. package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
  317. package/src/msg_validators/tx_validator/size_validator.ts +18 -0
  318. package/src/msg_validators/tx_validator/test_utils.ts +1 -1
  319. package/src/msg_validators/tx_validator/timestamp_validator.ts +5 -2
  320. package/src/services/dummy_service.ts +6 -0
  321. package/src/services/encoding.ts +6 -5
  322. package/src/services/libp2p/instrumentation.ts +26 -71
  323. package/src/services/libp2p/libp2p_service.ts +555 -145
  324. package/src/services/peer-manager/metrics.ts +27 -16
  325. package/src/services/peer-manager/peer_manager.ts +7 -4
  326. package/src/services/peer-manager/peer_scoring.ts +42 -3
  327. package/src/services/reqresp/connection-sampler/connection_sampler.ts +3 -1
  328. package/src/services/reqresp/constants.ts +14 -0
  329. package/src/services/reqresp/interface.ts +3 -3
  330. package/src/services/reqresp/metrics.ts +7 -23
  331. package/src/services/reqresp/protocols/auth.ts +2 -2
  332. package/src/services/reqresp/protocols/block.ts +3 -2
  333. package/src/services/reqresp/protocols/block_txs/bitvector.ts +9 -0
  334. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
  335. package/src/services/reqresp/protocols/status.ts +16 -12
  336. package/src/services/reqresp/protocols/tx.ts +1 -2
  337. package/src/services/service.ts +19 -4
  338. package/src/services/tx_collection/config.ts +1 -1
  339. package/src/services/tx_collection/fast_tx_collection.ts +3 -2
  340. package/src/services/tx_collection/instrumentation.ts +4 -21
  341. package/src/services/tx_collection/slow_tx_collection.ts +7 -6
  342. package/src/services/tx_collection/tx_collection.ts +10 -9
  343. package/src/services/tx_provider.ts +21 -5
  344. package/src/services/tx_provider_instrumentation.ts +18 -14
  345. package/src/test-helpers/mock-pubsub.ts +1 -1
  346. package/src/test-helpers/mock-tx-helpers.ts +1 -1
  347. package/src/test-helpers/reqresp-nodes.ts +1 -1
  348. package/src/testbench/p2p_client_testbench_worker.ts +45 -22
  349. package/src/testbench/worker_client_manager.ts +6 -1
  350. package/src/util.ts +12 -2
  351. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -80
  352. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
  353. package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -238
  354. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
  355. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
  356. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +0 -70
  357. package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
  358. package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
  359. package/dest/msg_validators/block_proposal_validator/index.js +0 -1
  360. package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -283
  361. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +0 -81
  362. package/src/msg_validators/block_proposal_validator/index.ts +0 -1
@@ -1,20 +1,22 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import { randomInt } from '@aztec/foundation/crypto';
3
- import { Fr } from '@aztec/foundation/fields';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { randomInt } from '@aztec/foundation/crypto/random';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
5
- import { SerialQueue } from '@aztec/foundation/queue';
6
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
7
  import { Timer } from '@aztec/foundation/timer';
8
8
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
9
9
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
10
10
  import { protocolContractsHash } from '@aztec/protocol-contracts';
11
- import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
11
+ import type { EthAddress, L2BlockNew, L2BlockSource } from '@aztec/stdlib/block';
12
12
  import type { ContractDataSource } from '@aztec/stdlib/contract';
13
13
  import { GasFees } from '@aztec/stdlib/gas';
14
14
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
15
15
  import {
16
- BlockAttestation,
17
16
  BlockProposal,
17
+ CheckpointAttestation,
18
+ CheckpointProposal,
19
+ type CheckpointProposalCore,
18
20
  type Gossipable,
19
21
  P2PClientType,
20
22
  P2PMessage,
@@ -28,7 +30,14 @@ import { MerkleTreeId } from '@aztec/stdlib/trees';
28
30
  import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
29
31
  import type { UInt64 } from '@aztec/stdlib/types';
30
32
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
31
- import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
33
+ import {
34
+ Attributes,
35
+ OtelMetricsAdapter,
36
+ SpanStatusCode,
37
+ type TelemetryClient,
38
+ WithTracer,
39
+ trackSpan,
40
+ } from '@aztec/telemetry-client';
32
41
 
33
42
  import {
34
43
  type GossipSub,
@@ -50,8 +59,15 @@ import { ENR } from '@nethermindeth/enr';
50
59
  import { createLibp2p } from 'libp2p';
51
60
 
52
61
  import type { P2PConfig } from '../../config.js';
62
+ import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
53
63
  import type { MemPools } from '../../mem_pools/interface.js';
54
- import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
64
+ import {
65
+ BlockProposalValidator,
66
+ CheckpointAttestationValidator,
67
+ CheckpointProposalValidator,
68
+ FishermanAttestationValidator,
69
+ SizeTxValidator,
70
+ } from '../../msg_validators/index.js';
55
71
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
56
72
  import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
57
73
  import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
@@ -96,7 +112,12 @@ import {
96
112
  reqRespTxHandler,
97
113
  } from '../reqresp/protocols/index.js';
98
114
  import { ReqResp } from '../reqresp/reqresp.js';
99
- import type { P2PBlockReceivedCallback, P2PService, PeerDiscoveryService } from '../service.js';
115
+ import type {
116
+ P2PBlockReceivedCallback,
117
+ P2PCheckpointReceivedCallback,
118
+ P2PService,
119
+ PeerDiscoveryService,
120
+ } from '../service.js';
100
121
  import { P2PInstrumentation } from './instrumentation.js';
101
122
 
102
123
  interface ValidationResult {
@@ -116,18 +137,18 @@ type ReceivedMessageValidationResult<T> =
116
137
  * Lib P2P implementation of the P2PService interface.
117
138
  */
118
139
  export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
119
- private jobQueue: SerialQueue = new SerialQueue();
120
140
  private discoveryRunningPromise?: RunningPromise;
121
141
  private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
122
142
 
123
143
  // Message validators
124
- private attestationValidator: AttestationValidator;
125
144
  private blockProposalValidator: BlockProposalValidator;
145
+ private checkpointProposalValidator: CheckpointProposalValidator;
146
+ private checkpointAttestationValidator: CheckpointAttestationValidator;
126
147
 
127
148
  private protocolVersion = '';
128
149
  private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
129
150
 
130
- private feesCache: { blockNumber: number; gasFees: GasFees } | undefined;
151
+ private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
131
152
 
132
153
  /**
133
154
  * Callback for when a block is received from a peer.
@@ -136,10 +157,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
136
157
  */
137
158
  private blockReceivedCallback: P2PBlockReceivedCallback;
138
159
 
160
+ /**
161
+ * Callback for when a checkpoint proposal is received from a peer.
162
+ * @param checkpoint - The checkpoint proposal received from the peer.
163
+ * @returns The attestations for the checkpoint, if any.
164
+ */
165
+ private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
166
+
139
167
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
140
168
 
141
169
  private instrumentation: P2PInstrumentation;
142
170
 
171
+ private telemetry: TelemetryClient;
172
+
173
+ protected logger: Logger;
174
+
143
175
  constructor(
144
176
  private clientType: T,
145
177
  private config: P2PConfig,
@@ -147,21 +179,26 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
147
179
  private peerDiscoveryService: PeerDiscoveryService,
148
180
  private reqresp: ReqRespInterface,
149
181
  private peerManager: PeerManagerInterface,
150
- protected mempools: MemPools<T>,
182
+ protected mempools: MemPools,
151
183
  private archiver: L2BlockSource & ContractDataSource,
152
184
  private epochCache: EpochCacheInterface,
153
185
  private proofVerifier: ClientProtocolCircuitVerifier,
154
186
  private worldStateSynchronizer: WorldStateSynchronizer,
155
187
  telemetry: TelemetryClient,
156
- protected logger = createLogger('p2p:libp2p_service'),
188
+ logger: Logger = createLogger('p2p:libp2p_service'),
157
189
  ) {
158
190
  super(telemetry, 'LibP2PService');
191
+ this.telemetry = telemetry;
192
+
193
+ // Create child logger with fisherman prefix if in fisherman mode
194
+ this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
159
195
 
160
196
  this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
161
197
 
162
198
  this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
163
199
  this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
164
- this.msgIdSeenValidators[TopicType.block_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
200
+ this.msgIdSeenValidators[TopicType.checkpoint_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
201
+ this.msgIdSeenValidators[TopicType.checkpoint_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
165
202
 
166
203
  const versions = getVersions(config);
167
204
  this.protocolVersion = compressComponentVersions(versions);
@@ -169,22 +206,40 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
169
206
 
170
207
  this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
171
208
  this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
172
- this.topicStrings[TopicType.block_attestation] = createTopicString(
173
- TopicType.block_attestation,
209
+ this.topicStrings[TopicType.checkpoint_proposal] = createTopicString(
210
+ TopicType.checkpoint_proposal,
211
+ this.protocolVersion,
212
+ );
213
+ this.topicStrings[TopicType.checkpoint_attestation] = createTopicString(
214
+ TopicType.checkpoint_attestation,
174
215
  this.protocolVersion,
175
216
  );
176
217
 
177
- this.attestationValidator = new AttestationValidator(epochCache);
178
218
  this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
219
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
220
+ txsPermitted: !config.disableTransactions,
221
+ });
222
+ this.checkpointAttestationValidator = config.fishermanMode
223
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
224
+ : new CheckpointAttestationValidator(epochCache);
179
225
 
180
226
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
181
227
 
182
- this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
228
+ this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
183
229
  this.logger.debug(
184
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber.toNumber()} from peer.`,
185
- { p2pMessageIdentifier: await block.p2pMessageIdentifier() },
230
+ `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
231
+ { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
186
232
  );
187
- return undefined;
233
+ return false;
234
+ };
235
+
236
+ this.checkpointReceivedCallback = (
237
+ checkpoint: CheckpointProposalCore,
238
+ ): Promise<CheckpointAttestation[] | undefined> => {
239
+ this.logger.debug(
240
+ `Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
241
+ );
242
+ return Promise.resolve(undefined);
188
243
  };
189
244
  }
190
245
 
@@ -203,7 +258,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
203
258
  config: P2PConfig,
204
259
  peerId: PeerId,
205
260
  deps: {
206
- mempools: MemPools<T>;
261
+ mempools: MemPools;
207
262
  l2BlockSource: L2BlockSource & ContractDataSource;
208
263
  epochCache: EpochCacheInterface;
209
264
  proofVerifier: ClientProtocolCircuitVerifier;
@@ -253,7 +308,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
253
308
 
254
309
  const txTopic = createTopicString(TopicType.tx, protocolVersion);
255
310
  const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
256
- const blockAttestationTopic = createTopicString(TopicType.block_attestation, protocolVersion);
311
+ const checkpointProposalTopic = createTopicString(TopicType.checkpoint_proposal, protocolVersion);
312
+ const checkpointAttestationTopic = createTopicString(TopicType.checkpoint_attestation, protocolVersion);
257
313
 
258
314
  const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
259
315
  const directPeers = (
@@ -375,12 +431,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
375
431
  invalidMessageDeliveriesWeight: -20,
376
432
  invalidMessageDeliveriesDecay: 0.5,
377
433
  }),
378
- [blockAttestationTopic]: createTopicScoreParams({
434
+ [blockProposalTopic]: createTopicScoreParams({
379
435
  topicWeight: 1,
380
436
  invalidMessageDeliveriesWeight: -20,
381
437
  invalidMessageDeliveriesDecay: 0.5,
382
438
  }),
383
- [blockProposalTopic]: createTopicScoreParams({
439
+ [checkpointProposalTopic]: createTopicScoreParams({
440
+ topicWeight: 1,
441
+ invalidMessageDeliveriesWeight: -20,
442
+ invalidMessageDeliveriesDecay: 0.5,
443
+ }),
444
+ [checkpointAttestationTopic]: createTopicScoreParams({
384
445
  topicWeight: 1,
385
446
  invalidMessageDeliveriesWeight: -20,
386
447
  invalidMessageDeliveriesDecay: 0.5,
@@ -395,7 +456,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
395
456
  logger: createLibp2pComponentLogger(logger.module),
396
457
  });
397
458
 
398
- const peerScoring = new PeerScoring(config);
459
+ const peerScoring = new PeerScoring(config, telemetry);
399
460
  const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
400
461
 
401
462
  const peerManager = new PeerManager(
@@ -450,20 +511,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
450
511
  }
451
512
  const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
452
513
 
453
- // Start job queue, peer discovery service and libp2p node
454
- this.jobQueue.start();
455
-
456
- await this.peerManager.initializePeers();
457
- if (!this.config.p2pDiscoveryDisabled) {
458
- await this.peerDiscoveryService.start();
459
- }
460
- await this.node.start();
461
-
462
- // Subscribe to standard GossipSub topics by default
463
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
464
- this.subscribeToTopic(this.topicStrings[topic]);
465
- }
466
-
467
514
  // Create request response protocol handlers
468
515
  const txHandler = reqRespTxHandler(this.mempools);
469
516
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
@@ -477,8 +524,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
477
524
  [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
478
525
  };
479
526
 
480
- // Only handle block transactions request if attestation pool is available to the client
481
- if (this.mempools.attestationPool && !this.config.disableTransactions) {
527
+ if (!this.config.disableTransactions) {
482
528
  const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
483
529
  requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
484
530
  }
@@ -487,25 +533,41 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
487
533
  requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
488
534
  }
489
535
 
536
+ // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
537
+ const reqrespSubProtocolValidators = {
538
+ ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
539
+ [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
540
+ [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
541
+ [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
542
+ };
543
+
544
+ await this.peerManager.initializePeers();
545
+
546
+ await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
547
+
548
+ await this.node.start();
549
+
550
+ // Subscribe to standard GossipSub topics by default
551
+ for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
552
+ this.subscribeToTopic(this.topicStrings[topic]);
553
+ }
554
+
490
555
  // add GossipSub listener
491
556
  this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
492
557
 
493
- // Start running promise for peer discovery
558
+ // Start running promise for peer discovery and metrics collection
559
+ if (!this.config.p2pDiscoveryDisabled) {
560
+ await this.peerDiscoveryService.start();
561
+ }
494
562
  this.discoveryRunningPromise = new RunningPromise(
495
- () => this.peerManager.heartbeat(),
563
+ async () => {
564
+ await this.peerManager.heartbeat();
565
+ },
496
566
  this.logger,
497
567
  this.config.peerCheckIntervalMS,
498
568
  );
499
569
  this.discoveryRunningPromise.start();
500
570
 
501
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
502
- const reqrespSubProtocolValidators = {
503
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
504
- // TODO(#11336): A request validator for blocks
505
- [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
506
- [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
507
- };
508
- await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
509
571
  this.logger.info(`Started P2P service`, {
510
572
  listen: this.config.listenAddress,
511
573
  port: this.config.p2pPort,
@@ -525,9 +587,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
525
587
  // Stop peer manager
526
588
  this.logger.debug('Stopping peer manager...');
527
589
  await this.peerManager.stop();
528
-
529
- this.logger.debug('Stopping job queue...');
530
- await this.jobQueue.end();
531
590
  this.logger.debug('Stopping running promise...');
532
591
  await this.discoveryRunningPromise?.stop();
533
592
  this.logger.debug('Stopping peer discovery service...');
@@ -594,6 +653,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
594
653
  this.blockReceivedCallback = callback;
595
654
  }
596
655
 
656
+ public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
657
+ this.checkpointReceivedCallback = callback;
658
+ }
659
+
597
660
  /**
598
661
  * Subscribes to a topic.
599
662
  * @param topic - The topic to subscribe to.
@@ -615,7 +678,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
615
678
  if (!this.node.services.pubsub) {
616
679
  throw new Error('Pubsub service not available.');
617
680
  }
618
- const p2pMessage = P2PMessage.fromGossipable(message);
681
+ const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
682
+ const traceContext =
683
+ this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
684
+ const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
619
685
  const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
620
686
  return result.recipients.length;
621
687
  }
@@ -636,12 +702,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
636
702
  case this.topicStrings[TopicType.tx]:
637
703
  topicType = TopicType.tx;
638
704
  break;
639
- case this.topicStrings[TopicType.block_attestation]:
640
- topicType = TopicType.block_attestation;
641
- break;
642
705
  case this.topicStrings[TopicType.block_proposal]:
643
706
  topicType = TopicType.block_proposal;
644
707
  break;
708
+ case this.topicStrings[TopicType.checkpoint_proposal]:
709
+ topicType = TopicType.checkpoint_proposal;
710
+ break;
711
+ case this.topicStrings[TopicType.checkpoint_attestation]:
712
+ topicType = TopicType.checkpoint_attestation;
713
+ break;
645
714
  default:
646
715
  this.logger.error(`Received message on unknown topic: ${msg.topic}`);
647
716
  break;
@@ -660,13 +729,39 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
660
729
  return { result: true, topicType };
661
730
  }
662
731
 
732
+ /**
733
+ * Safely deserializes a P2PMessage from raw message data.
734
+ * @param msgId - The message ID.
735
+ * @param source - The peer ID of the message source.
736
+ * @param data - The raw message data.
737
+ * @returns The deserialized P2PMessage or undefined if deserialization fails.
738
+ */
739
+ private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
740
+ try {
741
+ return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
742
+ } catch (err) {
743
+ this.logger.error(`Error deserializing P2PMessage`, err, {
744
+ msgId,
745
+ source: source.toString(),
746
+ });
747
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
748
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
749
+ return undefined;
750
+ }
751
+ }
752
+
663
753
  /**
664
754
  * Handles a new gossip message that was received by the client.
665
755
  * @param topic - The message's topic.
666
756
  * @param data - The message data
667
757
  */
668
758
  protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
669
- const p2pMessage = P2PMessage.fromMessageData(Buffer.from(msg.data));
759
+ const msgReceivedTime = Date.now();
760
+ let topicType: TopicType | undefined;
761
+ const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
762
+ if (!p2pMessage) {
763
+ return;
764
+ }
670
765
 
671
766
  const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
672
767
 
@@ -674,14 +769,75 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
674
769
  return;
675
770
  }
676
771
 
772
+ // Determine topic type for attributes
677
773
  if (msg.topic === this.topicStrings[TopicType.tx]) {
678
- await this.handleGossipedTx(p2pMessage.payload, msgId, source);
774
+ topicType = TopicType.tx;
775
+ } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
776
+ topicType = TopicType.checkpoint_attestation;
777
+ } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
778
+ topicType = TopicType.block_proposal;
779
+ } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
780
+ topicType = TopicType.checkpoint_proposal;
679
781
  }
680
- if (msg.topic === this.topicStrings[TopicType.block_attestation] && this.clientType === P2PClientType.Full) {
681
- await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
782
+
783
+ // Process the message, optionally within a linked span for trace propagation
784
+ const processMessage = async () => {
785
+ if (msg.topic === this.topicStrings[TopicType.tx]) {
786
+ await this.handleGossipedTx(p2pMessage.payload, msgId, source);
787
+ } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
788
+ if (this.clientType === P2PClientType.Full) {
789
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
790
+ }
791
+ } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
792
+ await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
793
+ } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
794
+ await this.handleGossipedCheckpointProposal(p2pMessage.payload, msgId, source);
795
+ } else {
796
+ this.logger.error(`Received message on unknown topic: ${msg.topic}`);
797
+ }
798
+ };
799
+
800
+ const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
801
+ const propagatedContext = p2pMessage.traceContext
802
+ ? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
803
+ : undefined;
804
+
805
+ if (propagatedContext) {
806
+ await this.tracer.startActiveSpan(
807
+ 'LibP2PService.processMessage',
808
+ {
809
+ attributes: {
810
+ [Attributes.TOPIC_NAME]: topicType!,
811
+ [Attributes.PEER_ID]: source.toString(),
812
+ },
813
+ },
814
+ propagatedContext,
815
+ async span => {
816
+ try {
817
+ await processMessage();
818
+ span.setStatus({
819
+ code: SpanStatusCode.OK,
820
+ });
821
+ } catch (err) {
822
+ span.setStatus({
823
+ code: SpanStatusCode.ERROR,
824
+ message: String(err),
825
+ });
826
+ if (typeof err === 'string' || (err && err instanceof Error)) {
827
+ span.recordException(err);
828
+ }
829
+ throw err;
830
+ } finally {
831
+ span.end();
832
+ }
833
+ },
834
+ );
835
+ } else {
836
+ await processMessage();
682
837
  }
683
- if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
684
- await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
838
+
839
+ if (latency !== undefined && topicType !== undefined) {
840
+ this.instrumentation.recordMessageLatency(topicType, latency);
685
841
  }
686
842
 
687
843
  return;
@@ -698,6 +854,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
698
854
  try {
699
855
  resultAndObj = await validationFunc();
700
856
  } catch (err) {
857
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
701
858
  this.logger.error(`Error deserializing and validating gossipsub message`, err, {
702
859
  msgId,
703
860
  source: source.toString(),
@@ -751,24 +908,37 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
751
908
  return;
752
909
  }
753
910
 
911
+ this.instrumentation.incrementTxReceived(1);
754
912
  await this.mempools.txPool.addTxs([tx]);
755
913
  }
756
914
 
757
915
  /**
758
- * Process Attestation From Peer
759
- * When a proposal is received from a peer, we add it to the attestation pool, so it can be accessed by other services.
760
- *
761
- * @param attestation - The attestation to process.
916
+ * Process a checkpoint attestation from a peer.
917
+ * Validates the attestation and adds it to the pool.
762
918
  */
763
- private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
764
- const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
765
- const attestation = BlockAttestation.fromBuffer(payloadData);
766
- const isValid = await this.validateAttestation(source, attestation);
767
- const exists = isValid && (await this.mempools.attestationPool!.hasAttestation(attestation));
919
+ private async processCheckpointAttestationFromPeer(
920
+ payloadData: Buffer,
921
+ msgId: string,
922
+ source: PeerId,
923
+ ): Promise<void> {
924
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointAttestation>> = async () => {
925
+ const attestation = CheckpointAttestation.fromBuffer(payloadData);
926
+ const pool = this.mempools.attestationPool;
927
+ const isValid = await this.validateCheckpointAttestation(source, attestation);
928
+ const exists = isValid && (await pool.hasCheckpointAttestation(attestation));
929
+
930
+ let canAdd = true;
931
+ if (isValid && !exists) {
932
+ const slot = attestation.payload.header.slotNumber;
933
+ const { committee } = await this.epochCache.getCommittee(slot);
934
+ const committeeSize = committee?.length ?? 0;
935
+ canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
936
+ }
768
937
 
769
- this.logger.trace(`Validate propagated block attestation`, {
938
+ this.logger.trace(`Validate propagated checkpoint attestation`, {
770
939
  isValid,
771
940
  exists,
941
+ canAdd,
772
942
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
773
943
  [Attributes.P2P_ID]: source.toString(),
774
944
  });
@@ -777,16 +947,23 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
777
947
  return { result: TopicValidatorResult.Reject };
778
948
  } else if (exists) {
779
949
  return { result: TopicValidatorResult.Ignore, obj: attestation };
950
+ } else if (!canAdd) {
951
+ this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
952
+ slot: attestation.payload.header.slotNumber.toString(),
953
+ archive: attestation.archive.toString(),
954
+ source: source.toString(),
955
+ });
956
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
780
957
  } else {
781
958
  return { result: TopicValidatorResult.Accept, obj: attestation };
782
959
  }
783
960
  };
784
961
 
785
- const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
962
+ const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
786
963
  validationFunc,
787
964
  msgId,
788
965
  source,
789
- TopicType.block_attestation,
966
+ TopicType.checkpoint_attestation,
790
967
  );
791
968
 
792
969
  if (result !== TopicValidatorResult.Accept || !attestation) {
@@ -794,31 +971,32 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
794
971
  }
795
972
 
796
973
  this.logger.debug(
797
- `Received attestation for slot ${attestation.slotNumber.toNumber()} from external peer ${source.toString()}`,
974
+ `Received checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
798
975
  {
799
- p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
800
- slot: attestation.slotNumber.toNumber(),
976
+ p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
977
+ slot: attestation.slotNumber,
801
978
  archive: attestation.archive.toString(),
802
979
  source: source.toString(),
803
980
  },
804
981
  );
805
982
 
806
- await this.mempools.attestationPool!.addAttestations([attestation]);
983
+ await this.mempools.attestationPool.addCheckpointAttestations([attestation]);
807
984
  }
808
985
 
809
986
  private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
810
987
  const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
811
988
  const block = BlockProposal.fromBuffer(payloadData);
812
989
  const isValid = await this.validateBlockProposal(source, block);
990
+ const pool = this.mempools.attestationPool;
813
991
 
814
- // Note that we dont have an attestation pool if we're a prover node, but we still
815
- // subscribe to block proposal topics in order to prevent their txs from being cleared.
816
- const exists = isValid && (await this.mempools.attestationPool?.hasBlockProposal(block));
992
+ const exists = isValid && (await pool.hasBlockProposal(block));
993
+ const canAdd = isValid && (await pool.canAddProposal(block));
817
994
 
818
995
  this.logger.trace(`Validate propagated block proposal`, {
819
996
  isValid,
820
997
  exists,
821
- [Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
998
+ canAdd,
999
+ [Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
822
1000
  [Attributes.P2P_ID]: source.toString(),
823
1001
  });
824
1002
 
@@ -826,6 +1004,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
826
1004
  return { result: TopicValidatorResult.Reject };
827
1005
  } else if (exists) {
828
1006
  return { result: TopicValidatorResult.Ignore, obj: block };
1007
+ } else if (!canAdd) {
1008
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
1009
+ this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
1010
+ slot: block.slotNumber.toString(),
1011
+ archive: block.archive.toString(),
1012
+ source: source.toString(),
1013
+ });
1014
+ return { result: TopicValidatorResult.Reject };
829
1015
  } else {
830
1016
  return { result: TopicValidatorResult.Accept, obj: block };
831
1017
  }
@@ -846,55 +1032,155 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
846
1032
  }
847
1033
 
848
1034
  // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
1035
+ // REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
1036
+ // should not be here as it does not deal with p2p networking.
849
1037
  @trackSpan('Libp2pService.processValidBlockProposal', async block => ({
850
- [Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
1038
+ [Attributes.SLOT_NUMBER]: block.slotNumber,
851
1039
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
852
- [Attributes.P2P_ID]: await block.p2pMessageIdentifier().then(i => i.toString()),
1040
+ [Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
853
1041
  }))
854
1042
  private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
855
- const slot = block.slotNumber.toBigInt();
856
- const previousSlot = slot - 1n;
1043
+ const slot = block.slotNumber;
857
1044
  this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
858
- p2pMessageIdentifier: await block.p2pMessageIdentifier(),
859
- slot: block.slotNumber.toNumber(),
860
- archive: block.archive.toString(),
1045
+ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
861
1046
  source: sender.toString(),
1047
+ ...block.toBlockInfo(),
862
1048
  });
863
- const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
864
- if (attestationsForPreviousSlot !== undefined) {
865
- this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
1049
+
1050
+ // Attempt to add proposal
1051
+ try {
1052
+ await this.mempools.attestationPool.addBlockProposal(block);
1053
+ } catch (err: unknown) {
1054
+ // Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
1055
+ if (err instanceof ProposalSlotCapExceededError) {
1056
+ this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
1057
+ slot: String(slot),
1058
+ archive: block.archive.toString(),
1059
+ error: (err as Error).message,
1060
+ });
1061
+ return;
1062
+ }
1063
+ throw err;
866
1064
  }
867
1065
 
868
1066
  // Mark the txs in this proposal as non-evictable
869
1067
  await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
870
- await this.mempools.attestationPool?.addBlockProposal(block);
871
- const attestations = await this.blockReceivedCallback(block, sender);
872
1068
 
873
- // TODO: fix up this pattern - the abstraction is not nice
874
- // The attestation can be undefined if no handler is registered / the validator deems the block invalid
875
- if (attestations?.length) {
876
- for (const attestation of attestations) {
877
- this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber.toNumber()}`, {
878
- p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
879
- slot: attestation.slotNumber.toNumber(),
880
- archive: attestation.archive.toString(),
1069
+ // Call the block received callback to validate the proposal.
1070
+ // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1071
+ const isValid = await this.blockReceivedCallback(block, sender);
1072
+ if (!isValid) {
1073
+ this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1074
+ }
1075
+ }
1076
+
1077
+ /**
1078
+ * Handle a gossiped checkpoint proposal.
1079
+ * Validates and processes the checkpoint proposal, then triggers the callback for attestation.
1080
+ */
1081
+ private async handleGossipedCheckpointProposal(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
1082
+ // TODO(palla/mbps): This pattern is repeated across multiple message handlers, consider abstracting it.
1083
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<CheckpointProposal>> = async () => {
1084
+ const checkpoint = CheckpointProposal.fromBuffer(payloadData);
1085
+ const isValid = await this.validateCheckpointProposal(source, checkpoint);
1086
+ const pool = this.mempools.attestationPool;
1087
+
1088
+ const exists = isValid && (await pool.hasCheckpointProposal(checkpoint));
1089
+ const canAdd = isValid && (await pool.canAddCheckpointProposal(checkpoint));
1090
+
1091
+ this.logger.trace(`Validate propagated checkpoint proposal`, {
1092
+ isValid,
1093
+ exists,
1094
+ canAdd,
1095
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1096
+ [Attributes.P2P_ID]: source.toString(),
1097
+ });
1098
+
1099
+ if (!isValid) {
1100
+ return { result: TopicValidatorResult.Reject };
1101
+ } else if (exists) {
1102
+ return { result: TopicValidatorResult.Ignore, obj: checkpoint };
1103
+ } else if (!canAdd) {
1104
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
1105
+ this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1106
+ slot: checkpoint.slotNumber.toString(),
1107
+ archive: checkpoint.archive.toString(),
1108
+ source: source.toString(),
881
1109
  });
882
- await this.broadcastAttestation(attestation);
1110
+ return { result: TopicValidatorResult.Reject };
1111
+ } else {
1112
+ return { result: TopicValidatorResult.Accept, obj: checkpoint };
883
1113
  }
1114
+ };
1115
+
1116
+ const { result, obj: checkpoint } = await this.validateReceivedMessage<CheckpointProposal>(
1117
+ validationFunc,
1118
+ msgId,
1119
+ source,
1120
+ TopicType.checkpoint_proposal,
1121
+ );
1122
+
1123
+ if (result !== TopicValidatorResult.Accept || !checkpoint) {
1124
+ return;
884
1125
  }
1126
+
1127
+ await this.processValidCheckpointProposal(checkpoint, source);
885
1128
  }
886
1129
 
887
1130
  /**
888
- * Broadcast an attestation to all peers.
889
- * @param attestation - The attestation to broadcast.
1131
+ * Process a validated checkpoint proposal.
1132
+ * Extracts and processes the last block proposal (if present) first, then processes the checkpoint.
1133
+ * The block callback is invoked before the checkpoint callback.
890
1134
  */
891
- @trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
892
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
893
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
894
- [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
1135
+ @trackSpan('Libp2pService.processValidCheckpointProposal', async checkpoint => ({
1136
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
1137
+ [Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
1138
+ [Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then(i => i.toString()),
895
1139
  }))
896
- private async broadcastAttestation(attestation: BlockAttestation) {
897
- await this.propagate(attestation);
1140
+ private async processValidCheckpointProposal(checkpoint: CheckpointProposal, sender: PeerId) {
1141
+ const slot = checkpoint.slotNumber;
1142
+ this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
1143
+ p2pMessageIdentifier: await checkpoint.p2pMessageLoggingIdentifier(),
1144
+ slot: checkpoint.slotNumber,
1145
+ archive: checkpoint.archive.toString(),
1146
+ source: sender.toString(),
1147
+ });
1148
+
1149
+ // Extract block proposal before adding to pool (pool stores them separately)
1150
+ const blockProposal = checkpoint.getBlockProposal();
1151
+
1152
+ // Add proposal to the pool (this extracts and stores block proposal separately)
1153
+ await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
1154
+
1155
+ // Mark txs as non-evictable if present (from the last block)
1156
+ if (checkpoint.txHashes.length > 0) {
1157
+ await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
1158
+ }
1159
+
1160
+ // If there was a last block proposal, invoke the block callback first for validation.
1161
+ // Note: The block proposal is already stored in the pool by addCheckpointProposal.
1162
+ if (blockProposal) {
1163
+ const isValid = await this.blockReceivedCallback(blockProposal, sender);
1164
+ if (!isValid) {
1165
+ this.logger.warn(`Block proposal from checkpoint failed validation`, {
1166
+ slot: slot.toString(),
1167
+ archive: checkpoint.archive.toString(),
1168
+ blockNumber: blockProposal.blockNumber.toString(),
1169
+ });
1170
+ return;
1171
+ }
1172
+ }
1173
+
1174
+ // Call the checkpoint received callback with the core version (without lastBlock)
1175
+ // to validate and potentially generate attestations
1176
+ const attestations = await this.checkpointReceivedCallback(checkpoint.toCore(), sender);
1177
+ if (attestations && attestations.length > 0) {
1178
+ // If the callback returned attestations, add them to the pool and propagate them
1179
+ await this.mempools.attestationPool.addCheckpointAttestations(attestations);
1180
+ for (const attestation of attestations) {
1181
+ await this.propagate(attestation);
1182
+ }
1183
+ }
898
1184
  }
899
1185
 
900
1186
  /**
@@ -902,19 +1188,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
902
1188
  * @param message - The message to propagate.
903
1189
  */
904
1190
  public async propagate<T extends Gossipable>(message: T) {
905
- const p2pMessageIdentifier = await message.p2pMessageIdentifier();
1191
+ const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
906
1192
  this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
907
- void this.jobQueue
908
- .put(async () => {
909
- await this.sendToPeers(message);
910
- })
911
- .catch(error => {
912
- this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
913
- });
1193
+ void this.sendToPeers(message).catch(error => {
1194
+ this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
1195
+ });
914
1196
  }
915
1197
 
916
1198
  /**
917
- * Validate the requested block transactions.
1199
+ * Validate the requested block transactions. Allow partial returns.
918
1200
  * @param request - The block transactions request.
919
1201
  * @param response - The block transactions response.
920
1202
  * @param peerId - The ID of the peer that made the request.
@@ -924,14 +1206,71 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
924
1206
  [Attributes.BLOCK_HASH]: request.blockHash.toString(),
925
1207
  }))
926
1208
  private async validateRequestedBlockTxs(
927
- _request: BlockTxsRequest,
1209
+ request: BlockTxsRequest,
928
1210
  response: BlockTxsResponse,
929
1211
  peerId: PeerId,
930
1212
  ): Promise<boolean> {
931
1213
  const requestedTxValidator = this.createRequestedTxValidator();
932
1214
 
933
1215
  try {
934
- // TODO(palla/txs): Validate that this tx belongs to the block hash being requested
1216
+ if (!response.blockHash.equals(request.blockHash)) {
1217
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1218
+ throw new ValidationError(
1219
+ `Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
1220
+ );
1221
+ }
1222
+
1223
+ if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1224
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1225
+ throw new ValidationError(
1226
+ `Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
1227
+ );
1228
+ }
1229
+
1230
+ // Check no duplicates and not exceeding returnable count
1231
+ const requestedIndices = new Set(request.txIndices.getTrueIndices());
1232
+ const availableIndices = new Set(response.txIndices.getTrueIndices());
1233
+ const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
1234
+
1235
+ const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
1236
+ const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1237
+ if (uniqueReturned.size !== returnedHashes.length) {
1238
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1239
+ throw new ValidationError(`Received duplicate txs in block txs response`);
1240
+ }
1241
+ if (response.txs.length > maxReturnable) {
1242
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1243
+ throw new ValidationError(
1244
+ `Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
1245
+ );
1246
+ }
1247
+
1248
+ // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1249
+ const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
1250
+ if (proposal) {
1251
+ // Build intersected indices
1252
+ const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1253
+
1254
+ // Enforce subset membership and preserve increasing order by index.
1255
+ const hashToIndexInProposal = new Map<string, number>(
1256
+ proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
1257
+ );
1258
+ const allowedIndexSet = new Set(intersectIdx);
1259
+ const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
1260
+ const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
1261
+ const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
1262
+ if (!allAllowed || !strictlyIncreasing) {
1263
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1264
+ throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1265
+ }
1266
+ } else {
1267
+ // No local proposal, cannot check the membership/order of the returned txs
1268
+ this.logger.warn(
1269
+ `Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
1270
+ );
1271
+ return false;
1272
+ }
1273
+
935
1274
  await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
936
1275
  return true;
937
1276
  } catch (e: any) {
@@ -955,7 +1294,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
955
1294
  * ReqRespSubProtocol.TX subprotocol validation.
956
1295
  *
957
1296
  * @param requestedTxHash - The collection of the txs that was requested.
958
- * @param responseTx - The collectin of txs that was received as a response to the request.
1297
+ * @param responseTx - The collection of txs that was received as a response to the request.
959
1298
  * @param peerId - The peer ID of the peer that sent the tx.
960
1299
  * @returns True if the whole collection of txs is valid, false otherwise.
961
1300
  */
@@ -982,9 +1321,57 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
982
1321
  }
983
1322
  }
984
1323
 
1324
+ /**
1325
+ * Validates a BLOCK response.
1326
+ *
1327
+ * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1328
+ * Penalizes on block number mismatch or hash mismatch.
1329
+ *
1330
+ * @param requestedBlockNumber - The requested block number.
1331
+ * @param responseBlock - The block returned by the peer.
1332
+ * @param peerId - The peer that returned the block.
1333
+ * @returns True if the response is valid, false otherwise.
1334
+ */
1335
+ @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1336
+ [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1337
+ }))
1338
+ private async validateRequestedBlock(
1339
+ requestedBlockNumber: Fr,
1340
+ responseBlock: L2BlockNew,
1341
+ peerId: PeerId,
1342
+ ): Promise<boolean> {
1343
+ try {
1344
+ const reqNum = Number(requestedBlockNumber.toString());
1345
+ if (responseBlock.number !== reqNum) {
1346
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1347
+ return false;
1348
+ }
1349
+
1350
+ const local = await this.archiver.getBlock(BlockNumber(reqNum));
1351
+ if (!local) {
1352
+ // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1353
+ // TODO: Consider extending this validator to accept an expected hash or
1354
+ // performing quorum-based checks when using P2P syncing prior to L1 sync.
1355
+ this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1356
+ return false;
1357
+ }
1358
+ const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1359
+ if (!localHash.equals(respHash)) {
1360
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1361
+ return false;
1362
+ }
1363
+
1364
+ return true;
1365
+ } catch (e) {
1366
+ this.logger.warn(`Error validating requested block`, e);
1367
+ return false;
1368
+ }
1369
+ }
1370
+
985
1371
  private createRequestedTxValidator(): TxValidator {
986
1372
  return new AggregateTxValidator(
987
1373
  new DataTxValidator(),
1374
+ new SizeTxValidator(),
988
1375
  new MetadataTxValidator({
989
1376
  l1ChainId: new Fr(this.config.l1ChainId),
990
1377
  rollupVersion: new Fr(this.config.rollupVersion),
@@ -996,19 +1383,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
996
1383
  }
997
1384
 
998
1385
  private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
1386
+ const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
1387
+
999
1388
  if (!(await tx.validateTxHash())) {
1000
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1389
+ penalize(PeerErrorSeverity.MidToleranceError);
1001
1390
  throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
1002
1391
  }
1003
1392
 
1004
1393
  if (requested && !requested.has(tx.getTxHash().toString())) {
1005
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1394
+ penalize(PeerErrorSeverity.MidToleranceError);
1006
1395
  throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1007
1396
  }
1008
1397
 
1009
1398
  const { result } = await txValidator.validateTx(tx);
1010
1399
  if (result === 'invalid') {
1011
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1400
+ penalize(PeerErrorSeverity.LowToleranceError);
1012
1401
  throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1013
1402
  }
1014
1403
  }
@@ -1034,7 +1423,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1034
1423
 
1035
1424
  // Double spend validator has a special case handler
1036
1425
  if (name === 'doubleSpendValidator') {
1037
- const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
1426
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1038
1427
  severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1039
1428
  }
1040
1429
 
@@ -1044,7 +1433,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1044
1433
  return true;
1045
1434
  }
1046
1435
 
1047
- private async getGasFees(blockNumber: number): Promise<GasFees> {
1436
+ private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
1048
1437
  if (blockNumber === this.feesCache?.blockNumber) {
1049
1438
  return this.feesCache.gasFees;
1050
1439
  }
@@ -1085,13 +1474,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1085
1474
  * @returns The message validators.
1086
1475
  */
1087
1476
  private async createMessageValidators(
1088
- currentBlockNumber: number,
1477
+ currentBlockNumber: BlockNumber,
1089
1478
  nextSlotTimestamp: UInt64,
1090
1479
  ): Promise<Record<string, MessageValidator>[]> {
1091
1480
  const gasFees = await this.getGasFees(currentBlockNumber);
1092
1481
  const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1093
1482
 
1094
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
1483
+ const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1095
1484
 
1096
1485
  return createTxMessageValidators(
1097
1486
  nextSlotTimestamp,
@@ -1153,7 +1542,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1153
1542
  * @param peerId - The peer ID of the peer that sent the tx.
1154
1543
  * @returns Severity
1155
1544
  */
1156
- private async handleDoubleSpendFailure(tx: Tx, blockNumber: number): Promise<PeerErrorSeverity> {
1545
+ private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
1157
1546
  if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
1158
1547
  return PeerErrorSeverity.HighToleranceError;
1159
1548
  }
@@ -1161,7 +1550,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1161
1550
  const snapshotValidator = new DoubleSpendTxValidator({
1162
1551
  nullifiersExist: async (nullifiers: Buffer[]) => {
1163
1552
  const merkleTree = this.worldStateSynchronizer.getSnapshot(
1164
- blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow,
1553
+ BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
1165
1554
  );
1166
1555
  const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
1167
1556
  return indices.map(index => index !== undefined);
@@ -1177,19 +1566,20 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1177
1566
  }
1178
1567
 
1179
1568
  /**
1180
- * Validate an attestation.
1569
+ * Validate a checkpoint attestation.
1181
1570
  *
1182
- * @param attestation - The attestation to validate.
1183
- * @returns True if the attestation is valid, false otherwise.
1571
+ * @param attestation - The checkpoint attestation to validate.
1572
+ * @returns True if the checkpoint attestation is valid, false otherwise.
1184
1573
  */
1185
- @trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
1186
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
1574
+ @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1575
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1187
1576
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1188
- [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
1577
+ [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1189
1578
  }))
1190
- public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
1191
- const severity = await this.attestationValidator.validate(attestation);
1579
+ public async validateCheckpointAttestation(peerId: PeerId, attestation: CheckpointAttestation): Promise<boolean> {
1580
+ const severity = await this.checkpointAttestationValidator.validate(attestation);
1192
1581
  if (severity) {
1582
+ this.logger.debug(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1193
1583
  this.peerManager.penalizePeer(peerId, severity);
1194
1584
  return false;
1195
1585
  }
@@ -1204,7 +1594,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1204
1594
  * @returns True if the block proposal is valid, false otherwise.
1205
1595
  */
1206
1596
  @trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
1207
- [Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
1597
+ [Attributes.SLOT_NUMBER]: block.slotNumber.toString(),
1208
1598
  }))
1209
1599
  public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
1210
1600
  const severity = await this.blockProposalValidator.validate(block);
@@ -1217,6 +1607,26 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1217
1607
  return true;
1218
1608
  }
1219
1609
 
1610
+ /**
1611
+ * Validate a checkpoint proposal.
1612
+ *
1613
+ * @param checkpoint - The checkpoint proposal to validate.
1614
+ * @returns True if the checkpoint proposal is valid, false otherwise.
1615
+ */
1616
+ @trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint) => ({
1617
+ [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1618
+ }))
1619
+ public async validateCheckpointProposal(peerId: PeerId, checkpoint: CheckpointProposal): Promise<boolean> {
1620
+ const severity = await this.checkpointProposalValidator.validate(checkpoint);
1621
+ if (severity) {
1622
+ this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1623
+ this.peerManager.penalizePeer(peerId, severity);
1624
+ return false;
1625
+ }
1626
+
1627
+ return true;
1628
+ }
1629
+
1220
1630
  public getPeerScore(peerId: PeerId): number {
1221
1631
  return this.node.services.pubsub.score.score(peerId.toString());
1222
1632
  }
@@ -1228,7 +1638,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1228
1638
  private async sendToPeers<T extends Gossipable>(message: T) {
1229
1639
  const parent = message.constructor as typeof Gossipable;
1230
1640
 
1231
- const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
1641
+ const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
1232
1642
  this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
1233
1643
 
1234
1644
  const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);