@aztec/validator-client 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5a9928

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 (56) hide show
  1. package/README.md +54 -10
  2. package/dest/checkpoint_builder.d.ts +32 -11
  3. package/dest/checkpoint_builder.d.ts.map +1 -1
  4. package/dest/checkpoint_builder.js +136 -47
  5. package/dest/config.d.ts +9 -3
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +45 -7
  8. package/dest/duties/validation_service.d.ts +12 -13
  9. package/dest/duties/validation_service.d.ts.map +1 -1
  10. package/dest/duties/validation_service.js +33 -45
  11. package/dest/factory.d.ts +11 -5
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +8 -7
  14. package/dest/index.d.ts +2 -3
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +1 -2
  17. package/dest/key_store/ha_key_store.js +1 -1
  18. package/dest/key_store/web3signer_key_store.d.ts +10 -2
  19. package/dest/key_store/web3signer_key_store.d.ts.map +1 -1
  20. package/dest/key_store/web3signer_key_store.js +32 -41
  21. package/dest/metrics.d.ts +14 -2
  22. package/dest/metrics.d.ts.map +1 -1
  23. package/dest/metrics.js +27 -1
  24. package/dest/proposal_handler.d.ts +173 -0
  25. package/dest/proposal_handler.d.ts.map +1 -0
  26. package/dest/proposal_handler.js +1302 -0
  27. package/dest/validator.d.ts +62 -26
  28. package/dest/validator.d.ts.map +1 -1
  29. package/dest/validator.js +347 -238
  30. package/package.json +19 -19
  31. package/src/checkpoint_builder.ts +156 -42
  32. package/src/config.ts +53 -9
  33. package/src/duties/validation_service.ts +59 -54
  34. package/src/factory.ts +20 -7
  35. package/src/index.ts +1 -2
  36. package/src/key_store/ha_key_store.ts +1 -1
  37. package/src/key_store/web3signer_key_store.ts +43 -59
  38. package/src/metrics.ts +39 -1
  39. package/src/proposal_handler.ts +1418 -0
  40. package/src/validator.ts +480 -286
  41. package/dest/block_proposal_handler.d.ts +0 -63
  42. package/dest/block_proposal_handler.d.ts.map +0 -1
  43. package/dest/block_proposal_handler.js +0 -546
  44. package/dest/tx_validator/index.d.ts +0 -3
  45. package/dest/tx_validator/index.d.ts.map +0 -1
  46. package/dest/tx_validator/index.js +0 -2
  47. package/dest/tx_validator/nullifier_cache.d.ts +0 -14
  48. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  49. package/dest/tx_validator/nullifier_cache.js +0 -24
  50. package/dest/tx_validator/tx_validator_factory.d.ts +0 -19
  51. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  52. package/dest/tx_validator/tx_validator_factory.js +0 -54
  53. package/src/block_proposal_handler.ts +0 -555
  54. package/src/tx_validator/index.ts +0 -2
  55. package/src/tx_validator/nullifier_cache.ts +0 -30
  56. package/src/tx_validator/tx_validator_factory.ts +0 -154
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.0.1-commit.f2ce05ee",
3
+ "version": "0.0.1-commit.f5a9928",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,30 +64,30 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/blob-client": "0.0.1-commit.f2ce05ee",
68
- "@aztec/blob-lib": "0.0.1-commit.f2ce05ee",
69
- "@aztec/constants": "0.0.1-commit.f2ce05ee",
70
- "@aztec/epoch-cache": "0.0.1-commit.f2ce05ee",
71
- "@aztec/ethereum": "0.0.1-commit.f2ce05ee",
72
- "@aztec/foundation": "0.0.1-commit.f2ce05ee",
73
- "@aztec/node-keystore": "0.0.1-commit.f2ce05ee",
74
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f2ce05ee",
75
- "@aztec/p2p": "0.0.1-commit.f2ce05ee",
76
- "@aztec/protocol-contracts": "0.0.1-commit.f2ce05ee",
77
- "@aztec/prover-client": "0.0.1-commit.f2ce05ee",
78
- "@aztec/simulator": "0.0.1-commit.f2ce05ee",
79
- "@aztec/slasher": "0.0.1-commit.f2ce05ee",
80
- "@aztec/stdlib": "0.0.1-commit.f2ce05ee",
81
- "@aztec/telemetry-client": "0.0.1-commit.f2ce05ee",
82
- "@aztec/validator-ha-signer": "0.0.1-commit.f2ce05ee",
67
+ "@aztec/blob-client": "0.0.1-commit.f5a9928",
68
+ "@aztec/blob-lib": "0.0.1-commit.f5a9928",
69
+ "@aztec/constants": "0.0.1-commit.f5a9928",
70
+ "@aztec/epoch-cache": "0.0.1-commit.f5a9928",
71
+ "@aztec/ethereum": "0.0.1-commit.f5a9928",
72
+ "@aztec/foundation": "0.0.1-commit.f5a9928",
73
+ "@aztec/node-keystore": "0.0.1-commit.f5a9928",
74
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f5a9928",
75
+ "@aztec/p2p": "0.0.1-commit.f5a9928",
76
+ "@aztec/protocol-contracts": "0.0.1-commit.f5a9928",
77
+ "@aztec/prover-client": "0.0.1-commit.f5a9928",
78
+ "@aztec/simulator": "0.0.1-commit.f5a9928",
79
+ "@aztec/slasher": "0.0.1-commit.f5a9928",
80
+ "@aztec/stdlib": "0.0.1-commit.f5a9928",
81
+ "@aztec/telemetry-client": "0.0.1-commit.f5a9928",
82
+ "@aztec/validator-ha-signer": "0.0.1-commit.f5a9928",
83
83
  "koa": "^2.16.1",
84
84
  "koa-router": "^13.1.1",
85
85
  "tslib": "^2.4.0",
86
86
  "viem": "npm:@aztec/viem@2.38.2"
87
87
  },
88
88
  "devDependencies": {
89
- "@aztec/archiver": "0.0.1-commit.f2ce05ee",
90
- "@aztec/world-state": "0.0.1-commit.f2ce05ee",
89
+ "@aztec/archiver": "0.0.1-commit.f5a9928",
90
+ "@aztec/world-state": "0.0.1-commit.f5a9928",
91
91
  "@electric-sql/pglite": "^0.3.14",
92
92
  "@jest/globals": "^30.0.0",
93
93
  "@types/jest": "^30.0.0",
@@ -1,10 +1,12 @@
1
+ import { NUM_CHECKPOINT_END_MARKER_FIELDS, getNumBlockEndBlobFields } from '@aztec/blob-lib/encoding';
2
+ import { BLOBS_PER_CHECKPOINT, FIELDS_PER_BLOB, MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT } from '@aztec/constants';
1
3
  import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
- import { merge, pick } from '@aztec/foundation/collection';
4
+ import { merge, pick, sum } from '@aztec/foundation/collection';
3
5
  import { Fr } from '@aztec/foundation/curves/bn254';
4
6
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
5
7
  import { bufferToHex } from '@aztec/foundation/string';
6
8
  import { DateProvider, elapsed } from '@aztec/foundation/timer';
7
- import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
9
+ import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
8
10
  import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
9
11
  import {
10
12
  GuardedMerkleTreeOperations,
@@ -12,27 +14,28 @@ import {
12
14
  PublicProcessor,
13
15
  createPublicTxSimulatorForBlockBuilding,
14
16
  } from '@aztec/simulator/server';
15
- import { L2Block } from '@aztec/stdlib/block';
17
+ import { type BlockHash, L2Block } from '@aztec/stdlib/block';
16
18
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
17
19
  import type { ContractDataSource } from '@aztec/stdlib/contract';
18
20
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
19
21
  import { Gas } from '@aztec/stdlib/gas';
20
22
  import {
23
+ type BlockBuilderOptions,
21
24
  type BuildBlockInCheckpointResult,
22
25
  type FullNodeBlockBuilderConfig,
23
26
  FullNodeBlockBuilderConfigKeys,
24
27
  type ICheckpointBlockBuilder,
25
28
  type ICheckpointsBuilder,
29
+ InsufficientValidTxsError,
26
30
  type MerkleTreeWriteOperations,
27
- NoValidTxsError,
28
31
  type PublicProcessorLimits,
29
32
  type WorldStateSynchronizer,
30
33
  } from '@aztec/stdlib/interfaces/server';
34
+ import { type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
31
35
  import { MerkleTreeId } from '@aztec/stdlib/trees';
32
36
  import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
33
37
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
34
-
35
- import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_factory.js';
38
+ import { ForkCheckpoint } from '@aztec/world-state';
36
39
 
37
40
  // Re-export for backward compatibility
38
41
  export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
@@ -44,6 +47,9 @@ export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/serv
44
47
  export class CheckpointBuilder implements ICheckpointBlockBuilder {
45
48
  private log: Logger;
46
49
 
50
+ /** Persistent contracts DB shared across all blocks in this checkpoint. */
51
+ protected contractsDB: PublicContractsDB;
52
+
47
53
  constructor(
48
54
  private checkpointBuilder: LightweightCheckpointBuilder,
49
55
  private fork: MerkleTreeWriteOperations,
@@ -52,11 +58,13 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
52
58
  private dateProvider: DateProvider,
53
59
  private telemetryClient: TelemetryClient,
54
60
  bindings?: LoggerBindings,
61
+ private debugLogStore: DebugLogStore = new NullDebugLogStore(),
55
62
  ) {
56
63
  this.log = createLogger('checkpoint-builder', {
57
64
  ...bindings,
58
65
  instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
59
66
  });
67
+ this.contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
60
68
  }
61
69
 
62
70
  getConstantData(): CheckpointGlobalVariables {
@@ -65,12 +73,13 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
65
73
 
66
74
  /**
67
75
  * Builds a single block within this checkpoint.
76
+ * Automatically caps gas and blob field limits based on checkpoint-level budgets and prior blocks.
68
77
  */
69
78
  async buildBlock(
70
79
  pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
71
80
  blockNumber: BlockNumber,
72
81
  timestamp: bigint,
73
- opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
82
+ opts: BlockBuilderOptions & { expectedEndState?: StateReference },
74
83
  ): Promise<BuildBlockInCheckpointResult> {
75
84
  const slot = this.checkpointBuilder.constants.slotNumber;
76
85
 
@@ -94,39 +103,60 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
94
103
  });
95
104
  const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
96
105
 
97
- const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs, _, usedTxBlobFields]] = await elapsed(() =>
98
- processor.process(pendingTxs, opts, validator),
99
- );
100
-
101
- // Throw if we didn't collect a single valid tx and we're not allowed to build empty blocks
102
- // (only the first block in a checkpoint can be empty)
103
- if (processedTxs.length === 0 && this.checkpointBuilder.getBlockCount() > 0) {
104
- throw new NoValidTxsError(failedTxs);
105
- }
106
-
107
- // Add block to checkpoint
108
- const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
109
- expectedEndState: opts.expectedEndState,
110
- });
106
+ // Cap gas limits amd available blob fields by remaining checkpoint-level budgets
107
+ const cappedOpts: PublicProcessorLimits & { expectedEndState?: StateReference } = {
108
+ ...opts,
109
+ ...this.capLimitsByCheckpointBudgets(opts),
110
+ };
111
111
 
112
- // How much public gas was processed
113
- const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
112
+ // Create a block-level checkpoint on the contracts DB so we can roll back on failure
113
+ this.contractsDB.createCheckpoint();
114
+ // We execute all merkle tree operations on a world state fork checkpoint
115
+ // This enables us to discard all modifications in the event that we fail to successfully process sufficient transactions
116
+ const forkCheckpoint = await ForkCheckpoint.new(this.fork);
114
117
 
115
- this.log.debug('Built block within checkpoint', {
116
- header: block.header.toInspect(),
117
- processedTxs: processedTxs.map(tx => tx.hash.toString()),
118
- failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
119
- });
118
+ try {
119
+ const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
120
+ processor.process(pendingTxs, cappedOpts, validator),
121
+ );
120
122
 
121
- return {
122
- block,
123
- publicGas,
124
- publicProcessorDuration,
125
- numTxs: processedTxs.length,
126
- failedTxs,
127
- usedTxs,
128
- usedTxBlobFields,
129
- };
123
+ // Throw before updating state if we don't have enough valid txs
124
+ const minValidTxs = opts.minValidTxs ?? 0;
125
+ if (processedTxs.length < minValidTxs) {
126
+ throw new InsufficientValidTxsError(processedTxs.length, minValidTxs, failedTxs);
127
+ }
128
+
129
+ // Commit the fork checkpoint
130
+ await forkCheckpoint.commit();
131
+
132
+ // Add block to checkpoint
133
+ const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
134
+ expectedEndState: opts.expectedEndState,
135
+ });
136
+
137
+ this.contractsDB.commitCheckpoint();
138
+
139
+ this.log.debug('Built block within checkpoint', {
140
+ header: block.header.toInspect(),
141
+ processedTxs: processedTxs.map(tx => tx.hash.toString()),
142
+ failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
143
+ });
144
+
145
+ return {
146
+ block,
147
+ publicProcessorDuration,
148
+ numTxs: processedTxs.length,
149
+ failedTxs,
150
+ usedTxs,
151
+ };
152
+ } catch (err) {
153
+ // Revert all changes to contracts db
154
+ this.contractsDB.revertCheckpoint();
155
+ // If we reached the point of committing the checkpoint, this does nothing
156
+ // Otherwise it reverts any changes made to the fork for this failed block
157
+ await forkCheckpoint.revert();
158
+ throw err;
159
+ }
130
160
  }
131
161
 
132
162
  /** Completes the checkpoint and returns it. */
@@ -147,11 +177,74 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
147
177
  return this.checkpointBuilder.clone().completeCheckpoint();
148
178
  }
149
179
 
180
+ /**
181
+ * Caps per-block gas and blob field limits by remaining checkpoint-level budgets.
182
+ * When building a proposal (isBuildingProposal=true), computes a fair share of remaining budget
183
+ * across remaining blocks scaled by the multiplier. When validating, only caps by per-block limit
184
+ * and remaining checkpoint budget (no redistribution or multiplier).
185
+ */
186
+ protected capLimitsByCheckpointBudgets(
187
+ opts: BlockBuilderOptions,
188
+ ): Pick<PublicProcessorLimits, 'maxBlockGas' | 'maxBlobFields' | 'maxTransactions'> {
189
+ const existingBlocks = this.checkpointBuilder.getBlocks();
190
+
191
+ // Remaining L2 gas (mana)
192
+ // IMPORTANT: This assumes mana is computed solely based on L2 gas used in transactions.
193
+ // This may change in the future.
194
+ const usedMana = sum(existingBlocks.map(b => b.header.totalManaUsed.toNumber()));
195
+ const remainingMana = this.config.rollupManaLimit - usedMana;
196
+
197
+ // Remaining DA gas
198
+ const usedDAGas = sum(existingBlocks.map(b => b.computeDAGasUsed())) ?? 0;
199
+ const remainingDAGas = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT - usedDAGas;
200
+
201
+ // Remaining blob fields (block blob fields include both tx data and block-end overhead)
202
+ const usedBlobFields = sum(existingBlocks.map(b => b.toBlobFields().length));
203
+ const totalBlobCapacity = BLOBS_PER_CHECKPOINT * FIELDS_PER_BLOB - NUM_CHECKPOINT_END_MARKER_FIELDS;
204
+ const isFirstBlock = existingBlocks.length === 0;
205
+ const blockEndOverhead = getNumBlockEndBlobFields(isFirstBlock);
206
+ const maxBlobFieldsForTxs = totalBlobCapacity - usedBlobFields - blockEndOverhead;
207
+
208
+ // Remaining txs
209
+ const usedTxs = sum(existingBlocks.map(b => b.body.txEffects.length));
210
+ const remainingTxs = Math.max(0, (this.config.maxTxsPerCheckpoint ?? Infinity) - usedTxs);
211
+
212
+ // Cap by per-block limit + remaining checkpoint budget
213
+ let cappedL2Gas = Math.min(opts.maxBlockGas?.l2Gas ?? Infinity, remainingMana);
214
+ let cappedDAGas = Math.min(opts.maxBlockGas?.daGas ?? Infinity, remainingDAGas);
215
+ let cappedBlobFields = Math.min(opts.maxBlobFields ?? Infinity, maxBlobFieldsForTxs);
216
+ let cappedMaxTransactions = Math.min(opts.maxTransactions ?? Infinity, remainingTxs);
217
+
218
+ // Proposer mode: further cap by fair share of remaining budget across remaining blocks
219
+ if (opts.isBuildingProposal) {
220
+ const remainingBlocks = Math.max(1, opts.maxBlocksPerCheckpoint - existingBlocks.length);
221
+ const multiplier = opts.perBlockAllocationMultiplier;
222
+ // DA gas and blob fields use a higher multiplier so the largest contract class deploy fits a block.
223
+ const daMultiplier = opts.perBlockDAAllocationMultiplier ?? multiplier;
224
+
225
+ cappedL2Gas = Math.min(cappedL2Gas, Math.ceil((remainingMana / remainingBlocks) * multiplier));
226
+ cappedDAGas = Math.min(cappedDAGas, Math.ceil((remainingDAGas / remainingBlocks) * daMultiplier));
227
+ cappedBlobFields = Math.min(cappedBlobFields, Math.ceil((maxBlobFieldsForTxs / remainingBlocks) * daMultiplier));
228
+ cappedMaxTransactions = Math.min(cappedMaxTransactions, Math.ceil((remainingTxs / remainingBlocks) * multiplier));
229
+ }
230
+
231
+ return {
232
+ maxBlockGas: new Gas(cappedDAGas, cappedL2Gas),
233
+ maxBlobFields: cappedBlobFields,
234
+ maxTransactions: Number.isFinite(cappedMaxTransactions) ? cappedMaxTransactions : undefined,
235
+ };
236
+ }
237
+
150
238
  protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
151
- const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
152
- const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
239
+ const txPublicSetupAllowList = [
240
+ ...(await getDefaultAllowedSetupFunctions()),
241
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
242
+ ];
243
+ const contractsDB = this.contractsDB;
153
244
  const guardedFork = new GuardedMerkleTreeOperations(fork);
154
245
 
246
+ const collectDebugLogs = this.debugLogStore.isEnabled;
247
+
155
248
  const bindings = this.log.getBindings();
156
249
  const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
157
250
  guardedFork,
@@ -159,6 +252,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
159
252
  globalVariables,
160
253
  this.telemetryClient,
161
254
  bindings,
255
+ collectDebugLogs,
162
256
  );
163
257
 
164
258
  const processor = new PublicProcessor(
@@ -170,9 +264,10 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
170
264
  this.telemetryClient,
171
265
  createLogger('simulator:public-processor', bindings),
172
266
  this.config,
267
+ this.debugLogStore,
173
268
  );
174
269
 
175
- const validator = createValidatorForBlockBuilding(
270
+ const validator = createTxValidatorForBlockBuilding(
176
271
  fork,
177
272
  this.contractDataSource,
178
273
  globalVariables,
@@ -197,6 +292,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
197
292
  private contractDataSource: ContractDataSource,
198
293
  private dateProvider: DateProvider,
199
294
  private telemetryClient: TelemetryClient = getTelemetryClient(),
295
+ private debugLogStore: DebugLogStore = new NullDebugLogStore(),
200
296
  ) {
201
297
  this.log = createLogger('checkpoint-builder');
202
298
  }
@@ -215,6 +311,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
215
311
  async startCheckpoint(
216
312
  checkpointNumber: CheckpointNumber,
217
313
  constants: CheckpointGlobalVariables,
314
+ feeAssetPriceModifier: bigint,
218
315
  l1ToL2Messages: Fr[],
219
316
  previousCheckpointOutHashes: Fr[],
220
317
  fork: MerkleTreeWriteOperations,
@@ -229,6 +326,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
229
326
  initialStateReference: stateReference.toInspect(),
230
327
  initialArchiveRoot: bufferToHex(archiveTree.root),
231
328
  constants,
329
+ feeAssetPriceModifier,
232
330
  });
233
331
 
234
332
  const lightweightBuilder = await LightweightCheckpointBuilder.startNewCheckpoint(
@@ -238,6 +336,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
238
336
  previousCheckpointOutHashes,
239
337
  fork,
240
338
  bindings,
339
+ feeAssetPriceModifier,
241
340
  );
242
341
 
243
342
  return new CheckpointBuilder(
@@ -248,6 +347,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
248
347
  this.dateProvider,
249
348
  this.telemetryClient,
250
349
  bindings,
350
+ this.debugLogStore,
251
351
  );
252
352
  }
253
353
 
@@ -257,6 +357,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
257
357
  async openCheckpoint(
258
358
  checkpointNumber: CheckpointNumber,
259
359
  constants: CheckpointGlobalVariables,
360
+ feeAssetPriceModifier: bigint,
260
361
  l1ToL2Messages: Fr[],
261
362
  previousCheckpointOutHashes: Fr[],
262
363
  fork: MerkleTreeWriteOperations,
@@ -270,6 +371,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
270
371
  return this.startCheckpoint(
271
372
  checkpointNumber,
272
373
  constants,
374
+ feeAssetPriceModifier,
273
375
  l1ToL2Messages,
274
376
  previousCheckpointOutHashes,
275
377
  fork,
@@ -284,11 +386,13 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
284
386
  initialStateReference: stateReference.toInspect(),
285
387
  initialArchiveRoot: bufferToHex(archiveTree.root),
286
388
  constants,
389
+ feeAssetPriceModifier,
287
390
  });
288
391
 
289
392
  const lightweightBuilder = await LightweightCheckpointBuilder.resumeCheckpoint(
290
393
  checkpointNumber,
291
394
  constants,
395
+ feeAssetPriceModifier,
292
396
  l1ToL2Messages,
293
397
  previousCheckpointOutHashes,
294
398
  fork,
@@ -304,11 +408,21 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
304
408
  this.dateProvider,
305
409
  this.telemetryClient,
306
410
  bindings,
411
+ this.debugLogStore,
307
412
  );
308
413
  }
309
414
 
310
- /** Returns a fork of the world state at the given block number. */
311
- getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations> {
415
+ /**
416
+ * Syncs world state to the given block number and returns a fork of it at that block.
417
+ *
418
+ * Syncing first is required: the block source (archiver) can already hold a block while world state
419
+ * still trails it, and forking a not-yet-applied block throws a raw "initialize from future block"
420
+ * tree error. syncImmediate blocks until world state reaches the block, or throws a typed error if it
421
+ * genuinely cannot. When `blockHash` is provided it is verified against the synced block, triggering a
422
+ * resync on mismatch (reorg detection).
423
+ */
424
+ async getFork(blockNumber: BlockNumber, blockHash?: BlockHash): Promise<MerkleTreeWriteOperations> {
425
+ await this.worldState.syncImmediate(blockNumber, blockHash);
312
426
  return this.worldState.fork(blockNumber);
313
427
  }
314
428
  }
package/src/config.ts CHANGED
@@ -3,15 +3,27 @@ import {
3
3
  booleanConfigHelper,
4
4
  getConfigFromMappings,
5
5
  numberConfigHelper,
6
+ optionalNumberConfigHelper,
7
+ pickConfigMappings,
6
8
  secretValueConfigHelper,
7
9
  } from '@aztec/foundation/config';
8
10
  import { EthAddress } from '@aztec/foundation/eth-address';
11
+ import { type SequencerConfig, sharedSequencerConfigMappings } from '@aztec/stdlib/config';
12
+ import { localSignerConfigMappings, validatorHASignerConfigMappings } from '@aztec/stdlib/ha-signing';
9
13
  import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
10
- import { validatorHASignerConfigMappings } from '@aztec/validator-ha-signer/config';
11
14
 
12
15
  export type { ValidatorClientConfig };
13
16
 
14
- export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientConfig> = {
17
+ /**
18
+ * Default clock-disparity tolerance (ms) for proposal/attestation receive windows, mirroring the p2p config
19
+ * default. Used by the validator-client validators when the merged node config does not carry the value.
20
+ */
21
+ export const DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS = 500;
22
+
23
+ export const validatorClientConfigMappings: ConfigMappingsType<
24
+ ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'>
25
+ > = {
26
+ ...pickConfigMappings(sharedSequencerConfigMappings, ['blockDurationMs']),
15
27
  validatorPrivateKeys: {
16
28
  env: 'VALIDATOR_PRIVATE_KEYS',
17
29
  description: 'List of private keys of the validators participating in attestation duties',
@@ -30,6 +42,12 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
30
42
  .map(address => EthAddress.fromString(address.trim())),
31
43
  defaultValue: [],
32
44
  },
45
+ l1ChainId: {
46
+ env: 'L1_CHAIN_ID',
47
+ description: 'The chain ID of the ethereum host.',
48
+ parseEnv: (val: string) => +val,
49
+ defaultValue: 31337,
50
+ },
33
51
  disableValidator: {
34
52
  env: 'VALIDATOR_DISABLED',
35
53
  description: 'Do not run the validator',
@@ -49,11 +67,6 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
49
67
  description: 'Interval between polling for new attestations',
50
68
  ...numberConfigHelper(200),
51
69
  },
52
- validatorReexecute: {
53
- env: 'VALIDATOR_REEXECUTE',
54
- description: 'Re-execute transactions before attesting',
55
- ...booleanConfigHelper(true),
56
- },
57
70
  alwaysReexecuteBlockProposals: {
58
71
  description:
59
72
  'Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status).',
@@ -73,6 +86,35 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
73
86
  description: 'Skip pushing re-executed blocks to archiver (default: false)',
74
87
  defaultValue: false,
75
88
  },
89
+ attestToEquivocatedProposals: {
90
+ description: 'Agree to attest to equivocated checkpoint proposals (for testing purposes only)',
91
+ ...booleanConfigHelper(false),
92
+ },
93
+ skipProposalSlotValidation: {
94
+ description: 'Accept proposal validation regardless of slot timing (for testing only)',
95
+ ...booleanConfigHelper(false),
96
+ },
97
+ validateMaxL2BlockGas: {
98
+ env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
99
+ description: 'Maximum L2 block gas for validation. Proposals exceeding this limit are rejected.',
100
+ ...optionalNumberConfigHelper(),
101
+ },
102
+ validateMaxDABlockGas: {
103
+ env: 'VALIDATOR_MAX_DA_BLOCK_GAS',
104
+ description: 'Maximum DA block gas for validation. Proposals exceeding this limit are rejected.',
105
+ ...optionalNumberConfigHelper(),
106
+ },
107
+ validateMaxTxsPerBlock: {
108
+ env: 'VALIDATOR_MAX_TX_PER_BLOCK',
109
+ description: 'Maximum transactions per block for validation. Proposals exceeding this limit are rejected.',
110
+ ...optionalNumberConfigHelper(),
111
+ },
112
+ validateMaxTxsPerCheckpoint: {
113
+ env: 'VALIDATOR_MAX_TX_PER_CHECKPOINT',
114
+ description: 'Maximum transactions per checkpoint for validation. Proposals exceeding this limit are rejected.',
115
+ ...optionalNumberConfigHelper(),
116
+ },
117
+ ...localSignerConfigMappings,
76
118
  ...validatorHASignerConfigMappings,
77
119
  };
78
120
 
@@ -81,6 +123,8 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
81
123
  * Note: If an environment variable is not set, the default value is used.
82
124
  * @returns The validator configuration.
83
125
  */
84
- export function getProverEnvVars(): ValidatorClientConfig {
85
- return getConfigFromMappings<ValidatorClientConfig>(validatorClientConfigMappings);
126
+ export function getProverEnvVars(): ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'> {
127
+ return getConfigFromMappings<ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'>>(
128
+ validatorClientConfigMappings,
129
+ );
86
130
  }