@aztec/p2p 0.0.1-commit.7035c9bd6 → 0.0.1-commit.71324e566

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 (225) hide show
  1. package/dest/client/factory.d.ts +1 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +5 -4
  4. package/dest/client/interface.d.ts +9 -2
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +3 -2
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +30 -10
  9. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +16 -6
  10. package/dest/config.d.ts +103 -99
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +10 -5
  13. package/dest/errors/p2p-service.error.d.ts +9 -0
  14. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  15. package/dest/errors/p2p-service.error.js +10 -0
  16. package/dest/index.d.ts +1 -2
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +0 -1
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -2
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.js +8 -5
  22. package/dest/mem_pools/index.d.ts +1 -2
  23. package/dest/mem_pools/index.d.ts.map +1 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  25. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +1 -1
  26. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  27. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +6 -2
  28. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
  29. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  30. package/dest/msg_validators/attestation_validator/attestation_validator.js +17 -9
  31. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -2
  32. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  33. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
  34. package/dest/msg_validators/clock_tolerance.d.ts +12 -1
  35. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  36. package/dest/msg_validators/clock_tolerance.js +50 -0
  37. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
  38. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  39. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +2 -1
  40. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  41. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
  42. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  43. package/dest/msg_validators/proposal_validator/proposal_validator.js +16 -8
  44. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  45. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  46. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  47. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  48. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  49. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  50. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  51. package/dest/msg_validators/tx_validator/factory.d.ts +1 -1
  52. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  53. package/dest/msg_validators/tx_validator/factory.js +8 -2
  54. package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
  55. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  56. package/dest/msg_validators/tx_validator/gas_validator.js +11 -9
  57. package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
  58. package/dest/services/data_store.d.ts +1 -1
  59. package/dest/services/data_store.d.ts.map +1 -1
  60. package/dest/services/data_store.js +5 -5
  61. package/dest/services/dummy_service.d.ts +6 -3
  62. package/dest/services/dummy_service.d.ts.map +1 -1
  63. package/dest/services/dummy_service.js +6 -1
  64. package/dest/services/gossipsub/topic_score_params.d.ts +13 -2
  65. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  66. package/dest/services/gossipsub/topic_score_params.js +21 -4
  67. package/dest/services/libp2p/libp2p_service.d.ts +15 -18
  68. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  69. package/dest/services/libp2p/libp2p_service.js +117 -91
  70. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  71. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  72. package/dest/services/peer-manager/peer_manager.js +35 -8
  73. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  74. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  75. package/dest/services/peer-manager/peer_scoring.js +32 -10
  76. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -1
  77. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  78. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +3 -0
  79. package/dest/services/reqresp/config.d.ts +3 -3
  80. package/dest/services/reqresp/config.d.ts.map +1 -1
  81. package/dest/services/reqresp/interface.d.ts +14 -9
  82. package/dest/services/reqresp/interface.d.ts.map +1 -1
  83. package/dest/services/reqresp/interface.js +10 -11
  84. package/dest/services/reqresp/metrics.d.ts +1 -1
  85. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  86. package/dest/services/reqresp/metrics.js +0 -1
  87. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  88. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  89. package/dest/services/reqresp/protocols/index.js +0 -1
  90. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  91. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  92. package/dest/services/reqresp/protocols/tx.js +1 -3
  93. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  94. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  95. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  96. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  97. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  98. package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
  99. package/dest/services/reqresp/reqresp.d.ts +4 -2
  100. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  101. package/dest/services/reqresp/reqresp.js +11 -2
  102. package/dest/services/service.d.ts +5 -2
  103. package/dest/services/service.d.ts.map +1 -1
  104. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  105. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  106. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  107. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  108. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  109. package/dest/services/tx_collection/tx_source.js +9 -7
  110. package/dest/test-helpers/mock-pubsub.d.ts +11 -3
  111. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  112. package/dest/test-helpers/mock-pubsub.js +35 -10
  113. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  114. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  115. package/dest/test-helpers/reqresp-nodes.js +1 -2
  116. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  117. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  118. package/dest/test-helpers/testbench-utils.js +1 -0
  119. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  120. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  121. package/dest/testbench/p2p_client_testbench_worker.js +65 -15
  122. package/dest/testbench/worker_client_manager.d.ts +8 -1
  123. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  124. package/dest/testbench/worker_client_manager.js +49 -1
  125. package/package.json +14 -14
  126. package/src/client/factory.ts +7 -2
  127. package/src/client/interface.ts +9 -1
  128. package/src/client/p2p_client.ts +34 -11
  129. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +17 -6
  130. package/src/config.ts +18 -6
  131. package/src/errors/p2p-service.error.ts +11 -0
  132. package/src/index.ts +0 -1
  133. package/src/mem_pools/attestation_pool/attestation_pool.ts +9 -5
  134. package/src/mem_pools/index.ts +0 -3
  135. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
  136. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +8 -2
  137. package/src/msg_validators/attestation_validator/attestation_validator.ts +18 -7
  138. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
  139. package/src/msg_validators/clock_tolerance.ts +68 -0
  140. package/src/msg_validators/proposal_validator/README.md +1 -1
  141. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -1
  142. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +4 -1
  143. package/src/msg_validators/proposal_validator/proposal_validator.ts +13 -7
  144. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  145. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  146. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  147. package/src/msg_validators/tx_validator/factory.ts +7 -0
  148. package/src/msg_validators/tx_validator/gas_validator.ts +25 -9
  149. package/src/msg_validators/tx_validator/phases_validator.ts +1 -1
  150. package/src/services/data_store.ts +5 -13
  151. package/src/services/dummy_service.ts +8 -2
  152. package/src/services/gossipsub/topic_score_params.ts +36 -4
  153. package/src/services/libp2p/libp2p_service.ts +117 -102
  154. package/src/services/peer-manager/peer_manager.ts +40 -8
  155. package/src/services/peer-manager/peer_scoring.ts +27 -5
  156. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +3 -0
  157. package/src/services/reqresp/config.ts +2 -2
  158. package/src/services/reqresp/interface.ts +21 -11
  159. package/src/services/reqresp/metrics.ts +0 -1
  160. package/src/services/reqresp/protocols/index.ts +0 -1
  161. package/src/services/reqresp/protocols/tx.ts +1 -3
  162. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  163. package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
  164. package/src/services/reqresp/reqresp.ts +18 -1
  165. package/src/services/service.ts +6 -1
  166. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  167. package/src/services/tx_collection/tx_source.ts +8 -7
  168. package/src/test-helpers/mock-pubsub.ts +31 -5
  169. package/src/test-helpers/reqresp-nodes.ts +2 -2
  170. package/src/test-helpers/testbench-utils.ts +1 -0
  171. package/src/testbench/p2p_client_testbench_worker.ts +70 -12
  172. package/src/testbench/worker_client_manager.ts +55 -1
  173. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  174. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  175. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  176. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  177. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  178. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  179. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  180. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  181. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  182. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  183. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  184. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
  185. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  186. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  187. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  188. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  189. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  190. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  191. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  192. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  193. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  194. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  195. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  196. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  197. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  198. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  199. package/dest/mem_pools/tx_pool/index.js +0 -2
  200. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  201. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  202. package/dest/mem_pools/tx_pool/priority.js +0 -15
  203. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  204. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  205. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  206. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  207. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  208. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
  209. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  210. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  211. package/dest/services/reqresp/protocols/block.js +0 -32
  212. package/src/mem_pools/tx_pool/README.md +0 -270
  213. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  214. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  215. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  216. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
  217. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  218. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  219. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  220. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  221. package/src/mem_pools/tx_pool/index.ts +0 -2
  222. package/src/mem_pools/tx_pool/priority.ts +0 -20
  223. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  224. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
  225. package/src/services/reqresp/protocols/block.ts +0 -37
package/src/config.ts CHANGED
@@ -39,7 +39,14 @@ export interface P2PConfig
39
39
  ChainConfig,
40
40
  TxCollectionConfig,
41
41
  TxFileStoreConfig,
42
- Pick<SequencerConfig, 'blockDurationMs' | 'expectedBlockProposalsPerSlot' | 'maxTxsPerBlock'> {
42
+ Pick<
43
+ SequencerConfig,
44
+ | 'blockDurationMs'
45
+ | 'expectedBlockProposalsPerSlot'
46
+ | 'l1PublishingTime'
47
+ | 'maxTxsPerBlock'
48
+ | 'attestationPropagationTime'
49
+ > {
43
50
  /** Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set. */
44
51
  validateMaxTxsPerBlock?: number;
45
52
 
@@ -218,23 +225,23 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
218
225
  env: 'VALIDATOR_MAX_TX_PER_BLOCK',
219
226
  description:
220
227
  'Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set.',
221
- parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
228
+ parseEnv: (val: string) => parseInt(val, 10),
222
229
  },
223
230
  validateMaxTxsPerCheckpoint: {
224
231
  env: 'VALIDATOR_MAX_TX_PER_CHECKPOINT',
225
232
  description:
226
233
  'Maximum transactions per checkpoint for validation. Used as fallback for maxTxsPerBlock when that is not set.',
227
- parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
234
+ parseEnv: (val: string) => parseInt(val, 10),
228
235
  },
229
236
  validateMaxL2BlockGas: {
230
237
  env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
231
238
  description: 'Maximum L2 gas per block for validation. When set, txs exceeding this limit are rejected.',
232
- parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
239
+ parseEnv: (val: string) => parseInt(val, 10),
233
240
  },
234
241
  validateMaxDABlockGas: {
235
242
  env: 'VALIDATOR_MAX_DA_BLOCK_GAS',
236
243
  description: 'Maximum DA gas per block for validation. When set, txs exceeding this limit are rejected.',
237
- parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
244
+ parseEnv: (val: string) => parseInt(val, 10),
238
245
  },
239
246
  p2pEnabled: {
240
247
  env: 'P2P_ENABLED',
@@ -436,7 +443,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
436
443
  },
437
444
  p2pStoreMapSizeKb: {
438
445
  env: 'P2P_STORE_MAP_SIZE_KB',
439
- parseEnv: (val: string | undefined) => (val ? +val : undefined),
446
+ parseEnv: (val: string) => +val,
440
447
  description: 'The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb.',
441
448
  },
442
449
  txPublicSetupAllowListExtend: {
@@ -495,6 +502,11 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
495
502
  description: 'Alters the format of p2p messages to include things like broadcast timestamp FOR TESTING ONLY',
496
503
  ...booleanConfigHelper(false),
497
504
  },
505
+ l1PublishingTime: {
506
+ env: 'SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT',
507
+ description: 'How much time (in seconds) we allow in the slot for publishing the L1 tx (defaults to 1 L1 slot).',
508
+ parseEnv: (val: string) => parseInt(val, 10),
509
+ },
498
510
  fishermanMode: {
499
511
  env: 'FISHERMAN_MODE',
500
512
  description:
@@ -0,0 +1,11 @@
1
+ /** Checkpoint Proposal Received Callback Not Registered Error
2
+ *
3
+ * Error triggered if the allNodesCheckpointReceivedCallback is not registered
4
+ * @category Errors
5
+ */
6
+ export class CheckpointProposalReceivedCallbackNotRegisteredError extends Error {
7
+ constructor() {
8
+ super('FATAL (allNodesCheckpointReceivedCallback): All nodes should register a checkpoint proposal handler');
9
+ this.name = 'CheckpointProposalReceivedCallbackNotRegisteredError';
10
+ }
11
+ }
package/src/index.ts CHANGED
@@ -6,7 +6,6 @@ export * from './client/index.js';
6
6
  export * from './enr/index.js';
7
7
  export * from './config.js';
8
8
  export * from './mem_pools/attestation_pool/index.js';
9
- export * from './mem_pools/tx_pool/index.js';
10
9
  export * from './mem_pools/tx_pool_v2/index.js';
11
10
  export * from './msg_validators/index.js';
12
11
  export * from './services/index.js';
@@ -154,14 +154,16 @@ export class AttestationPool {
154
154
  /** Maximum indexWithinCheckpoint value (2^10 - 1 = 1023). */
155
155
  private static readonly MAX_INDEX = (1 << AttestationPool.INDEX_BITS) - 1;
156
156
 
157
- /** Creates a position key for block proposals: (slot << 10) | indexWithinCheckpoint. */
157
+ /** Creates a position key for block proposals: slot * 1024 + indexWithinCheckpoint.
158
+ * Uses multiplication instead of bit-shift to avoid 32-bit signed integer overflow
159
+ * (bit-shift overflows after slot ~2^21, roughly 278 days of uptime). */
158
160
  private getBlockPositionKey(slot: number, indexWithinCheckpoint: number): number {
159
161
  if (indexWithinCheckpoint > AttestationPool.MAX_INDEX) {
160
162
  throw new Error(
161
163
  `Value for indexWithinCheckpoint ${indexWithinCheckpoint} exceeds maximum ${AttestationPool.MAX_INDEX}`,
162
164
  );
163
165
  }
164
- return (slot << AttestationPool.INDEX_BITS) | indexWithinCheckpoint;
166
+ return slot * (1 << AttestationPool.INDEX_BITS) + indexWithinCheckpoint;
165
167
  }
166
168
 
167
169
  /**
@@ -278,7 +280,7 @@ export class AttestationPool {
278
280
  * @returns Result indicating whether the proposal was added and duplicate detection info
279
281
  */
280
282
  public async tryAddCheckpointProposal(proposal: CheckpointProposalCore): Promise<TryAddResult> {
281
- return await this.store.transactionAsync(async () => {
283
+ const result = await this.store.transactionAsync(async () => {
282
284
  const proposalId = proposal.archive.toString();
283
285
 
284
286
  // Check if already exists
@@ -304,6 +306,8 @@ export class AttestationPool {
304
306
 
305
307
  return { added: true, alreadyExists: false, count: count + 1 };
306
308
  });
309
+
310
+ return result;
307
311
  }
308
312
 
309
313
  /** Internal method - must be called within a transaction. */
@@ -345,7 +349,7 @@ export class AttestationPool {
345
349
  await this.store.transactionAsync(async () => {
346
350
  for (const attestation of attestations) {
347
351
  const slotNumber = attestation.payload.header.slotNumber;
348
- const proposalId = attestation.archive;
352
+ const proposalId = attestation.archive.toString();
349
353
  const sender = attestation.getSender();
350
354
 
351
355
  // Skip attestations with invalid signatures
@@ -452,7 +456,7 @@ export class AttestationPool {
452
456
 
453
457
  // Delete block proposals for slots < oldestSlot, using blockProposalsForSlotAndIndex as index
454
458
  // Key format: (slot << INDEX_BITS) | indexWithinCheckpoint
455
- const blockPositionEndKey = oldestSlot << AttestationPool.INDEX_BITS;
459
+ const blockPositionEndKey = oldestSlot * (1 << AttestationPool.INDEX_BITS);
456
460
  for await (const positionKey of this.blockProposalsForSlotAndIndex.keysAsync({ end: blockPositionEndKey })) {
457
461
  const proposalIds = await toArray(this.blockProposalsForSlotAndIndex.getValuesAsync(positionKey));
458
462
  for (const proposalId of proposalIds) {
@@ -1,6 +1,3 @@
1
1
  export { AttestationPool, type AttestationPoolApi } from './attestation_pool/attestation_pool.js';
2
2
  export { type MemPools } from './interface.js';
3
- // Old TxPool exports - kept temporarily for external consumers
4
- export { type TxPool } from './tx_pool/tx_pool.js';
5
- // New TxPoolV2 exports
6
3
  export { type TxPoolV2, type TxPoolV2Config, type TxPoolV2Events, type AddTxsResult } from './tx_pool_v2/index.js';
@@ -1,5 +1,5 @@
1
- import { Fr } from '@aztec/foundation/curves/bn254';
2
1
  import { createLogger } from '@aztec/foundation/log';
2
+ import { BlockHash } from '@aztec/stdlib/block';
3
3
  import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
4
4
  import { MerkleTreeId } from '@aztec/stdlib/trees';
5
5
 
@@ -33,14 +33,14 @@ export class InvalidTxsAfterReorgRule implements EvictionRule {
33
33
  const pendingTxs = pool.getPendingTxs();
34
34
 
35
35
  // Deduplicate block hashes to reduce redundant DB lookups
36
- const uniqueBlockHashes = new Map<string, Fr>();
36
+ const uniqueBlockHashes = new Map<string, BlockHash>();
37
37
  const txsByBlockHash = new Map<string, string[]>();
38
38
 
39
39
  for (const meta of pendingTxs) {
40
40
  const blockHashStr = meta.anchorBlockHeaderHash;
41
41
  if (!txsByBlockHash.has(blockHashStr)) {
42
42
  txsByBlockHash.set(blockHashStr, []);
43
- uniqueBlockHashes.set(blockHashStr, Fr.fromHexString(blockHashStr));
43
+ uniqueBlockHashes.set(blockHashStr, BlockHash.fromString(blockHashStr));
44
44
  }
45
45
  txsByBlockHash.get(blockHashStr)!.push(meta.txHash);
46
46
  }
@@ -1,3 +1,4 @@
1
+ import { minBigint } from '@aztec/foundation/bigint';
1
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
3
  import { Fr } from '@aztec/foundation/curves/bn254';
3
4
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
@@ -6,7 +7,6 @@ import { Gas } from '@aztec/stdlib/gas';
6
7
  import { type Tx, TxHash } from '@aztec/stdlib/tx';
7
8
 
8
9
  import { getFeePayerBalanceDelta } from '../../msg_validators/tx_validator/fee_payer_balance.js';
9
- import { getTxPriorityFee } from '../tx_pool/priority.js';
10
10
  import { type PreAddResult, TxPoolRejectionCode } from './eviction/interfaces.js';
11
11
 
12
12
  /** Validator-compatible data interface, mirroring the subset of PrivateKernelTailCircuitPublicInputs used by validators. */
@@ -291,7 +291,7 @@ export function stubTxMetaValidationData(overrides: { expirationTimestamp?: bigi
291
291
  expirationTimestamp: overrides.expirationTimestamp ?? 0n,
292
292
  constants: {
293
293
  anchorBlockHeader: {
294
- hash: () => Promise.resolve(new BlockHash(Fr.ZERO)),
294
+ hash: () => Promise.resolve(BlockHash.ZERO),
295
295
  globalVariables: { blockNumber: BlockNumber(0) },
296
296
  },
297
297
  txContext: {
@@ -335,3 +335,9 @@ export function stubTxMetaData(
335
335
  data: stubTxMetaValidationData({ expirationTimestamp }),
336
336
  };
337
337
  }
338
+
339
+ /** Returns the priority fee for a tx, based on the L2 priority fee capped by the max fee per gas. */
340
+ function getTxPriorityFee(tx: Tx): bigint {
341
+ const { maxPriorityFeesPerGas: priorityFees, maxFeesPerGas } = tx.getGasSettings();
342
+ return minBigint(maxFeesPerGas.feePerL2Gas, priorityFees.feePerL2Gas);
343
+ }
@@ -8,14 +8,21 @@ import {
8
8
  type ValidationResult,
9
9
  } from '@aztec/stdlib/p2p';
10
10
 
11
- import { isWithinClockTolerance } from '../clock_tolerance.js';
11
+ import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
12
12
 
13
13
  export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
14
14
  protected epochCache: EpochCacheInterface;
15
15
  protected logger: Logger;
16
+ private readonly pipeliningWindow: PipeliningWindow;
16
17
 
17
- constructor(epochCache: EpochCacheInterface) {
18
+ constructor(
19
+ epochCache: EpochCacheInterface,
20
+ opts: {
21
+ l1PublishingTime?: number;
22
+ },
23
+ ) {
18
24
  this.epochCache = epochCache;
25
+ this.pipeliningWindow = new PipeliningWindow(epochCache, { l1PublishingTime: opts.l1PublishingTime });
19
26
  this.logger = createLogger('p2p:checkpoint-attestation-validator');
20
27
  }
21
28
 
@@ -23,19 +30,23 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
23
30
  const slotNumber = message.payload.header.slotNumber;
24
31
 
25
32
  try {
26
- // Use target slots since proposals target pipeline slots (slot + 1 when pipelining)
33
+ // Use target slots since proposals target pipeline slots (slot + 1 when pipelining).
27
34
  const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
28
35
 
29
36
  if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
30
- // Check if message is for previous slot and within clock tolerance
31
- if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
37
+ // When pipelining, accept attestations for the current slot (built in the previous slot)
38
+ // until the target slot reaches its L1 publish cutoff.
39
+ if (this.pipeliningWindow.acceptsAttestation(slotNumber)) {
40
+ // Fall through to remaining validation (signature, committee, etc.)
41
+ } else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
32
42
  this.logger.warn(
33
43
  `Checkpoint attestation slot ${slotNumber} is not current (${targetSlot}) or next (${nextSlot}) slot`,
34
44
  );
35
45
  return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
46
+ } else {
47
+ this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
48
+ return { result: 'ignore' };
36
49
  }
37
- this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
38
- return { result: 'ignore' };
39
50
  }
40
51
 
41
52
  // Verify the signature is valid
@@ -20,8 +20,11 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
20
20
  epochCache: EpochCacheInterface,
21
21
  private attestationPool: AttestationPoolApi,
22
22
  telemetryClient: TelemetryClient,
23
+ opts: {
24
+ l1PublishingTime?: number;
25
+ } = {},
23
26
  ) {
24
- super(epochCache);
27
+ super(epochCache, opts);
25
28
  this.logger = this.logger.createChild('[FISHERMAN]');
26
29
 
27
30
  const meter = telemetryClient.getMeter('FishermanAttestationValidator');
@@ -1,5 +1,6 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { DEFAULT_P2P_PROPAGATION_TIME, createPipelinedCheckpointTimingModel } from '@aztec/stdlib/timetable';
3
4
 
4
5
  /**
5
6
  * Maximum clock disparity tolerance for P2P message validation (in milliseconds).
@@ -50,3 +51,70 @@ export function isWithinClockTolerance(
50
51
 
51
52
  return elapsedMs < MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
52
53
  }
54
+
55
+ /**
56
+ * Checks if a message should be accepted under the pipelining grace period.
57
+ *
58
+ * When pipelining is enabled, `targetSlot = slotNow + 1`. A proposal built in slot N-1
59
+ * for slot N arrives when validators are in slot N, so their `targetSlot = N+1`.
60
+ * This function accepts proposals for the current wallclock slot if we're within the
61
+ * first `windowSeconds` seconds of the slot (the pipelining grace period). - see stdlib/timetable/index.ts
62
+ *
63
+ * @param messageSlot - The slot number from the received message
64
+ * @param epochCache - EpochCache to get timing and pipelining state
65
+ * @param windowSeconds - The window grace period allowed for attestations into the next slot
66
+ * @returns true if pipelining is enabled, the message is for the current slot, and we're within the grace period
67
+ */
68
+ function isWithinPipeliningWindow(
69
+ messageSlot: SlotNumber,
70
+ epochCache: EpochCacheInterface,
71
+ windowSeconds: number,
72
+ ): boolean {
73
+ if (!epochCache.isProposerPipeliningEnabled()) {
74
+ return false;
75
+ }
76
+
77
+ const currentSlot = epochCache.getSlotNow();
78
+ if (messageSlot !== currentSlot) {
79
+ return false;
80
+ }
81
+
82
+ const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
83
+ const slotStartMs = slotStartTs * 1000n;
84
+ const elapsedMs = Number(nowMs - slotStartMs);
85
+ const windowMs = windowSeconds * 1000 + MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
86
+
87
+ return elapsedMs < windowMs;
88
+ }
89
+
90
+ export class PipeliningWindow {
91
+ private readonly proposalWindowIntoTargetSlot: number;
92
+ private readonly attestationWindowIntoTargetSlot: number;
93
+
94
+ constructor(
95
+ private readonly epochCache: EpochCacheInterface,
96
+ opts: {
97
+ p2pPropagationTime?: number;
98
+ l1PublishingTime?: number;
99
+ } = {},
100
+ ) {
101
+ const l1Constants = epochCache.getL1Constants();
102
+ const checkpointTiming = createPipelinedCheckpointTimingModel({
103
+ aztecSlotDuration: l1Constants.slotDuration,
104
+ ethereumSlotDuration: l1Constants.ethereumSlotDuration,
105
+ l1PublishingTime: opts.l1PublishingTime ?? l1Constants.ethereumSlotDuration,
106
+ p2pPropagationTime: opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME,
107
+ });
108
+
109
+ this.proposalWindowIntoTargetSlot = checkpointTiming.proposalWindowIntoTargetSlot;
110
+ this.attestationWindowIntoTargetSlot = checkpointTiming.attestationWindowIntoTargetSlot;
111
+ }
112
+
113
+ public acceptsProposal(messageSlot: SlotNumber): boolean {
114
+ return isWithinPipeliningWindow(messageSlot, this.epochCache, this.proposalWindowIntoTargetSlot);
115
+ }
116
+
117
+ public acceptsAttestation(messageSlot: SlotNumber): boolean {
118
+ return isWithinPipeliningWindow(messageSlot, this.epochCache, this.attestationWindowIntoTargetSlot);
119
+ }
120
+ }
@@ -53,7 +53,7 @@ Only runs on validator nodes. Non-validator nodes use a default handler that tri
53
53
 
54
54
  **Escape hatch**: during escape hatch periods (`isEscapeHatchOpenAtSlot`), re-execution and slashing are both disabled, and the proposal is rejected locally.
55
55
 
56
- **Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0` with `validatorReexecute`, committee membership with `validatorReexecute`, `alwaysReexecuteBlockProposals`, or `blobClient.canUpload()`.
56
+ **Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0`, committee membership, `alwaysReexecuteBlockProposals`, or `blobClient.canUpload()`.
57
57
 
58
58
  **Slashing**: only `state_mismatch` and `failed_txs` trigger on-chain slashing (`OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL`, gated by `slashBroadcastedInvalidBlockPenalty > 0`). Unknown errors during re-execution do NOT slash.
59
59
 
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
6
6
  export class BlockProposalValidator implements P2PValidator<BlockProposal> {
7
7
  private proposalValidator: ProposalValidator;
8
8
 
9
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
9
+ constructor(
10
+ epochCache: EpochCacheInterface,
11
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
12
+ ) {
10
13
  this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
11
14
  }
12
15
 
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
6
6
  export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
7
7
  private proposalValidator: ProposalValidator;
8
8
 
9
- constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
9
+ constructor(
10
+ epochCache: EpochCacheInterface,
11
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
12
+ ) {
10
13
  this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
11
14
  }
12
15
 
@@ -8,7 +8,7 @@ import {
8
8
  type ValidationResult,
9
9
  } from '@aztec/stdlib/p2p';
10
10
 
11
- import { isWithinClockTolerance } from '../clock_tolerance.js';
11
+ import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
12
12
 
13
13
  /** Validates header-level and tx-level fields of block and checkpoint proposals. */
14
14
  export class ProposalValidator {
@@ -16,33 +16,39 @@ export class ProposalValidator {
16
16
  private logger: Logger;
17
17
  private txsPermitted: boolean;
18
18
  private maxTxsPerBlock?: number;
19
+ private pipeliningWindow: PipeliningWindow;
19
20
 
20
21
  constructor(
21
22
  epochCache: EpochCacheInterface,
22
- opts: { txsPermitted: boolean; maxTxsPerBlock?: number },
23
+ opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
23
24
  loggerName: string,
24
25
  ) {
25
26
  this.epochCache = epochCache;
26
27
  this.txsPermitted = opts.txsPermitted;
27
28
  this.maxTxsPerBlock = opts.maxTxsPerBlock;
29
+ this.pipeliningWindow = new PipeliningWindow(epochCache, { p2pPropagationTime: opts.p2pPropagationTime });
28
30
  this.logger = createLogger(loggerName);
29
31
  }
30
32
 
31
33
  /** Validates header-level fields: slot, signature, and proposer. */
32
34
  public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
33
35
  try {
34
- // Slot check: use target slots since proposals target pipeline slots (slot + 1 when pipelining)
36
+ // Slot check: use target slots since proposals target pipeline slots (slot + 1 when pipelining).
35
37
  const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
36
38
 
37
39
  const slotNumber = proposal.slotNumber;
38
40
  if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
39
- // Check if message is for previous slot and within clock tolerance
40
- if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
41
+ // When pipelining, accept proposals for the current slot (built in the previous slot)
42
+ // if they're still within the shared proposal acceptance window.
43
+ if (this.pipeliningWindow.acceptsProposal(slotNumber)) {
44
+ // Fall through to remaining validation (signature, proposer, etc.)
45
+ } else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
41
46
  this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { targetSlot, nextSlot });
42
47
  return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
48
+ } else {
49
+ this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
50
+ return { result: 'ignore' };
43
51
  }
44
- this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
45
- return { result: 'ignore' };
46
52
  }
47
53
 
48
54
  // Signature validity
@@ -15,7 +15,7 @@ export class ArchiveCache implements ArchiveSource {
15
15
  }
16
16
 
17
17
  public async getArchiveIndices(archives: BlockHash[]): Promise<(bigint | undefined)[]> {
18
- const toCheckDb = archives.filter(n => !this.archives.has(n.toString())).map(n => n.toFr());
18
+ const toCheckDb = archives.filter(n => !this.archives.has(n.toString()));
19
19
  const dbHits = await this.db.findLeafIndices(MerkleTreeId.ARCHIVE, toCheckDb);
20
20
  dbHits.forEach((x, index) => {
21
21
  if (x !== undefined) {
@@ -0,0 +1,56 @@
1
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
2
+ import { ContractInstancePublishedEvent } from '@aztec/protocol-contracts/instance-registry';
3
+ import { computeContractAddressFromInstance } from '@aztec/stdlib/contract';
4
+ import {
5
+ TX_ERROR_INCORRECT_CONTRACT_ADDRESS,
6
+ TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG,
7
+ type Tx,
8
+ type TxValidationResult,
9
+ type TxValidator,
10
+ } from '@aztec/stdlib/tx';
11
+
12
+ /** Validates that contract instance deployment logs contain correct addresses. */
13
+ export class ContractInstanceTxValidator implements TxValidator<Tx> {
14
+ #log: Logger;
15
+
16
+ constructor(bindings?: LoggerBindings) {
17
+ this.#log = createLogger('p2p:tx_validator:contract_instance', bindings);
18
+ }
19
+
20
+ async validateTx(tx: Tx): Promise<TxValidationResult> {
21
+ const reason = await this.#hasCorrectContractInstanceAddresses(tx);
22
+ return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
23
+ }
24
+
25
+ async #hasCorrectContractInstanceAddresses(tx: Tx): Promise<string | undefined> {
26
+ const privateLogs = tx.data.getNonEmptyPrivateLogs();
27
+ for (const log of privateLogs) {
28
+ if (!ContractInstancePublishedEvent.isContractInstancePublishedEvent(log)) {
29
+ continue;
30
+ }
31
+
32
+ let event;
33
+ try {
34
+ event = ContractInstancePublishedEvent.fromLog(log);
35
+ } catch (e) {
36
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract instance event: ${e}`);
37
+ return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
38
+ }
39
+
40
+ try {
41
+ const instance = event.toContractInstance();
42
+ const computedAddress = await computeContractAddressFromInstance(instance);
43
+ if (!computedAddress.equals(instance.address)) {
44
+ this.#log.warn(
45
+ `Rejecting tx ${tx.getTxHash()}: contract instance address mismatch. Claimed ${instance.address}, computed ${computedAddress}`,
46
+ );
47
+ return TX_ERROR_INCORRECT_CONTRACT_ADDRESS;
48
+ }
49
+ } catch (e) {
50
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract instance address: ${e}`);
51
+ return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ }
@@ -1,5 +1,7 @@
1
1
  import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS } from '@aztec/constants';
2
2
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
3
+ import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
4
+ import { computeContractClassId } from '@aztec/stdlib/contract';
3
5
  import { computeCalldataHash } from '@aztec/stdlib/hash';
4
6
  import {
5
7
  TX_ERROR_CALLDATA_COUNT_MISMATCH,
@@ -9,7 +11,9 @@ import {
9
11
  TX_ERROR_CONTRACT_CLASS_LOG_LENGTH,
10
12
  TX_ERROR_CONTRACT_CLASS_LOG_SORTING,
11
13
  TX_ERROR_INCORRECT_CALLDATA,
14
+ TX_ERROR_INCORRECT_CONTRACT_CLASS_ID,
12
15
  TX_ERROR_INCORRECT_HASH,
16
+ TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG,
13
17
  Tx,
14
18
  type TxValidationResult,
15
19
  type TxValidator,
@@ -26,7 +30,8 @@ export class DataTxValidator implements TxValidator<Tx> {
26
30
  const reason =
27
31
  (await this.#hasCorrectHash(tx)) ??
28
32
  (await this.#hasCorrectCalldata(tx)) ??
29
- (await this.#hasCorrectContractClassLogs(tx));
33
+ (await this.#hasCorrectContractClassLogs(tx)) ??
34
+ (await this.#hasCorrectContractClassIds(tx));
30
35
  return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
31
36
  }
32
37
 
@@ -127,4 +132,40 @@ export class DataTxValidator implements TxValidator<Tx> {
127
132
 
128
133
  return undefined;
129
134
  }
135
+
136
+ async #hasCorrectContractClassIds(tx: Tx): Promise<string | undefined> {
137
+ const contractClassLogs = tx.getContractClassLogs();
138
+ for (const log of contractClassLogs) {
139
+ if (!ContractClassPublishedEvent.isContractClassPublishedEvent(log)) {
140
+ continue;
141
+ }
142
+
143
+ let event;
144
+ try {
145
+ event = ContractClassPublishedEvent.fromLog(log);
146
+ } catch (e) {
147
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract class event: ${e}`);
148
+ return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
149
+ }
150
+
151
+ try {
152
+ const { publicBytecodeCommitment } = await event.toContractClassPublicWithBytecodeCommitment();
153
+ const computedClassId = await computeContractClassId({
154
+ artifactHash: event.artifactHash,
155
+ privateFunctionsRoot: event.privateFunctionsRoot,
156
+ publicBytecodeCommitment,
157
+ });
158
+ if (!computedClassId.equals(event.contractClassId)) {
159
+ this.#log.warn(
160
+ `Rejecting tx ${tx.getTxHash()}: contract class id mismatch. Claimed ${event.contractClassId}, computed ${computedClassId}`,
161
+ );
162
+ return TX_ERROR_INCORRECT_CONTRACT_CLASS_ID;
163
+ }
164
+ } catch (e) {
165
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract class id: ${e}`);
166
+ return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
167
+ }
168
+ }
169
+ return undefined;
170
+ }
130
171
  }
@@ -53,6 +53,7 @@ import type { TxMetaData } from '../../mem_pools/tx_pool_v2/tx_metadata.js';
53
53
  import { AggregateTxValidator } from './aggregate_tx_validator.js';
54
54
  import { ArchiveCache } from './archive_cache.js';
55
55
  import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_validator.js';
56
+ import { ContractInstanceTxValidator } from './contract_instance_validator.js';
56
57
  import { DataTxValidator } from './data_validator.js';
57
58
  import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
58
59
  import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
@@ -167,6 +168,10 @@ export function createFirstStageTxValidationsForGossipedTransactions(
167
168
  validator: new DataTxValidator(bindings),
168
169
  severity: PeerErrorSeverity.MidToleranceError,
169
170
  },
171
+ contractInstanceValidator: {
172
+ validator: new ContractInstanceTxValidator(bindings),
173
+ severity: PeerErrorSeverity.MidToleranceError,
174
+ },
170
175
  };
171
176
  }
172
177
 
@@ -218,6 +223,7 @@ function createTxValidatorForMinimumTxIntegrityChecks(
218
223
  ),
219
224
  new SizeTxValidator(bindings),
220
225
  new DataTxValidator(bindings),
226
+ new ContractInstanceTxValidator(bindings),
221
227
  new TxProofValidator(verifier, bindings),
222
228
  );
223
229
  }
@@ -321,6 +327,7 @@ export function createTxValidatorForAcceptingTxsOverRPC(
321
327
  new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
322
328
  new DoubleSpendTxValidator(new NullifierCache(db), bindings),
323
329
  new DataTxValidator(bindings),
330
+ new ContractInstanceTxValidator(bindings),
324
331
  ];
325
332
 
326
333
  if (!skipFeeEnforcement) {