@aztec/validator-client 0.0.1-commit.3469e52 → 0.0.1-commit.54489865

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.
@@ -1,7 +1,7 @@
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
6
  import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
7
7
  import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
@@ -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';
@@ -36,8 +36,6 @@ import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_fac
36
36
  // Re-export for backward compatibility
37
37
  export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
38
38
 
39
- const log = createLogger('checkpoint-builder');
40
-
41
39
  /** Result of building a block within a checkpoint. Extends the base interface with timer. */
42
40
  export interface BuildBlockInCheckpointResultWithTimer extends BuildBlockInCheckpointResult {
43
41
  blockBuildingTimer: Timer;
@@ -48,6 +46,8 @@ export interface BuildBlockInCheckpointResultWithTimer extends BuildBlockInCheck
48
46
  * and completing it.
49
47
  */
50
48
  export class CheckpointBuilder implements ICheckpointBlockBuilder {
49
+ private log: Logger;
50
+
51
51
  constructor(
52
52
  private checkpointBuilder: LightweightCheckpointBuilder,
53
53
  private fork: MerkleTreeWriteOperations,
@@ -55,7 +55,13 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
55
55
  private contractDataSource: ContractDataSource,
56
56
  private dateProvider: DateProvider,
57
57
  private telemetryClient: TelemetryClient,
58
- ) {}
58
+ bindings?: LoggerBindings,
59
+ ) {
60
+ this.log = createLogger('checkpoint-builder', {
61
+ ...bindings,
62
+ instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
63
+ });
64
+ }
59
65
 
60
66
  getConstantData(): CheckpointGlobalVariables {
61
67
  return this.checkpointBuilder.constants;
@@ -68,12 +74,12 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
68
74
  pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
69
75
  blockNumber: BlockNumber,
70
76
  timestamp: bigint,
71
- opts: PublicProcessorLimits & { expectedEndState?: StateReference },
77
+ opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
72
78
  ): Promise<BuildBlockInCheckpointResultWithTimer> {
73
79
  const blockBuildingTimer = new Timer();
74
80
  const slot = this.checkpointBuilder.constants.slotNumber;
75
81
 
76
- log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
82
+ this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
77
83
  slot,
78
84
  blockNumber,
79
85
  ...opts,
@@ -115,7 +121,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
115
121
  usedTxs,
116
122
  usedTxBlobFields,
117
123
  };
118
- log.debug('Built block within checkpoint', res.block.header);
124
+ this.log.debug('Built block within checkpoint', res.block.header);
119
125
  return res;
120
126
  }
121
127
 
@@ -123,7 +129,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
123
129
  async completeCheckpoint(): Promise<Checkpoint> {
124
130
  const checkpoint = await this.checkpointBuilder.completeCheckpoint();
125
131
 
126
- log.verbose(`Completed checkpoint ${checkpoint.number}`, {
132
+ this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
127
133
  checkpointNumber: checkpoint.number,
128
134
  numBlocks: checkpoint.blocks.length,
129
135
  archiveRoot: checkpoint.archive.root.toString(),
@@ -139,14 +145,16 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
139
145
 
140
146
  protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
141
147
  const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
142
- const contractsDB = new PublicContractsDB(this.contractDataSource);
148
+ const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
143
149
  const guardedFork = new GuardedMerkleTreeOperations(fork);
144
150
 
151
+ const bindings = this.log.getBindings();
145
152
  const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
146
153
  guardedFork,
147
154
  contractsDB,
148
155
  globalVariables,
149
156
  this.telemetryClient,
157
+ bindings,
150
158
  );
151
159
 
152
160
  const processor = new PublicProcessor(
@@ -156,7 +164,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
156
164
  publicTxSimulator,
157
165
  this.dateProvider,
158
166
  this.telemetryClient,
159
- undefined,
167
+ createLogger('simulator:public-processor', bindings),
160
168
  this.config,
161
169
  );
162
170
 
@@ -165,6 +173,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
165
173
  this.contractDataSource,
166
174
  globalVariables,
167
175
  txPublicSetupAllowList,
176
+ this.log.getBindings(),
168
177
  );
169
178
 
170
179
  return {
@@ -176,13 +185,17 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
176
185
 
177
186
  /** Factory for creating checkpoint builders. */
178
187
  export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
188
+ private log: Logger;
189
+
179
190
  constructor(
180
191
  private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
181
192
  private worldState: WorldStateSynchronizer,
182
193
  private contractDataSource: ContractDataSource,
183
194
  private dateProvider: DateProvider,
184
195
  private telemetryClient: TelemetryClient = getTelemetryClient(),
185
- ) {}
196
+ ) {
197
+ this.log = createLogger('checkpoint-builder');
198
+ }
186
199
 
187
200
  public getConfig(): FullNodeBlockBuilderConfig {
188
201
  return this.config;
@@ -201,11 +214,12 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
201
214
  l1ToL2Messages: Fr[],
202
215
  previousCheckpointOutHashes: Fr[],
203
216
  fork: MerkleTreeWriteOperations,
217
+ bindings?: LoggerBindings,
204
218
  ): Promise<CheckpointBuilder> {
205
219
  const stateReference = await fork.getStateReference();
206
220
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
207
221
 
208
- log.verbose(`Building new checkpoint ${checkpointNumber}`, {
222
+ this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
209
223
  checkpointNumber,
210
224
  msgCount: l1ToL2Messages.length,
211
225
  initialStateReference: stateReference.toInspect(),
@@ -219,6 +233,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
219
233
  l1ToL2Messages,
220
234
  previousCheckpointOutHashes,
221
235
  fork,
236
+ bindings,
222
237
  );
223
238
 
224
239
  return new CheckpointBuilder(
@@ -228,6 +243,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
228
243
  this.contractDataSource,
229
244
  this.dateProvider,
230
245
  this.telemetryClient,
246
+ bindings,
231
247
  );
232
248
  }
233
249
 
@@ -240,16 +256,24 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
240
256
  l1ToL2Messages: Fr[],
241
257
  previousCheckpointOutHashes: Fr[],
242
258
  fork: MerkleTreeWriteOperations,
243
- existingBlocks: L2BlockNew[] = [],
259
+ existingBlocks: L2Block[] = [],
260
+ bindings?: LoggerBindings,
244
261
  ): Promise<CheckpointBuilder> {
245
262
  const stateReference = await fork.getStateReference();
246
263
  const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
247
264
 
248
265
  if (existingBlocks.length === 0) {
249
- return this.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork);
266
+ return this.startCheckpoint(
267
+ checkpointNumber,
268
+ constants,
269
+ l1ToL2Messages,
270
+ previousCheckpointOutHashes,
271
+ fork,
272
+ bindings,
273
+ );
250
274
  }
251
275
 
252
- log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
276
+ this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
253
277
  checkpointNumber,
254
278
  msgCount: l1ToL2Messages.length,
255
279
  existingBlockCount: existingBlocks.length,
@@ -265,6 +289,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
265
289
  previousCheckpointOutHashes,
266
290
  fork,
267
291
  existingBlocks,
292
+ bindings,
268
293
  );
269
294
 
270
295
  return new CheckpointBuilder(
@@ -274,6 +299,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
274
299
  this.contractDataSource,
275
300
  this.dateProvider,
276
301
  this.telemetryClient,
302
+ bindings,
277
303
  );
278
304
  }
279
305
 
package/src/config.ts CHANGED
@@ -65,15 +65,13 @@ 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,
77
75
  },
78
76
  ...validatorHASignerConfigMappings,
79
77
  };
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,
@@ -1,5 +1,6 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import type { LoggerBindings } from '@aztec/foundation/log';
3
4
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
4
5
  import {
5
6
  AggregateTxValidator,
@@ -53,32 +54,41 @@ export function createValidatorForAcceptingTxs(
53
54
  blockNumber: BlockNumber;
54
55
  txsPermitted: boolean;
55
56
  },
57
+ bindings?: LoggerBindings,
56
58
  ): TxValidator<Tx> {
57
59
  const validators: TxValidator<Tx>[] = [
58
- new TxPermittedValidator(txsPermitted),
59
- new SizeTxValidator(),
60
- new DataTxValidator(),
61
- new MetadataTxValidator({
62
- l1ChainId: new Fr(l1ChainId),
63
- rollupVersion: new Fr(rollupVersion),
64
- protocolContractsHash,
65
- vkTreeRoot: getVKTreeRoot(),
66
- }),
67
- new TimestampTxValidator({
68
- timestamp,
69
- blockNumber,
70
- }),
71
- new DoubleSpendTxValidator(new NullifierCache(db)),
72
- new PhasesTxValidator(contractDataSource, setupAllowList, timestamp),
73
- new BlockHeaderTxValidator(new ArchiveCache(db)),
60
+ new TxPermittedValidator(txsPermitted, bindings),
61
+ new SizeTxValidator(bindings),
62
+ new DataTxValidator(bindings),
63
+ new MetadataTxValidator(
64
+ {
65
+ l1ChainId: new Fr(l1ChainId),
66
+ rollupVersion: new Fr(rollupVersion),
67
+ protocolContractsHash,
68
+ vkTreeRoot: getVKTreeRoot(),
69
+ },
70
+ bindings,
71
+ ),
72
+ new TimestampTxValidator(
73
+ {
74
+ timestamp,
75
+ blockNumber,
76
+ },
77
+ bindings,
78
+ ),
79
+ new DoubleSpendTxValidator(new NullifierCache(db), bindings),
80
+ new PhasesTxValidator(contractDataSource, setupAllowList, timestamp, bindings),
81
+ new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
74
82
  ];
75
83
 
76
84
  if (!skipFeeEnforcement) {
77
- validators.push(new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees));
85
+ validators.push(
86
+ new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings),
87
+ );
78
88
  }
79
89
 
80
90
  if (verifier) {
81
- validators.push(new TxProofValidator(verifier));
91
+ validators.push(new TxProofValidator(verifier, bindings));
82
92
  }
83
93
 
84
94
  return new AggregateTxValidator(...validators);
@@ -89,6 +99,7 @@ export function createValidatorForBlockBuilding(
89
99
  contractDataSource: ContractDataSource,
90
100
  globalVariables: GlobalVariables,
91
101
  setupAllowList: AllowedElement[],
102
+ bindings?: LoggerBindings,
92
103
  ): PublicProcessorValidator {
93
104
  const nullifierCache = new NullifierCache(db);
94
105
  const archiveCache = new ArchiveCache(db);
@@ -102,6 +113,7 @@ export function createValidatorForBlockBuilding(
102
113
  contractDataSource,
103
114
  globalVariables,
104
115
  setupAllowList,
116
+ bindings,
105
117
  ),
106
118
  nullifierCache,
107
119
  };
@@ -114,22 +126,29 @@ function preprocessValidator(
114
126
  contractDataSource: ContractDataSource,
115
127
  globalVariables: GlobalVariables,
116
128
  setupAllowList: AllowedElement[],
129
+ bindings?: LoggerBindings,
117
130
  ): TxValidator<Tx> {
118
131
  // We don't include the TxProofValidator nor the DataTxValidator here because they are already checked by the time we get to block building.
119
132
  return new AggregateTxValidator(
120
- new MetadataTxValidator({
121
- l1ChainId: globalVariables.chainId,
122
- rollupVersion: globalVariables.version,
123
- protocolContractsHash,
124
- vkTreeRoot: getVKTreeRoot(),
125
- }),
126
- new TimestampTxValidator({
127
- timestamp: globalVariables.timestamp,
128
- blockNumber: globalVariables.blockNumber,
129
- }),
130
- new DoubleSpendTxValidator(nullifierCache),
131
- new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.timestamp),
132
- new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees),
133
- new BlockHeaderTxValidator(archiveCache),
133
+ new MetadataTxValidator(
134
+ {
135
+ l1ChainId: globalVariables.chainId,
136
+ rollupVersion: globalVariables.version,
137
+ protocolContractsHash,
138
+ vkTreeRoot: getVKTreeRoot(),
139
+ },
140
+ bindings,
141
+ ),
142
+ new TimestampTxValidator(
143
+ {
144
+ timestamp: globalVariables.timestamp,
145
+ blockNumber: globalVariables.blockNumber,
146
+ },
147
+ bindings,
148
+ ),
149
+ new DoubleSpendTxValidator(nullifierCache, bindings),
150
+ new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.timestamp, bindings),
151
+ new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees, bindings),
152
+ new BlockHeaderTxValidator(archiveCache, bindings),
134
153
  );
135
154
  }
package/src/validator.ts CHANGED
@@ -18,19 +18,20 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
18
18
  import { sleep } from '@aztec/foundation/sleep';
19
19
  import { DateProvider } from '@aztec/foundation/timer';
20
20
  import type { KeystoreManager } from '@aztec/node-keystore';
21
- import type { P2P, PeerId, TxProvider } from '@aztec/p2p';
21
+ import type { P2P, PeerId } from '@aztec/p2p';
22
22
  import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
23
23
  import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
24
24
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
25
- import type { CommitteeAttestationsAndSigners, L2BlockNew, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
25
+ import type { CommitteeAttestationsAndSigners, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
26
26
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
27
27
  import type {
28
28
  CreateCheckpointProposalLastBlockData,
29
+ ITxProvider,
29
30
  Validator,
30
31
  ValidatorClientFullConfig,
31
32
  WorldStateSynchronizer,
32
33
  } from '@aztec/stdlib/interfaces/server';
33
- import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
34
+ import { type L1ToL2MessageSource, accumulateCheckpointOutHashes } from '@aztec/stdlib/messaging';
34
35
  import type {
35
36
  BlockProposal,
36
37
  BlockProposalOptions,
@@ -87,11 +88,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
87
88
 
88
89
  private proposersOfInvalidBlocks: Set<string> = new Set();
89
90
 
90
- // TODO(palla/mbps): Remove this once checkpoint validation is stable and we can validate all blocks properly.
91
- // Tracks slots for which we have successfully validated a block proposal, so we can attest to checkpoint proposals for those slots.
92
- // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
93
- private validatedBlockSlots: Set<SlotNumber> = new Set();
94
-
95
91
  protected constructor(
96
92
  private keyStore: ExtendedValidatorKeyStore,
97
93
  private epochCache: EpochCache,
@@ -184,7 +180,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
184
180
  p2pClient: P2P,
185
181
  blockSource: L2BlockSource & L2BlockSink,
186
182
  l1ToL2MessageSource: L1ToL2MessageSource,
187
- txProvider: TxProvider,
183
+ txProvider: ITxProvider,
188
184
  keyStoreManager: KeystoreManager,
189
185
  blobClient: BlobClientInterface,
190
186
  dateProvider: DateProvider = new DateProvider(),
@@ -413,10 +409,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
413
409
  return false;
414
410
  }
415
411
 
416
- // TODO(palla/mbps): Remove this once checkpoint validation is stable.
417
- // Track that we successfully validated a block for this slot, so we can attest to checkpoint proposals for it.
418
- this.validatedBlockSlots.add(slotNumber);
419
-
420
412
  return true;
421
413
  }
422
414
 
@@ -461,17 +453,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
461
453
  fishermanMode: this.config.fishermanMode || false,
462
454
  });
463
455
 
464
- // TODO(palla/mbps): Remove this once checkpoint validation is stable.
465
- // Check that we have successfully validated a block for this slot before attesting to the checkpoint.
466
- if (!this.validatedBlockSlots.has(slotNumber)) {
467
- this.log.warn(`No validated block found for slot ${slotNumber}, refusing to attest to checkpoint`, proposalInfo);
468
- return undefined;
469
- }
470
-
471
456
  // Validate the checkpoint proposal before attesting (unless skipCheckpointProposalValidation is set)
472
- // TODO(palla/mbps): Change default to false once checkpoint validation is stable.
473
- if (this.config.skipCheckpointProposalValidation !== false) {
474
- this.log.verbose(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
457
+ if (this.config.skipCheckpointProposalValidation) {
458
+ this.log.warn(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
475
459
  } else {
476
460
  const validationResult = await this.validateCheckpointProposal(proposal, proposalInfo);
477
461
  if (!validationResult.isValid) {
@@ -547,7 +531,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
547
531
  proposalInfo: LogData,
548
532
  ): Promise<{ isValid: true } | { isValid: false; reason: string }> {
549
533
  const slot = proposal.slotNumber;
550
- const timeoutSeconds = 10;
534
+ const timeoutSeconds = 10; // TODO(palla/mbps): This should map to the timetable settings
551
535
 
552
536
  // Wait for last block to sync by archive
553
537
  let lastBlockHeader: BlockHeader | undefined;
@@ -617,6 +601,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
617
601
  previousCheckpointOutHashes,
618
602
  fork,
619
603
  blocks,
604
+ this.log.getBindings(),
620
605
  );
621
606
 
622
607
  // Complete the checkpoint to get computed values
@@ -642,13 +627,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
642
627
  return { isValid: false, reason: 'archive_mismatch' };
643
628
  }
644
629
 
645
- // Check that the accumulated out hash matches the value in the proposal.
646
- const computedOutHash = computedCheckpoint.getCheckpointOutHash();
647
- const proposalOutHash = proposal.checkpointHeader.epochOutHash;
648
- if (!computedOutHash.equals(proposalOutHash)) {
630
+ // Check that the accumulated epoch out hash matches the value in the proposal.
631
+ // The epoch out hash is the accumulated hash of all checkpoint out hashes in the epoch.
632
+ const checkpointOutHash = computedCheckpoint.getCheckpointOutHash();
633
+ const computedEpochOutHash = accumulateCheckpointOutHashes([...previousCheckpointOutHashes, checkpointOutHash]);
634
+ const proposalEpochOutHash = proposal.checkpointHeader.epochOutHash;
635
+ if (!computedEpochOutHash.equals(proposalEpochOutHash)) {
649
636
  this.log.warn(`Epoch out hash mismatch`, {
650
- proposalOutHash: proposalOutHash.toString(),
651
- computedOutHash: computedOutHash.toString(),
637
+ proposalEpochOutHash: proposalEpochOutHash.toString(),
638
+ computedEpochOutHash: computedEpochOutHash.toString(),
639
+ checkpointOutHash: checkpointOutHash.toString(),
640
+ previousCheckpointOutHashes: previousCheckpointOutHashes.map(h => h.toString()),
652
641
  ...proposalInfo,
653
642
  });
654
643
  return { isValid: false, reason: 'out_hash_mismatch' };
@@ -664,7 +653,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
664
653
  /**
665
654
  * Extract checkpoint global variables from a block.
666
655
  */
667
- private extractCheckpointConstants(block: L2BlockNew): CheckpointGlobalVariables {
656
+ private extractCheckpointConstants(block: L2Block): CheckpointGlobalVariables {
668
657
  const gv = block.header.globalVariables;
669
658
  return {
670
659
  chainId: gv.chainId,
@@ -739,7 +728,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
739
728
  archive: Fr,
740
729
  txs: Tx[],
741
730
  proposerAddress: EthAddress | undefined,
742
- options: BlockProposalOptions,
731
+ options: BlockProposalOptions = {},
743
732
  ): Promise<BlockProposal> {
744
733
  // TODO(palla/mbps): Prevent double proposals properly
745
734
  // if (this.previousProposal?.slotNumber === blockHeader.globalVariables.slotNumber) {
@@ -771,7 +760,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
771
760
  archive: Fr,
772
761
  lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
773
762
  proposerAddress: EthAddress | undefined,
774
- options: CheckpointProposalOptions,
763
+ options: CheckpointProposalOptions = {},
775
764
  ): Promise<CheckpointProposal> {
776
765
  this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
777
766
  return await this.validationService.createCheckpointProposal(