@aztec/validator-client 0.0.1-commit.f295ac2 → 0.0.1-commit.f8ca9b2f3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.0.1-commit.f295ac2",
3
+ "version": "0.0.1-commit.f8ca9b2f3",
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.f295ac2",
68
- "@aztec/blob-lib": "0.0.1-commit.f295ac2",
69
- "@aztec/constants": "0.0.1-commit.f295ac2",
70
- "@aztec/epoch-cache": "0.0.1-commit.f295ac2",
71
- "@aztec/ethereum": "0.0.1-commit.f295ac2",
72
- "@aztec/foundation": "0.0.1-commit.f295ac2",
73
- "@aztec/node-keystore": "0.0.1-commit.f295ac2",
74
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f295ac2",
75
- "@aztec/p2p": "0.0.1-commit.f295ac2",
76
- "@aztec/protocol-contracts": "0.0.1-commit.f295ac2",
77
- "@aztec/prover-client": "0.0.1-commit.f295ac2",
78
- "@aztec/simulator": "0.0.1-commit.f295ac2",
79
- "@aztec/slasher": "0.0.1-commit.f295ac2",
80
- "@aztec/stdlib": "0.0.1-commit.f295ac2",
81
- "@aztec/telemetry-client": "0.0.1-commit.f295ac2",
82
- "@aztec/validator-ha-signer": "0.0.1-commit.f295ac2",
67
+ "@aztec/blob-client": "0.0.1-commit.f8ca9b2f3",
68
+ "@aztec/blob-lib": "0.0.1-commit.f8ca9b2f3",
69
+ "@aztec/constants": "0.0.1-commit.f8ca9b2f3",
70
+ "@aztec/epoch-cache": "0.0.1-commit.f8ca9b2f3",
71
+ "@aztec/ethereum": "0.0.1-commit.f8ca9b2f3",
72
+ "@aztec/foundation": "0.0.1-commit.f8ca9b2f3",
73
+ "@aztec/node-keystore": "0.0.1-commit.f8ca9b2f3",
74
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f8ca9b2f3",
75
+ "@aztec/p2p": "0.0.1-commit.f8ca9b2f3",
76
+ "@aztec/protocol-contracts": "0.0.1-commit.f8ca9b2f3",
77
+ "@aztec/prover-client": "0.0.1-commit.f8ca9b2f3",
78
+ "@aztec/simulator": "0.0.1-commit.f8ca9b2f3",
79
+ "@aztec/slasher": "0.0.1-commit.f8ca9b2f3",
80
+ "@aztec/stdlib": "0.0.1-commit.f8ca9b2f3",
81
+ "@aztec/telemetry-client": "0.0.1-commit.f8ca9b2f3",
82
+ "@aztec/validator-ha-signer": "0.0.1-commit.f8ca9b2f3",
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.f8ca9b2f3",
90
+ "@aztec/world-state": "0.0.1-commit.f8ca9b2f3",
89
91
  "@electric-sql/pglite": "^0.3.14",
90
92
  "@jest/globals": "^30.0.0",
91
93
  "@types/jest": "^30.0.0",
@@ -1,17 +1,17 @@
1
1
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
2
  import type { EpochCache } from '@aztec/epoch-cache';
3
3
  import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
4
+ import { chunkBy } from '@aztec/foundation/collection';
4
5
  import { Fr } from '@aztec/foundation/curves/bn254';
5
6
  import { TimeoutError } from '@aztec/foundation/error';
6
7
  import { createLogger } from '@aztec/foundation/log';
7
8
  import { retryUntil } from '@aztec/foundation/retry';
8
9
  import { DateProvider, Timer } from '@aztec/foundation/timer';
9
10
  import type { P2P, PeerId } from '@aztec/p2p';
10
- import { TxProvider } from '@aztec/p2p';
11
11
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
12
- import type { L2BlockNew, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
12
+ import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
13
13
  import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
14
- import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
14
+ import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
15
15
  import {
16
16
  type L1ToL2MessageSource,
17
17
  computeCheckpointOutHash,
@@ -44,7 +44,7 @@ export type BlockProposalValidationFailureReason =
44
44
  | 'unknown_error';
45
45
 
46
46
  type ReexecuteTransactionsResult = {
47
- block: L2BlockNew;
47
+ block: L2Block;
48
48
  failedTxs: FailedTx[];
49
49
  reexecutionTimeMs: number;
50
50
  totalManaUsed: number;
@@ -77,7 +77,7 @@ export class BlockProposalHandler {
77
77
  private worldState: WorldStateSynchronizer,
78
78
  private blockSource: L2BlockSource & L2BlockSink,
79
79
  private l1ToL2MessageSource: L1ToL2MessageSource,
80
- private txProvider: TxProvider,
80
+ private txProvider: ITxProvider,
81
81
  private blockProposalValidator: BlockProposalValidator,
82
82
  private epochCache: EpochCache,
83
83
  private config: ValidatorClientFullConfig,
@@ -146,8 +146,8 @@ export class BlockProposalHandler {
146
146
 
147
147
  // Check that the proposal is from the current proposer, or the next proposer
148
148
  // This should have been handled by the p2p layer, but we double check here out of caution
149
- const invalidProposal = await this.blockProposalValidator.validate(proposal);
150
- if (invalidProposal) {
149
+ const validationResult = await this.blockProposalValidator.validate(proposal);
150
+ if (validationResult.result !== 'accept') {
151
151
  this.log.warn(`Proposal is not valid, skipping processing`, proposalInfo);
152
152
  return { isValid: false, reason: 'invalid_proposal' };
153
153
  }
@@ -159,9 +159,9 @@ export class BlockProposalHandler {
159
159
  return { isValid: false, reason: 'parent_block_not_found' };
160
160
  }
161
161
 
162
- // Check that the parent block's slot is less than the proposal's slot (should not happen, but we check anyway)
163
- if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() >= slotNumber) {
164
- this.log.warn(`Parent block slot is greater than or equal to proposal slot, skipping processing`, {
162
+ // Check that the parent block's slot is not greater than the proposal's slot.
163
+ if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() > slotNumber) {
164
+ this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
165
165
  parentBlockSlot: parentBlockHeader.getSlot().toString(),
166
166
  proposalSlot: slotNumber.toString(),
167
167
  ...proposalInfo,
@@ -219,15 +219,15 @@ export class BlockProposalHandler {
219
219
  let reexecutionResult;
220
220
  if (shouldReexecute) {
221
221
  // Compute the previous checkpoint out hashes for the epoch.
222
- // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
223
- // TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch all
224
- // the blocks.
222
+ // TODO(leila/mbps): There can be a more efficient way to get the previous checkpoint out
223
+ // hashes without having to fetch all the blocks.
225
224
  const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
226
- const previousBlocks = (await this.blockSource.getBlocksForEpoch(epoch))
227
- .filter(b => b.number < blockNumber)
228
- .sort((a, b) => a.number - b.number);
229
- const previousCheckpointOutHashes = previousBlocks.map(b =>
230
- computeCheckpointOutHash([b.body.txEffects.map(tx => tx.l2ToL1Msgs)]),
225
+ const checkpointedBlocks = (await this.blockSource.getCheckpointedBlocksForEpoch(epoch))
226
+ .filter(b => b.block.number < blockNumber)
227
+ .sort((a, b) => a.block.number - b.block.number);
228
+ const blocksByCheckpoint = chunkBy(checkpointedBlocks, b => b.checkpointNumber);
229
+ const previousCheckpointOutHashes = blocksByCheckpoint.map(checkpointBlocks =>
230
+ computeCheckpointOutHash(checkpointBlocks.map(b => b.block.body.txEffects.map(tx => tx.l2ToL1Msgs))),
231
231
  );
232
232
 
233
233
  try {
@@ -248,7 +248,6 @@ export class BlockProposalHandler {
248
248
  }
249
249
 
250
250
  // If we succeeded, push this block into the archiver (unless disabled)
251
- // TODO(palla/mbps): Change default to false once block sync is stable.
252
251
  if (reexecutionResult?.block && this.config.skipPushProposedBlocksToArchiver === false) {
253
252
  await this.blockSource.addBlock(reexecutionResult?.block);
254
253
  }
@@ -316,7 +315,7 @@ export class BlockProposalHandler {
316
315
  // TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
317
316
  // or at least the L2BlockSource should return a different struct that includes it.
318
317
  const parentBlockNumber = parentBlockHeader.getBlockNumber();
319
- const parentBlock = await this.blockSource.getL2BlockNew(parentBlockNumber);
318
+ const parentBlock = await this.blockSource.getL2Block(parentBlockNumber);
320
319
  if (!parentBlock) {
321
320
  this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
322
321
  return { reason: 'invalid_proposal' };
@@ -357,7 +356,7 @@ export class BlockProposalHandler {
357
356
  */
358
357
  private validateNonFirstBlockInCheckpoint(
359
358
  proposal: BlockProposal,
360
- parentBlock: L2BlockNew,
359
+ parentBlock: L2Block,
361
360
  proposalInfo: object,
362
361
  ): CheckpointComputationResult | undefined {
363
362
  const proposalGlobals = proposal.blockHeader.globalVariables;
@@ -436,29 +435,6 @@ export class BlockProposalHandler {
436
435
  return new Date(nextSlotTimestampSeconds * 1000);
437
436
  }
438
437
 
439
- /**
440
- * Gets all prior blocks in the same checkpoint (same slot and checkpoint number) up to but not including upToBlockNumber.
441
- */
442
- private async getBlocksInCheckpoint(
443
- slot: SlotNumber,
444
- upToBlockNumber: BlockNumber,
445
- checkpointNumber: CheckpointNumber,
446
- ): Promise<L2BlockNew[]> {
447
- const blocks: L2BlockNew[] = [];
448
- let currentBlockNumber = BlockNumber(upToBlockNumber - 1);
449
-
450
- while (currentBlockNumber >= INITIAL_L2_BLOCK_NUM) {
451
- const block = await this.blockSource.getL2BlockNew(currentBlockNumber);
452
- if (!block || block.header.getSlot() !== slot || block.checkpointNumber !== checkpointNumber) {
453
- break;
454
- }
455
- blocks.unshift(block);
456
- currentBlockNumber = BlockNumber(currentBlockNumber - 1);
457
- }
458
-
459
- return blocks;
460
- }
461
-
462
438
  private getReexecuteFailureReason(err: any) {
463
439
  if (err instanceof ReExStateMismatchError) {
464
440
  return 'state_mismatch';
@@ -492,11 +468,13 @@ export class BlockProposalHandler {
492
468
  const slot = proposal.slotNumber;
493
469
  const config = this.checkpointsBuilder.getConfig();
494
470
 
495
- // Get prior blocks in this checkpoint (same slot and checkpoint number)
496
- const priorBlocks = await this.getBlocksInCheckpoint(slot, blockNumber, checkpointNumber);
471
+ // Get prior blocks in this checkpoint (same slot before current block)
472
+ const allBlocksInSlot = await this.blockSource.getBlocksForSlot(slot);
473
+ const priorBlocks = allBlocksInSlot.filter(b => b.number < blockNumber && b.header.getSlot() === slot);
497
474
 
498
475
  // Fork before the block to be built
499
476
  const parentBlockNumber = BlockNumber(blockNumber - 1);
477
+ await this.worldState.syncImmediate(parentBlockNumber);
500
478
  using fork = await this.worldState.fork(parentBlockNumber);
501
479
 
502
480
  // Build checkpoint constants from proposal (excludes blockNumber and timestamp which are per-block)
@@ -517,6 +495,7 @@ export class BlockProposalHandler {
517
495
  previousCheckpointOutHashes,
518
496
  fork,
519
497
  priorBlocks,
498
+ this.log.getBindings(),
520
499
  );
521
500
 
522
501
  // Build the new block
@@ -1,9 +1,9 @@
1
1
  import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
2
  import { merge, pick } from '@aztec/foundation/collection';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
- import { createLogger } from '@aztec/foundation/log';
4
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
5
5
  import { bufferToHex } from '@aztec/foundation/string';
6
- import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
6
+ import { DateProvider, elapsed } from '@aztec/foundation/timer';
7
7
  import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
8
8
  import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
9
9
  import {
@@ -12,7 +12,7 @@ import {
12
12
  PublicProcessor,
13
13
  createPublicTxSimulatorForBlockBuilding,
14
14
  } from '@aztec/simulator/server';
15
- import { L2BlockNew } from '@aztec/stdlib/block';
15
+ import { L2Block } from '@aztec/stdlib/block';
16
16
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
17
17
  import type { ContractDataSource } from '@aztec/stdlib/contract';
18
18
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
@@ -24,6 +24,7 @@ import {
24
24
  type ICheckpointBlockBuilder,
25
25
  type ICheckpointsBuilder,
26
26
  type MerkleTreeWriteOperations,
27
+ NoValidTxsError,
27
28
  type PublicProcessorLimits,
28
29
  type WorldStateSynchronizer,
29
30
  } from '@aztec/stdlib/interfaces/server';
@@ -36,18 +37,13 @@ import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_fac
36
37
  // Re-export for backward compatibility
37
38
  export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
38
39
 
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
40
  /**
47
41
  * Builder for a single checkpoint. Handles building blocks within the checkpoint
48
42
  * and completing it.
49
43
  */
50
44
  export class CheckpointBuilder implements ICheckpointBlockBuilder {
45
+ private log: Logger;
46
+
51
47
  constructor(
52
48
  private checkpointBuilder: LightweightCheckpointBuilder,
53
49
  private fork: MerkleTreeWriteOperations,
@@ -55,7 +51,13 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
55
51
  private contractDataSource: ContractDataSource,
56
52
  private dateProvider: DateProvider,
57
53
  private telemetryClient: TelemetryClient,
58
- ) {}
54
+ bindings?: LoggerBindings,
55
+ ) {
56
+ this.log = createLogger('checkpoint-builder', {
57
+ ...bindings,
58
+ instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
59
+ });
60
+ }
59
61
 
60
62
  getConstantData(): CheckpointGlobalVariables {
61
63
  return this.checkpointBuilder.constants;
@@ -68,12 +70,11 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
68
70
  pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
69
71
  blockNumber: BlockNumber,
70
72
  timestamp: bigint,
71
- opts: PublicProcessorLimits & { expectedEndState?: StateReference },
72
- ): Promise<BuildBlockInCheckpointResultWithTimer> {
73
- const blockBuildingTimer = new Timer();
73
+ opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
74
+ ): Promise<BuildBlockInCheckpointResult> {
74
75
  const slot = this.checkpointBuilder.constants.slotNumber;
75
76
 
76
- log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
77
+ this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
77
78
  slot,
78
79
  blockNumber,
79
80
  ...opts,
@@ -97,6 +98,12 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
97
98
  processor.process(pendingTxs, opts, validator),
98
99
  );
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
+
100
107
  // Add block to checkpoint
101
108
  const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
102
109
  expectedEndState: opts.expectedEndState,
@@ -105,25 +112,28 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
105
112
  // How much public gas was processed
106
113
  const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
107
114
 
108
- const res = {
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
+ });
120
+
121
+ return {
109
122
  block,
110
123
  publicGas,
111
124
  publicProcessorDuration,
112
125
  numTxs: processedTxs.length,
113
126
  failedTxs,
114
- blockBuildingTimer,
115
127
  usedTxs,
116
128
  usedTxBlobFields,
117
129
  };
118
- log.debug('Built block within checkpoint', res.block.header);
119
- return res;
120
130
  }
121
131
 
122
132
  /** Completes the checkpoint and returns it. */
123
133
  async completeCheckpoint(): Promise<Checkpoint> {
124
134
  const checkpoint = await this.checkpointBuilder.completeCheckpoint();
125
135
 
126
- log.verbose(`Completed checkpoint ${checkpoint.number}`, {
136
+ this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
127
137
  checkpointNumber: checkpoint.number,
128
138
  numBlocks: checkpoint.blocks.length,
129
139
  archiveRoot: checkpoint.archive.root.toString(),
@@ -139,14 +149,16 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
139
149
 
140
150
  protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
141
151
  const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
142
- const contractsDB = new PublicContractsDB(this.contractDataSource);
152
+ const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
143
153
  const guardedFork = new GuardedMerkleTreeOperations(fork);
144
154
 
155
+ const bindings = this.log.getBindings();
145
156
  const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
146
157
  guardedFork,
147
158
  contractsDB,
148
159
  globalVariables,
149
160
  this.telemetryClient,
161
+ bindings,
150
162
  );
151
163
 
152
164
  const processor = new PublicProcessor(
@@ -156,7 +168,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
156
168
  publicTxSimulator,
157
169
  this.dateProvider,
158
170
  this.telemetryClient,
159
- undefined,
171
+ createLogger('simulator:public-processor', bindings),
160
172
  this.config,
161
173
  );
162
174
 
@@ -165,6 +177,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
165
177
  this.contractDataSource,
166
178
  globalVariables,
167
179
  txPublicSetupAllowList,
180
+ this.log.getBindings(),
168
181
  );
169
182
 
170
183
  return {
@@ -176,13 +189,17 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
176
189
 
177
190
  /** Factory for creating checkpoint builders. */
178
191
  export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
192
+ private log: Logger;
193
+
179
194
  constructor(
180
195
  private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
181
196
  private worldState: WorldStateSynchronizer,
182
197
  private contractDataSource: ContractDataSource,
183
198
  private dateProvider: DateProvider,
184
199
  private telemetryClient: TelemetryClient = getTelemetryClient(),
185
- ) {}
200
+ ) {
201
+ this.log = createLogger('checkpoint-builder');
202
+ }
186
203
 
187
204
  public getConfig(): FullNodeBlockBuilderConfig {
188
205
  return this.config;
@@ -201,11 +218,12 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
201
218
  l1ToL2Messages: Fr[],
202
219
  previousCheckpointOutHashes: Fr[],
203
220
  fork: MerkleTreeWriteOperations,
221
+ bindings?: LoggerBindings,
204
222
  ): Promise<CheckpointBuilder> {
205
223
  const stateReference = await fork.getStateReference();
206
224
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
207
225
 
208
- log.verbose(`Building new checkpoint ${checkpointNumber}`, {
226
+ this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
209
227
  checkpointNumber,
210
228
  msgCount: l1ToL2Messages.length,
211
229
  initialStateReference: stateReference.toInspect(),
@@ -219,6 +237,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
219
237
  l1ToL2Messages,
220
238
  previousCheckpointOutHashes,
221
239
  fork,
240
+ bindings,
222
241
  );
223
242
 
224
243
  return new CheckpointBuilder(
@@ -228,6 +247,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
228
247
  this.contractDataSource,
229
248
  this.dateProvider,
230
249
  this.telemetryClient,
250
+ bindings,
231
251
  );
232
252
  }
233
253
 
@@ -240,16 +260,24 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
240
260
  l1ToL2Messages: Fr[],
241
261
  previousCheckpointOutHashes: Fr[],
242
262
  fork: MerkleTreeWriteOperations,
243
- existingBlocks: L2BlockNew[] = [],
263
+ existingBlocks: L2Block[] = [],
264
+ bindings?: LoggerBindings,
244
265
  ): Promise<CheckpointBuilder> {
245
266
  const stateReference = await fork.getStateReference();
246
267
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
247
268
 
248
269
  if (existingBlocks.length === 0) {
249
- return this.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork);
270
+ return this.startCheckpoint(
271
+ checkpointNumber,
272
+ constants,
273
+ l1ToL2Messages,
274
+ previousCheckpointOutHashes,
275
+ fork,
276
+ bindings,
277
+ );
250
278
  }
251
279
 
252
- log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
280
+ this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
253
281
  checkpointNumber,
254
282
  msgCount: l1ToL2Messages.length,
255
283
  existingBlockCount: existingBlocks.length,
@@ -265,6 +293,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
265
293
  previousCheckpointOutHashes,
266
294
  fork,
267
295
  existingBlocks,
296
+ bindings,
268
297
  );
269
298
 
270
299
  return new CheckpointBuilder(
@@ -274,6 +303,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
274
303
  this.contractDataSource,
275
304
  this.dateProvider,
276
305
  this.telemetryClient,
306
+ bindings,
277
307
  );
278
308
  }
279
309
 
package/src/config.ts CHANGED
@@ -65,15 +65,17 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
65
65
  'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
66
66
  ...booleanConfigHelper(false),
67
67
  },
68
- // TODO(palla/mbps): Change default to false once checkpoint validation is stable
69
68
  skipCheckpointProposalValidation: {
70
- description: 'Skip checkpoint proposal validation and always attest (default: true)',
71
- defaultValue: true,
69
+ description: 'Skip checkpoint proposal validation and always attest (default: false)',
70
+ defaultValue: false,
72
71
  },
73
- // TODO(palla/mbps): Change default to false once block sync is stable
74
72
  skipPushProposedBlocksToArchiver: {
75
- description: 'Skip pushing re-executed blocks to archiver (default: true)',
76
- defaultValue: true,
73
+ description: 'Skip pushing re-executed blocks to archiver (default: false)',
74
+ defaultValue: false,
75
+ },
76
+ attestToEquivocatedProposals: {
77
+ description: 'Agree to attest to equivocated checkpoint proposals (for testing purposes only)',
78
+ ...booleanConfigHelper(false),
77
79
  },
78
80
  ...validatorHASignerConfigMappings,
79
81
  };
@@ -256,8 +256,8 @@ export class HAKeyStore implements ExtendedValidatorKeyStore {
256
256
  /**
257
257
  * Start the high-availability key store
258
258
  */
259
- public start(): Promise<void> {
260
- return Promise.resolve(this.haSigner.start());
259
+ public async start() {
260
+ await this.haSigner.start();
261
261
  }
262
262
 
263
263
  /**
package/src/metrics.ts CHANGED
@@ -6,8 +6,11 @@ import {
6
6
  Metrics,
7
7
  type TelemetryClient,
8
8
  type UpDownCounter,
9
+ createUpDownCounterWithDefault,
9
10
  } from '@aztec/telemetry-client';
10
11
 
12
+ import type { BlockProposalValidationFailureReason } from './block_proposal_handler.js';
13
+
11
14
  export class ValidatorMetrics {
12
15
  private failedReexecutionCounter: UpDownCounter;
13
16
  private successfulAttestationsCount: UpDownCounter;
@@ -21,16 +24,44 @@ export class ValidatorMetrics {
21
24
  constructor(telemetryClient: TelemetryClient) {
22
25
  const meter = telemetryClient.getMeter('Validator');
23
26
 
24
- this.failedReexecutionCounter = meter.createUpDownCounter(Metrics.VALIDATOR_FAILED_REEXECUTION_COUNT);
27
+ this.failedReexecutionCounter = createUpDownCounterWithDefault(meter, Metrics.VALIDATOR_FAILED_REEXECUTION_COUNT, {
28
+ [Attributes.STATUS]: ['failed'],
29
+ });
25
30
 
26
- this.successfulAttestationsCount = meter.createUpDownCounter(Metrics.VALIDATOR_ATTESTATION_SUCCESS_COUNT);
31
+ this.successfulAttestationsCount = createUpDownCounterWithDefault(
32
+ meter,
33
+ Metrics.VALIDATOR_ATTESTATION_SUCCESS_COUNT,
34
+ );
27
35
 
28
- this.failedAttestationsBadProposalCount = meter.createUpDownCounter(
36
+ this.failedAttestationsBadProposalCount = createUpDownCounterWithDefault(
37
+ meter,
29
38
  Metrics.VALIDATOR_ATTESTATION_FAILED_BAD_PROPOSAL_COUNT,
39
+ {
40
+ [Attributes.ERROR_TYPE]: [
41
+ 'invalid_proposal',
42
+ 'state_mismatch',
43
+ 'failed_txs',
44
+ 'in_hash_mismatch',
45
+ 'parent_block_wrong_slot',
46
+ ],
47
+ [Attributes.IS_COMMITTEE_MEMBER]: [true, false],
48
+ },
30
49
  );
31
50
 
32
- this.failedAttestationsNodeIssueCount = meter.createUpDownCounter(
51
+ this.failedAttestationsNodeIssueCount = createUpDownCounterWithDefault(
52
+ meter,
33
53
  Metrics.VALIDATOR_ATTESTATION_FAILED_NODE_ISSUE_COUNT,
54
+ {
55
+ [Attributes.ERROR_TYPE]: [
56
+ 'parent_block_not_found',
57
+ 'global_variables_mismatch',
58
+ 'block_number_already_exists',
59
+ 'txs_not_available',
60
+ 'timeout',
61
+ 'unknown_error',
62
+ ],
63
+ [Attributes.IS_COMMITTEE_MEMBER]: [true, false],
64
+ },
34
65
  );
35
66
 
36
67
  this.reexMana = meter.createHistogram(Metrics.VALIDATOR_RE_EXECUTION_MANA);
@@ -58,14 +89,22 @@ export class ValidatorMetrics {
58
89
  this.successfulAttestationsCount.add(num);
59
90
  }
60
91
 
61
- public incFailedAttestationsBadProposal(num: number, reason: string, inCommittee: boolean) {
92
+ public incFailedAttestationsBadProposal(
93
+ num: number,
94
+ reason: BlockProposalValidationFailureReason,
95
+ inCommittee: boolean,
96
+ ) {
62
97
  this.failedAttestationsBadProposalCount.add(num, {
63
98
  [Attributes.ERROR_TYPE]: reason,
64
99
  [Attributes.IS_COMMITTEE_MEMBER]: inCommittee,
65
100
  });
66
101
  }
67
102
 
68
- public incFailedAttestationsNodeIssue(num: number, reason: string, inCommittee: boolean) {
103
+ public incFailedAttestationsNodeIssue(
104
+ num: number,
105
+ reason: BlockProposalValidationFailureReason,
106
+ inCommittee: boolean,
107
+ ) {
69
108
  this.failedAttestationsNodeIssueCount.add(num, {
70
109
  [Attributes.ERROR_TYPE]: reason,
71
110
  [Attributes.IS_COMMITTEE_MEMBER]: inCommittee,