@aztec/p2p 4.0.0-devnet.2-patch.4 → 4.0.0-devnet.3-patch.1

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 (212) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +4 -5
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +30 -28
  5. package/dest/client/interface.d.ts +8 -13
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +6 -13
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +22 -88
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +2 -4
  11. package/dest/config.d.ts +29 -10
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +80 -31
  14. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  15. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  16. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
  17. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  18. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  19. package/dest/mem_pools/tx_pool/priority.js +4 -4
  20. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  21. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  23. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +3 -2
  26. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
  27. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +2 -0
  29. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  32. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  33. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +10 -6
  35. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  36. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  38. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  39. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  41. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  42. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  44. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +9 -5
  45. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  47. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +46 -8
  48. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +81 -17
  50. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  51. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  52. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +9 -10
  53. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +5 -3
  54. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  55. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  56. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +2 -2
  57. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  58. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +179 -151
  59. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  60. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  62. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  63. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  64. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  65. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  66. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  67. package/dest/msg_validators/proposal_validator/proposal_validator.js +48 -36
  68. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  69. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  70. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  71. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  72. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  73. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  74. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  75. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  76. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  77. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  78. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  79. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  80. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  81. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  82. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  83. package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
  84. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  85. package/dest/msg_validators/tx_validator/factory.js +247 -60
  86. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  87. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  88. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  89. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  90. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  92. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  93. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  94. package/dest/msg_validators/tx_validator/index.js +2 -0
  95. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  96. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  97. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  98. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  99. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  100. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  101. package/dest/services/dummy_service.d.ts +4 -4
  102. package/dest/services/dummy_service.d.ts.map +1 -1
  103. package/dest/services/dummy_service.js +4 -4
  104. package/dest/services/encoding.d.ts +6 -2
  105. package/dest/services/encoding.d.ts.map +1 -1
  106. package/dest/services/encoding.js +14 -8
  107. package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
  108. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  109. package/dest/services/gossipsub/topic_score_params.js +32 -10
  110. package/dest/services/libp2p/libp2p_service.d.ts +16 -13
  111. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  112. package/dest/services/libp2p/libp2p_service.js +97 -93
  113. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  114. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  115. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  116. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  117. package/dest/services/reqresp/reqresp.d.ts +1 -1
  118. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  119. package/dest/services/reqresp/reqresp.js +16 -8
  120. package/dest/services/service.d.ts +5 -3
  121. package/dest/services/service.d.ts.map +1 -1
  122. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  123. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  124. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  125. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  126. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  127. package/dest/services/tx_collection/tx_source.js +9 -7
  128. package/dest/services/tx_provider.d.ts +3 -3
  129. package/dest/services/tx_provider.d.ts.map +1 -1
  130. package/dest/services/tx_provider.js +4 -4
  131. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  132. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  133. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  134. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  135. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  136. package/dest/test-helpers/mock-pubsub.js +8 -2
  137. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  138. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  139. package/dest/test-helpers/reqresp-nodes.js +2 -2
  140. package/dest/test-helpers/testbench-utils.d.ts +2 -2
  141. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  142. package/dest/test-helpers/testbench-utils.js +2 -1
  143. package/dest/testbench/p2p_client_testbench_worker.js +7 -6
  144. package/dest/testbench/worker_client_manager.d.ts +3 -1
  145. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  146. package/dest/testbench/worker_client_manager.js +4 -1
  147. package/dest/util.d.ts +2 -2
  148. package/dest/util.d.ts.map +1 -1
  149. package/package.json +14 -14
  150. package/src/client/factory.ts +49 -45
  151. package/src/client/interface.ts +8 -13
  152. package/src/client/p2p_client.ts +24 -117
  153. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +2 -3
  154. package/src/config.ts +115 -33
  155. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  156. package/src/mem_pools/tx_pool/priority.ts +4 -4
  157. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  158. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  159. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +3 -2
  160. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -0
  161. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  162. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +2 -2
  163. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +10 -6
  164. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  165. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  166. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  167. package/src/mem_pools/tx_pool_v2/interfaces.ts +9 -4
  168. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +113 -18
  169. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +11 -11
  170. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +14 -2
  171. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +188 -153
  172. package/src/msg_validators/attestation_validator/README.md +49 -0
  173. package/src/msg_validators/proposal_validator/README.md +123 -0
  174. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  175. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  176. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -40
  177. package/src/msg_validators/tx_validator/README.md +119 -0
  178. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
  179. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  180. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  181. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  182. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  183. package/src/msg_validators/tx_validator/factory.ts +394 -78
  184. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  185. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  186. package/src/msg_validators/tx_validator/index.ts +2 -0
  187. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  188. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  189. package/src/services/dummy_service.ts +6 -6
  190. package/src/services/encoding.ts +14 -7
  191. package/src/services/gossipsub/README.md +29 -14
  192. package/src/services/gossipsub/topic_score_params.ts +49 -13
  193. package/src/services/libp2p/libp2p_service.ts +111 -101
  194. package/src/services/reqresp/README.md +229 -0
  195. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  196. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  197. package/src/services/reqresp/reqresp.ts +18 -10
  198. package/src/services/service.ts +11 -2
  199. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  200. package/src/services/tx_collection/tx_source.ts +8 -7
  201. package/src/services/tx_provider.ts +2 -2
  202. package/src/test-helpers/make-test-p2p-clients.ts +0 -2
  203. package/src/test-helpers/mock-pubsub.ts +13 -6
  204. package/src/test-helpers/reqresp-nodes.ts +2 -5
  205. package/src/test-helpers/testbench-utils.ts +2 -1
  206. package/src/testbench/p2p_client_testbench_worker.ts +3 -6
  207. package/src/testbench/worker_client_manager.ts +11 -4
  208. package/src/util.ts +7 -1
  209. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  210. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  211. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  212. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
@@ -15,6 +15,8 @@ export type TopicScoringNetworkParams = {
15
15
  targetCommitteeSize: number;
16
16
  /** Duration per block in milliseconds when building multiple blocks per slot. If undefined, single block mode. */
17
17
  blockDurationMs?: number;
18
+ /** Expected number of block proposals per slot for scoring override. 0 disables scoring, undefined falls back to blocksPerSlot - 1. */
19
+ expectedBlockProposalsPerSlot?: number;
18
20
  };
19
21
 
20
22
  /**
@@ -89,18 +91,41 @@ export function computeThreshold(convergence: number, conservativeFactor: number
89
91
  return convergence * conservativeFactor;
90
92
  }
91
93
 
94
+ /**
95
+ * Determines the effective expected block proposals per slot for scoring.
96
+ * Returns undefined if scoring should be disabled, or a positive number if enabled.
97
+ *
98
+ * @param blocksPerSlot - Number of blocks per slot from timetable
99
+ * @param expectedBlockProposalsPerSlot - Config override. 0 disables scoring, undefined falls back to blocksPerSlot - 1.
100
+ * @returns Positive number of expected block proposals, or undefined if scoring is disabled
101
+ */
102
+ export function getEffectiveBlockProposalsPerSlot(
103
+ blocksPerSlot: number,
104
+ expectedBlockProposalsPerSlot?: number,
105
+ ): number | undefined {
106
+ if (expectedBlockProposalsPerSlot !== undefined) {
107
+ return expectedBlockProposalsPerSlot > 0 ? expectedBlockProposalsPerSlot : undefined;
108
+ }
109
+ // Fallback: In MBPS mode, N-1 block proposals per slot (last one bundled with checkpoint)
110
+ // In single block mode (blocksPerSlot=1), this is 0 → disabled
111
+ const fallback = Math.max(0, blocksPerSlot - 1);
112
+ return fallback > 0 ? fallback : undefined;
113
+ }
114
+
92
115
  /**
93
116
  * Gets the expected messages per slot for a given topic type.
94
117
  *
95
118
  * @param topicType - The topic type
96
119
  * @param targetCommitteeSize - Target committee size
97
120
  * @param blocksPerSlot - Number of blocks per slot
121
+ * @param expectedBlockProposalsPerSlot - Override for block proposals. 0 disables scoring, undefined falls back to blocksPerSlot - 1.
98
122
  * @returns Expected messages per slot, or undefined if unpredictable
99
123
  */
100
124
  export function getExpectedMessagesPerSlot(
101
125
  topicType: TopicType,
102
126
  targetCommitteeSize: number,
103
127
  blocksPerSlot: number,
128
+ expectedBlockProposalsPerSlot?: number,
104
129
  ): number | undefined {
105
130
  switch (topicType) {
106
131
  case TopicType.tx:
@@ -108,9 +133,7 @@ export function getExpectedMessagesPerSlot(
108
133
  return undefined;
109
134
 
110
135
  case TopicType.block_proposal:
111
- // In MBPS mode, N-1 block proposals per slot (last one bundled with checkpoint)
112
- // In single block mode (blocksPerSlot=1), this is 0
113
- return Math.max(0, blocksPerSlot - 1);
136
+ return getEffectiveBlockProposalsPerSlot(blocksPerSlot, expectedBlockProposalsPerSlot);
114
137
 
115
138
  case TopicType.checkpoint_proposal:
116
139
  // Exactly 1 checkpoint proposal per slot
@@ -190,10 +213,12 @@ const P2_DECAY_WINDOW_SLOTS = 2;
190
213
  // |P3| > 8 + 25 = 33
191
214
  //
192
215
  // We set P3 max = -34 per topic (slightly more than P1+P2) to ensure pruning.
193
- // With 3 topics having P3 enabled, total P3b after pruning = -102.
216
+ // The number of P3-enabled topics depends on config: by default 2 (checkpoint_proposal +
217
+ // checkpoint_attestation), or 3 if block proposal scoring is enabled via
218
+ // expectedBlockProposalsPerSlot. Total P3b after pruning = -68 (2 topics) or -102 (3 topics).
194
219
  //
195
- // With appSpecificWeight=10, ~20 HighTolerance errors (-40 app score) plus max P3b (-102)
196
- // would cross gossipThreshold (-500). This keeps non-contributors from being disconnected
220
+ // With appSpecificWeight=10, ~20 HighTolerance errors (-40 app score) plus max P3b (-68 or -102)
221
+ // would not cross gossipThreshold (-500). This keeps non-contributors from being disconnected
197
222
  // unless they also accrue app-level penalties.
198
223
  //
199
224
  // The weight formula ensures max penalty equals MAX_P3_PENALTY_PER_TOPIC:
@@ -203,12 +228,6 @@ const P2_DECAY_WINDOW_SLOTS = 2;
203
228
  /** Maximum P3 penalty per topic (must exceed P1 + P2 to cause pruning) */
204
229
  export const MAX_P3_PENALTY_PER_TOPIC = -(MAX_P1_SCORE + MAX_P2_SCORE + 1); // -34
205
230
 
206
- /** Number of topics with P3 enabled in MBPS mode (block_proposal + checkpoint_proposal + checkpoint_attestation) */
207
- export const NUM_P3_ENABLED_TOPICS = 3;
208
-
209
- /** Total maximum P3b penalty across all topics after pruning in MBPS mode */
210
- export const TOTAL_MAX_P3B_PENALTY = MAX_P3_PENALTY_PER_TOPIC * NUM_P3_ENABLED_TOPICS; // -102
211
-
212
231
  /**
213
232
  * Factory class for creating gossipsub topic scoring parameters.
214
233
  * Computes shared values once and reuses them across all topics.
@@ -384,6 +403,18 @@ export class TopicScoreParamsFactory {
384
403
  });
385
404
  }
386
405
 
406
+ /** Number of topics with P3 enabled, computed from config. Always 2 (checkpoint_proposal + checkpoint_attestation) plus optionally block_proposal. */
407
+ get numP3EnabledTopics(): number {
408
+ const blockProposalP3Enabled =
409
+ getEffectiveBlockProposalsPerSlot(this.blocksPerSlot, this.params.expectedBlockProposalsPerSlot) !== undefined;
410
+ return blockProposalP3Enabled ? 3 : 2;
411
+ }
412
+
413
+ /** Total maximum P3b penalty across all topics after pruning, computed from config */
414
+ get totalMaxP3bPenalty(): number {
415
+ return MAX_P3_PENALTY_PER_TOPIC * this.numP3EnabledTopics;
416
+ }
417
+
387
418
  /**
388
419
  * Creates topic score parameters for a specific topic type.
389
420
  *
@@ -391,7 +422,12 @@ export class TopicScoreParamsFactory {
391
422
  * @returns TopicScoreParams for the topic
392
423
  */
393
424
  createForTopic(topicType: TopicType): ReturnType<typeof createTopicScoreParams> {
394
- const expectedPerSlot = getExpectedMessagesPerSlot(topicType, this.params.targetCommitteeSize, this.blocksPerSlot);
425
+ const expectedPerSlot = getExpectedMessagesPerSlot(
426
+ topicType,
427
+ this.params.targetCommitteeSize,
428
+ this.blocksPerSlot,
429
+ this.params.expectedBlockProposalsPerSlot,
430
+ );
395
431
 
396
432
  // For unpredictable topics (tx) or topics with 0 expected messages, disable P3/P3b
397
433
  if (expectedPerSlot === undefined || expectedPerSlot === 0) {
@@ -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,13 @@ import {
16
17
  CheckpointProposal,
17
18
  type CheckpointProposalCore,
18
19
  type Gossipable,
19
- P2PClientType,
20
20
  P2PMessage,
21
21
  type ValidationResult as P2PValidationResult,
22
22
  PeerErrorSeverity,
23
+ PeerErrorSeverityByHarshness,
23
24
  TopicType,
24
25
  createTopicString,
25
- getTopicsForClientAndConfig,
26
+ getTopicsForConfig,
26
27
  metricsTopicStrToLabels,
27
28
  } from '@aztec/stdlib/p2p';
28
29
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -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,
@@ -135,7 +136,7 @@ type ReceivedMessageValidationResult<T, M = undefined> =
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
 
@@ -182,7 +183,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
182
183
  protected logger: Logger;
183
184
 
184
185
  constructor(
185
- private clientType: T,
186
186
  private config: P2PConfig,
187
187
  protected node: PubSubLibp2p,
188
188
  private peerDiscoveryService: PeerDiscoveryService,
@@ -224,10 +224,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
224
224
  this.protocolVersion,
225
225
  );
226
226
 
227
- this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
228
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
227
+ const proposalValidatorOpts = {
229
228
  txsPermitted: !config.disableTransactions,
230
- });
229
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
230
+ };
231
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
232
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
231
233
  this.checkpointAttestationValidator = config.fishermanMode
232
234
  ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
233
235
  : new CheckpointAttestationValidator(epochCache);
@@ -235,11 +237,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
235
237
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
236
238
 
237
239
  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.`,
240
+ this.logger.warn(
241
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
240
242
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
241
243
  );
242
- return false;
244
+ return true;
243
245
  };
244
246
 
245
247
  this.checkpointReceivedCallback = (
@@ -262,8 +264,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
262
264
  * @param txPool - The transaction pool to be accessed by the service.
263
265
  * @returns The new service.
264
266
  */
265
- public static async new<T extends P2PClientType>(
266
- clientType: T,
267
+ public static async new(
267
268
  config: P2PConfig,
268
269
  peerId: PeerId,
269
270
  deps: {
@@ -341,6 +342,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
341
342
  heartbeatIntervalMs: config.gossipsubInterval,
342
343
  targetCommitteeSize: l1Constants.targetCommitteeSize,
343
344
  blockDurationMs: config.blockDurationMs,
345
+ expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
344
346
  });
345
347
 
346
348
  const node = await createLibp2p({
@@ -474,7 +476,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
474
476
  peerManager.shouldDisableP2PGossip(peerId) ? -Infinity : peerManager.getPeerScore(peerId);
475
477
 
476
478
  return new LibP2PService(
477
- clientType,
478
479
  config,
479
480
  node,
480
481
  peerDiscoveryService,
@@ -548,7 +549,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
548
549
  await this.node.start();
549
550
 
550
551
  // Subscribe to standard GossipSub topics by default
551
- for (const topic of getTopicsForClientAndConfig(this.clientType, this.config.disableTransactions)) {
552
+ for (const topic of getTopicsForConfig(this.config.disableTransactions)) {
552
553
  this.subscribeToTopic(this.topicStrings[topic]);
553
554
  }
554
555
 
@@ -614,6 +615,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
614
615
  return this.peerManager.getPeers(includePending);
615
616
  }
616
617
 
618
+ public getGossipMeshPeerCount(topicType: TopicType): number {
619
+ return this.node.services.pubsub.getMeshPeers(this.topicStrings[topicType]).length;
620
+ }
621
+
617
622
  private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
618
623
  this.logger.trace(`Received PUBSUB message.`);
619
624
 
@@ -813,9 +818,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
813
818
  if (msg.topic === this.topicStrings[TopicType.tx]) {
814
819
  await this.handleGossipedTx(p2pMessage.payload, msgId, source);
815
820
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_attestation]) {
816
- if (this.clientType === P2PClientType.Full) {
817
- await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
818
- }
821
+ await this.processCheckpointAttestationFromPeer(p2pMessage.payload, msgId, source);
819
822
  } else if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
820
823
  await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
821
824
  } else if (msg.topic === this.topicStrings[TopicType.checkpoint_proposal]) {
@@ -901,15 +904,45 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
901
904
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
902
905
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
903
906
  const tx = Tx.fromBuffer(payloadData);
904
- const isValid = await this.validatePropagatedTx(tx, source);
905
- if (!isValid) {
906
- this.logger.trace(`Rejecting invalid propagated tx`, {
907
- [Attributes.P2P_ID]: source.toString(),
908
- });
907
+
908
+ const currentBlockNumber = await this.archiver.getBlockNumber();
909
+ const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
910
+
911
+ // Stage 1: fast validators (metadata, data, timestamps, double-spend, gas, phases, block header)
912
+ const firstStageValidators = await this.createFirstStageMessageValidators(currentBlockNumber, nextSlotTimestamp);
913
+ const firstStageOutcome = await this.runValidations(tx, firstStageValidators);
914
+ if (!firstStageOutcome.allPassed) {
915
+ const { name } = firstStageOutcome.failure;
916
+ let { severity } = firstStageOutcome.failure;
917
+
918
+ // Double spend validator has a special case handler. We perform more detailed examination
919
+ // as to how recently the nullifier was entered into the tree and if the transaction should
920
+ // have 'known' the nullifier existed. This determines the severity of the penalty applied to the peer.
921
+ if (name === 'doubleSpendValidator') {
922
+ const txBlockNumber = BlockNumber(currentBlockNumber + 1);
923
+ severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
924
+ }
925
+
926
+ this.peerManager.penalizePeer(source, severity);
909
927
  return { result: TopicValidatorResult.Reject };
910
928
  }
911
929
 
912
- // Propagate only on pool acceptance
930
+ // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
931
+ const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
932
+ if (canAdd === 'ignored') {
933
+ return { result: TopicValidatorResult.Ignore, obj: tx };
934
+ }
935
+
936
+ // Stage 2: expensive proof verification
937
+ const secondStageValidators = this.createSecondStageMessageValidators();
938
+ const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
939
+ if (!secondStageOutcome.allPassed) {
940
+ const { severity } = secondStageOutcome.failure;
941
+ this.peerManager.penalizePeer(source, severity);
942
+ return { result: TopicValidatorResult.Reject };
943
+ }
944
+
945
+ // Pool add: persist the tx
913
946
  const txHash = tx.getTxHash();
914
947
  const addResult = await this.mempools.txPool.addPendingTxs([tx], { source: 'gossip' });
915
948
 
@@ -917,7 +950,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
917
950
  const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
918
951
 
919
952
  this.logger.trace(`Validate propagated tx`, {
920
- isValid,
921
953
  wasAccepted,
922
954
  wasIgnored,
923
955
  [Attributes.P2P_ID]: source.toString(),
@@ -928,6 +960,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
928
960
  } else if (wasIgnored) {
929
961
  return { result: TopicValidatorResult.Ignore, obj: tx };
930
962
  } else {
963
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
964
+ source: source.toString(),
965
+ txHash: txHash.toString(),
966
+ });
967
+ this.peerManager.penalizePeer(source, PeerErrorSeverity.HighToleranceError);
931
968
  return { result: TopicValidatorResult.Reject };
932
969
  }
933
970
  };
@@ -1160,7 +1197,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1160
1197
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1161
1198
  const isValid = await this.blockReceivedCallback(block, sender);
1162
1199
  if (!isValid) {
1163
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1200
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1164
1201
  }
1165
1202
  }
1166
1203
 
@@ -1532,43 +1569,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1532
1569
  }
1533
1570
 
1534
1571
  protected createRequestedTxValidator(): TxValidator {
1535
- return createTxReqRespValidator(this.proofVerifier, {
1572
+ return createTxValidatorForReqResponseReceivedTxs(this.proofVerifier, {
1536
1573
  l1ChainId: this.config.l1ChainId,
1537
1574
  rollupVersion: this.config.rollupVersion,
1538
1575
  });
1539
1576
  }
1540
1577
 
1541
- @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
1542
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
1543
- }))
1544
- protected async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
1545
- const currentBlockNumber = await this.archiver.getBlockNumber();
1546
-
1547
- // We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
1548
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1549
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1550
-
1551
- for (const validator of messageValidators) {
1552
- const outcome = await this.runValidations(tx, validator);
1553
-
1554
- if (outcome.allPassed) {
1555
- continue;
1556
- }
1557
- const { name } = outcome.failure;
1558
- let { severity } = outcome.failure;
1559
-
1560
- // Double spend validator has a special case handler
1561
- if (name === 'doubleSpendValidator') {
1562
- const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
1563
- severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
1564
- }
1565
-
1566
- this.peerManager.penalizePeer(peerId, severity);
1567
- return false;
1568
- }
1569
- return true;
1570
- }
1571
-
1572
1578
  private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
1573
1579
  if (blockNumber === this.feesCache?.blockNumber) {
1574
1580
  return this.feesCache.gasFees;
@@ -1596,60 +1602,62 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1596
1602
  };
1597
1603
  }
1598
1604
 
1599
- public async validate(txs: Tx[]): Promise<void> {
1600
- const currentBlockNumber = await this.archiver.getBlockNumber();
1601
-
1602
- // We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
1603
- const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1604
- const messageValidators = await this.createMessageValidators(currentBlockNumber, nextSlotTimestamp);
1605
+ public async validateTxsReceivedInBlockProposal(txs: Tx[]): Promise<void> {
1606
+ const validator = createTxValidatorForBlockProposalReceivedTxs(
1607
+ this.proofVerifier,
1608
+ { l1ChainId: this.config.l1ChainId, rollupVersion: this.config.rollupVersion },
1609
+ this.logger.getBindings(),
1610
+ );
1605
1611
 
1606
- await Promise.all(
1612
+ const results = await Promise.all(
1607
1613
  txs.map(async tx => {
1608
- for (const validator of messageValidators) {
1609
- const outcome = await this.runValidations(tx, validator);
1610
- if (!outcome.allPassed) {
1611
- throw new Error('Invalid tx detected', { cause: { outcome } });
1612
- }
1613
- }
1614
+ const result = await validator.validateTx(tx);
1615
+ return result.result !== 'invalid';
1614
1616
  }),
1615
1617
  );
1618
+ if (results.some(value => value === false)) {
1619
+ throw new Error('Invalid tx detected');
1620
+ }
1616
1621
  }
1617
1622
 
1618
- /**
1619
- * Create message validators for the given block number and timestamp.
1620
- *
1621
- * Each validator is a pair of a validator and a severity.
1622
- * If a validator fails, the peer is penalized with the severity of the validator.
1623
- *
1624
- * @param currentBlockNumber - The current synced block number.
1625
- * @param nextSlotTimestamp - The timestamp of the next slot (used to validate txs are not expired).
1626
- * @returns The message validators.
1627
- */
1628
- private async createMessageValidators(
1623
+ /** Creates the first stage (fast) validators for gossiped transactions. */
1624
+ protected async createFirstStageMessageValidators(
1629
1625
  currentBlockNumber: BlockNumber,
1630
1626
  nextSlotTimestamp: UInt64,
1631
- ): Promise<Record<string, MessageValidator>[]> {
1627
+ ): Promise<Record<string, TransactionValidator>> {
1632
1628
  const gasFees = await this.getGasFees(currentBlockNumber);
1633
- const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
1634
-
1635
- const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
1636
-
1637
- return createTxMessageValidators(
1629
+ const allowedInSetup = [
1630
+ ...(await getDefaultAllowedSetupFunctions()),
1631
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
1632
+ ];
1633
+ const blockNumber = BlockNumber(currentBlockNumber + 1);
1634
+ const l1Constants = await this.archiver.getL1Constants();
1635
+
1636
+ return createFirstStageTxValidationsForGossipedTransactions(
1638
1637
  nextSlotTimestamp,
1639
- blockNumberInWhichTheTxIsConsideredToBeIncluded,
1638
+ blockNumber,
1640
1639
  this.worldStateSynchronizer,
1641
1640
  gasFees,
1642
1641
  this.config.l1ChainId,
1643
1642
  this.config.rollupVersion,
1644
1643
  protocolContractsHash,
1645
1644
  this.archiver,
1646
- this.proofVerifier,
1647
1645
  !this.config.disableTransactions,
1648
1646
  allowedInSetup,
1649
1647
  this.logger.getBindings(),
1648
+ {
1649
+ rollupManaLimit: l1Constants.rollupManaLimit,
1650
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1651
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1652
+ },
1650
1653
  );
1651
1654
  }
1652
1655
 
1656
+ /** Creates the second stage (expensive proof verification) validators for gossiped transactions. */
1657
+ protected createSecondStageMessageValidators(): Record<string, TransactionValidator> {
1658
+ return createSecondStageTxValidationsForGossipedTransactions(this.proofVerifier, this.logger.getBindings());
1659
+ }
1660
+
1653
1661
  /**
1654
1662
  * Run validations on a tx.
1655
1663
  * @param tx - The tx to validate.
@@ -1658,7 +1666,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1658
1666
  */
1659
1667
  private async runValidations(
1660
1668
  tx: Tx,
1661
- messageValidators: Record<string, MessageValidator>,
1669
+ messageValidators: Record<string, TransactionValidator>,
1662
1670
  ): Promise<ValidationOutcome> {
1663
1671
  const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
1664
1672
  const { result } = await validator.validateTx(tx);
@@ -1667,8 +1675,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1667
1675
 
1668
1676
  // A promise that resolves when all validations have been run
1669
1677
  const allValidations = await Promise.all(validationPromises);
1670
- const failed = allValidations.find(x => !x.isValid);
1671
- if (failed) {
1678
+ const failures = allValidations.filter(x => !x.isValid);
1679
+ if (failures.length > 0) {
1680
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1681
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1672
1682
  return {
1673
1683
  allPassed: false,
1674
1684
  failure: {