@aztec/p2p 0.0.0-test.1 → 0.0.1-commit.24de95ac

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 (339) hide show
  1. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  2. package/dest/bootstrap/bootstrap.js +22 -9
  3. package/dest/client/factory.d.ts +13 -3
  4. package/dest/client/factory.d.ts.map +1 -1
  5. package/dest/client/factory.js +60 -24
  6. package/dest/client/index.d.ts +1 -0
  7. package/dest/client/index.d.ts.map +1 -1
  8. package/dest/client/index.js +1 -0
  9. package/dest/client/interface.d.ts +155 -0
  10. package/dest/client/interface.d.ts.map +1 -0
  11. package/dest/client/interface.js +9 -0
  12. package/dest/client/p2p_client.d.ts +72 -169
  13. package/dest/client/p2p_client.d.ts.map +1 -1
  14. package/dest/client/p2p_client.js +365 -174
  15. package/dest/config.d.ts +123 -103
  16. package/dest/config.d.ts.map +1 -1
  17. package/dest/config.js +173 -34
  18. package/dest/enr/generate-enr.d.ts +10 -2
  19. package/dest/enr/generate-enr.d.ts.map +1 -1
  20. package/dest/enr/generate-enr.js +27 -5
  21. package/dest/index.d.ts +3 -0
  22. package/dest/index.d.ts.map +1 -1
  23. package/dest/index.js +2 -0
  24. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +42 -4
  25. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +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 +204 -54
  28. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +10 -2
  29. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +93 -15
  31. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +10 -2
  32. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +86 -18
  34. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -2
  35. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/mocks.js +9 -15
  37. package/dest/mem_pools/instrumentation.d.ts +7 -11
  38. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  39. package/dest/mem_pools/instrumentation.js +25 -37
  40. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +93 -9
  41. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  42. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +469 -97
  43. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +33 -9
  44. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  45. package/dest/mem_pools/tx_pool/memory_tx_pool.js +133 -36
  46. package/dest/mem_pools/tx_pool/priority.js +1 -1
  47. package/dest/mem_pools/tx_pool/tx_pool.d.ts +64 -8
  48. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +264 -39
  51. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -0
  52. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  53. package/dest/msg_validators/attestation_validator/attestation_validator.js +45 -9
  54. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +5 -1
  55. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
  56. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +61 -12
  57. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +10 -0
  58. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -0
  59. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.js +36 -0
  60. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +3 -0
  61. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -0
  62. package/dest/msg_validators/tx_validator/allowed_public_setup.js +27 -0
  63. package/dest/msg_validators/tx_validator/archive_cache.d.ts +14 -0
  64. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -0
  65. package/dest/msg_validators/tx_validator/archive_cache.js +22 -0
  66. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  67. package/dest/msg_validators/tx_validator/block_header_validator.js +4 -4
  68. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  69. package/dest/msg_validators/tx_validator/data_validator.js +56 -86
  70. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +0 -2
  71. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  72. package/dest/msg_validators/tx_validator/double_spend_validator.js +21 -27
  73. package/dest/msg_validators/tx_validator/factory.d.ts +15 -0
  74. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
  75. package/dest/msg_validators/tx_validator/factory.js +74 -0
  76. package/dest/msg_validators/tx_validator/gas_validator.d.ts +11 -0
  77. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -0
  78. package/dest/msg_validators/tx_validator/gas_validator.js +115 -0
  79. package/dest/msg_validators/tx_validator/index.d.ts +7 -0
  80. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  81. package/dest/msg_validators/tx_validator/index.js +7 -0
  82. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +7 -3
  83. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  84. package/dest/msg_validators/tx_validator/metadata_validator.js +39 -20
  85. package/dest/msg_validators/tx_validator/phases_validator.d.ts +14 -0
  86. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -0
  87. package/dest/msg_validators/tx_validator/phases_validator.js +91 -0
  88. package/dest/msg_validators/tx_validator/test_utils.d.ts +17 -0
  89. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -0
  90. package/dest/msg_validators/tx_validator/test_utils.js +22 -0
  91. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +12 -0
  92. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
  93. package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
  94. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +8 -0
  95. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -0
  96. package/dest/msg_validators/tx_validator/tx_permitted_validator.js +24 -0
  97. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/tx_proof_validator.js +6 -5
  99. package/dest/services/discv5/discV5_service.d.ts +9 -8
  100. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  101. package/dest/services/discv5/discV5_service.js +63 -36
  102. package/dest/services/dummy_service.d.ts +49 -10
  103. package/dest/services/dummy_service.d.ts.map +1 -1
  104. package/dest/services/dummy_service.js +88 -5
  105. package/dest/services/encoding.d.ts +25 -6
  106. package/dest/services/encoding.d.ts.map +1 -1
  107. package/dest/services/encoding.js +73 -5
  108. package/dest/services/index.d.ts +4 -0
  109. package/dest/services/index.d.ts.map +1 -1
  110. package/dest/services/index.js +4 -0
  111. package/dest/services/libp2p/instrumentation.d.ts +18 -0
  112. package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
  113. package/dest/services/libp2p/instrumentation.js +157 -0
  114. package/dest/services/libp2p/libp2p_service.d.ts +87 -42
  115. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  116. package/dest/services/libp2p/libp2p_service.js +500 -218
  117. package/dest/services/peer-manager/interface.d.ts +23 -0
  118. package/dest/services/peer-manager/interface.d.ts.map +1 -0
  119. package/dest/services/peer-manager/interface.js +1 -0
  120. package/dest/services/peer-manager/metrics.d.ts +3 -1
  121. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  122. package/dest/services/peer-manager/metrics.js +11 -2
  123. package/dest/services/peer-manager/peer_manager.d.ts +126 -15
  124. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  125. package/dest/services/peer-manager/peer_manager.js +547 -72
  126. package/dest/services/reqresp/config.d.ts +10 -8
  127. package/dest/services/reqresp/config.d.ts.map +1 -1
  128. package/dest/services/reqresp/config.js +18 -4
  129. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
  130. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  131. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +10 -6
  132. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +30 -13
  133. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  134. package/dest/services/reqresp/connection-sampler/connection_sampler.js +142 -84
  135. package/dest/services/reqresp/index.d.ts +2 -1
  136. package/dest/services/reqresp/index.d.ts.map +1 -1
  137. package/dest/services/reqresp/index.js +2 -1
  138. package/dest/services/reqresp/interface.d.ts +72 -23
  139. package/dest/services/reqresp/interface.d.ts.map +1 -1
  140. package/dest/services/reqresp/interface.js +45 -26
  141. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  142. package/dest/services/reqresp/protocols/auth.d.ts +43 -0
  143. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -0
  144. package/dest/services/reqresp/protocols/auth.js +71 -0
  145. package/dest/services/reqresp/protocols/block.d.ts +5 -0
  146. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  147. package/dest/services/reqresp/protocols/block.js +28 -5
  148. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +30 -0
  149. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -0
  150. package/dest/services/reqresp/protocols/block_txs/bitvector.js +75 -0
  151. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +11 -0
  152. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -0
  153. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +39 -0
  154. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +49 -0
  155. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -0
  156. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +75 -0
  157. package/dest/services/reqresp/protocols/block_txs/index.d.ts +4 -0
  158. package/dest/services/reqresp/protocols/block_txs/index.d.ts.map +1 -0
  159. package/dest/services/reqresp/protocols/block_txs/index.js +3 -0
  160. package/dest/services/reqresp/protocols/goodbye.d.ts +2 -4
  161. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  162. package/dest/services/reqresp/protocols/goodbye.js +7 -7
  163. package/dest/services/reqresp/protocols/index.d.ts +2 -0
  164. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  165. package/dest/services/reqresp/protocols/index.js +2 -0
  166. package/dest/services/reqresp/protocols/ping.d.ts +0 -2
  167. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
  168. package/dest/services/reqresp/protocols/status.d.ts +38 -6
  169. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  170. package/dest/services/reqresp/protocols/status.js +72 -5
  171. package/dest/services/reqresp/protocols/tx.d.ts +12 -1
  172. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  173. package/dest/services/reqresp/protocols/tx.js +34 -6
  174. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +4 -2
  175. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  176. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -2
  177. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  178. package/dest/services/reqresp/rate-limiter/rate_limits.js +21 -1
  179. package/dest/services/reqresp/reqresp.d.ts +45 -47
  180. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  181. package/dest/services/reqresp/reqresp.js +298 -207
  182. package/dest/services/reqresp/status.d.ts +9 -3
  183. package/dest/services/reqresp/status.d.ts.map +1 -1
  184. package/dest/services/reqresp/status.js +9 -2
  185. package/dest/services/service.d.ts +22 -18
  186. package/dest/services/service.d.ts.map +1 -1
  187. package/dest/services/tx_collection/config.d.ts +25 -0
  188. package/dest/services/tx_collection/config.d.ts.map +1 -0
  189. package/dest/services/tx_collection/config.js +58 -0
  190. package/dest/services/tx_collection/fast_tx_collection.d.ts +56 -0
  191. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -0
  192. package/dest/services/tx_collection/fast_tx_collection.js +300 -0
  193. package/dest/services/tx_collection/index.d.ts +3 -0
  194. package/dest/services/tx_collection/index.d.ts.map +1 -0
  195. package/dest/services/tx_collection/index.js +2 -0
  196. package/dest/services/tx_collection/instrumentation.d.ts +10 -0
  197. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -0
  198. package/dest/services/tx_collection/instrumentation.js +34 -0
  199. package/dest/services/tx_collection/slow_tx_collection.d.ts +54 -0
  200. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -0
  201. package/dest/services/tx_collection/slow_tx_collection.js +176 -0
  202. package/dest/services/tx_collection/tx_collection.d.ts +110 -0
  203. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -0
  204. package/dest/services/tx_collection/tx_collection.js +128 -0
  205. package/dest/services/tx_collection/tx_collection_sink.d.ts +30 -0
  206. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -0
  207. package/dest/services/tx_collection/tx_collection_sink.js +111 -0
  208. package/dest/services/tx_collection/tx_source.d.ts +18 -0
  209. package/dest/services/tx_collection/tx_source.d.ts.map +1 -0
  210. package/dest/services/tx_collection/tx_source.js +31 -0
  211. package/dest/services/tx_provider.d.ts +49 -0
  212. package/dest/services/tx_provider.d.ts.map +1 -0
  213. package/dest/services/tx_provider.js +210 -0
  214. package/dest/services/tx_provider_instrumentation.d.ts +13 -0
  215. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -0
  216. package/dest/services/tx_provider_instrumentation.js +34 -0
  217. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  218. package/dest/test-helpers/index.d.ts +1 -0
  219. package/dest/test-helpers/index.d.ts.map +1 -1
  220. package/dest/test-helpers/index.js +1 -0
  221. package/dest/test-helpers/make-enrs.d.ts.map +1 -1
  222. package/dest/test-helpers/make-enrs.js +4 -5
  223. package/dest/test-helpers/make-test-p2p-clients.d.ts +32 -4
  224. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  225. package/dest/test-helpers/make-test-p2p-clients.js +86 -16
  226. package/dest/test-helpers/mock-pubsub.d.ts +59 -0
  227. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -0
  228. package/dest/test-helpers/mock-pubsub.js +130 -0
  229. package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
  230. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
  231. package/dest/test-helpers/mock-tx-helpers.js +19 -0
  232. package/dest/test-helpers/reqresp-nodes.d.ts +14 -10
  233. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  234. package/dest/test-helpers/reqresp-nodes.js +62 -28
  235. package/dest/testbench/p2p_client_testbench_worker.js +96 -25
  236. package/dest/testbench/parse_log_file.js +4 -4
  237. package/dest/testbench/testbench.js +4 -4
  238. package/dest/testbench/worker_client_manager.d.ts +0 -5
  239. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  240. package/dest/testbench/worker_client_manager.js +11 -19
  241. package/dest/types/index.d.ts +3 -1
  242. package/dest/types/index.d.ts.map +1 -1
  243. package/dest/types/index.js +2 -0
  244. package/dest/util.d.ts +22 -15
  245. package/dest/util.d.ts.map +1 -1
  246. package/dest/util.js +64 -67
  247. package/dest/versioning.d.ts +3 -3
  248. package/dest/versioning.d.ts.map +1 -1
  249. package/dest/versioning.js +8 -3
  250. package/package.json +28 -24
  251. package/src/bootstrap/bootstrap.ts +27 -11
  252. package/src/client/factory.ts +136 -45
  253. package/src/client/index.ts +1 -0
  254. package/src/client/interface.ts +195 -0
  255. package/src/client/p2p_client.ts +460 -327
  256. package/src/config.ts +288 -134
  257. package/src/enr/generate-enr.ts +39 -6
  258. package/src/index.ts +4 -0
  259. package/src/mem_pools/attestation_pool/attestation_pool.ts +48 -4
  260. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +241 -55
  261. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +117 -20
  262. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +114 -22
  263. package/src/mem_pools/attestation_pool/mocks.ts +11 -10
  264. package/src/mem_pools/instrumentation.ts +32 -46
  265. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +549 -108
  266. package/src/mem_pools/tx_pool/memory_tx_pool.ts +153 -44
  267. package/src/mem_pools/tx_pool/priority.ts +1 -1
  268. package/src/mem_pools/tx_pool/tx_pool.ts +67 -8
  269. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +217 -34
  270. package/src/msg_validators/attestation_validator/attestation_validator.ts +55 -10
  271. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +66 -14
  272. package/src/msg_validators/msg_seen_validator/msg_seen_validator.ts +36 -0
  273. package/src/msg_validators/tx_validator/allowed_public_setup.ts +35 -0
  274. package/src/msg_validators/tx_validator/archive_cache.ts +28 -0
  275. package/src/msg_validators/tx_validator/block_header_validator.ts +4 -4
  276. package/src/msg_validators/tx_validator/data_validator.ts +81 -69
  277. package/src/msg_validators/tx_validator/double_spend_validator.ts +19 -17
  278. package/src/msg_validators/tx_validator/factory.ts +109 -0
  279. package/src/msg_validators/tx_validator/gas_validator.ts +134 -0
  280. package/src/msg_validators/tx_validator/index.ts +7 -0
  281. package/src/msg_validators/tx_validator/metadata_validator.ts +58 -21
  282. package/src/msg_validators/tx_validator/phases_validator.ts +114 -0
  283. package/src/msg_validators/tx_validator/test_utils.ts +43 -0
  284. package/src/msg_validators/tx_validator/timestamp_validator.ts +46 -0
  285. package/src/msg_validators/tx_validator/tx_permitted_validator.ts +17 -0
  286. package/src/msg_validators/tx_validator/tx_proof_validator.ts +6 -5
  287. package/src/services/discv5/discV5_service.ts +84 -38
  288. package/src/services/dummy_service.ts +147 -9
  289. package/src/services/encoding.ts +80 -5
  290. package/src/services/index.ts +4 -0
  291. package/src/services/libp2p/instrumentation.ts +158 -0
  292. package/src/services/libp2p/libp2p_service.ts +646 -263
  293. package/src/services/peer-manager/interface.ts +29 -0
  294. package/src/services/peer-manager/metrics.ts +16 -1
  295. package/src/services/peer-manager/peer_manager.ts +652 -78
  296. package/src/services/reqresp/config.ts +26 -9
  297. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +12 -6
  298. package/src/services/reqresp/connection-sampler/connection_sampler.ts +148 -95
  299. package/src/services/reqresp/index.ts +2 -0
  300. package/src/services/reqresp/interface.ts +91 -36
  301. package/src/services/reqresp/metrics.ts +4 -1
  302. package/src/services/reqresp/protocols/auth.ts +83 -0
  303. package/src/services/reqresp/protocols/block.ts +24 -3
  304. package/src/services/reqresp/protocols/block_txs/bitvector.ts +90 -0
  305. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +53 -0
  306. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +79 -0
  307. package/src/services/reqresp/protocols/block_txs/index.ts +3 -0
  308. package/src/services/reqresp/protocols/goodbye.ts +9 -7
  309. package/src/services/reqresp/protocols/index.ts +2 -0
  310. package/src/services/reqresp/protocols/status.ts +117 -5
  311. package/src/services/reqresp/protocols/tx.ts +35 -6
  312. package/src/services/reqresp/rate-limiter/rate_limiter.ts +12 -3
  313. package/src/services/reqresp/rate-limiter/rate_limits.ts +21 -1
  314. package/src/services/reqresp/reqresp.ts +387 -256
  315. package/src/services/reqresp/status.ts +12 -3
  316. package/src/services/service.ts +45 -21
  317. package/src/services/tx_collection/config.ts +84 -0
  318. package/src/services/tx_collection/fast_tx_collection.ts +340 -0
  319. package/src/services/tx_collection/index.ts +2 -0
  320. package/src/services/tx_collection/instrumentation.ts +43 -0
  321. package/src/services/tx_collection/slow_tx_collection.ts +232 -0
  322. package/src/services/tx_collection/tx_collection.ts +215 -0
  323. package/src/services/tx_collection/tx_collection_sink.ts +129 -0
  324. package/src/services/tx_collection/tx_source.ts +37 -0
  325. package/src/services/tx_provider.ts +216 -0
  326. package/src/services/tx_provider_instrumentation.ts +44 -0
  327. package/src/test-helpers/index.ts +1 -0
  328. package/src/test-helpers/make-enrs.ts +4 -5
  329. package/src/test-helpers/make-test-p2p-clients.ts +111 -21
  330. package/src/test-helpers/mock-pubsub.ts +188 -0
  331. package/src/test-helpers/mock-tx-helpers.ts +24 -0
  332. package/src/test-helpers/reqresp-nodes.ts +86 -35
  333. package/src/testbench/p2p_client_testbench_worker.ts +145 -22
  334. package/src/testbench/parse_log_file.ts +4 -4
  335. package/src/testbench/testbench.ts +4 -4
  336. package/src/testbench/worker_client_manager.ts +17 -23
  337. package/src/types/index.ts +2 -0
  338. package/src/util.ts +93 -89
  339. package/src/versioning.ts +11 -4
@@ -1,26 +1,35 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
+ import { randomInt } from '@aztec/foundation/crypto';
2
3
  import { Fr } from '@aztec/foundation/fields';
3
- import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
4
+ import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
4
5
  import { SerialQueue } from '@aztec/foundation/queue';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
+ import { Timer } from '@aztec/foundation/timer';
6
8
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
7
- import type { 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, L2BlockSource } from '@aztec/stdlib/block';
12
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
13
+ import { GasFees } from '@aztec/stdlib/gas';
8
14
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
9
15
  import {
10
16
  BlockAttestation,
11
17
  BlockProposal,
12
18
  type Gossipable,
13
19
  P2PClientType,
20
+ P2PMessage,
14
21
  PeerErrorSeverity,
15
- TopicTypeMap,
16
- getTopicTypeForClientType,
22
+ TopicType,
23
+ createTopicString,
24
+ getTopicsForClientAndConfig,
17
25
  metricsTopicStrToLabels,
18
26
  } from '@aztec/stdlib/p2p';
19
27
  import { MerkleTreeId } from '@aztec/stdlib/trees';
20
- import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
28
+ import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
29
+ import type { UInt64 } from '@aztec/stdlib/types';
30
+ import { compressComponentVersions } from '@aztec/stdlib/versioning';
21
31
  import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
22
32
 
23
- import type { ENR } from '@chainsafe/enr';
24
33
  import {
25
34
  type GossipSub,
26
35
  type GossipSubComponents,
@@ -33,17 +42,21 @@ import { noise } from '@chainsafe/libp2p-noise';
33
42
  import { yamux } from '@chainsafe/libp2p-yamux';
34
43
  import { bootstrap } from '@libp2p/bootstrap';
35
44
  import { identify } from '@libp2p/identify';
36
- import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
45
+ import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
37
46
  import type { ConnectionManager } from '@libp2p/interface-internal';
38
- import '@libp2p/kad-dht';
39
47
  import { mplex } from '@libp2p/mplex';
40
48
  import { tcp } from '@libp2p/tcp';
49
+ import { ENR } from '@nethermindeth/enr';
41
50
  import { createLibp2p } from 'libp2p';
42
51
 
43
52
  import type { P2PConfig } from '../../config.js';
44
53
  import type { MemPools } from '../../mem_pools/interface.js';
45
54
  import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
55
+ import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
56
+ import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
57
+ import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
46
58
  import {
59
+ AggregateTxValidator,
47
60
  DataTxValidator,
48
61
  DoubleSpendTxValidator,
49
62
  MetadataTxValidator,
@@ -51,23 +64,40 @@ import {
51
64
  } from '../../msg_validators/tx_validator/index.js';
52
65
  import { GossipSubEvent } from '../../types/index.js';
53
66
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
67
+ import { getVersions } from '../../versioning.js';
54
68
  import { AztecDatastore } from '../data_store.js';
69
+ import { DiscV5Service } from '../discv5/discV5_service.js';
55
70
  import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
56
71
  import { gossipScoreThresholds } from '../gossipsub/scoring.js';
72
+ import type { PeerManagerInterface } from '../peer-manager/interface.js';
57
73
  import { PeerManager } from '../peer-manager/peer_manager.js';
58
74
  import { PeerScoring } from '../peer-manager/peer_scoring.js';
59
- import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, type SubProtocolMap } from '../reqresp/interface.js';
75
+ import type { P2PReqRespConfig } from '../reqresp/config.js';
76
+ import {
77
+ DEFAULT_SUB_PROTOCOL_VALIDATORS,
78
+ type ReqRespInterface,
79
+ ReqRespSubProtocol,
80
+ type ReqRespSubProtocolHandler,
81
+ type ReqRespSubProtocolHandlers,
82
+ type ReqRespSubProtocolValidators,
83
+ type SubProtocolMap,
84
+ ValidationError,
85
+ } from '../reqresp/interface.js';
86
+ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs_handler.js';
60
87
  import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
61
- import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } from '../reqresp/protocols/index.js';
88
+ import {
89
+ AuthRequest,
90
+ BlockTxsRequest,
91
+ BlockTxsResponse,
92
+ StatusMessage,
93
+ pingHandler,
94
+ reqRespBlockHandler,
95
+ reqRespStatusHandler,
96
+ reqRespTxHandler,
97
+ } from '../reqresp/protocols/index.js';
62
98
  import { ReqResp } from '../reqresp/reqresp.js';
63
- import type { P2PService, PeerDiscoveryService } from '../service.js';
64
-
65
- interface MessageValidator {
66
- validator: {
67
- validateTx(tx: Tx): Promise<TxValidationResult>;
68
- };
69
- severity: PeerErrorSeverity;
70
- }
99
+ import type { P2PBlockReceivedCallback, P2PService, PeerDiscoveryService } from '../service.js';
100
+ import { P2PInstrumentation } from './instrumentation.js';
71
101
 
72
102
  interface ValidationResult {
73
103
  name: string;
@@ -77,66 +107,79 @@ interface ValidationResult {
77
107
 
78
108
  type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
79
109
 
110
+ // REFACTOR: Unify with the type above
111
+ type ReceivedMessageValidationResult<T> =
112
+ | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
113
+ | { obj?: undefined; result: TopicValidatorResult.Reject };
114
+
80
115
  /**
81
116
  * Lib P2P implementation of the P2PService interface.
82
117
  */
83
- export class LibP2PService<T extends P2PClientType> extends WithTracer implements P2PService {
118
+ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
84
119
  private jobQueue: SerialQueue = new SerialQueue();
85
- private peerManager: PeerManager;
86
120
  private discoveryRunningPromise?: RunningPromise;
121
+ private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
87
122
 
88
123
  // Message validators
89
124
  private attestationValidator: AttestationValidator;
90
125
  private blockProposalValidator: BlockProposalValidator;
91
126
 
92
- // Request and response sub service
93
- public reqresp: ReqResp;
127
+ private protocolVersion = '';
128
+ private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
129
+
130
+ private feesCache: { blockNumber: number; gasFees: GasFees } | undefined;
94
131
 
95
132
  /**
96
133
  * Callback for when a block is received from a peer.
97
134
  * @param block - The block received from the peer.
98
135
  * @returns The attestation for the block, if any.
99
136
  */
100
- private blockReceivedCallback: (block: BlockProposal) => Promise<BlockAttestation | undefined>;
137
+ private blockReceivedCallback: P2PBlockReceivedCallback;
138
+
139
+ private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
140
+
141
+ private instrumentation: P2PInstrumentation;
101
142
 
102
143
  constructor(
103
144
  private clientType: T,
104
145
  private config: P2PConfig,
105
- private node: PubSubLibp2p,
146
+ protected node: PubSubLibp2p,
106
147
  private peerDiscoveryService: PeerDiscoveryService,
107
- private mempools: MemPools<T>,
108
- private l2BlockSource: L2BlockSource,
109
- epochCache: EpochCacheInterface,
148
+ private reqresp: ReqRespInterface,
149
+ private peerManager: PeerManagerInterface,
150
+ protected mempools: MemPools<T>,
151
+ private archiver: L2BlockSource & ContractDataSource,
152
+ private epochCache: EpochCacheInterface,
110
153
  private proofVerifier: ClientProtocolCircuitVerifier,
111
154
  private worldStateSynchronizer: WorldStateSynchronizer,
112
155
  telemetry: TelemetryClient,
113
- private logger = createLogger('p2p:libp2p_service'),
156
+ protected logger = createLogger('p2p:libp2p_service'),
114
157
  ) {
115
158
  super(telemetry, 'LibP2PService');
116
159
 
117
- const peerScoring = new PeerScoring(config);
118
- this.reqresp = new ReqResp(config, node, peerScoring);
160
+ this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
119
161
 
120
- this.peerManager = new PeerManager(
121
- node,
122
- peerDiscoveryService,
123
- config,
124
- telemetry,
125
- createLogger(`${logger.module}:peer_manager`),
126
- peerScoring,
127
- this.reqresp,
128
- );
162
+ this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
163
+ this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
164
+ this.msgIdSeenValidators[TopicType.block_attestation] = new MessageSeenValidator(config.seenMessageCacheSize);
129
165
 
130
- // Update gossipsub score params
131
- this.node.services.pubsub.score.params.appSpecificScore = (peerId: string) => {
132
- return this.peerManager.getPeerScore(peerId);
133
- };
134
- this.node.services.pubsub.score.params.appSpecificWeight = 10;
166
+ const versions = getVersions(config);
167
+ this.protocolVersion = compressComponentVersions(versions);
168
+ logger.info(`Started libp2p service with protocol version ${this.protocolVersion}`);
169
+
170
+ this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
171
+ this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
172
+ this.topicStrings[TopicType.block_attestation] = createTopicString(
173
+ TopicType.block_attestation,
174
+ this.protocolVersion,
175
+ );
135
176
 
136
177
  this.attestationValidator = new AttestationValidator(epochCache);
137
- this.blockProposalValidator = new BlockProposalValidator(epochCache);
178
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
179
+
180
+ this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
138
181
 
139
- this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation | undefined> => {
182
+ this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
140
183
  this.logger.debug(
141
184
  `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber.toNumber()} from peer.`,
142
185
  { p2pMessageIdentifier: await block.p2pMessageIdentifier() },
@@ -145,6 +188,10 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
145
188
  };
146
189
  }
147
190
 
191
+ public updateConfig(config: Partial<P2PReqRespConfig>) {
192
+ this.reqresp.updateConfig(config);
193
+ }
194
+
148
195
  /**
149
196
  * Creates an instance of the LibP2P service.
150
197
  * @param config - The configuration to use when creating the service.
@@ -154,69 +201,151 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
154
201
  public static async new<T extends P2PClientType>(
155
202
  clientType: T,
156
203
  config: P2PConfig,
157
- peerDiscoveryService: PeerDiscoveryService,
158
204
  peerId: PeerId,
159
- mempools: MemPools<T>,
160
- l2BlockSource: L2BlockSource,
161
- epochCache: EpochCacheInterface,
162
- proofVerifier: ClientProtocolCircuitVerifier,
163
- worldStateSynchronizer: WorldStateSynchronizer,
164
- store: AztecAsyncKVStore,
165
- telemetry: TelemetryClient,
166
- logger = createLogger('p2p:libp2p_service'),
205
+ deps: {
206
+ mempools: MemPools<T>;
207
+ l2BlockSource: L2BlockSource & ContractDataSource;
208
+ epochCache: EpochCacheInterface;
209
+ proofVerifier: ClientProtocolCircuitVerifier;
210
+ worldStateSynchronizer: WorldStateSynchronizer;
211
+ peerStore: AztecAsyncKVStore;
212
+ telemetry: TelemetryClient;
213
+ logger: Logger;
214
+ packageVersion: string;
215
+ },
167
216
  ) {
168
- const { tcpListenAddress, tcpAnnounceAddress, maxPeerCount } = config;
169
- const bindAddrTcp = convertToMultiaddr(tcpListenAddress, 'tcp');
170
- // We know tcpAnnounceAddress cannot be null here because we set it or throw when setting up the service.
171
- const announceAddrTcp = convertToMultiaddr(tcpAnnounceAddress!, 'tcp');
217
+ const {
218
+ worldStateSynchronizer,
219
+ epochCache,
220
+ l2BlockSource,
221
+ mempools,
222
+ proofVerifier,
223
+ peerStore,
224
+ telemetry,
225
+ logger,
226
+ packageVersion,
227
+ } = deps;
228
+ const { p2pPort, maxPeerCount, listenAddress } = config;
229
+ const bindAddrTcp = convertToMultiaddr(listenAddress, p2pPort, 'tcp');
172
230
 
173
- const datastore = new AztecDatastore(store);
231
+ const datastore = new AztecDatastore(peerStore);
174
232
 
175
233
  const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
176
234
 
177
- // If bootstrap nodes are provided, also provide them to the p2p service
235
+ const peerDiscoveryService = new DiscV5Service(
236
+ peerId,
237
+ config,
238
+ packageVersion,
239
+ telemetry,
240
+ createLogger(`${logger.module}:discv5_service`),
241
+ );
242
+
243
+ // Seed libp2p's bootstrap discovery with private and trusted peers
244
+ const bootstrapNodes = [...config.privatePeers, ...config.trustedPeers];
245
+
178
246
  const peerDiscovery = [];
179
- if (peerDiscoveryService.bootstrapNodes.length > 0) {
180
- peerDiscovery.push(bootstrap({ list: peerDiscoveryService.bootstrapNodes }));
247
+ if (bootstrapNodes.length > 0) {
248
+ peerDiscovery.push(bootstrap({ list: bootstrapNodes }));
181
249
  }
182
250
 
251
+ const versions = getVersions(config);
252
+ const protocolVersion = compressComponentVersions(versions);
253
+
254
+ const txTopic = createTopicString(TopicType.tx, protocolVersion);
255
+ const blockProposalTopic = createTopicString(TopicType.block_proposal, protocolVersion);
256
+ const blockAttestationTopic = createTopicString(TopicType.block_attestation, protocolVersion);
257
+
258
+ const preferredPeersEnrs: ENR[] = config.preferredPeers.map(enr => ENR.decodeTxt(enr));
259
+ const directPeers = (
260
+ await Promise.all(
261
+ preferredPeersEnrs.map(async enr => {
262
+ const peerId = await enr.peerId();
263
+ const address = enr.getLocationMultiaddr('tcp');
264
+ if (address === undefined) {
265
+ throw new Error(`Direct peer ${peerId.toString()} has no TCP address, ENR: ${enr.encodeTxt()}`);
266
+ }
267
+ return {
268
+ id: peerId,
269
+ addrs: [address],
270
+ };
271
+ }),
272
+ )
273
+ ).filter(peer => peer !== undefined);
274
+
275
+ const announceTcpMultiaddr = config.p2pIp ? [convertToMultiaddr(config.p2pIp, p2pPort, 'tcp')] : [];
276
+
183
277
  const node = await createLibp2p({
184
278
  start: false,
185
279
  peerId,
186
280
  addresses: {
187
281
  listen: [bindAddrTcp],
188
- announce: [announceAddrTcp],
282
+ announce: announceTcpMultiaddr,
189
283
  },
190
284
  transports: [
191
285
  tcp({
192
- maxConnections: config.maxPeerCount,
286
+ // It's better to have this number a bit higher than our maxPeerCount because it's sets the limit on transport (TCP) layer
287
+ // 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
288
+ // If we hit the limit, the connection will be temporarily accepted and immediately dropped.
289
+ // Docs: https://nodejs.org/api/net.html#servermaxconnections
290
+ maxConnections: maxPeerCount * 2,
193
291
  // socket option: the maximum length of the queue of pending connections
194
- // https://nodejs.org/dist/latest-v18.x/docs/api/net.html#serverlisten
292
+ // https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
195
293
  // it's not safe if we increase this number
196
294
  backlog: 5,
197
295
  closeServerOnMaxConnections: {
198
- closeAbove: maxPeerCount ?? Infinity,
199
- listenBelow: maxPeerCount ?? Infinity,
296
+ // The property `maxConnections` will protect us against the most DDOS attack
297
+ // This property protects us in case of burst of new connections where server is not able to close them quickly enough
298
+ // In case closeAbove is reached, the server stops listening altogether
299
+ // It's important that there is enough difference between closeAbove and listenAbove,
300
+ // otherwise the server.listener will flap between being closed and open potentially degrading perf even more
301
+ closeAbove: maxPeerCount * 3,
302
+ listenBelow: Math.floor(maxPeerCount * 0.9),
200
303
  },
201
304
  }),
202
305
  ],
203
306
  datastore,
204
307
  peerDiscovery,
205
- streamMuxers: [mplex(), yamux()],
308
+ streamMuxers: [yamux(), mplex()],
206
309
  connectionEncryption: [noise()],
207
310
  connectionManager: {
208
- minConnections: 0,
209
-
311
+ minConnections: 0, // Disable libp2p peer dialing, we do it manually
312
+ // We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
313
+ // libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
314
+ maxConnections: maxPeerCount * 2,
210
315
  maxParallelDials: 100,
211
316
  dialTimeout: 30_000,
212
317
  maxPeerAddrsToDial: 5,
213
318
  maxIncomingPendingConnections: 5,
214
319
  },
320
+ connectionGater: {
321
+ denyInboundConnection: (maConn: MultiaddrConnection) => {
322
+ const allowed = peerManager.isNodeAllowedToConnect(maConn.remoteAddr.nodeAddress().address);
323
+ if (allowed) {
324
+ return false;
325
+ }
326
+
327
+ logger.debug(`Connection gater: Denying inbound connection from ${maConn.remoteAddr.toString()}`);
328
+ return true;
329
+ },
330
+ denyInboundEncryptedConnection: (peerId: PeerId, _maConn: MultiaddrConnection) => {
331
+ //NOTE: it is not necessary to check address here because this was already done by
332
+ // denyInboundConnection
333
+ const allowed = peerManager.isNodeAllowedToConnect(peerId);
334
+ if (allowed) {
335
+ return false;
336
+ }
337
+
338
+ logger.debug(`Connection gater: Denying inbound encrypted connection from ${peerId.toString()}`);
339
+ return true;
340
+ },
341
+ },
215
342
  services: {
216
343
  identify: identify({
217
344
  protocolPrefix: 'aztec',
345
+ runOnConnectionOpen: true,
218
346
  }),
219
347
  pubsub: gossipsub({
348
+ directPeers,
220
349
  debugName: 'gossipsub',
221
350
  globalSignaturePolicy: SignaturePolicy.StrictNoSign,
222
351
  allowPublishToZeroTopicPeers: true,
@@ -228,29 +357,30 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
228
357
  heartbeatInterval: config.gossipsubInterval,
229
358
  mcacheLength: config.gossipsubMcacheLength,
230
359
  mcacheGossip: config.gossipsubMcacheGossip,
360
+ seenTTL: config.gossipsubSeenTTL,
231
361
  msgIdFn: getMsgIdFn,
232
362
  msgIdToStrFn: msgIdToStrFn,
233
363
  fastMsgIdFn: fastMsgIdFn,
234
364
  dataTransform: new SnappyTransform(),
235
365
  metricsRegister: otelMetricsAdapter,
236
- metricsTopicStrToLabel: metricsTopicStrToLabels(),
366
+ metricsTopicStrToLabel: metricsTopicStrToLabels(protocolVersion),
237
367
  asyncValidation: true,
238
368
  scoreThresholds: gossipScoreThresholds,
239
369
  scoreParams: createPeerScoreParams({
240
370
  // IPColocation factor can be disabled for local testing - default to -5
241
371
  IPColocationFactorWeight: config.debugDisableColocationPenalty ? 0 : -5.0,
242
372
  topics: {
243
- [Tx.p2pTopic]: createTopicScoreParams({
373
+ [txTopic]: createTopicScoreParams({
244
374
  topicWeight: 1,
245
375
  invalidMessageDeliveriesWeight: -20,
246
376
  invalidMessageDeliveriesDecay: 0.5,
247
377
  }),
248
- [BlockAttestation.p2pTopic]: createTopicScoreParams({
378
+ [blockAttestationTopic]: createTopicScoreParams({
249
379
  topicWeight: 1,
250
380
  invalidMessageDeliveriesWeight: -20,
251
381
  invalidMessageDeliveriesDecay: 0.5,
252
382
  }),
253
- [BlockProposal.p2pTopic]: createTopicScoreParams({
383
+ [blockProposalTopic]: createTopicScoreParams({
254
384
  topicWeight: 1,
255
385
  invalidMessageDeliveriesWeight: -20,
256
386
  invalidMessageDeliveriesDecay: 0.5,
@@ -265,11 +395,34 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
265
395
  logger: createLibp2pComponentLogger(logger.module),
266
396
  });
267
397
 
398
+ const peerScoring = new PeerScoring(config);
399
+ const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
400
+
401
+ const peerManager = new PeerManager(
402
+ node,
403
+ peerDiscoveryService,
404
+ config,
405
+ telemetry,
406
+ createLogger(`${logger.module}:peer_manager`),
407
+ peerScoring,
408
+ reqresp,
409
+ worldStateSynchronizer,
410
+ protocolVersion,
411
+ epochCache,
412
+ );
413
+
414
+ // Update gossipsub score params
415
+ node.services.pubsub.score.params.appSpecificWeight = 10;
416
+ node.services.pubsub.score.params.appSpecificScore = (peerId: string) =>
417
+ peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
418
+
268
419
  return new LibP2PService(
269
420
  clientType,
270
421
  config,
271
422
  node,
272
423
  peerDiscoveryService,
424
+ reqresp,
425
+ peerManager,
273
426
  mempools,
274
427
  l2BlockSource,
275
428
  epochCache,
@@ -291,37 +444,51 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
291
444
  }
292
445
 
293
446
  // Get listen & announce addresses for logging
294
- const { tcpListenAddress, tcpAnnounceAddress } = this.config;
295
- if (!tcpAnnounceAddress) {
447
+ const { p2pIp, p2pPort } = this.config;
448
+ if (!p2pIp) {
296
449
  throw new Error('Announce address not provided.');
297
450
  }
298
- const announceTcpMultiaddr = convertToMultiaddr(tcpAnnounceAddress, 'tcp');
451
+ const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
299
452
 
300
453
  // Start job queue, peer discovery service and libp2p node
301
454
  this.jobQueue.start();
302
- await this.peerDiscoveryService.start();
455
+
456
+ await this.peerManager.initializePeers();
457
+ if (!this.config.p2pDiscoveryDisabled) {
458
+ await this.peerDiscoveryService.start();
459
+ }
303
460
  await this.node.start();
304
461
 
305
462
  // Subscribe to standard GossipSub topics by default
306
- for (const topic of getTopicTypeForClientType(this.clientType)) {
307
- this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
463
+ for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
464
+ this.subscribeToTopic(this.topicStrings[topic]);
308
465
  }
309
466
 
310
467
  // Create request response protocol handlers
311
468
  const txHandler = reqRespTxHandler(this.mempools);
312
469
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
313
- const blockHandler = reqRespBlockHandler(this.l2BlockSource);
470
+ const blockHandler = reqRespBlockHandler(this.archiver);
471
+ const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
314
472
 
315
- const requestResponseHandlers = {
473
+ const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
316
474
  [ReqRespSubProtocol.PING]: pingHandler,
317
- [ReqRespSubProtocol.STATUS]: statusHandler,
318
- [ReqRespSubProtocol.TX]: txHandler.bind(this),
475
+ [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
319
476
  [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
320
477
  [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
321
478
  };
322
479
 
480
+ // Only handle block transactions request if attestation pool is available to the client
481
+ if (this.mempools.attestationPool && !this.config.disableTransactions) {
482
+ const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
483
+ requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
484
+ }
485
+
486
+ if (!this.config.disableTransactions) {
487
+ requestResponseHandlers[ReqRespSubProtocol.TX] = txHandler.bind(this);
488
+ }
489
+
323
490
  // add GossipSub listener
324
- this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
491
+ this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
325
492
 
326
493
  // Start running promise for peer discovery
327
494
  this.discoveryRunningPromise = new RunningPromise(
@@ -335,11 +502,13 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
335
502
  const reqrespSubProtocolValidators = {
336
503
  ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
337
504
  // TODO(#11336): A request validator for blocks
338
- [ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
505
+ [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
506
+ [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
339
507
  };
340
508
  await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
341
509
  this.logger.info(`Started P2P service`, {
342
- listen: tcpListenAddress,
510
+ listen: this.config.listenAddress,
511
+ port: this.config.p2pPort,
343
512
  announce: announceTcpMultiaddr,
344
513
  peerId: this.node.peerId.toString(),
345
514
  });
@@ -351,7 +520,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
351
520
  */
352
521
  public async stop() {
353
522
  // Remove gossip sub listener
354
- this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
523
+ this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
355
524
 
356
525
  // Stop peer manager
357
526
  this.logger.debug('Stopping peer manager...');
@@ -370,6 +539,18 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
370
539
  this.logger.info('LibP2P service stopped');
371
540
  }
372
541
 
542
+ addReqRespSubProtocol(
543
+ subProtocol: ReqRespSubProtocol,
544
+ handler: ReqRespSubProtocolHandler,
545
+ validator?: ReqRespSubProtocolValidators[ReqRespSubProtocol],
546
+ ): Promise<void> {
547
+ return this.reqresp.addSubProtocol(subProtocol, handler, validator);
548
+ }
549
+
550
+ public registerThisValidatorAddresses(address: EthAddress[]): void {
551
+ this.peerManager.registerThisValidatorAddresses(address);
552
+ }
553
+
373
554
  public getPeers(includePending?: boolean): PeerInfo[] {
374
555
  return this.peerManager.getPeers(includePending);
375
556
  }
@@ -387,23 +568,6 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
387
568
  setImmediate(() => void safeJob());
388
569
  }
389
570
 
390
- /**
391
- * Send Request via the ReqResp service
392
- * The subprotocol defined will determine the request and response types
393
- *
394
- * See the subProtocolMap for the mapping of subprotocols to request/response types in `interface.ts`
395
- *
396
- * @param protocol The request response protocol to use
397
- * @param request The request type to send
398
- * @returns
399
- */
400
- sendRequest<SubProtocol extends ReqRespSubProtocol>(
401
- protocol: SubProtocol,
402
- request: InstanceType<SubProtocolMap[SubProtocol]['request']>,
403
- ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined> {
404
- return this.reqresp.sendRequest(protocol, request);
405
- }
406
-
407
571
  /**
408
572
  * Send a batch of requests to peers, and return the responses
409
573
  * @param protocol - The request response protocol to use
@@ -413,8 +577,9 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
413
577
  sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
414
578
  protocol: SubProtocol,
415
579
  requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
416
- ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[] | undefined> {
417
- return this.reqresp.sendBatchRequest(protocol, requests);
580
+ pinnedPeerId: PeerId | undefined,
581
+ ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
582
+ return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
418
583
  }
419
584
 
420
585
  /**
@@ -425,9 +590,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
425
590
  return this.peerDiscoveryService.getEnr();
426
591
  }
427
592
 
428
- public registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation | undefined>) {
593
+ public registerBlockReceivedCallback(callback: P2PBlockReceivedCallback) {
429
594
  this.blockReceivedCallback = callback;
430
- this.logger.verbose('Block received callback registered');
431
595
  }
432
596
 
433
597
  /**
@@ -444,160 +608,279 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
444
608
  /**
445
609
  * Publishes data to a topic.
446
610
  * @param topic - The topic to publish to.
447
- * @param data - The data to publish.
611
+ * @param data - The message to publish.
448
612
  * @returns The number of recipients the data was sent to.
449
613
  */
450
- private async publishToTopic(topic: string, data: Uint8Array) {
614
+ private async publishToTopic(topic: string, message: Gossipable) {
451
615
  if (!this.node.services.pubsub) {
452
616
  throw new Error('Pubsub service not available.');
453
617
  }
454
- const result = await this.node.services.pubsub.publish(topic, data);
455
-
618
+ const p2pMessage = P2PMessage.fromGossipable(message);
619
+ const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
456
620
  return result.recipients.length;
457
621
  }
458
622
 
623
+ /**
624
+ * Checks if this message has already been seen, based on its msgId computed from hashing the message data.
625
+ * Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
626
+ * messages to avoid tx echoes across the network.
627
+ */
628
+ protected preValidateReceivedMessage(
629
+ msg: Message,
630
+ msgId: string,
631
+ source: PeerId,
632
+ ): { result: boolean; topicType?: TopicType } {
633
+ let topicType: TopicType | undefined;
634
+
635
+ switch (msg.topic) {
636
+ case this.topicStrings[TopicType.tx]:
637
+ topicType = TopicType.tx;
638
+ break;
639
+ case this.topicStrings[TopicType.block_attestation]:
640
+ topicType = TopicType.block_attestation;
641
+ break;
642
+ case this.topicStrings[TopicType.block_proposal]:
643
+ topicType = TopicType.block_proposal;
644
+ break;
645
+ default:
646
+ this.logger.error(`Received message on unknown topic: ${msg.topic}`);
647
+ break;
648
+ }
649
+
650
+ const validator = topicType ? this.msgIdSeenValidators[topicType] : undefined;
651
+
652
+ if (!validator || !validator.addMessage(msgId)) {
653
+ this.instrumentation.incMessagePrevalidationStatus(false, topicType);
654
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
655
+ return { result: false, topicType };
656
+ }
657
+
658
+ this.instrumentation.incMessagePrevalidationStatus(true, topicType);
659
+
660
+ return { result: true, topicType };
661
+ }
662
+
459
663
  /**
460
664
  * Handles a new gossip message that was received by the client.
461
665
  * @param topic - The message's topic.
462
666
  * @param data - The message data
463
667
  */
464
- private async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
465
- if (msg.topic === Tx.p2pTopic) {
466
- await this.handleGossipedTx(msg, msgId, source);
668
+ protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
669
+ const p2pMessage = P2PMessage.fromMessageData(Buffer.from(msg.data));
670
+
671
+ const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
672
+
673
+ if (!preValidationResult.result) {
674
+ return;
675
+ }
676
+
677
+ if (msg.topic === this.topicStrings[TopicType.tx]) {
678
+ await this.handleGossipedTx(p2pMessage.payload, msgId, source);
467
679
  }
468
- if (msg.topic === BlockAttestation.p2pTopic && this.clientType === P2PClientType.Full) {
469
- await this.processAttestationFromPeer(msg, msgId, source);
680
+ if (msg.topic === this.topicStrings[TopicType.block_attestation] && this.clientType === P2PClientType.Full) {
681
+ await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
470
682
  }
471
- if (msg.topic == BlockProposal.p2pTopic) {
472
- await this.processBlockFromPeer(msg, msgId, source);
683
+ if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
684
+ await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
473
685
  }
474
686
 
475
687
  return;
476
688
  }
477
689
 
478
- private async validateReceivedMessage<T>(
479
- validationFunc: () => Promise<{ result: boolean; obj: T }>,
690
+ protected async validateReceivedMessage<T>(
691
+ validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
480
692
  msgId: string,
481
693
  source: PeerId,
482
- ): Promise<{ result: boolean; obj: T | undefined }> {
483
- let resultAndObj: { result: boolean; obj: T | undefined } = { result: false, obj: undefined };
694
+ topicType: TopicType,
695
+ ): Promise<ReceivedMessageValidationResult<T>> {
696
+ let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
697
+ const timer = new Timer();
484
698
  try {
485
699
  resultAndObj = await validationFunc();
486
700
  } catch (err) {
487
- this.logger.error(`Error deserialising and validating message `, err);
701
+ this.logger.error(`Error deserializing and validating gossipsub message`, err, {
702
+ msgId,
703
+ source: source.toString(),
704
+ topicType,
705
+ });
488
706
  }
489
707
 
490
- this.node.services.pubsub.reportMessageValidationResult(
491
- msgId,
492
- source.toString(),
493
- resultAndObj.result && resultAndObj.obj ? TopicValidatorResult.Accept : TopicValidatorResult.Reject,
494
- );
708
+ if (resultAndObj.result === TopicValidatorResult.Accept) {
709
+ this.instrumentation.recordMessageValidation(topicType, timer);
710
+ }
711
+
712
+ this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
495
713
  return resultAndObj;
496
714
  }
497
715
 
498
- private async handleGossipedTx(msg: Message, msgId: string, source: PeerId) {
499
- const validationFunc = async () => {
500
- const tx = Tx.fromBuffer(Buffer.from(msg.data));
501
- const result = await this.validatePropagatedTx(tx, source);
502
- return { result, obj: tx };
716
+ protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
717
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
718
+ const tx = Tx.fromBuffer(payloadData);
719
+ const isValid = await this.validatePropagatedTx(tx, source);
720
+ const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
721
+
722
+ this.logger.trace(`Validate propagated tx`, {
723
+ isValid,
724
+ exists,
725
+ [Attributes.P2P_ID]: source.toString(),
726
+ });
727
+
728
+ if (!isValid) {
729
+ return { result: TopicValidatorResult.Reject };
730
+ } else if (exists) {
731
+ return { result: TopicValidatorResult.Ignore, obj: tx };
732
+ } else {
733
+ return { result: TopicValidatorResult.Accept, obj: tx };
734
+ }
503
735
  };
504
736
 
505
- const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source);
506
- if (!result || !tx) {
737
+ const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
738
+ if (result !== TopicValidatorResult.Accept || !tx) {
507
739
  return;
508
740
  }
509
- const txHash = await tx.getTxHash();
741
+
742
+ const txHash = tx.getTxHash();
510
743
  const txHashString = txHash.toString();
511
- this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()}.`);
744
+ this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
745
+ source: source.toString(),
746
+ txHash: txHashString,
747
+ });
748
+
749
+ if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
750
+ this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
751
+ return;
752
+ }
753
+
512
754
  await this.mempools.txPool.addTxs([tx]);
513
755
  }
514
756
 
515
- /**Process Attestation From Peer
757
+ /**
758
+ * Process Attestation From Peer
516
759
  * When a proposal is received from a peer, we add it to the attestation pool, so it can be accessed by other services.
517
760
  *
518
761
  * @param attestation - The attestation to process.
519
762
  */
520
- private async processAttestationFromPeer(msg: Message, msgId: string, source: PeerId): Promise<void> {
521
- const validationFunc = async () => {
522
- const attestation = BlockAttestation.fromBuffer(Buffer.from(msg.data));
523
- const result = await this.validateAttestation(source, attestation);
524
- this.logger.trace(`validatePropagatedAttestation: ${result}`, {
525
- [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toString(),
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));
768
+
769
+ this.logger.trace(`Validate propagated block attestation`, {
770
+ isValid,
771
+ exists,
772
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
526
773
  [Attributes.P2P_ID]: source.toString(),
527
774
  });
528
- return { result, obj: attestation };
775
+
776
+ if (!isValid) {
777
+ return { result: TopicValidatorResult.Reject };
778
+ } else if (exists) {
779
+ return { result: TopicValidatorResult.Ignore, obj: attestation };
780
+ } else {
781
+ return { result: TopicValidatorResult.Accept, obj: attestation };
782
+ }
529
783
  };
530
784
 
531
785
  const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
532
786
  validationFunc,
533
787
  msgId,
534
788
  source,
789
+ TopicType.block_attestation,
535
790
  );
536
- if (!result || !attestation) {
791
+
792
+ if (result !== TopicValidatorResult.Accept || !attestation) {
537
793
  return;
538
794
  }
795
+
539
796
  this.logger.debug(
540
- `Received attestation for block ${attestation.blockNumber.toNumber()} slot ${attestation.slotNumber.toNumber()} from external peer.`,
797
+ `Received attestation for slot ${attestation.slotNumber.toNumber()} from external peer ${source.toString()}`,
541
798
  {
542
799
  p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
543
800
  slot: attestation.slotNumber.toNumber(),
544
801
  archive: attestation.archive.toString(),
545
- block: attestation.blockNumber.toNumber(),
802
+ source: source.toString(),
546
803
  },
547
804
  );
805
+
548
806
  await this.mempools.attestationPool!.addAttestations([attestation]);
549
807
  }
550
808
 
551
- private async processBlockFromPeer(msg: Message, msgId: string, source: PeerId): Promise<void> {
552
- const validationFunc = async () => {
553
- const block = BlockProposal.fromBuffer(Buffer.from(msg.data));
554
- const result = await this.validateBlockProposal(source, block);
555
- this.logger.trace(`validatePropagatedBlock: ${result}`, {
556
- [Attributes.SLOT_NUMBER]: block.payload.header.globalVariables.slotNumber.toString(),
809
+ private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
810
+ const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
811
+ const block = BlockProposal.fromBuffer(payloadData);
812
+ const isValid = await this.validateBlockProposal(source, block);
813
+
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));
817
+
818
+ this.logger.trace(`Validate propagated block proposal`, {
819
+ isValid,
820
+ exists,
821
+ [Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
557
822
  [Attributes.P2P_ID]: source.toString(),
558
823
  });
559
- return { result, obj: block };
824
+
825
+ if (!isValid) {
826
+ return { result: TopicValidatorResult.Reject };
827
+ } else if (exists) {
828
+ return { result: TopicValidatorResult.Ignore, obj: block };
829
+ } else {
830
+ return { result: TopicValidatorResult.Accept, obj: block };
831
+ }
560
832
  };
561
833
 
562
- const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(validationFunc, msgId, source);
834
+ const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
835
+ validationFunc,
836
+ msgId,
837
+ source,
838
+ TopicType.block_proposal,
839
+ );
840
+
563
841
  if (!result || !block) {
564
842
  return;
565
843
  }
566
- await this.processValidBlockProposal(block);
844
+
845
+ await this.processValidBlockProposal(block, source);
567
846
  }
568
847
 
569
848
  // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
570
849
  @trackSpan('Libp2pService.processValidBlockProposal', async block => ({
571
- [Attributes.BLOCK_NUMBER]: block.blockNumber.toNumber(),
572
850
  [Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
573
851
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
574
852
  [Attributes.P2P_ID]: await block.p2pMessageIdentifier().then(i => i.toString()),
575
853
  }))
576
- private async processValidBlockProposal(block: BlockProposal) {
577
- this.logger.verbose(
578
- `Received block ${block.blockNumber.toNumber()} for slot ${block.slotNumber.toNumber()} from external peer.`,
579
- {
580
- p2pMessageIdentifier: await block.p2pMessageIdentifier(),
581
- slot: block.slotNumber.toNumber(),
582
- archive: block.archive.toString(),
583
- block: block.blockNumber.toNumber(),
584
- },
585
- );
586
- const attestation = await this.blockReceivedCallback(block);
854
+ private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
855
+ const slot = block.slotNumber.toBigInt();
856
+ const previousSlot = slot - 1n;
857
+ 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(),
861
+ source: sender.toString(),
862
+ });
863
+ const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
864
+ if (attestationsForPreviousSlot !== undefined) {
865
+ this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
866
+ }
867
+
868
+ // Mark the txs in this proposal as non-evictable
869
+ await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
870
+ await this.mempools.attestationPool?.addBlockProposal(block);
871
+ const attestations = await this.blockReceivedCallback(block, sender);
587
872
 
588
873
  // TODO: fix up this pattern - the abstraction is not nice
589
874
  // The attestation can be undefined if no handler is registered / the validator deems the block invalid
590
- if (attestation != undefined) {
591
- this.logger.verbose(
592
- `Broadcasting attestation for block ${attestation.blockNumber.toNumber()} slot ${attestation.slotNumber.toNumber()}`,
593
- {
875
+ if (attestations?.length) {
876
+ for (const attestation of attestations) {
877
+ this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber.toNumber()}`, {
594
878
  p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
595
879
  slot: attestation.slotNumber.toNumber(),
596
880
  archive: attestation.archive.toString(),
597
- block: attestation.blockNumber.toNumber(),
598
- },
599
- );
600
- await this.broadcastAttestation(attestation);
881
+ });
882
+ await this.broadcastAttestation(attestation);
883
+ }
601
884
  }
602
885
  }
603
886
 
@@ -606,8 +889,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
606
889
  * @param attestation - The attestation to broadcast.
607
890
  */
608
891
  @trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
609
- [Attributes.BLOCK_NUMBER]: attestation.payload.header.globalVariables.blockNumber.toNumber(),
610
- [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
892
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
611
893
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
612
894
  [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
613
895
  }))
@@ -632,99 +914,198 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
632
914
  }
633
915
 
634
916
  /**
635
- * Validate a tx that has been requested from a peer.
917
+ * Validate the requested block transactions.
918
+ * @param request - The block transactions request.
919
+ * @param response - The block transactions response.
920
+ * @param peerId - The ID of the peer that made the request.
921
+ * @returns True if the requested block transactions are valid, false otherwise.
922
+ */
923
+ @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
924
+ [Attributes.BLOCK_HASH]: request.blockHash.toString(),
925
+ }))
926
+ private async validateRequestedBlockTxs(
927
+ _request: BlockTxsRequest,
928
+ response: BlockTxsResponse,
929
+ peerId: PeerId,
930
+ ): Promise<boolean> {
931
+ const requestedTxValidator = this.createRequestedTxValidator();
932
+
933
+ try {
934
+ // TODO(palla/txs): Validate that this tx belongs to the block hash being requested
935
+ await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
936
+ return true;
937
+ } catch (e: any) {
938
+ if (e instanceof ValidationError) {
939
+ this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
940
+ } else {
941
+ this.logger.error(`Error during validation of requested block txs`, e);
942
+ }
943
+
944
+ return false;
945
+ }
946
+ }
947
+
948
+ /**
949
+ * Validate a collection of txs that has been requested from a peer.
636
950
  *
637
- * The core component of this validator is that the tx hash MUST match the requested tx hash,
951
+ * The core component of this validator is that each tx hash MUST match the requested tx hash,
638
952
  * In order to perform this check, the tx proof must be verified.
639
953
  *
640
954
  * Note: This function is called from within `ReqResp.sendRequest` as part of the
641
955
  * ReqRespSubProtocol.TX subprotocol validation.
642
956
  *
643
- * @param requestedTxHash - The hash of the tx that was requested.
644
- * @param responseTx - The tx that was received as a response to the request.
957
+ * @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.
645
959
  * @param peerId - The peer ID of the peer that sent the tx.
646
- * @returns True if the tx is valid, false otherwise.
960
+ * @returns True if the whole collection of txs is valid, false otherwise.
647
961
  */
648
962
  @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
649
963
  [Attributes.TX_HASH]: requestedTxHash.toString(),
650
964
  }))
651
- private async validateRequestedTx(requestedTxHash: TxHash, responseTx: Tx, peerId: PeerId): Promise<boolean> {
652
- const proofValidator = new TxProofValidator(this.proofVerifier);
653
- const validProof = await proofValidator.validateTx(responseTx);
965
+ private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
966
+ const requested = new Set(requestedTxHash.map(h => h.toString()));
967
+ const requestedTxValidator = this.createRequestedTxValidator();
968
+
969
+ //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
970
+ // I think we should still extract the valid txs and return them, so that we can still use the response.
971
+ try {
972
+ await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
973
+ return true;
974
+ } catch (e: any) {
975
+ if (e instanceof ValidationError) {
976
+ this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
977
+ } else {
978
+ this.logger.error(`Error during validation of requested txs`, e);
979
+ }
654
980
 
655
- // If the node returns the wrong data, we penalize it
656
- if (!requestedTxHash.equals(await responseTx.getTxHash())) {
657
- // Returning the wrong data is a low tolerance error
658
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
659
981
  return false;
660
982
  }
983
+ }
661
984
 
662
- if (validProof.result === 'invalid') {
663
- // If the proof is invalid, but the txHash is correct, then this is an active attack and we severly punish
664
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
665
- return false;
985
+ private createRequestedTxValidator(): TxValidator {
986
+ return new AggregateTxValidator(
987
+ new DataTxValidator(),
988
+ new MetadataTxValidator({
989
+ l1ChainId: new Fr(this.config.l1ChainId),
990
+ rollupVersion: new Fr(this.config.rollupVersion),
991
+ protocolContractsHash,
992
+ vkTreeRoot: getVKTreeRoot(),
993
+ }),
994
+ new TxProofValidator(this.proofVerifier),
995
+ );
996
+ }
997
+
998
+ private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
999
+ if (!(await tx.validateTxHash())) {
1000
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1001
+ throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
666
1002
  }
667
1003
 
668
- return true;
1004
+ if (requested && !requested.has(tx.getTxHash().toString())) {
1005
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1006
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
1007
+ }
1008
+
1009
+ const { result } = await txValidator.validateTx(tx);
1010
+ if (result === 'invalid') {
1011
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1012
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
1013
+ }
669
1014
  }
670
1015
 
671
- @trackSpan('Libp2pService.validatePropagatedTx', async tx => ({
672
- [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
1016
+ @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
1017
+ [Attributes.TX_HASH]: tx.getTxHash().toString(),
673
1018
  }))
674
1019
  private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
675
- const blockNumber = (await this.l2BlockSource.getBlockNumber()) + 1;
676
- const messageValidators = this.createMessageValidators(blockNumber);
677
- const outcome = await this.runValidations(tx, messageValidators);
1020
+ const currentBlockNumber = await this.archiver.getBlockNumber();
678
1021
 
679
- if (outcome.allPassed) {
680
- return true;
1022
+ // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1023
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1024
+ const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1025
+
1026
+ for (const validator of messageValidators) {
1027
+ const outcome = await this.runValidations(tx, validator);
1028
+
1029
+ if (outcome.allPassed) {
1030
+ continue;
1031
+ }
1032
+ const { name } = outcome.failure;
1033
+ let { severity } = outcome.failure;
1034
+
1035
+ // Double spend validator has a special case handler
1036
+ if (name === 'doubleSpendValidator') {
1037
+ const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
1038
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1039
+ }
1040
+
1041
+ this.peerManager.penalizePeer(peerId, severity);
1042
+ return false;
681
1043
  }
682
- const { name } = outcome.failure;
683
- let { severity } = outcome.failure;
1044
+ return true;
1045
+ }
684
1046
 
685
- // Double spend validator has a special case handler
686
- if (name === 'doubleSpendValidator') {
687
- severity = await this.handleDoubleSpendFailure(tx, blockNumber);
1047
+ private async getGasFees(blockNumber: number): Promise<GasFees> {
1048
+ if (blockNumber === this.feesCache?.blockNumber) {
1049
+ return this.feesCache.gasFees;
688
1050
  }
689
1051
 
690
- this.peerManager.penalizePeer(peerId, severity);
691
- return false;
1052
+ const header = await this.archiver.getBlockHeader(blockNumber);
1053
+ const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
1054
+ this.feesCache = { blockNumber, gasFees };
1055
+ return gasFees;
1056
+ }
1057
+
1058
+ public async validate(txs: Tx[]): Promise<void> {
1059
+ const currentBlockNumber = await this.archiver.getBlockNumber();
1060
+
1061
+ // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1062
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1063
+ const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1064
+
1065
+ await Promise.all(
1066
+ txs.map(async tx => {
1067
+ for (const validator of messageValidators) {
1068
+ const outcome = await this.runValidations(tx, validator);
1069
+ if (!outcome.allPassed) {
1070
+ throw new Error('Invalid tx detected', { cause: { outcome } });
1071
+ }
1072
+ }
1073
+ }),
1074
+ );
692
1075
  }
693
1076
 
694
1077
  /**
695
- * Create message validators for the given block number.
1078
+ * Create message validators for the given block number and timestamp.
696
1079
  *
697
1080
  * Each validator is a pair of a validator and a severity.
698
1081
  * If a validator fails, the peer is penalized with the severity of the validator.
699
1082
  *
700
- * @param blockNumber - The block number to create validators for.
1083
+ * @param currentBlockNumber - The current synced block number.
1084
+ * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
701
1085
  * @returns The message validators.
702
1086
  */
703
- private createMessageValidators(blockNumber: number): Record<string, MessageValidator> {
704
- return {
705
- dataValidator: {
706
- validator: new DataTxValidator(),
707
- severity: PeerErrorSeverity.HighToleranceError,
708
- },
709
- metadataValidator: {
710
- validator: new MetadataTxValidator(new Fr(this.config.l1ChainId), new Fr(blockNumber)),
711
- severity: PeerErrorSeverity.HighToleranceError,
712
- },
713
- proofValidator: {
714
- validator: new TxProofValidator(this.proofVerifier),
715
- severity: PeerErrorSeverity.MidToleranceError,
716
- },
717
- doubleSpendValidator: {
718
- validator: new DoubleSpendTxValidator({
719
- nullifiersExist: async (nullifiers: Buffer[]) => {
720
- const merkleTree = this.worldStateSynchronizer.getCommitted();
721
- const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
722
- return indices.map(index => index !== undefined);
723
- },
724
- }),
725
- severity: PeerErrorSeverity.HighToleranceError,
726
- },
727
- };
1087
+ private async createMessageValidators(
1088
+ currentBlockNumber: number,
1089
+ nextSlotTimestamp: UInt64,
1090
+ ): Promise<Record<string, MessageValidator>[]> {
1091
+ const gasFees = await this.getGasFees(currentBlockNumber);
1092
+ const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1093
+
1094
+ const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
1095
+
1096
+ return createTxMessageValidators(
1097
+ nextSlotTimestamp,
1098
+ blockNumberInWhichTheTxIsConsideredToBeIncluded,
1099
+ this.worldStateSynchronizer,
1100
+ gasFees,
1101
+ this.config.l1ChainId,
1102
+ this.config.rollupVersion,
1103
+ protocolContractsHash,
1104
+ this.archiver,
1105
+ this.proofVerifier,
1106
+ !this.config.disableTransactions,
1107
+ allowedInSetup,
1108
+ );
728
1109
  }
729
1110
 
730
1111
  /**
@@ -739,28 +1120,26 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
739
1120
  ): Promise<ValidationOutcome> {
740
1121
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
741
1122
  const { result } = await validator.validateTx(tx);
742
- return { name, isValid: result === 'valid', severity };
1123
+ return { name, isValid: result !== 'invalid', severity };
743
1124
  });
744
1125
 
745
1126
  // A promise that resolves when all validations have been run
746
- const allValidations = Promise.all(validationPromises);
747
-
748
- // A promise that resolves when the first validation fails
749
- const firstFailure = Promise.race(
750
- validationPromises.map(async promise => {
751
- const result = await promise;
752
- return result.isValid ? new Promise(() => {}) : result;
753
- }),
754
- );
755
-
756
- // Wait for the first validation to fail or all validations to pass
757
- const result = await Promise.race([
758
- allValidations.then(() => ({ allPassed: true as const })),
759
- firstFailure.then(failure => ({ allPassed: false as const, failure: failure as ValidationResult })),
760
- ]);
761
-
762
- // If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
763
- return result;
1127
+ const allValidations = await Promise.all(validationPromises);
1128
+ const failed = allValidations.find(x => !x.isValid);
1129
+ if (failed) {
1130
+ return {
1131
+ allPassed: false,
1132
+ failure: {
1133
+ isValid: { result: 'invalid' as const, reason: ['Failed validation'] },
1134
+ name: failed.name,
1135
+ severity: failed.severity,
1136
+ },
1137
+ };
1138
+ } else {
1139
+ return {
1140
+ allPassed: true,
1141
+ };
1142
+ }
764
1143
  }
765
1144
 
766
1145
  /**
@@ -804,8 +1183,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
804
1183
  * @returns True if the attestation is valid, false otherwise.
805
1184
  */
806
1185
  @trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
807
- [Attributes.BLOCK_NUMBER]: attestation.payload.header.globalVariables.blockNumber.toNumber(),
808
- [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
1186
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
809
1187
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
810
1188
  [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
811
1189
  }))
@@ -826,11 +1204,12 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
826
1204
  * @returns True if the block proposal is valid, false otherwise.
827
1205
  */
828
1206
  @trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
829
- [Attributes.SLOT_NUMBER]: block.payload.header.globalVariables.slotNumber.toString(),
1207
+ [Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
830
1208
  }))
831
1209
  public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
832
1210
  const severity = await this.blockProposalValidator.validate(block);
833
1211
  if (severity) {
1212
+ this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
834
1213
  this.peerManager.penalizePeer(peerId, severity);
835
1214
  return false;
836
1215
  }
@@ -842,13 +1221,17 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
842
1221
  return this.node.services.pubsub.score.score(peerId.toString());
843
1222
  }
844
1223
 
1224
+ public handleAuthRequestFromPeer(authRequest: AuthRequest, peerId: PeerId): Promise<StatusMessage> {
1225
+ return this.peerManager.handleAuthRequestFromPeer(authRequest, peerId);
1226
+ }
1227
+
845
1228
  private async sendToPeers<T extends Gossipable>(message: T) {
846
1229
  const parent = message.constructor as typeof Gossipable;
847
1230
 
848
1231
  const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
849
1232
  this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
850
1233
 
851
- const recipientsNum = await this.publishToTopic(parent.p2pTopic, message.toBuffer());
1234
+ const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
852
1235
  this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, {
853
1236
  p2pMessageIdentifier: identifier,
854
1237
  sourcePeer: this.node.peerId.toString(),