@aztec/p2p 4.0.0-nightly.20250907 → 4.0.0-nightly.20260108

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 (334) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +1 -1
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +14 -4
  4. package/dest/client/factory.d.ts +3 -2
  5. package/dest/client/factory.d.ts.map +1 -1
  6. package/dest/client/factory.js +9 -5
  7. package/dest/client/index.d.ts +1 -1
  8. package/dest/client/interface.d.ts +8 -6
  9. package/dest/client/interface.d.ts.map +1 -1
  10. package/dest/client/p2p_client.d.ts +13 -36
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +460 -63
  13. package/dest/config.d.ts +67 -61
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +28 -15
  16. package/dest/enr/generate-enr.d.ts +2 -2
  17. package/dest/enr/generate-enr.d.ts.map +1 -1
  18. package/dest/enr/generate-enr.js +1 -1
  19. package/dest/enr/index.d.ts +1 -1
  20. package/dest/errors/attestation-pool.error.d.ts +7 -0
  21. package/dest/errors/attestation-pool.error.d.ts.map +1 -0
  22. package/dest/errors/attestation-pool.error.js +12 -0
  23. package/dest/errors/reqresp.error.d.ts +1 -1
  24. package/dest/errors/reqresp.error.d.ts.map +1 -1
  25. package/dest/index.d.ts +1 -1
  26. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +43 -6
  27. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  28. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  29. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +72 -46
  31. package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
  32. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +15 -6
  33. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  34. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +73 -18
  35. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +13 -6
  36. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  37. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +69 -11
  38. package/dest/mem_pools/attestation_pool/mocks.d.ts +226 -5
  39. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  40. package/dest/mem_pools/attestation_pool/mocks.js +9 -7
  41. package/dest/mem_pools/index.d.ts +1 -1
  42. package/dest/mem_pools/instrumentation.d.ts +9 -1
  43. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  44. package/dest/mem_pools/instrumentation.js +38 -2
  45. package/dest/mem_pools/interface.d.ts +3 -4
  46. package/dest/mem_pools/interface.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +39 -58
  48. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +314 -317
  50. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +18 -0
  51. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
  52. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +56 -0
  53. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +83 -0
  54. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
  55. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +5 -0
  56. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts +15 -0
  57. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts.map +1 -0
  58. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.js +88 -0
  59. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
  60. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  61. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
  62. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
  63. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  64. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
  65. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
  66. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  67. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -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 +28 -9
  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 +155 -25
  79. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -2
  80. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  81. package/dest/msg_validators/attestation_validator/attestation_validator.js +32 -5
  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 +67 -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/block_proposal_validator/block_proposal_validator.d.ts +5 -2
  89. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
  90. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +44 -12
  91. package/dest/msg_validators/block_proposal_validator/index.d.ts +1 -1
  92. package/dest/msg_validators/index.d.ts +1 -1
  93. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
  94. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
  95. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  96. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  97. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  98. package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
  99. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  100. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
  101. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  102. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  103. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  104. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  105. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
  106. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  107. package/dest/msg_validators/tx_validator/double_spend_validator.js +1 -1
  108. package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
  109. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  110. package/dest/msg_validators/tx_validator/factory.js +11 -5
  111. package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
  112. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  113. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  114. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  115. package/dest/msg_validators/tx_validator/index.js +1 -0
  116. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -6
  117. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  118. package/dest/msg_validators/tx_validator/metadata_validator.js +6 -24
  119. package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
  120. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  121. package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
  122. package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
  123. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
  124. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +13 -0
  125. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
  126. package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
  127. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
  128. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  129. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
  130. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  131. package/dest/services/data_store.d.ts +1 -1
  132. package/dest/services/data_store.d.ts.map +1 -1
  133. package/dest/services/discv5/discV5_service.d.ts +3 -3
  134. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  135. package/dest/services/discv5/discV5_service.js +2 -2
  136. package/dest/services/dummy_service.d.ts +2 -2
  137. package/dest/services/dummy_service.d.ts.map +1 -1
  138. package/dest/services/encoding.d.ts +25 -4
  139. package/dest/services/encoding.d.ts.map +1 -1
  140. package/dest/services/encoding.js +74 -6
  141. package/dest/services/gossipsub/scoring.d.ts +1 -1
  142. package/dest/services/index.d.ts +1 -1
  143. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  144. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  145. package/dest/services/libp2p/instrumentation.js +9 -2
  146. package/dest/services/libp2p/libp2p_service.d.ts +33 -72
  147. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  148. package/dest/services/libp2p/libp2p_service.js +841 -175
  149. package/dest/services/peer-manager/interface.d.ts +1 -1
  150. package/dest/services/peer-manager/metrics.d.ts +8 -1
  151. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  152. package/dest/services/peer-manager/metrics.js +28 -0
  153. package/dest/services/peer-manager/peer_manager.d.ts +2 -33
  154. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  155. package/dest/services/peer-manager/peer_manager.js +29 -22
  156. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  157. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  158. package/dest/services/peer-manager/peer_scoring.js +40 -2
  159. package/dest/services/reqresp/config.d.ts +1 -1
  160. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
  161. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  162. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
  163. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  164. package/dest/services/reqresp/index.d.ts +1 -1
  165. package/dest/services/reqresp/interface.d.ts +2 -11
  166. package/dest/services/reqresp/interface.d.ts.map +1 -1
  167. package/dest/services/reqresp/interface.js +1 -18
  168. package/dest/services/reqresp/metrics.d.ts +1 -1
  169. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  170. package/dest/services/reqresp/protocols/auth.d.ts +2 -2
  171. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
  172. package/dest/services/reqresp/protocols/auth.js +2 -2
  173. package/dest/services/reqresp/protocols/block.d.ts +1 -1
  174. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  175. package/dest/services/reqresp/protocols/block.js +3 -2
  176. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
  177. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  178. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  179. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
  180. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  181. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +1 -1
  182. package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
  183. package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
  184. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  185. package/dest/services/reqresp/protocols/index.d.ts +1 -1
  186. package/dest/services/reqresp/protocols/ping.d.ts +1 -1
  187. package/dest/services/reqresp/protocols/status.d.ts +6 -5
  188. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  189. package/dest/services/reqresp/protocols/status.js +4 -3
  190. package/dest/services/reqresp/protocols/tx.d.ts +2 -3
  191. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  192. package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
  193. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
  194. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  195. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  196. package/dest/services/reqresp/reqresp.d.ts +1 -41
  197. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  198. package/dest/services/reqresp/reqresp.js +416 -34
  199. package/dest/services/reqresp/status.d.ts +2 -2
  200. package/dest/services/reqresp/status.d.ts.map +1 -1
  201. package/dest/services/service.d.ts +2 -2
  202. package/dest/services/service.d.ts.map +1 -1
  203. package/dest/services/tx_collection/config.d.ts +1 -1
  204. package/dest/services/tx_collection/config.js +1 -1
  205. package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
  206. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  207. package/dest/services/tx_collection/fast_tx_collection.js +6 -1
  208. package/dest/services/tx_collection/index.d.ts +1 -1
  209. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  210. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  211. package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -7
  212. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  213. package/dest/services/tx_collection/slow_tx_collection.js +2 -1
  214. package/dest/services/tx_collection/tx_collection.d.ts +12 -11
  215. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  216. package/dest/services/tx_collection/tx_collection.js +3 -2
  217. package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
  218. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  219. package/dest/services/tx_collection/tx_collection_sink.js +34 -4
  220. package/dest/services/tx_collection/tx_source.d.ts +1 -1
  221. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  222. package/dest/services/tx_collection/tx_source.js +2 -2
  223. package/dest/services/tx_provider.d.ts +6 -4
  224. package/dest/services/tx_provider.d.ts.map +1 -1
  225. package/dest/services/tx_provider.js +19 -6
  226. package/dest/services/tx_provider_instrumentation.d.ts +5 -2
  227. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  228. package/dest/services/tx_provider_instrumentation.js +14 -1
  229. package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
  230. package/dest/test-helpers/get-ports.d.ts +1 -1
  231. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  232. package/dest/test-helpers/index.d.ts +1 -1
  233. package/dest/test-helpers/make-enrs.d.ts +1 -1
  234. package/dest/test-helpers/make-enrs.js +1 -1
  235. package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
  236. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  237. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  238. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  239. package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
  240. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
  241. package/dest/test-helpers/mock-tx-helpers.js +19 -0
  242. package/dest/test-helpers/reqresp-nodes.d.ts +3 -3
  243. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  244. package/dest/test-helpers/reqresp-nodes.js +4 -3
  245. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  246. package/dest/testbench/p2p_client_testbench_worker.js +17 -9
  247. package/dest/testbench/parse_log_file.d.ts +1 -1
  248. package/dest/testbench/testbench.d.ts +1 -1
  249. package/dest/testbench/testbench.js +2 -2
  250. package/dest/testbench/worker_client_manager.d.ts +1 -1
  251. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  252. package/dest/types/index.d.ts +1 -1
  253. package/dest/util.d.ts +2 -1
  254. package/dest/util.d.ts.map +1 -1
  255. package/dest/util.js +11 -2
  256. package/dest/versioning.d.ts +2 -2
  257. package/dest/versioning.d.ts.map +1 -1
  258. package/dest/versioning.js +2 -2
  259. package/package.json +21 -21
  260. package/src/bootstrap/bootstrap.ts +15 -4
  261. package/src/client/factory.ts +21 -12
  262. package/src/client/interface.ts +8 -5
  263. package/src/client/p2p_client.ts +106 -106
  264. package/src/config.ts +42 -21
  265. package/src/enr/generate-enr.ts +1 -1
  266. package/src/errors/attestation-pool.error.ts +13 -0
  267. package/src/mem_pools/attestation_pool/attestation_pool.ts +46 -5
  268. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +89 -48
  269. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +107 -24
  270. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +98 -19
  271. package/src/mem_pools/attestation_pool/mocks.ts +11 -8
  272. package/src/mem_pools/instrumentation.ts +46 -0
  273. package/src/mem_pools/interface.ts +2 -4
  274. package/src/mem_pools/tx_pool/README.md +255 -0
  275. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +368 -360
  276. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +71 -0
  277. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +93 -0
  278. package/src/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.ts +108 -0
  279. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
  280. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
  281. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
  282. package/src/mem_pools/tx_pool/index.ts +0 -1
  283. package/src/mem_pools/tx_pool/priority.ts +8 -1
  284. package/src/mem_pools/tx_pool/tx_pool.ts +28 -8
  285. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +131 -18
  286. package/src/msg_validators/attestation_validator/attestation_validator.ts +41 -6
  287. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
  288. package/src/msg_validators/attestation_validator/index.ts +1 -0
  289. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +53 -12
  290. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  291. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  292. package/src/msg_validators/tx_validator/double_spend_validator.ts +1 -1
  293. package/src/msg_validators/tx_validator/factory.ts +13 -6
  294. package/src/msg_validators/tx_validator/index.ts +1 -0
  295. package/src/msg_validators/tx_validator/metadata_validator.ts +8 -42
  296. package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
  297. package/src/msg_validators/tx_validator/test_utils.ts +1 -1
  298. package/src/msg_validators/tx_validator/timestamp_validator.ts +47 -0
  299. package/src/services/discv5/discV5_service.ts +2 -2
  300. package/src/services/dummy_service.ts +1 -1
  301. package/src/services/encoding.ts +81 -6
  302. package/src/services/libp2p/instrumentation.ts +10 -1
  303. package/src/services/libp2p/libp2p_service.ts +494 -169
  304. package/src/services/peer-manager/metrics.ts +32 -0
  305. package/src/services/peer-manager/peer_manager.ts +25 -16
  306. package/src/services/peer-manager/peer_scoring.ts +46 -3
  307. package/src/services/reqresp/interface.ts +1 -22
  308. package/src/services/reqresp/protocols/auth.ts +2 -2
  309. package/src/services/reqresp/protocols/block.ts +3 -2
  310. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
  311. package/src/services/reqresp/protocols/status.ts +9 -8
  312. package/src/services/reqresp/protocols/tx.ts +1 -2
  313. package/src/services/reqresp/reqresp.ts +15 -11
  314. package/src/services/service.ts +1 -1
  315. package/src/services/tx_collection/config.ts +1 -1
  316. package/src/services/tx_collection/fast_tx_collection.ts +8 -5
  317. package/src/services/tx_collection/slow_tx_collection.ts +7 -6
  318. package/src/services/tx_collection/tx_collection.ts +12 -10
  319. package/src/services/tx_collection/tx_collection_sink.ts +34 -3
  320. package/src/services/tx_collection/tx_source.ts +2 -2
  321. package/src/services/tx_provider.ts +26 -9
  322. package/src/services/tx_provider_instrumentation.ts +19 -2
  323. package/src/test-helpers/make-enrs.ts +1 -1
  324. package/src/test-helpers/mock-pubsub.ts +1 -1
  325. package/src/test-helpers/mock-tx-helpers.ts +24 -0
  326. package/src/test-helpers/reqresp-nodes.ts +4 -3
  327. package/src/testbench/p2p_client_testbench_worker.ts +14 -6
  328. package/src/testbench/testbench.ts +2 -2
  329. package/src/util.ts +12 -2
  330. package/src/versioning.ts +3 -3
  331. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -68
  332. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
  333. package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -160
  334. package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -199
@@ -1,12 +1,14 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import { randomInt } from '@aztec/foundation/crypto';
2
+ import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { randomInt } from '@aztec/foundation/crypto/random';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
5
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
4
- import { SerialQueue } from '@aztec/foundation/queue';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
6
7
  import { Timer } from '@aztec/foundation/timer';
7
8
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
8
- import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
9
- import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
9
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
10
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
11
+ import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
10
12
  import type { ContractDataSource } from '@aztec/stdlib/contract';
11
13
  import { GasFees } from '@aztec/stdlib/gas';
12
14
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
@@ -23,12 +25,18 @@ import {
23
25
  metricsTopicStrToLabels,
24
26
  } from '@aztec/stdlib/p2p';
25
27
  import { MerkleTreeId } from '@aztec/stdlib/trees';
26
- import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
28
+ import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
27
29
  import type { UInt64 } from '@aztec/stdlib/types';
28
30
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
29
- import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
31
+ import {
32
+ Attributes,
33
+ OtelMetricsAdapter,
34
+ SpanStatusCode,
35
+ type TelemetryClient,
36
+ WithTracer,
37
+ trackSpan,
38
+ } from '@aztec/telemetry-client';
30
39
 
31
- import { ENR } from '@chainsafe/enr';
32
40
  import {
33
41
  type GossipSub,
34
42
  type GossipSubComponents,
@@ -43,18 +51,29 @@ import { bootstrap } from '@libp2p/bootstrap';
43
51
  import { identify } from '@libp2p/identify';
44
52
  import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
45
53
  import type { ConnectionManager } from '@libp2p/interface-internal';
46
- import '@libp2p/kad-dht';
47
54
  import { mplex } from '@libp2p/mplex';
48
55
  import { tcp } from '@libp2p/tcp';
56
+ import { ENR } from '@nethermindeth/enr';
49
57
  import { createLibp2p } from 'libp2p';
50
58
 
51
59
  import type { P2PConfig } from '../../config.js';
60
+ import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
52
61
  import type { MemPools } from '../../mem_pools/interface.js';
53
- import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
62
+ import {
63
+ AttestationValidator,
64
+ BlockProposalValidator,
65
+ FishermanAttestationValidator,
66
+ } from '../../msg_validators/index.js';
54
67
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
55
68
  import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
56
69
  import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
57
- import { DoubleSpendTxValidator, TxProofValidator } from '../../msg_validators/tx_validator/index.js';
70
+ import {
71
+ AggregateTxValidator,
72
+ DataTxValidator,
73
+ DoubleSpendTxValidator,
74
+ MetadataTxValidator,
75
+ TxProofValidator,
76
+ } from '../../msg_validators/tx_validator/index.js';
58
77
  import { GossipSubEvent } from '../../types/index.js';
59
78
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
60
79
  import { getVersions } from '../../versioning.js';
@@ -80,6 +99,8 @@ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs
80
99
  import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
81
100
  import {
82
101
  AuthRequest,
102
+ BlockTxsRequest,
103
+ BlockTxsResponse,
83
104
  StatusMessage,
84
105
  pingHandler,
85
106
  reqRespBlockHandler,
@@ -98,11 +119,15 @@ interface ValidationResult {
98
119
 
99
120
  type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
100
121
 
122
+ // REFACTOR: Unify with the type above
123
+ type ReceivedMessageValidationResult<T> =
124
+ | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
125
+ | { obj?: undefined; result: TopicValidatorResult.Reject };
126
+
101
127
  /**
102
128
  * Lib P2P implementation of the P2PService interface.
103
129
  */
104
130
  export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
105
- private jobQueue: SerialQueue = new SerialQueue();
106
131
  private discoveryRunningPromise?: RunningPromise;
107
132
  private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
108
133
 
@@ -113,7 +138,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
113
138
  private protocolVersion = '';
114
139
  private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
115
140
 
116
- private feesCache: { blockNumber: number; gasFees: GasFees } | undefined;
141
+ private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
117
142
 
118
143
  /**
119
144
  * Callback for when a block is received from a peer.
@@ -126,6 +151,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
126
151
 
127
152
  private instrumentation: P2PInstrumentation;
128
153
 
154
+ private telemetry: TelemetryClient;
155
+
156
+ protected logger: Logger;
157
+
129
158
  constructor(
130
159
  private clientType: T,
131
160
  private config: P2PConfig,
@@ -133,15 +162,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
133
162
  private peerDiscoveryService: PeerDiscoveryService,
134
163
  private reqresp: ReqRespInterface,
135
164
  private peerManager: PeerManagerInterface,
136
- protected mempools: MemPools<T>,
165
+ protected mempools: MemPools,
137
166
  private archiver: L2BlockSource & ContractDataSource,
138
167
  private epochCache: EpochCacheInterface,
139
168
  private proofVerifier: ClientProtocolCircuitVerifier,
140
169
  private worldStateSynchronizer: WorldStateSynchronizer,
141
170
  telemetry: TelemetryClient,
142
- protected logger = createLogger('p2p:libp2p_service'),
171
+ logger: Logger = createLogger('p2p:libp2p_service'),
143
172
  ) {
144
173
  super(telemetry, 'LibP2PService');
174
+ this.telemetry = telemetry;
175
+
176
+ // Create child logger with fisherman prefix if in fisherman mode
177
+ this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
145
178
 
146
179
  this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
147
180
 
@@ -160,15 +193,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
160
193
  this.protocolVersion,
161
194
  );
162
195
 
163
- this.attestationValidator = new AttestationValidator(epochCache);
164
- this.blockProposalValidator = new BlockProposalValidator(epochCache);
196
+ // Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
197
+ this.attestationValidator = config.fishermanMode
198
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
199
+ : new AttestationValidator(epochCache);
200
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
165
201
 
166
202
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
167
203
 
168
204
  this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
169
205
  this.logger.debug(
170
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber.toNumber()} from peer.`,
171
- { p2pMessageIdentifier: await block.p2pMessageIdentifier() },
206
+ `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
207
+ { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
172
208
  );
173
209
  return undefined;
174
210
  };
@@ -189,7 +225,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
189
225
  config: P2PConfig,
190
226
  peerId: PeerId,
191
227
  deps: {
192
- mempools: MemPools<T>;
228
+ mempools: MemPools;
193
229
  l2BlockSource: L2BlockSource & ContractDataSource;
194
230
  epochCache: EpochCacheInterface;
195
231
  proofVerifier: ClientProtocolCircuitVerifier;
@@ -273,7 +309,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
273
309
  // The connection attempts to the node on TCP layer are not necessarily valid Aztec peers so we want to have a bit of leeway here
274
310
  // If we hit the limit, the connection will be temporarily accepted and immediately dropped.
275
311
  // Docs: https://nodejs.org/api/net.html#servermaxconnections
276
- maxConnections: Math.ceil(maxPeerCount * 1.5),
312
+ maxConnections: maxPeerCount * 2,
277
313
  // socket option: the maximum length of the queue of pending connections
278
314
  // https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
279
315
  // it's not safe if we increase this number
@@ -284,7 +320,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
284
320
  // In case closeAbove is reached, the server stops listening altogether
285
321
  // It's important that there is enough difference between closeAbove and listenAbove,
286
322
  // otherwise the server.listener will flap between being closed and open potentially degrading perf even more
287
- closeAbove: maxPeerCount * 2,
323
+ closeAbove: maxPeerCount * 3,
288
324
  listenBelow: Math.floor(maxPeerCount * 0.9),
289
325
  },
290
326
  }),
@@ -294,8 +330,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
294
330
  streamMuxers: [yamux(), mplex()],
295
331
  connectionEncryption: [noise()],
296
332
  connectionManager: {
297
- minConnections: 0,
298
- maxConnections: maxPeerCount,
333
+ minConnections: 0, // Disable libp2p peer dialing, we do it manually
334
+ // We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
335
+ // libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
336
+ maxConnections: maxPeerCount * 2,
299
337
  maxParallelDials: 100,
300
338
  dialTimeout: 30_000,
301
339
  maxPeerAddrsToDial: 5,
@@ -379,7 +417,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
379
417
  logger: createLibp2pComponentLogger(logger.module),
380
418
  });
381
419
 
382
- const peerScoring = new PeerScoring(config);
420
+ const peerScoring = new PeerScoring(config, telemetry);
383
421
  const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
384
422
 
385
423
  const peerManager = new PeerManager(
@@ -434,9 +472,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
434
472
  }
435
473
  const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
436
474
 
437
- // Start job queue, peer discovery service and libp2p node
438
- this.jobQueue.start();
439
-
440
475
  await this.peerManager.initializePeers();
441
476
  if (!this.config.p2pDiscoveryDisabled) {
442
477
  await this.peerDiscoveryService.start();
@@ -453,10 +488,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
453
488
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
454
489
  const blockHandler = reqRespBlockHandler(this.archiver);
455
490
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
456
- // In case P2P client doesnt'have attestation pool,
457
- // const blockTxsHandler = this.mempools.attestationPool
458
- // ? reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool)
459
- // : def;
460
491
 
461
492
  const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
462
493
  [ReqRespSubProtocol.PING]: pingHandler,
@@ -465,8 +496,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
465
496
  [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
466
497
  };
467
498
 
468
- // Only handle block transactions request if attestation pool is available to the client
469
- if (this.mempools.attestationPool) {
499
+ if (!this.config.disableTransactions) {
470
500
  const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
471
501
  requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
472
502
  }
@@ -478,9 +508,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
478
508
  // add GossipSub listener
479
509
  this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
480
510
 
481
- // Start running promise for peer discovery
511
+ // Start running promise for peer discovery and metrics collection
482
512
  this.discoveryRunningPromise = new RunningPromise(
483
- () => this.peerManager.heartbeat(),
513
+ async () => {
514
+ await this.peerManager.heartbeat();
515
+ },
484
516
  this.logger,
485
517
  this.config.peerCheckIntervalMS,
486
518
  );
@@ -489,8 +521,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
489
521
  // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
490
522
  const reqrespSubProtocolValidators = {
491
523
  ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
492
- // TODO(#11336): A request validator for blocks
493
- [ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
524
+ [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
525
+ [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
526
+ [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
494
527
  };
495
528
  await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
496
529
  this.logger.info(`Started P2P service`, {
@@ -512,9 +545,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
512
545
  // Stop peer manager
513
546
  this.logger.debug('Stopping peer manager...');
514
547
  await this.peerManager.stop();
515
-
516
- this.logger.debug('Stopping job queue...');
517
- await this.jobQueue.end();
518
548
  this.logger.debug('Stopping running promise...');
519
549
  await this.discoveryRunningPromise?.stop();
520
550
  this.logger.debug('Stopping peer discovery service...');
@@ -602,16 +632,19 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
602
632
  if (!this.node.services.pubsub) {
603
633
  throw new Error('Pubsub service not available.');
604
634
  }
605
- const p2pMessage = await P2PMessage.fromGossipable(message);
606
- this.logger.debug(`Publishing message`, {
607
- topic,
608
- messageId: p2pMessage.id,
609
- });
635
+ const isBlockProposal = topic === this.topicStrings[TopicType.block_proposal];
636
+ const traceContext =
637
+ this.config.debugP2PInstrumentMessages && isBlockProposal ? this.telemetry.getTraceContext() : undefined;
638
+ const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages, traceContext);
610
639
  const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
611
-
612
640
  return result.recipients.length;
613
641
  }
614
642
 
643
+ /**
644
+ * Checks if this message has already been seen, based on its msgId computed from hashing the message data.
645
+ * Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
646
+ * messages to avoid tx echoes across the network.
647
+ */
615
648
  protected preValidateReceivedMessage(
616
649
  msg: Message,
617
650
  msgId: string,
@@ -647,82 +680,169 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
647
680
  return { result: true, topicType };
648
681
  }
649
682
 
683
+ /**
684
+ * Safely deserializes a P2PMessage from raw message data.
685
+ * @param msgId - The message ID.
686
+ * @param source - The peer ID of the message source.
687
+ * @param data - The raw message data.
688
+ * @returns The deserialized P2PMessage or undefined if deserialization fails.
689
+ */
690
+ private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
691
+ try {
692
+ return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
693
+ } catch (err) {
694
+ this.logger.error(`Error deserializing P2PMessage`, err, {
695
+ msgId,
696
+ source: source.toString(),
697
+ });
698
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
699
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
700
+ return undefined;
701
+ }
702
+ }
703
+
650
704
  /**
651
705
  * Handles a new gossip message that was received by the client.
652
706
  * @param topic - The message's topic.
653
707
  * @param data - The message data
654
708
  */
655
709
  protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
656
- const p2pMessage = P2PMessage.fromMessageData(Buffer.from(msg.data));
657
- const currentTime = new Date();
658
- const messageLatency = currentTime.getTime() - p2pMessage.publishTime.getTime();
659
- this.logger.debug(`Received message`, {
660
- topic: msg.topic,
661
- messageId: p2pMessage.id,
662
- messageLatency,
663
- });
710
+ const msgReceivedTime = Date.now();
711
+ let topicType: TopicType | undefined;
712
+ const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
713
+ if (!p2pMessage) {
714
+ return;
715
+ }
664
716
 
665
717
  const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
666
718
 
667
719
  if (!preValidationResult.result) {
668
720
  return;
669
- } else if (preValidationResult.topicType !== undefined) {
670
- // guard against clock skew & DST
671
- if (messageLatency > 0) {
672
- this.instrumentation.recordMessageLatency(preValidationResult.topicType, messageLatency);
673
- }
674
721
  }
675
722
 
723
+ // Determine topic type for attributes
676
724
  if (msg.topic === this.topicStrings[TopicType.tx]) {
677
- await this.handleGossipedTx(p2pMessage.payload, msgId, source);
725
+ topicType = TopicType.tx;
726
+ } else if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
727
+ topicType = TopicType.block_attestation;
728
+ } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
729
+ topicType = TopicType.block_proposal;
678
730
  }
679
- if (msg.topic === this.topicStrings[TopicType.block_attestation] && this.clientType === P2PClientType.Full) {
680
- await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
731
+
732
+ // Process the message, optionally within a linked span for trace propagation
733
+ const processMessage = async () => {
734
+ if (msg.topic === this.topicStrings[TopicType.tx]) {
735
+ await this.handleGossipedTx(p2pMessage.payload, msgId, source);
736
+ }
737
+ if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
738
+ if (this.clientType === P2PClientType.Full) {
739
+ await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
740
+ }
741
+ }
742
+ if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
743
+ await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
744
+ }
745
+ };
746
+
747
+ const latency = p2pMessage.timestamp !== undefined ? msgReceivedTime - p2pMessage.timestamp.getTime() : undefined;
748
+ const propagatedContext = p2pMessage.traceContext
749
+ ? this.telemetry.extractPropagatedContext(p2pMessage.traceContext)
750
+ : undefined;
751
+
752
+ if (propagatedContext) {
753
+ await this.tracer.startActiveSpan(
754
+ 'LibP2PService.processMessage',
755
+ {
756
+ attributes: {
757
+ [Attributes.TOPIC_NAME]: topicType!,
758
+ [Attributes.PEER_ID]: source.toString(),
759
+ },
760
+ },
761
+ propagatedContext,
762
+ async span => {
763
+ try {
764
+ await processMessage();
765
+ span.setStatus({
766
+ code: SpanStatusCode.OK,
767
+ });
768
+ } catch (err) {
769
+ span.setStatus({
770
+ code: SpanStatusCode.ERROR,
771
+ message: String(err),
772
+ });
773
+ if (typeof err === 'string' || (err && err instanceof Error)) {
774
+ span.recordException(err);
775
+ }
776
+ throw err;
777
+ } finally {
778
+ span.end();
779
+ }
780
+ },
781
+ );
782
+ } else {
783
+ await processMessage();
681
784
  }
682
- if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
683
- await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
785
+
786
+ if (latency !== undefined && topicType !== undefined) {
787
+ this.instrumentation.recordMessageLatency(topicType, latency);
684
788
  }
685
789
 
686
790
  return;
687
791
  }
688
792
 
689
793
  protected async validateReceivedMessage<T>(
690
- validationFunc: () => Promise<{ result: boolean; obj: T }>,
794
+ validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
691
795
  msgId: string,
692
796
  source: PeerId,
693
797
  topicType: TopicType,
694
- ): Promise<{ result: boolean; obj: T | undefined }> {
695
- let resultAndObj: { result: boolean; obj: T | undefined } = { result: false, obj: undefined };
798
+ ): Promise<ReceivedMessageValidationResult<T>> {
799
+ let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
696
800
  const timer = new Timer();
697
801
  try {
698
802
  resultAndObj = await validationFunc();
699
803
  } catch (err) {
700
- this.logger.error(`Error deserializing and validating message `, err);
804
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
805
+ this.logger.error(`Error deserializing and validating gossipsub message`, err, {
806
+ msgId,
807
+ source: source.toString(),
808
+ topicType,
809
+ });
701
810
  }
702
811
 
703
- if (resultAndObj.result) {
812
+ if (resultAndObj.result === TopicValidatorResult.Accept) {
704
813
  this.instrumentation.recordMessageValidation(topicType, timer);
705
814
  }
706
815
 
707
- this.node.services.pubsub.reportMessageValidationResult(
708
- msgId,
709
- source.toString(),
710
- resultAndObj.result && resultAndObj.obj ? TopicValidatorResult.Accept : TopicValidatorResult.Reject,
711
- );
816
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
712
817
  return resultAndObj;
713
818
  }
714
819
 
715
820
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
716
- const validationFunc = async () => {
821
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
717
822
  const tx = Tx.fromBuffer(payloadData);
718
- const result = await this.validatePropagatedTx(tx, source);
719
- return { result, obj: tx };
823
+ const isValid = await this.validatePropagatedTx(tx, source);
824
+ const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
825
+
826
+ this.logger.trace(`Validate propagated tx`, {
827
+ isValid,
828
+ exists,
829
+ [Attributes.P2P_ID]: source.toString(),
830
+ });
831
+
832
+ if (!isValid) {
833
+ return { result: TopicValidatorResult.Reject };
834
+ } else if (exists) {
835
+ return { result: TopicValidatorResult.Ignore, obj: tx };
836
+ } else {
837
+ return { result: TopicValidatorResult.Accept, obj: tx };
838
+ }
720
839
  };
721
840
 
722
841
  const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
723
- if (!result || !tx) {
842
+ if (result !== TopicValidatorResult.Accept || !tx) {
724
843
  return;
725
844
  }
845
+
726
846
  const txHash = tx.getTxHash();
727
847
  const txHashString = txHash.toString();
728
848
  this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
@@ -731,10 +851,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
731
851
  });
732
852
 
733
853
  if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
734
- this.logger.debug(`Intentionally dropping tx ${txHashString} (probability rule)`);
854
+ this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
735
855
  return;
736
856
  }
737
857
 
858
+ this.instrumentation.incrementTxReceived(1);
738
859
  await this.mempools.txPool.addTxs([tx]);
739
860
  }
740
861
 
@@ -745,14 +866,42 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
745
866
  * @param attestation - The attestation to process.
746
867
  */
747
868
  private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
748
- const validationFunc = async () => {
869
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
749
870
  const attestation = BlockAttestation.fromBuffer(payloadData);
750
- const result = await this.validateAttestation(source, attestation);
751
- this.logger.trace(`validatePropagatedAttestation: ${result}`, {
871
+ const pool = this.mempools.attestationPool;
872
+ const isValid = await this.validateAttestation(source, attestation);
873
+ const exists = isValid && (await pool.hasAttestation(attestation));
874
+
875
+ let canAdd = true;
876
+ if (isValid && !exists) {
877
+ const slot = attestation.payload.header.slotNumber;
878
+ const { committee } = await this.epochCache.getCommittee(slot);
879
+ const committeeSize = committee?.length ?? 0;
880
+ canAdd = await pool.canAddAttestation(attestation, committeeSize);
881
+ }
882
+
883
+ this.logger.trace(`Validate propagated block attestation`, {
884
+ isValid,
885
+ exists,
886
+ canAdd,
752
887
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
753
888
  [Attributes.P2P_ID]: source.toString(),
754
889
  });
755
- return { result, obj: attestation };
890
+
891
+ if (!isValid) {
892
+ return { result: TopicValidatorResult.Reject };
893
+ } else if (exists) {
894
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
895
+ } else if (!canAdd) {
896
+ this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
897
+ slot: attestation.payload.header.slotNumber.toString(),
898
+ archive: attestation.archive.toString(),
899
+ source: source.toString(),
900
+ });
901
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
902
+ } else {
903
+ return { result: TopicValidatorResult.Accept, obj: attestation };
904
+ }
756
905
  };
757
906
 
758
907
  const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
@@ -761,31 +910,56 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
761
910
  source,
762
911
  TopicType.block_attestation,
763
912
  );
764
- if (!result || !attestation) {
913
+
914
+ if (result !== TopicValidatorResult.Accept || !attestation) {
765
915
  return;
766
916
  }
917
+
767
918
  this.logger.debug(
768
- `Received attestation for block ${attestation.blockNumber} slot ${attestation.slotNumber.toNumber()} from external peer ${source.toString()}`,
919
+ `Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
769
920
  {
770
- p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
771
- slot: attestation.slotNumber.toNumber(),
921
+ p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
922
+ slot: attestation.slotNumber,
772
923
  archive: attestation.archive.toString(),
773
- block: attestation.blockNumber,
774
924
  source: source.toString(),
775
925
  },
776
926
  );
777
- await this.mempools.attestationPool!.addAttestations([attestation]);
927
+
928
+ await this.mempools.attestationPool.addAttestations([attestation]);
778
929
  }
779
930
 
780
931
  private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
781
- const validationFunc = async () => {
932
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
782
933
  const block = BlockProposal.fromBuffer(payloadData);
783
- const result = await this.validateBlockProposal(source, block);
784
- this.logger.trace(`validatePropagatedBlock: ${result}`, {
934
+ const isValid = await this.validateBlockProposal(source, block);
935
+ const pool = this.mempools.attestationPool;
936
+
937
+ const exists = isValid && (await pool.hasBlockProposal(block));
938
+ const canAdd = isValid && (await pool.canAddProposal(block));
939
+
940
+ this.logger.trace(`Validate propagated block proposal`, {
941
+ isValid,
942
+ exists,
943
+ canAdd,
785
944
  [Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
786
945
  [Attributes.P2P_ID]: source.toString(),
787
946
  });
788
- return { result, obj: block };
947
+
948
+ if (!isValid) {
949
+ return { result: TopicValidatorResult.Reject };
950
+ } else if (exists) {
951
+ return { result: TopicValidatorResult.Ignore, obj: block };
952
+ } else if (!canAdd) {
953
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
954
+ this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
955
+ slot: block.slotNumber.toString(),
956
+ archive: block.archive.toString(),
957
+ source: source.toString(),
958
+ });
959
+ return { result: TopicValidatorResult.Reject };
960
+ } else {
961
+ return { result: TopicValidatorResult.Accept, obj: block };
962
+ }
789
963
  };
790
964
 
791
965
  const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
@@ -794,6 +968,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
794
968
  source,
795
969
  TopicType.block_proposal,
796
970
  );
971
+
797
972
  if (!result || !block) {
798
973
  return;
799
974
  }
@@ -803,48 +978,49 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
803
978
 
804
979
  // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
805
980
  @trackSpan('Libp2pService.processValidBlockProposal', async block => ({
806
- [Attributes.BLOCK_NUMBER]: block.blockNumber,
807
- [Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
981
+ [Attributes.SLOT_NUMBER]: block.slotNumber,
808
982
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
809
- [Attributes.P2P_ID]: await block.p2pMessageIdentifier().then(i => i.toString()),
983
+ [Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
810
984
  }))
811
985
  private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
812
- const slot = block.slotNumber.toBigInt();
813
- const previousSlot = slot - 1n;
814
- const epoch = slot / 32n;
815
- this.logger.verbose(
816
- `Received block ${block.blockNumber} for slot ${slot} epoch ${epoch} from external peer ${sender.toString()}.`,
817
- {
818
- p2pMessageIdentifier: await block.p2pMessageIdentifier(),
819
- slot: block.slotNumber.toNumber(),
820
- archive: block.archive.toString(),
821
- block: block.blockNumber,
822
- source: sender.toString(),
823
- },
824
- );
825
- const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
826
- if (attestationsForPreviousSlot !== undefined) {
827
- this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
828
- }
986
+ const slot = block.slotNumber;
987
+ const previousSlot = SlotNumber(slot - 1);
988
+ this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
989
+ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
990
+ slot: block.slotNumber,
991
+ archive: block.archive.toString(),
992
+ source: sender.toString(),
993
+ });
994
+ const attestationsForPreviousSlot = await this.mempools.attestationPool.getAttestationsForSlot(previousSlot);
995
+ this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
829
996
 
830
- // Mark the txs in this proposal as non-evictable
997
+ // Attempt to add proposal, then mark the txs in this proposal as non-evictable
998
+ try {
999
+ await this.mempools.attestationPool.addBlockProposal(block);
1000
+ } catch (err: unknown) {
1001
+ // Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
1002
+ if (err instanceof ProposalSlotCapExceededError) {
1003
+ this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
1004
+ slot: String(slot),
1005
+ archive: block.archive.toString(),
1006
+ error: (err as Error).message,
1007
+ });
1008
+ return;
1009
+ }
1010
+ throw err;
1011
+ }
831
1012
  await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
832
- await this.mempools.attestationPool?.addBlockProposal(block);
833
1013
  const attestations = await this.blockReceivedCallback(block, sender);
834
1014
 
835
1015
  // TODO: fix up this pattern - the abstraction is not nice
836
- // The attestation can be undefined if no handler is registered / the validator deems the block invalid
1016
+ // The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
837
1017
  if (attestations?.length) {
838
1018
  for (const attestation of attestations) {
839
- this.logger.verbose(
840
- `Broadcasting attestation for block ${attestation.blockNumber} slot ${attestation.slotNumber.toNumber()}`,
841
- {
842
- p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
843
- slot: attestation.slotNumber.toNumber(),
844
- archive: attestation.archive.toString(),
845
- block: attestation.blockNumber,
846
- },
847
- );
1019
+ this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
1020
+ p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
1021
+ slot: attestation.slotNumber,
1022
+ archive: attestation.archive.toString(),
1023
+ });
848
1024
  await this.broadcastAttestation(attestation);
849
1025
  }
850
1026
  }
@@ -855,10 +1031,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
855
1031
  * @param attestation - The attestation to broadcast.
856
1032
  */
857
1033
  @trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
858
- [Attributes.BLOCK_NUMBER]: attestation.blockNumber,
859
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
1034
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
860
1035
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
861
- [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
1036
+ [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
862
1037
  }))
863
1038
  private async broadcastAttestation(attestation: BlockAttestation) {
864
1039
  await this.propagate(attestation);
@@ -869,15 +1044,100 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
869
1044
  * @param message - The message to propagate.
870
1045
  */
871
1046
  public async propagate<T extends Gossipable>(message: T) {
872
- const p2pMessageIdentifier = await message.p2pMessageIdentifier();
1047
+ const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
873
1048
  this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
874
- void this.jobQueue
875
- .put(async () => {
876
- await this.sendToPeers(message);
877
- })
878
- .catch(error => {
879
- this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
880
- });
1049
+ void this.sendToPeers(message).catch(error => {
1050
+ this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
1051
+ });
1052
+ }
1053
+
1054
+ /**
1055
+ * Validate the requested block transactions. Allow partial returns.
1056
+ * @param request - The block transactions request.
1057
+ * @param response - The block transactions response.
1058
+ * @param peerId - The ID of the peer that made the request.
1059
+ * @returns True if the requested block transactions are valid, false otherwise.
1060
+ */
1061
+ @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
1062
+ [Attributes.BLOCK_HASH]: request.blockHash.toString(),
1063
+ }))
1064
+ private async validateRequestedBlockTxs(
1065
+ request: BlockTxsRequest,
1066
+ response: BlockTxsResponse,
1067
+ peerId: PeerId,
1068
+ ): Promise<boolean> {
1069
+ const requestedTxValidator = this.createRequestedTxValidator();
1070
+
1071
+ try {
1072
+ if (!response.blockHash.equals(request.blockHash)) {
1073
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1074
+ throw new ValidationError(
1075
+ `Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
1076
+ );
1077
+ }
1078
+
1079
+ if (response.txIndices.getLength() !== request.txIndices.getLength()) {
1080
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1081
+ throw new ValidationError(
1082
+ `Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
1083
+ );
1084
+ }
1085
+
1086
+ // Check no duplicates and not exceeding returnable count
1087
+ const requestedIndices = new Set(request.txIndices.getTrueIndices());
1088
+ const availableIndices = new Set(response.txIndices.getTrueIndices());
1089
+ const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
1090
+
1091
+ const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
1092
+ const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
1093
+ if (uniqueReturned.size !== returnedHashes.length) {
1094
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1095
+ throw new ValidationError(`Received duplicate txs in block txs response`);
1096
+ }
1097
+ if (response.txs.length > maxReturnable) {
1098
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1099
+ throw new ValidationError(
1100
+ `Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
1101
+ );
1102
+ }
1103
+
1104
+ // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1105
+ const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
1106
+ if (proposal) {
1107
+ // Build intersected indices
1108
+ const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
1109
+
1110
+ // Enforce subset membership and preserve increasing order by index.
1111
+ const hashToIndexInProposal = new Map<string, number>(
1112
+ proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
1113
+ );
1114
+ const allowedIndexSet = new Set(intersectIdx);
1115
+ const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
1116
+ const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
1117
+ const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
1118
+ if (!allAllowed || !strictlyIncreasing) {
1119
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1120
+ throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
1121
+ }
1122
+ } else {
1123
+ // No local proposal, cannot check the membership/order of the returned txs
1124
+ this.logger.warn(
1125
+ `Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
1126
+ );
1127
+ return false;
1128
+ }
1129
+
1130
+ await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
1131
+ return true;
1132
+ } catch (e: any) {
1133
+ if (e instanceof ValidationError) {
1134
+ this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
1135
+ } else {
1136
+ this.logger.error(`Error during validation of requested block txs`, e);
1137
+ }
1138
+
1139
+ return false;
1140
+ }
881
1141
  }
882
1142
 
883
1143
  /**
@@ -890,47 +1150,113 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
890
1150
  * ReqRespSubProtocol.TX subprotocol validation.
891
1151
  *
892
1152
  * @param requestedTxHash - The collection of the txs that was requested.
893
- * @param responseTx - The collectin of txs that was received as a response to the request.
1153
+ * @param responseTx - The collection of txs that was received as a response to the request.
894
1154
  * @param peerId - The peer ID of the peer that sent the tx.
895
1155
  * @returns True if the whole collection of txs is valid, false otherwise.
896
1156
  */
897
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
898
- // I think we should still extract the valid txs and return them, so that we can still use the response.
899
1157
  @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
900
1158
  [Attributes.TX_HASH]: requestedTxHash.toString(),
901
1159
  }))
902
- private async validateRequestedTx(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
1160
+ private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
903
1161
  const requested = new Set(requestedTxHash.map(h => h.toString()));
1162
+ const requestedTxValidator = this.createRequestedTxValidator();
904
1163
 
905
- const proofValidator = new TxProofValidator(this.proofVerifier);
906
-
1164
+ //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
1165
+ // I think we should still extract the valid txs and return them, so that we can still use the response.
907
1166
  try {
908
- await Promise.all(
909
- responseTx.map(async tx => {
910
- if (!requested.has(tx.getTxHash().toString())) {
911
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
912
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
913
- }
914
-
915
- const { result } = await proofValidator.validateTx(tx);
916
- if (result === 'invalid') {
917
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
918
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
919
- }
920
- }),
921
- );
1167
+ await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
922
1168
  return true;
923
1169
  } catch (e: any) {
924
1170
  if (e instanceof ValidationError) {
925
- this.logger.debug(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
1171
+ this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
926
1172
  } else {
927
- this.logger.warn(`Error during validation of requested txs`, e);
1173
+ this.logger.error(`Error during validation of requested txs`, e);
928
1174
  }
929
1175
 
930
1176
  return false;
931
1177
  }
932
1178
  }
933
1179
 
1180
+ /**
1181
+ * Validates a BLOCK response.
1182
+ *
1183
+ * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1184
+ * Penalizes on block number mismatch or hash mismatch.
1185
+ *
1186
+ * @param requestedBlockNumber - The requested block number.
1187
+ * @param responseBlock - The block returned by the peer.
1188
+ * @param peerId - The peer that returned the block.
1189
+ * @returns True if the response is valid, false otherwise.
1190
+ */
1191
+ @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1192
+ [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1193
+ }))
1194
+ private async validateRequestedBlock(
1195
+ requestedBlockNumber: Fr,
1196
+ responseBlock: L2Block,
1197
+ peerId: PeerId,
1198
+ ): Promise<boolean> {
1199
+ try {
1200
+ const reqNum = Number(requestedBlockNumber.toString());
1201
+ if (responseBlock.number !== reqNum) {
1202
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1203
+ return false;
1204
+ }
1205
+
1206
+ const local = await this.archiver.getBlock(BlockNumber(reqNum));
1207
+ if (!local) {
1208
+ // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1209
+ // TODO: Consider extending this validator to accept an expected hash or
1210
+ // performing quorum-based checks when using P2P syncing prior to L1 sync.
1211
+ this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1212
+ return false;
1213
+ }
1214
+ const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1215
+ if (!localHash.equals(respHash)) {
1216
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1217
+ return false;
1218
+ }
1219
+
1220
+ return true;
1221
+ } catch (e) {
1222
+ this.logger.warn(`Error validating requested block`, e);
1223
+ return false;
1224
+ }
1225
+ }
1226
+
1227
+ private createRequestedTxValidator(): TxValidator {
1228
+ return new AggregateTxValidator(
1229
+ new DataTxValidator(),
1230
+ new MetadataTxValidator({
1231
+ l1ChainId: new Fr(this.config.l1ChainId),
1232
+ rollupVersion: new Fr(this.config.rollupVersion),
1233
+ protocolContractsHash,
1234
+ vkTreeRoot: getVKTreeRoot(),
1235
+ }),
1236
+ new TxProofValidator(this.proofVerifier),
1237
+ );
1238
+ }
1239
+
1240
+ private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
1241
+ const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
1242
+
1243
+ if (!(await tx.validateTxHash())) {
1244
+ penalize(PeerErrorSeverity.MidToleranceError);
1245
+ throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
1246
+ }
1247
+
1248
+ if (requested && !requested.has(tx.getTxHash().toString())) {
1249
+ penalize(PeerErrorSeverity.MidToleranceError);
1250
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1251
+ }
1252
+
1253
+ const { result } = await txValidator.validateTx(tx);
1254
+ if (result === 'invalid') {
1255
+ penalize(PeerErrorSeverity.LowToleranceError);
1256
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1257
+ }
1258
+ }
1259
+
934
1260
  @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
935
1261
  [Attributes.TX_HASH]: tx.getTxHash().toString(),
936
1262
  }))
@@ -952,7 +1278,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
952
1278
 
953
1279
  // Double spend validator has a special case handler
954
1280
  if (name === 'doubleSpendValidator') {
955
- const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
1281
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
956
1282
  severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
957
1283
  }
958
1284
 
@@ -962,7 +1288,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
962
1288
  return true;
963
1289
  }
964
1290
 
965
- private async getGasFees(blockNumber: number): Promise<GasFees> {
1291
+ private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
966
1292
  if (blockNumber === this.feesCache?.blockNumber) {
967
1293
  return this.feesCache.gasFees;
968
1294
  }
@@ -1003,13 +1329,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1003
1329
  * @returns The message validators.
1004
1330
  */
1005
1331
  private async createMessageValidators(
1006
- currentBlockNumber: number,
1332
+ currentBlockNumber: BlockNumber,
1007
1333
  nextSlotTimestamp: UInt64,
1008
1334
  ): Promise<Record<string, MessageValidator>[]> {
1009
1335
  const gasFees = await this.getGasFees(currentBlockNumber);
1010
1336
  const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1011
1337
 
1012
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
1338
+ const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1013
1339
 
1014
1340
  return createTxMessageValidators(
1015
1341
  nextSlotTimestamp,
@@ -1018,7 +1344,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1018
1344
  gasFees,
1019
1345
  this.config.l1ChainId,
1020
1346
  this.config.rollupVersion,
1021
- protocolContractTreeRoot,
1347
+ protocolContractsHash,
1022
1348
  this.archiver,
1023
1349
  this.proofVerifier,
1024
1350
  !this.config.disableTransactions,
@@ -1071,7 +1397,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1071
1397
  * @param peerId - The peer ID of the peer that sent the tx.
1072
1398
  * @returns Severity
1073
1399
  */
1074
- private async handleDoubleSpendFailure(tx: Tx, blockNumber: number): Promise<PeerErrorSeverity> {
1400
+ private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
1075
1401
  if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
1076
1402
  return PeerErrorSeverity.HighToleranceError;
1077
1403
  }
@@ -1079,7 +1405,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1079
1405
  const snapshotValidator = new DoubleSpendTxValidator({
1080
1406
  nullifiersExist: async (nullifiers: Buffer[]) => {
1081
1407
  const merkleTree = this.worldStateSynchronizer.getSnapshot(
1082
- blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow,
1408
+ BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
1083
1409
  );
1084
1410
  const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
1085
1411
  return indices.map(index => index !== undefined);
@@ -1101,10 +1427,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1101
1427
  * @returns True if the attestation is valid, false otherwise.
1102
1428
  */
1103
1429
  @trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
1104
- [Attributes.BLOCK_NUMBER]: attestation.blockNumber,
1105
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
1430
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1106
1431
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1107
- [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
1432
+ [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1108
1433
  }))
1109
1434
  public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
1110
1435
  const severity = await this.attestationValidator.validate(attestation);
@@ -1147,7 +1472,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1147
1472
  private async sendToPeers<T extends Gossipable>(message: T) {
1148
1473
  const parent = message.constructor as typeof Gossipable;
1149
1474
 
1150
- const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
1475
+ const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
1151
1476
  this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
1152
1477
 
1153
1478
  const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);