@aztec/validator-client 0.0.1-commit.2ed92850 → 0.0.1-commit.3100065

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 (58) hide show
  1. package/README.md +63 -18
  2. package/dest/checkpoint_builder.d.ts +26 -14
  3. package/dest/checkpoint_builder.d.ts.map +1 -1
  4. package/dest/checkpoint_builder.js +138 -45
  5. package/dest/config.d.ts +9 -3
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +47 -10
  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 +10 -4
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +19 -6
  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.d.ts +1 -1
  18. package/dest/key_store/ha_key_store.d.ts.map +1 -1
  19. package/dest/key_store/ha_key_store.js +3 -3
  20. package/dest/key_store/web3signer_key_store.d.ts +10 -2
  21. package/dest/key_store/web3signer_key_store.d.ts.map +1 -1
  22. package/dest/key_store/web3signer_key_store.js +32 -41
  23. package/dest/metrics.d.ts +16 -3
  24. package/dest/metrics.d.ts.map +1 -1
  25. package/dest/metrics.js +58 -5
  26. package/dest/proposal_handler.d.ts +165 -0
  27. package/dest/proposal_handler.d.ts.map +1 -0
  28. package/dest/proposal_handler.js +1207 -0
  29. package/dest/validator.d.ts +65 -25
  30. package/dest/validator.d.ts.map +1 -1
  31. package/dest/validator.js +377 -240
  32. package/package.json +19 -17
  33. package/src/checkpoint_builder.ts +185 -50
  34. package/src/config.ts +55 -12
  35. package/src/duties/validation_service.ts +59 -54
  36. package/src/factory.ts +29 -4
  37. package/src/index.ts +1 -2
  38. package/src/key_store/ha_key_store.ts +3 -3
  39. package/src/key_store/web3signer_key_store.ts +43 -59
  40. package/src/metrics.ts +81 -6
  41. package/src/proposal_handler.ts +1314 -0
  42. package/src/validator.ts +512 -291
  43. package/dest/block_proposal_handler.d.ts +0 -64
  44. package/dest/block_proposal_handler.d.ts.map +0 -1
  45. package/dest/block_proposal_handler.js +0 -545
  46. package/dest/tx_validator/index.d.ts +0 -3
  47. package/dest/tx_validator/index.d.ts.map +0 -1
  48. package/dest/tx_validator/index.js +0 -2
  49. package/dest/tx_validator/nullifier_cache.d.ts +0 -14
  50. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  51. package/dest/tx_validator/nullifier_cache.js +0 -24
  52. package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
  53. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  54. package/dest/tx_validator/tx_validator_factory.js +0 -54
  55. package/src/block_proposal_handler.ts +0 -554
  56. package/src/tx_validator/index.ts +0 -2
  57. package/src/tx_validator/nullifier_cache.ts +0 -30
  58. package/src/tx_validator/tx_validator_factory.ts +0 -135
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.0.1-commit.2ed92850",
3
+ "version": "0.0.1-commit.3100065",
4
4
  "main": "dest/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,28 +64,30 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/blob-client": "0.0.1-commit.2ed92850",
68
- "@aztec/blob-lib": "0.0.1-commit.2ed92850",
69
- "@aztec/constants": "0.0.1-commit.2ed92850",
70
- "@aztec/epoch-cache": "0.0.1-commit.2ed92850",
71
- "@aztec/ethereum": "0.0.1-commit.2ed92850",
72
- "@aztec/foundation": "0.0.1-commit.2ed92850",
73
- "@aztec/node-keystore": "0.0.1-commit.2ed92850",
74
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.2ed92850",
75
- "@aztec/p2p": "0.0.1-commit.2ed92850",
76
- "@aztec/protocol-contracts": "0.0.1-commit.2ed92850",
77
- "@aztec/prover-client": "0.0.1-commit.2ed92850",
78
- "@aztec/simulator": "0.0.1-commit.2ed92850",
79
- "@aztec/slasher": "0.0.1-commit.2ed92850",
80
- "@aztec/stdlib": "0.0.1-commit.2ed92850",
81
- "@aztec/telemetry-client": "0.0.1-commit.2ed92850",
82
- "@aztec/validator-ha-signer": "0.0.1-commit.2ed92850",
67
+ "@aztec/blob-client": "0.0.1-commit.3100065",
68
+ "@aztec/blob-lib": "0.0.1-commit.3100065",
69
+ "@aztec/constants": "0.0.1-commit.3100065",
70
+ "@aztec/epoch-cache": "0.0.1-commit.3100065",
71
+ "@aztec/ethereum": "0.0.1-commit.3100065",
72
+ "@aztec/foundation": "0.0.1-commit.3100065",
73
+ "@aztec/node-keystore": "0.0.1-commit.3100065",
74
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.3100065",
75
+ "@aztec/p2p": "0.0.1-commit.3100065",
76
+ "@aztec/protocol-contracts": "0.0.1-commit.3100065",
77
+ "@aztec/prover-client": "0.0.1-commit.3100065",
78
+ "@aztec/simulator": "0.0.1-commit.3100065",
79
+ "@aztec/slasher": "0.0.1-commit.3100065",
80
+ "@aztec/stdlib": "0.0.1-commit.3100065",
81
+ "@aztec/telemetry-client": "0.0.1-commit.3100065",
82
+ "@aztec/validator-ha-signer": "0.0.1-commit.3100065",
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.3100065",
90
+ "@aztec/world-state": "0.0.1-commit.3100065",
89
91
  "@electric-sql/pglite": "^0.3.14",
90
92
  "@jest/globals": "^30.0.0",
91
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
- import { createLogger } from '@aztec/foundation/log';
6
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
5
7
  import { bufferToHex } from '@aztec/foundation/string';
6
- import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
7
- import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
8
+ import { DateProvider, elapsed } from '@aztec/foundation/timer';
9
+ import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
8
10
  import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
9
11
  import {
10
12
  GuardedMerkleTreeOperations,
@@ -18,36 +20,36 @@ 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
31
  type PublicProcessorLimits,
28
32
  type WorldStateSynchronizer,
29
33
  } from '@aztec/stdlib/interfaces/server';
34
+ import { type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
30
35
  import { MerkleTreeId } from '@aztec/stdlib/trees';
31
36
  import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
32
37
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
33
-
34
- import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_factory.js';
38
+ import { ForkCheckpoint } from '@aztec/world-state';
35
39
 
36
40
  // Re-export for backward compatibility
37
41
  export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
38
42
 
39
- const log = createLogger('checkpoint-builder');
40
-
41
- /** Result of building a block within a checkpoint. Extends the base interface with timer. */
42
- export interface BuildBlockInCheckpointResultWithTimer extends BuildBlockInCheckpointResult {
43
- blockBuildingTimer: Timer;
44
- }
45
-
46
43
  /**
47
44
  * Builder for a single checkpoint. Handles building blocks within the checkpoint
48
45
  * and completing it.
49
46
  */
50
47
  export class CheckpointBuilder implements ICheckpointBlockBuilder {
48
+ private log: Logger;
49
+
50
+ /** Persistent contracts DB shared across all blocks in this checkpoint. */
51
+ protected contractsDB: PublicContractsDB;
52
+
51
53
  constructor(
52
54
  private checkpointBuilder: LightweightCheckpointBuilder,
53
55
  private fork: MerkleTreeWriteOperations,
@@ -55,7 +57,15 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
55
57
  private contractDataSource: ContractDataSource,
56
58
  private dateProvider: DateProvider,
57
59
  private telemetryClient: TelemetryClient,
58
- ) {}
60
+ bindings?: LoggerBindings,
61
+ private debugLogStore: DebugLogStore = new NullDebugLogStore(),
62
+ ) {
63
+ this.log = createLogger('checkpoint-builder', {
64
+ ...bindings,
65
+ instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
66
+ });
67
+ this.contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
68
+ }
59
69
 
60
70
  getConstantData(): CheckpointGlobalVariables {
61
71
  return this.checkpointBuilder.constants;
@@ -63,17 +73,17 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
63
73
 
64
74
  /**
65
75
  * Builds a single block within this checkpoint.
76
+ * Automatically caps gas and blob field limits based on checkpoint-level budgets and prior blocks.
66
77
  */
67
78
  async buildBlock(
68
79
  pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
69
80
  blockNumber: BlockNumber,
70
81
  timestamp: bigint,
71
- opts: PublicProcessorLimits & { expectedEndState?: StateReference },
72
- ): Promise<BuildBlockInCheckpointResultWithTimer> {
73
- const blockBuildingTimer = new Timer();
82
+ opts: BlockBuilderOptions & { expectedEndState?: StateReference },
83
+ ): Promise<BuildBlockInCheckpointResult> {
74
84
  const slot = this.checkpointBuilder.constants.slotNumber;
75
85
 
76
- log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
86
+ this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
77
87
  slot,
78
88
  blockNumber,
79
89
  ...opts,
@@ -93,37 +103,67 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
93
103
  });
94
104
  const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
95
105
 
96
- const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs, _, usedTxBlobFields]] = await elapsed(() =>
97
- processor.process(pendingTxs, opts, validator),
98
- );
99
-
100
- // Add block to checkpoint
101
- const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
102
- expectedEndState: opts.expectedEndState,
103
- });
104
-
105
- // How much public gas was processed
106
- const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
107
-
108
- const res = {
109
- block,
110
- publicGas,
111
- publicProcessorDuration,
112
- numTxs: processedTxs.length,
113
- failedTxs,
114
- blockBuildingTimer,
115
- usedTxs,
116
- usedTxBlobFields,
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),
117
110
  };
118
- log.debug('Built block within checkpoint', res.block.header);
119
- return res;
111
+
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);
117
+
118
+ try {
119
+ const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
120
+ processor.process(pendingTxs, cappedOpts, validator),
121
+ );
122
+
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
+ }
120
160
  }
121
161
 
122
162
  /** Completes the checkpoint and returns it. */
123
163
  async completeCheckpoint(): Promise<Checkpoint> {
124
164
  const checkpoint = await this.checkpointBuilder.completeCheckpoint();
125
165
 
126
- log.verbose(`Completed checkpoint ${checkpoint.number}`, {
166
+ this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
127
167
  checkpointNumber: checkpoint.number,
128
168
  numBlocks: checkpoint.blocks.length,
129
169
  archiveRoot: checkpoint.archive.root.toString(),
@@ -137,16 +177,82 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
137
177
  return this.checkpointBuilder.clone().completeCheckpoint();
138
178
  }
139
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
+
140
238
  protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
141
- const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
142
- const contractsDB = new PublicContractsDB(this.contractDataSource);
239
+ const txPublicSetupAllowList = [
240
+ ...(await getDefaultAllowedSetupFunctions()),
241
+ ...(this.config.txPublicSetupAllowListExtend ?? []),
242
+ ];
243
+ const contractsDB = this.contractsDB;
143
244
  const guardedFork = new GuardedMerkleTreeOperations(fork);
144
245
 
246
+ const collectDebugLogs = this.debugLogStore.isEnabled;
247
+
248
+ const bindings = this.log.getBindings();
145
249
  const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
146
250
  guardedFork,
147
251
  contractsDB,
148
252
  globalVariables,
149
253
  this.telemetryClient,
254
+ bindings,
255
+ collectDebugLogs,
150
256
  );
151
257
 
152
258
  const processor = new PublicProcessor(
@@ -156,15 +262,17 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
156
262
  publicTxSimulator,
157
263
  this.dateProvider,
158
264
  this.telemetryClient,
159
- undefined,
265
+ createLogger('simulator:public-processor', bindings),
160
266
  this.config,
267
+ this.debugLogStore,
161
268
  );
162
269
 
163
- const validator = createValidatorForBlockBuilding(
270
+ const validator = createTxValidatorForBlockBuilding(
164
271
  fork,
165
272
  this.contractDataSource,
166
273
  globalVariables,
167
274
  txPublicSetupAllowList,
275
+ this.log.getBindings(),
168
276
  );
169
277
 
170
278
  return {
@@ -176,13 +284,18 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
176
284
 
177
285
  /** Factory for creating checkpoint builders. */
178
286
  export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
287
+ private log: Logger;
288
+
179
289
  constructor(
180
290
  private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
181
291
  private worldState: WorldStateSynchronizer,
182
292
  private contractDataSource: ContractDataSource,
183
293
  private dateProvider: DateProvider,
184
294
  private telemetryClient: TelemetryClient = getTelemetryClient(),
185
- ) {}
295
+ private debugLogStore: DebugLogStore = new NullDebugLogStore(),
296
+ ) {
297
+ this.log = createLogger('checkpoint-builder');
298
+ }
186
299
 
187
300
  public getConfig(): FullNodeBlockBuilderConfig {
188
301
  return this.config;
@@ -198,19 +311,22 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
198
311
  async startCheckpoint(
199
312
  checkpointNumber: CheckpointNumber,
200
313
  constants: CheckpointGlobalVariables,
314
+ feeAssetPriceModifier: bigint,
201
315
  l1ToL2Messages: Fr[],
202
316
  previousCheckpointOutHashes: Fr[],
203
317
  fork: MerkleTreeWriteOperations,
318
+ bindings?: LoggerBindings,
204
319
  ): Promise<CheckpointBuilder> {
205
320
  const stateReference = await fork.getStateReference();
206
321
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
207
322
 
208
- log.verbose(`Building new checkpoint ${checkpointNumber}`, {
323
+ this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
209
324
  checkpointNumber,
210
325
  msgCount: l1ToL2Messages.length,
211
326
  initialStateReference: stateReference.toInspect(),
212
327
  initialArchiveRoot: bufferToHex(archiveTree.root),
213
328
  constants,
329
+ feeAssetPriceModifier,
214
330
  });
215
331
 
216
332
  const lightweightBuilder = await LightweightCheckpointBuilder.startNewCheckpoint(
@@ -219,6 +335,8 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
219
335
  l1ToL2Messages,
220
336
  previousCheckpointOutHashes,
221
337
  fork,
338
+ bindings,
339
+ feeAssetPriceModifier,
222
340
  );
223
341
 
224
342
  return new CheckpointBuilder(
@@ -228,6 +346,8 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
228
346
  this.contractDataSource,
229
347
  this.dateProvider,
230
348
  this.telemetryClient,
349
+ bindings,
350
+ this.debugLogStore,
231
351
  );
232
352
  }
233
353
 
@@ -237,34 +357,47 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
237
357
  async openCheckpoint(
238
358
  checkpointNumber: CheckpointNumber,
239
359
  constants: CheckpointGlobalVariables,
360
+ feeAssetPriceModifier: bigint,
240
361
  l1ToL2Messages: Fr[],
241
362
  previousCheckpointOutHashes: Fr[],
242
363
  fork: MerkleTreeWriteOperations,
243
364
  existingBlocks: L2Block[] = [],
365
+ bindings?: LoggerBindings,
244
366
  ): Promise<CheckpointBuilder> {
245
367
  const stateReference = await fork.getStateReference();
246
368
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
247
369
 
248
370
  if (existingBlocks.length === 0) {
249
- return this.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork);
371
+ return this.startCheckpoint(
372
+ checkpointNumber,
373
+ constants,
374
+ feeAssetPriceModifier,
375
+ l1ToL2Messages,
376
+ previousCheckpointOutHashes,
377
+ fork,
378
+ bindings,
379
+ );
250
380
  }
251
381
 
252
- log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
382
+ this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
253
383
  checkpointNumber,
254
384
  msgCount: l1ToL2Messages.length,
255
385
  existingBlockCount: existingBlocks.length,
256
386
  initialStateReference: stateReference.toInspect(),
257
387
  initialArchiveRoot: bufferToHex(archiveTree.root),
258
388
  constants,
389
+ feeAssetPriceModifier,
259
390
  });
260
391
 
261
392
  const lightweightBuilder = await LightweightCheckpointBuilder.resumeCheckpoint(
262
393
  checkpointNumber,
263
394
  constants,
395
+ feeAssetPriceModifier,
264
396
  l1ToL2Messages,
265
397
  previousCheckpointOutHashes,
266
398
  fork,
267
399
  existingBlocks,
400
+ bindings,
268
401
  );
269
402
 
270
403
  return new CheckpointBuilder(
@@ -274,6 +407,8 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
274
407
  this.contractDataSource,
275
408
  this.dateProvider,
276
409
  this.telemetryClient,
410
+ bindings,
411
+ this.debugLogStore,
277
412
  );
278
413
  }
279
414
 
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).',
@@ -65,15 +78,43 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
65
78
  'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
66
79
  ...booleanConfigHelper(false),
67
80
  },
68
- // TODO(palla/mbps): Change default to false once checkpoint validation is stable
69
81
  skipCheckpointProposalValidation: {
70
- description: 'Skip checkpoint proposal validation and always attest (default: true)',
71
- defaultValue: true,
82
+ description: 'Skip checkpoint proposal validation and always attest (default: false)',
83
+ defaultValue: false,
72
84
  },
73
85
  skipPushProposedBlocksToArchiver: {
74
86
  description: 'Skip pushing re-executed blocks to archiver (default: false)',
75
87
  defaultValue: false,
76
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,
77
118
  ...validatorHASignerConfigMappings,
78
119
  };
79
120
 
@@ -82,6 +123,8 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
82
123
  * Note: If an environment variable is not set, the default value is used.
83
124
  * @returns The validator configuration.
84
125
  */
85
- export function getProverEnvVars(): ValidatorClientConfig {
86
- return getConfigFromMappings<ValidatorClientConfig>(validatorClientConfigMappings);
126
+ export function getProverEnvVars(): ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'> {
127
+ return getConfigFromMappings<ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'>>(
128
+ validatorClientConfigMappings,
129
+ );
87
130
  }