@aztec/p2p 0.0.1-commit.cd76b27 → 0.0.1-commit.ce4f8c4f2

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 (267) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +5 -6
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +28 -26
  5. package/dest/client/interface.d.ts +6 -13
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +5 -13
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +25 -92
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +4 -5
  11. package/dest/config.d.ts +33 -15
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +86 -37
  14. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -4
  15. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  16. package/dest/mem_pools/attestation_pool/attestation_pool.js +8 -4
  17. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
  18. package/dest/mem_pools/instrumentation.d.ts +4 -2
  19. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  20. package/dest/mem_pools/instrumentation.js +16 -14
  21. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  22. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
  24. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  25. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool/priority.js +4 -4
  27. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  28. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  32. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +3 -2
  33. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  35. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +2 -0
  36. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  37. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  38. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  39. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  40. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  41. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +10 -6
  42. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  43. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  45. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  46. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  48. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  49. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  51. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +15 -9
  52. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/interfaces.js +3 -1
  54. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +48 -11
  55. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +81 -17
  57. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  58. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -44
  60. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +5 -3
  61. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  62. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +6 -0
  63. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +3 -2
  64. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  65. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +196 -151
  66. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  67. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  68. package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
  69. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  70. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  71. package/dest/msg_validators/clock_tolerance.js +4 -3
  72. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  73. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  74. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  75. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  76. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  77. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  78. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  79. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  80. package/dest/msg_validators/proposal_validator/proposal_validator.js +53 -41
  81. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  82. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  83. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  84. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  85. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  86. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  87. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  88. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  89. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  90. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  91. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  92. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  93. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  94. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  95. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  96. package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
  97. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/factory.js +247 -60
  99. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  100. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  101. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  102. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  103. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  104. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  105. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  106. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  107. package/dest/msg_validators/tx_validator/index.js +2 -0
  108. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  109. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  110. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  111. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  112. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  113. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  114. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  115. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  116. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  117. package/dest/services/discv5/discV5_service.d.ts +1 -1
  118. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  119. package/dest/services/discv5/discV5_service.js +4 -2
  120. package/dest/services/dummy_service.d.ts +2 -3
  121. package/dest/services/dummy_service.d.ts.map +1 -1
  122. package/dest/services/dummy_service.js +1 -4
  123. package/dest/services/encoding.d.ts +6 -2
  124. package/dest/services/encoding.d.ts.map +1 -1
  125. package/dest/services/encoding.js +14 -8
  126. package/dest/services/libp2p/libp2p_service.d.ts +20 -20
  127. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  128. package/dest/services/libp2p/libp2p_service.js +221 -143
  129. package/dest/services/peer-manager/metrics.d.ts +3 -1
  130. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  131. package/dest/services/peer-manager/metrics.js +6 -0
  132. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  133. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  134. package/dest/services/peer-manager/peer_manager.js +6 -3
  135. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
  136. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  137. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +82 -101
  138. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
  139. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  140. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  141. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  142. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  143. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
  144. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  145. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
  146. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  147. package/dest/services/reqresp/reqresp.d.ts +1 -1
  148. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  149. package/dest/services/reqresp/reqresp.js +19 -10
  150. package/dest/services/service.d.ts +8 -2
  151. package/dest/services/service.d.ts.map +1 -1
  152. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
  153. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  154. package/dest/services/tx_collection/fast_tx_collection.js +57 -73
  155. package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
  156. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  157. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  158. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  159. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  160. package/dest/services/tx_collection/request_tracker.js +84 -0
  161. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  162. package/dest/services/tx_collection/tx_collection.d.ts +3 -6
  163. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  164. package/dest/services/tx_provider.d.ts +3 -3
  165. package/dest/services/tx_provider.d.ts.map +1 -1
  166. package/dest/services/tx_provider.js +4 -4
  167. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  168. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  169. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  170. package/dest/test-helpers/mock-pubsub.d.ts +7 -3
  171. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  172. package/dest/test-helpers/mock-pubsub.js +11 -3
  173. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  174. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  175. package/dest/test-helpers/reqresp-nodes.js +2 -2
  176. package/dest/test-helpers/testbench-utils.d.ts +2 -2
  177. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  178. package/dest/test-helpers/testbench-utils.js +22 -3
  179. package/dest/testbench/p2p_client_testbench_worker.js +10 -9
  180. package/dest/testbench/worker_client_manager.d.ts +3 -1
  181. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  182. package/dest/testbench/worker_client_manager.js +6 -2
  183. package/dest/util.d.ts +9 -4
  184. package/dest/util.d.ts.map +1 -1
  185. package/dest/util.js +2 -9
  186. package/package.json +14 -14
  187. package/src/client/factory.ts +45 -45
  188. package/src/client/interface.ts +5 -19
  189. package/src/client/p2p_client.ts +26 -122
  190. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +5 -8
  191. package/src/config.ts +125 -43
  192. package/src/mem_pools/attestation_pool/attestation_pool.ts +8 -7
  193. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  194. package/src/mem_pools/instrumentation.ts +17 -13
  195. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  196. package/src/mem_pools/tx_pool/priority.ts +4 -4
  197. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  198. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  199. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +3 -2
  200. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -0
  201. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  202. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +2 -2
  203. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +10 -6
  204. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  205. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  206. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  207. package/src/mem_pools/tx_pool_v2/interfaces.ts +16 -8
  208. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +115 -20
  209. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
  210. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +17 -2
  211. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +207 -154
  212. package/src/msg_validators/attestation_validator/README.md +49 -0
  213. package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
  214. package/src/msg_validators/clock_tolerance.ts +4 -3
  215. package/src/msg_validators/proposal_validator/README.md +123 -0
  216. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  217. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  218. package/src/msg_validators/proposal_validator/proposal_validator.ts +69 -45
  219. package/src/msg_validators/tx_validator/README.md +119 -0
  220. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
  221. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  222. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  223. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  224. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  225. package/src/msg_validators/tx_validator/factory.ts +394 -78
  226. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  227. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  228. package/src/msg_validators/tx_validator/index.ts +2 -0
  229. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  230. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  231. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  232. package/src/services/discv5/discV5_service.ts +4 -2
  233. package/src/services/dummy_service.ts +1 -5
  234. package/src/services/encoding.ts +14 -7
  235. package/src/services/libp2p/libp2p_service.ts +235 -166
  236. package/src/services/peer-manager/metrics.ts +7 -0
  237. package/src/services/peer-manager/peer_manager.ts +7 -3
  238. package/src/services/reqresp/README.md +229 -0
  239. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  240. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +78 -111
  241. package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
  242. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  243. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
  244. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  245. package/src/services/reqresp/reqresp.ts +22 -12
  246. package/src/services/service.ts +8 -1
  247. package/src/services/tx_collection/fast_tx_collection.ts +57 -83
  248. package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
  249. package/src/services/tx_collection/request_tracker.ts +127 -0
  250. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  251. package/src/services/tx_collection/tx_collection.ts +3 -5
  252. package/src/services/tx_provider.ts +2 -2
  253. package/src/test-helpers/make-test-p2p-clients.ts +1 -3
  254. package/src/test-helpers/mock-pubsub.ts +12 -6
  255. package/src/test-helpers/reqresp-nodes.ts +3 -6
  256. package/src/test-helpers/testbench-utils.ts +30 -4
  257. package/src/testbench/p2p_client_testbench_worker.ts +7 -12
  258. package/src/testbench/worker_client_manager.ts +13 -5
  259. package/src/util.ts +9 -13
  260. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  261. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  262. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  263. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  264. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  265. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  266. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
  267. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
@@ -1,5 +1,6 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { maxBy } from '@aztec/foundation/collection';
3
4
  import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -16,13 +17,12 @@ import {
16
17
  CheckpointProposal,
17
18
  type CheckpointProposalCore,
18
19
  type Gossipable,
19
- P2PClientType,
20
20
  P2PMessage,
21
- type ValidationResult as P2PValidationResult,
22
21
  PeerErrorSeverity,
22
+ PeerErrorSeverityByHarshness,
23
23
  TopicType,
24
24
  createTopicString,
25
- getTopicsForClientAndConfig,
25
+ getTopicsForConfig,
26
26
  metricsTopicStrToLabels,
27
27
  } from '@aztec/stdlib/p2p';
28
28
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -51,9 +51,10 @@ import { yamux } from '@chainsafe/libp2p-yamux';
51
51
  import { bootstrap } from '@libp2p/bootstrap';
52
52
  import { identify } from '@libp2p/identify';
53
53
  import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
54
- import type { ConnectionManager } from '@libp2p/interface-internal';
54
+ import type { AddressManager, ConnectionManager } from '@libp2p/interface-internal';
55
55
  import { mplex } from '@libp2p/mplex';
56
56
  import { tcp } from '@libp2p/tcp';
57
+ import { multiaddr } from '@multiformats/multiaddr';
57
58
  import { ENR } from '@nethermindeth/enr';
58
59
  import { createLibp2p } from 'libp2p';
59
60
 
@@ -69,9 +70,11 @@ import {
69
70
  } from '../../msg_validators/index.js';
70
71
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
71
72
  import {
72
- type MessageValidator,
73
- createTxMessageValidators,
74
- createTxReqRespValidator,
73
+ type TransactionValidator,
74
+ createFirstStageTxValidationsForGossipedTransactions,
75
+ createSecondStageTxValidationsForGossipedTransactions,
76
+ createTxValidatorForBlockProposalReceivedTxs,
77
+ createTxValidatorForReqResponseReceivedTxs,
75
78
  } from '../../msg_validators/tx_validator/factory.js';
76
79
  import { GossipSubEvent } from '../../types/index.js';
77
80
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
@@ -87,6 +90,9 @@ import { PeerScoring } from '../peer-manager/peer_scoring.js';
87
90
  import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
88
91
  import type { P2PReqRespConfig } from '../reqresp/config.js';
89
92
  import {
93
+ AuthRequest,
94
+ BlockTxsRequest,
95
+ BlockTxsResponse,
90
96
  DEFAULT_SUB_PROTOCOL_VALIDATORS,
91
97
  type ReqRespInterface,
92
98
  type ReqRespResponse,
@@ -94,14 +100,9 @@ import {
94
100
  type ReqRespSubProtocolHandler,
95
101
  type ReqRespSubProtocolHandlers,
96
102
  type ReqRespSubProtocolValidators,
103
+ StatusMessage,
97
104
  type SubProtocolMap,
98
105
  ValidationError,
99
- } from '../reqresp/index.js';
100
- import {
101
- AuthRequest,
102
- BlockTxsRequest,
103
- BlockTxsResponse,
104
- StatusMessage,
105
106
  pingHandler,
106
107
  reqGoodbyeHandler,
107
108
  reqRespBlockHandler,
@@ -130,12 +131,12 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
130
131
  // REFACTOR: Unify with the type above
131
132
  type ReceivedMessageValidationResult<T, M = undefined> =
132
133
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
133
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
134
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
134
135
 
135
136
  /**
136
137
  * Lib P2P implementation of the P2PService interface.
137
138
  */
138
- export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
139
+ export class LibP2PService extends WithTracer implements P2PService {
139
140
  private discoveryRunningPromise?: RunningPromise;
140
141
  private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
141
142
 
@@ -174,6 +175,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
174
175
  private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
175
176
 
176
177
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
178
+ private ipChangedHandler?: (ip: string) => void;
179
+
180
+ /** Discovered public IP address (set when queryForIp is enabled and no static IP was configured). */
181
+ private discoveredP2pIp?: string;
177
182
 
178
183
  private instrumentation: P2PInstrumentation;
179
184
 
@@ -182,7 +187,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
182
187
  protected logger: Logger;
183
188
 
184
189
  constructor(
185
- private clientType: T,
186
190
  private config: P2PConfig,
187
191
  protected node: PubSubLibp2p,
188
192
  private peerDiscoveryService: PeerDiscoveryService,
@@ -224,10 +228,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
224
228
  this.protocolVersion,
225
229
  );
226
230
 
227
- this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
228
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
231
+ const proposalValidatorOpts = {
229
232
  txsPermitted: !config.disableTransactions,
230
- });
233
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
234
+ };
235
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
236
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
231
237
  this.checkpointAttestationValidator = config.fishermanMode
232
238
  ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
233
239
  : new CheckpointAttestationValidator(epochCache);
@@ -235,11 +241,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
235
241
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
236
242
 
237
243
  this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
238
- this.logger.debug(
239
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
244
+ this.logger.warn(
245
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
240
246
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
241
247
  );
242
- return false;
248
+ return true;
243
249
  };
244
250
 
245
251
  this.checkpointReceivedCallback = (
@@ -262,8 +268,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
262
268
  * @param txPool - The transaction pool to be accessed by the service.
263
269
  * @returns The new service.
264
270
  */
265
- public static async new<T extends P2PClientType>(
266
- clientType: T,
271
+ public static async new(
267
272
  config: P2PConfig,
268
273
  peerId: PeerId,
269
274
  deps: {
@@ -442,8 +447,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
442
447
  topics: topicScoreParams,
443
448
  }),
444
449
  }) as (components: GossipSubComponents) => GossipSub,
445
- components: (components: { connectionManager: ConnectionManager }) => ({
450
+ components: (components: { connectionManager: ConnectionManager; addressManager: AddressManager }) => ({
446
451
  connectionManager: components.connectionManager,
452
+ addressManager: components.addressManager,
447
453
  }),
448
454
  },
449
455
  logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
@@ -475,7 +481,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
475
481
  peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
476
482
 
477
483
  return new LibP2PService(
478
- clientType,
479
484
  config,
480
485
  node,
481
486
  peerDiscoveryService,
@@ -503,10 +508,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
503
508
 
504
509
  // Get listen & announce addresses for logging
505
510
  const { p2pIp, p2pPort } = this.config;
506
- if (!p2pIp) {
511
+ if (!p2pIp && !this.config.queryForIp) {
507
512
  throw new Error('Announce address not provided.');
508
513
  }
509
- const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
514
+ const announceTcpMultiaddr = p2pIp ? convertToMultiaddr(p2pIp, p2pPort, 'tcp') : undefined;
510
515
 
511
516
  // Create request response protocol handlers
512
517
  const txHandler = reqRespTxHandler(this.mempools);
@@ -549,7 +554,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
549
554
  await this.node.start();
550
555
 
551
556
  // Subscribe to standard GossipSub topics by default
552
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
557
+ for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
553
558
  this.subscribeToTopic(this.topicStrings[topic]);
554
559
  }
555
560
 
@@ -560,6 +565,31 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
560
565
  if (!this.config.p2pDiscoveryDisabled) {
561
566
  await this.peerDiscoveryService.start();
562
567
  }
568
+
569
+ // When queryForIp is enabled and no static IP was configured, bridge discv5 IP discovery to libp2p.
570
+ // Discv5 discovers our public IP via peer WHOAREYOU exchanges (enrUpdate=true) and emits 'ip:changed'.
571
+ // We confirm the discovered address in the libp2p AddressManager so it appears in getMultiaddrs()
572
+ // and is pushed to all connected peers via the identify protocol.
573
+ if (this.config.queryForIp && !p2pIp) {
574
+ this.ipChangedHandler = (ip: string) => {
575
+ const addressManager = this.node.services.components.addressManager;
576
+ const newAddr = multiaddr(convertToMultiaddr(ip, this.config.p2pPort, 'tcp'));
577
+
578
+ // Remove old discovered IP if one exists
579
+ if (this.discoveredP2pIp) {
580
+ const oldAddr = multiaddr(convertToMultiaddr(this.discoveredP2pIp, this.config.p2pPort, 'tcp'));
581
+ addressManager.removeObservedAddr(oldAddr);
582
+ }
583
+
584
+ addressManager.addObservedAddr(newAddr);
585
+ addressManager.confirmObservedAddr(newAddr);
586
+ // Store discovered IP
587
+ this.discoveredP2pIp = ip;
588
+ this.logger.info('Public IP discovered via discv5', { ip });
589
+ };
590
+ this.peerDiscoveryService.on('ip:changed', this.ipChangedHandler);
591
+ }
592
+
563
593
  this.discoveryRunningPromise = new RunningPromise(
564
594
  async () => {
565
595
  await this.peerManager.heartbeat();
@@ -572,7 +602,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
572
602
  this.logger.info(`Started P2P service`, {
573
603
  listen: this.config.listenAddress,
574
604
  port: this.config.p2pPort,
575
- announce: announceTcpMultiaddr,
605
+ announce: announceTcpMultiaddr ?? 'pending (queryForIp=true)',
576
606
  peerId: this.node.peerId.toString(),
577
607
  });
578
608
  }
@@ -585,6 +615,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
585
615
  // Remove gossip sub listener
586
616
  this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
587
617
 
618
+ // Remove ip:changed listener if registered
619
+ if (this.ipChangedHandler) {
620
+ this.peerDiscoveryService.off('ip:changed', this.ipChangedHandler);
621
+ this.ipChangedHandler = undefined;
622
+ }
623
+
588
624
  // Stop peer manager
589
625
  this.logger.debug('Stopping peer manager...');
590
626
  await this.peerManager.stop();
@@ -754,6 +790,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
754
790
  if (!validator || !validator.addMessage(msgId)) {
755
791
  this.instrumentation.incMessagePrevalidationStatus(false, topicType);
756
792
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
793
+ if (topicType === TopicType.tx) {
794
+ this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
795
+ }
757
796
  return { result: false, topicType };
758
797
  }
759
798
 
@@ -818,9 +857,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
818
857
  if (msg.topic === this.topicStrings[TopicType.tx]) {
819
858
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
820
859
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
821
- if (this.clientType === P2PClientType.Full) {
822
- await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
823
- }
860
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
824
861
  } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
825
862
  await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
826
863
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
@@ -882,47 +919,113 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
882
919
  source: PeerId,
883
920
  topicType: TopicType,
884
921
  ): Promise<ReceivedMessageValidationResult<T, M>> {
885
- let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
922
+ // Default to reject result with a penalty if validation function throws an error
923
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
924
+ result: TopicValidatorResult.Reject,
925
+ severity: PeerErrorSeverity.MidToleranceError,
926
+ };
886
927
  const timer = new Timer();
887
928
  try {
888
929
  resultAndObj = await validationFunc();
889
930
  } catch (err) {
890
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
891
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
892
- msgId,
893
- source: source.toString(),
894
- topicType,
895
- });
931
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
896
932
  }
897
933
 
898
934
  if (resultAndObj.result === TopicValidatorResult.Accept) {
935
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
899
936
  this.instrumentation.recordMessageValidation(topicType, timer);
937
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
938
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
939
+ msgId,
940
+ source: source.toString(),
941
+ topicType,
942
+ severity: resultAndObj.severity,
943
+ });
944
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
945
+ } else {
946
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
900
947
  }
901
948
 
902
949
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
903
950
  return resultAndObj;
904
951
  }
905
952
 
953
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
954
+ try {
955
+ return deserializeFunc();
956
+ } catch (err) {
957
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
958
+ err,
959
+ msgId,
960
+ source: source.toString(),
961
+ });
962
+ return undefined;
963
+ }
964
+ }
965
+
906
966
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
907
967
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
908
- const tx = Tx.fromBuffer(payloadData);
909
- const isValid = await this.validatePropagatedTx(tx, source);
910
- if (!isValid) {
911
- this.logger.trace(`Rejecting invalid propagated tx`, {
912
- [Attributes.P2P_ID]: source.toString(),
968
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
969
+ if (!tx) {
970
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
971
+ }
972
+
973
+ const currentBlockNumber = await this.archiver.getBlockNumber();
974
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
975
+
976
+ // Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
977
+ const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
978
+ const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
979
+ if (!firstStageOutcome.allPassed) {
980
+ const { name } = firstStageOutcome.failure;
981
+ let { severity } = firstStageOutcome.failure;
982
+
983
+ // Double spend validator has a special case handler. We perform more detailed examination
984
+ // as to how recently the nullifier was entered into the tree and if the transaction should
985
+ // have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
986
+ if (name === 'doubleSpendValidator') {
987
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1);
988
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
989
+ }
990
+
991
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
992
+ validator: name,
993
+ severity,
994
+ source: source.toString(),
995
+ });
996
+ return { result: TopicValidatorResult.Reject, severity };
997
+ }
998
+
999
+ // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
1000
+ const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
1001
+ if (canAdd === 'ignored') {
1002
+ this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
1003
+ source: source.toString(),
913
1004
  });
914
- return { result: TopicValidatorResult.Reject };
1005
+ return { result: TopicValidatorResult.Ignore, obj: tx };
915
1006
  }
916
1007
 
917
- // Propagate only on pool acceptance
1008
+ // Stage 2: expensive proof verification
1009
+ const secondStageValidators = this.createSecondStageMessageValidators();
1010
+ const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
1011
+ if (!secondStageOutcome.allPassed) {
1012
+ const { severity, name } = secondStageOutcome.failure;
1013
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
1014
+ validator: name,
1015
+ severity,
1016
+ source: source.toString(),
1017
+ });
1018
+ return { result: TopicValidatorResult.Reject, severity };
1019
+ }
1020
+
1021
+ // Pool add: persist the tx
918
1022
  const txHash = tx.getTxHash();
919
1023
  const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
920
1024
 
921
1025
  const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
922
1026
  const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
923
1027
 
924
- this.logger.trace(`Validate propagated tx`, {
925
- isValid,
1028
+ this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
926
1029
  wasAccepted,
927
1030
  wasIgnored,
928
1031
  [Attributes.P2P_ID]: source.toString(),
@@ -933,7 +1036,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
933
1036
  } else if (wasIgnored) {
934
1037
  return { result: TopicValidatorResult.Ignore, obj: tx };
935
1038
  } else {
936
- return { result: TopicValidatorResult.Reject };
1039
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
1040
+ source: source.toString(),
1041
+ txHash: txHash.toString(),
1042
+ });
1043
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
937
1044
  }
938
1045
  };
939
1046
 
@@ -963,7 +1070,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
963
1070
  source: PeerId,
964
1071
  ): Promise<void> {
965
1072
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
966
- () => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
1073
+ () => {
1074
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1075
+ if (!attestation) {
1076
+ return Promise.resolve({
1077
+ result: TopicValidatorResult.Reject,
1078
+ severity: PeerErrorSeverity.LowToleranceError,
1079
+ });
1080
+ }
1081
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1082
+ },
967
1083
  msgId,
968
1084
  source,
969
1085
  TopicType.checkpoint_attestation,
@@ -996,8 +1112,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
996
1112
 
997
1113
  if (validationResult.result === 'reject') {
998
1114
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
999
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1000
- return { result: TopicValidatorResult.Reject };
1115
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1001
1116
  }
1002
1117
 
1003
1118
  if (validationResult.result === 'ignore') {
@@ -1023,16 +1138,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1023
1138
  return { result: TopicValidatorResult.Ignore, obj: attestation };
1024
1139
  }
1025
1140
 
1026
- // Could not add (cap reached for signer), no need to re-broadcast
1141
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1027
1142
  if (!added) {
1028
- this.logger.warn(`Dropping checkpoint attestation due to cap`, {
1143
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1029
1144
  slot: slot.toString(),
1030
1145
  archive: attestation.archive.toString(),
1031
1146
  source: peerId.toString(),
1032
1147
  attester: attestation.getSender()?.toString(),
1033
1148
  count,
1034
1149
  });
1035
- return { result: TopicValidatorResult.Ignore, obj: attestation };
1150
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1036
1151
  }
1037
1152
 
1038
1153
  // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
@@ -1087,8 +1202,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1087
1202
 
1088
1203
  if (validationResult.result === 'reject') {
1089
1204
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1090
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1091
- return { result: TopicValidatorResult.Reject };
1205
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1092
1206
  }
1093
1207
 
1094
1208
  if (validationResult.result === 'ignore') {
@@ -1112,7 +1226,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1112
1226
 
1113
1227
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1114
1228
  if (!added) {
1115
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1116
1229
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1117
1230
  ...block.toBlockInfo(),
1118
1231
  indexWithinCheckpoint: block.indexWithinCheckpoint,
@@ -1120,7 +1233,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1120
1233
  proposer: block.getSender()?.toString(),
1121
1234
  source: peerId.toString(),
1122
1235
  });
1123
- return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
1236
+ return {
1237
+ result: TopicValidatorResult.Reject,
1238
+ metadata: { isEquivocated },
1239
+ severity: PeerErrorSeverity.HighToleranceError,
1240
+ };
1124
1241
  }
1125
1242
 
1126
1243
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1165,7 +1282,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1165
1282
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1166
1283
  const isValid = await this.blockReceivedCallback(block, sender);
1167
1284
  if (!isValid) {
1168
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1285
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1169
1286
  }
1170
1287
  }
1171
1288
 
@@ -1213,8 +1330,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1213
1330
 
1214
1331
  if (validationResult.result === 'reject') {
1215
1332
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1216
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1217
- return { result: TopicValidatorResult.Reject };
1333
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1218
1334
  }
1219
1335
 
1220
1336
  if (validationResult.result === 'ignore') {
@@ -1229,20 +1345,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1229
1345
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1230
1346
  [Attributes.P2P_ID]: peerId.toString(),
1231
1347
  });
1232
- const {
1233
- result,
1234
- obj,
1235
- metadata: { isEquivocated } = {},
1236
- } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1237
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1348
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1349
+ const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1350
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1238
1351
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1239
1352
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1240
1353
  [Attributes.P2P_ID]: peerId.toString(),
1241
1354
  isEquivocated,
1242
- result,
1355
+ result: blockProposalResult.result,
1243
1356
  });
1244
- return { result: TopicValidatorResult.Reject };
1245
- } else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1357
+ return {
1358
+ result: TopicValidatorResult.Reject,
1359
+ severity:
1360
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1361
+ };
1362
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1246
1363
  processBlock = true;
1247
1364
  }
1248
1365
  }
@@ -1269,13 +1386,17 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1269
1386
  // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1270
1387
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1271
1388
  if (!added) {
1272
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1273
1389
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1274
1390
  ...checkpoint.toCheckpointInfo(),
1275
1391
  count,
1276
1392
  source: peerId.toString(),
1277
1393
  });
1278
- return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
1394
+ return {
1395
+ result: TopicValidatorResult.Reject,
1396
+ obj: checkpoint,
1397
+ metadata: { isEquivocated, processBlock },
1398
+ severity: PeerErrorSeverity.HighToleranceError,
1399
+ };
1279
1400
  }
1280
1401
 
1281
1402
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1537,43 +1658,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1537
1658
  }
1538
1659
 
1539
1660
  protected createRequestedTxValidator(): TxValidator {
1540
- return createTxReqRespValidator(this.proofVerifier, {
1661
+ return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
1541
1662
  l1ChainId: this.config.l1ChainId,
1542
1663
  rollupVersion: this.config.rollupVersion,
1543
1664
  });
1544
1665
  }
1545
1666
 
1546
- @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
1547
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
1548
- }))
1549
- protected async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
1550
- const currentBlockNumber = await this.archiver.getBlockNumber();
1551
-
1552
- // We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
1553
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1554
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1555
-
1556
- for (const validator of messageValidators) {
1557
- const outcome = await this.runValidations(tx, validator);
1558
-
1559
- if (outcome.allPassed) {
1560
- continue;
1561
- }
1562
- const { name } = outcome.failure;
1563
- let { severity } = outcome.failure;
1564
-
1565
- // Double spend validator has a special case handler
1566
- if (name === 'doubleSpendValidator') {
1567
- const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1568
- severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1569
- }
1570
-
1571
- this.peerManager.penalizePeer(peerId, severity);
1572
- return false;
1573
- }
1574
- return true;
1575
- }
1576
-
1577
1667
  private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
1578
1668
  if (blockNumber === this.feesCache?.blockNumber) {
1579
1669
  return this.feesCache.gasFees;
@@ -1601,60 +1691,62 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1601
1691
  };
1602
1692
  }
1603
1693
 
1604
- public async validate(txs: Tx[]): Promise<void> {
1605
- const currentBlockNumber = await this.archiver.getBlockNumber();
1606
-
1607
- // We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
1608
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1609
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1694
+ public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
1695
+ const validator = createTxValidatorForBlockProposalReceivedTxs(
1696
+ this.proofVerifier,
1697
+ { l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
1698
+ this.logger.getBindings(),
1699
+ );
1610
1700
 
1611
- await Promise.all(
1701
+ const results = await Promise.all(
1612
1702
  txs.map(async tx => {
1613
- for (const validator of messageValidators) {
1614
- const outcome = await this.runValidations(tx, validator);
1615
- if (!outcome.allPassed) {
1616
- throw new Error('Invalid tx detected', { cause: { outcome } });
1617
- }
1618
- }
1703
+ const result = await validator.validateTx(tx);
1704
+ return result.result !== 'invalid';
1619
1705
  }),
1620
1706
  );
1707
+ if (results.some(value => value === false)) {
1708
+ throw new Error('Invalid tx detected');
1709
+ }
1621
1710
  }
1622
1711
 
1623
- /**
1624
- * Create message validators for the given block number and timestamp.
1625
- *
1626
- * Each validator is a pair of a validator and a severity.
1627
- * If a validator fails, the peer is penalized with the severity of the validator.
1628
- *
1629
- * @param currentBlockNumber - The current synced block number.
1630
- * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
1631
- * @returns The message validators.
1632
- */
1633
- private async createMessageValidators(
1712
+ /** Creates the first stage (fast) validators for gossiped transactions. */
1713
+ protected async createFirstStageMessageValidators(
1634
1714
  currentBlockNumber: BlockNumber,
1635
1715
  nextSlotTimestamp: UInt64,
1636
- ): Promise<Record<string, MessageValidator>[]> {
1716
+ ): Promise<Record<string, TransactionValidator>> {
1637
1717
  const gasFees = await this.getGasFees(currentBlockNumber);
1638
- const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1639
-
1640
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1641
-
1642
- return createTxMessageValidators(
1718
+ const allowedInSetup = [
1719
+ ...(await getDefaultAllowedSetupFunctions()),
1720
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
1721
+ ];
1722
+ const blockNumber = BlockNumber(currentBlockNumber + 1);
1723
+ const l1Constants = await this.archiver.getL1Constants();
1724
+
1725
+ return createFirstStageTxValidationsForGossipedTransactions(
1643
1726
  nextSlotTimestamp,
1644
- blockNumberInWhichTheTxIsConsideredToBeIncluded,
1727
+ blockNumber,
1645
1728
  this.worldStateSynchronizer,
1646
1729
  gasFees,
1647
1730
  this.config.l1ChainId,
1648
1731
  this.config.rollupVersion,
1649
1732
  protocolContractsHash,
1650
1733
  this.archiver,
1651
- this.proofVerifier,
1652
1734
  !this.config.disableTransactions,
1653
1735
  allowedInSetup,
1654
1736
  this.logger.getBindings(),
1737
+ {
1738
+ rollupManaLimit: l1Constants.rollupManaLimit,
1739
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1740
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1741
+ },
1655
1742
  );
1656
1743
  }
1657
1744
 
1745
+ /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
1746
+ protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
1747
+ return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
1748
+ }
1749
+
1658
1750
  /**
1659
1751
  * Run validations on a tx.
1660
1752
  * @param tx - The tx to validate.
@@ -1663,7 +1755,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1663
1755
  */
1664
1756
  private async runValidations(
1665
1757
  tx: Tx,
1666
- messageValidators: Record<string, MessageValidator>,
1758
+ messageValidators: Record<string, TransactionValidator>,
1667
1759
  ): Promise<ValidationOutcome> {
1668
1760
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
1669
1761
  const { result } = await validator.validateTx(tx);
@@ -1672,8 +1764,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1672
1764
 
1673
1765
  // A promise that resolves when all validations have been run
1674
1766
  const allValidations = await Promise.all(validationPromises);
1675
- const failed = allValidations.find(x => !x.isValid);
1676
- if (failed) {
1767
+ const failures = allValidations.filter(x => !x.isValid);
1768
+ if (failures.length > 0) {
1769
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1770
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1677
1771
  return {
1678
1772
  allPassed: false,
1679
1773
  failure: {
@@ -1726,31 +1820,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1726
1820
  return PeerErrorSeverity.HighToleranceError;
1727
1821
  }
1728
1822
 
1729
- /**
1730
- * Validate a checkpoint attestation.
1731
- *
1732
- * @param attestation - The checkpoint attestation to validate.
1733
- * @returns True if the checkpoint attestation is valid, false otherwise.
1734
- */
1735
- @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1736
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1737
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1738
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1739
- }))
1740
- public async validateCheckpointAttestation(
1741
- peerId: PeerId,
1742
- attestation: CheckpointAttestation,
1743
- ): Promise<P2PValidationResult> {
1744
- const result = await this.checkpointAttestationValidator.validate(attestation);
1745
-
1746
- if (result.result === 'reject') {
1747
- this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1748
- this.peerManager.penalizePeer(peerId, result.severity);
1749
- }
1750
-
1751
- return result;
1752
- }
1753
-
1754
1823
  public getPeerScore(peerId: PeerId): number {
1755
1824
  return this.node.services.pubsub.score.score(peerId.toString());
1756
1825
  }