@aztec/validator-client 0.0.1-commit.b2a5d0dd1 → 0.0.1-commit.b3d3157a

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.
@@ -11,6 +11,7 @@ import type { P2P, PeerId } from '@aztec/p2p';
11
11
  import { type Watcher, type WatcherEmitter } from '@aztec/slasher';
12
12
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
13
13
  import type { CommitteeAttestationsAndSigners, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
14
+ import type { CheckpointReexecutionTracker } from '@aztec/stdlib/checkpoint';
14
15
  import type { ITxProvider, Validator, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
15
16
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
16
17
  import { type BlockProposal, type BlockProposalOptions, type CheckpointAttestation, CheckpointProposal, type CheckpointProposalCore, type CheckpointProposalOptions } from '@aztec/stdlib/p2p';
@@ -54,18 +55,25 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
54
55
  /** Tracks the last epoch in which each attester successfully submitted at least one attestation. */
55
56
  private lastAttestedEpochByAttester;
56
57
  private proposersOfInvalidBlocks;
58
+ private slotsWithInvalidProposals;
59
+ private invalidCheckpointProposalOffenseKeys;
60
+ private badAttestationOffenseKeys;
61
+ private slotsWithProposalEquivocation;
57
62
  /** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
58
63
  private lastAttestedProposal?;
59
64
  protected constructor(keyStore: ExtendedValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, proposalHandler: ProposalHandler, blockSource: L2BlockSource, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, l1ToL2MessageSource: L1ToL2MessageSource, config: ValidatorClientFullConfig, blobClient: BlobClientInterface, slashingProtectionSigner: ValidatorHASigner, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: Logger);
60
65
  static validateKeyStoreConfiguration(keyStoreManager: KeystoreManager, logger?: Logger): void;
61
66
  private handleEpochCommitteeUpdate;
62
- static new(config: ValidatorClientFullConfig, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, keyStoreManager: KeystoreManager, blobClient: BlobClientInterface, dateProvider?: DateProvider, telemetry?: TelemetryClient, slashingProtectionDb?: SlashingProtectionDatabase): Promise<ValidatorClient>;
67
+ static new(config: ValidatorClientFullConfig, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, keyStoreManager: KeystoreManager, blobClient: BlobClientInterface, reexecutionTracker: CheckpointReexecutionTracker, dateProvider?: DateProvider, telemetry?: TelemetryClient, slashingProtectionDb?: SlashingProtectionDatabase): Promise<ValidatorClient>;
63
68
  getValidatorAddresses(): EthAddress[];
64
69
  getProposalHandler(): ProposalHandler;
65
70
  signWithAddress(addr: EthAddress, msg: TypedDataDefinition, context: SigningContext): Promise<Signature>;
71
+ private getSignatureContext;
66
72
  getCoinbaseForAttestor(attestor: EthAddress): EthAddress;
67
73
  getFeeRecipientForAttestor(attestor: EthAddress): AztecAddress;
68
74
  getConfig(): ValidatorClientFullConfig;
75
+ hasProposalEquivocation(slotNumber: SlotNumber): boolean;
76
+ hasInvalidProposals(slotNumber: SlotNumber): boolean;
69
77
  updateConfig(config: Partial<ValidatorClientFullConfig>): void;
70
78
  reloadKeystore(newManager: KeystoreManager): void;
71
79
  start(): Promise<void>;
@@ -96,6 +104,11 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
96
104
  */
97
105
  protected uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void>;
98
106
  private slashInvalidBlock;
107
+ private handleInvalidCheckpointProposal;
108
+ private slashInvalidCheckpointProposal;
109
+ private markInvalidProposalSlot;
110
+ private handleCheckpointAttestation;
111
+ private slashAttestedToInvalidCheckpointProposal;
99
112
  /**
100
113
  * Handle detection of a duplicate proposal (equivocation).
101
114
  * Emits a slash event when a proposer sends multiple proposals for the same position.
@@ -115,4 +128,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
115
128
  private handleAuthRequest;
116
129
  }
117
130
  export {};
118
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFBb0MsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRyxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkcsT0FBTyxLQUFLLEVBQ1YsV0FBVyxFQUNYLFNBQVMsRUFDVCx5QkFBeUIsRUFDekIsc0JBQXNCLEVBQ3ZCLE1BQU0saUNBQWlDLENBQUM7QUFDekMsT0FB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
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFJTCxLQUFLLE9BQU8sRUFDWixLQUFLLGNBQWMsRUFFcEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkcsT0FBTyxLQUFLLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RSxPQUFPLEtBQUssRUFDVixXQUFXLEVBQ1gsU0FBUyxFQUNULHlC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
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
package/dest/validator.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { getBlobsPerL1Block } from '@aztec/blob-lib';
2
2
  import { CheckpointNumber } from '@aztec/foundation/branded-types';
3
+ import { FifoSet } from '@aztec/foundation/fifo-set';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
6
  import { sleep } from '@aztec/foundation/sleep';
6
7
  import { DateProvider } from '@aztec/foundation/timer';
7
8
  import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
8
- import { OffenseType, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
9
+ import { OffenseType, WANT_TO_CLEAR_SLASH_EVENT, WANT_TO_SLASH_EVENT, getOffenseTypeName } from '@aztec/slasher';
9
10
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
10
11
  import { AttestationTimeoutError } from '@aztec/stdlib/validators';
11
12
  import { getTelemetryClient } from '@aztec/telemetry-client';
@@ -20,11 +21,36 @@ import { ProposalHandler } from './proposal_handler.js';
20
21
  // We maintain a set of proposers who have proposed invalid blocks.
21
22
  // Just cap the set to avoid unbounded growth.
22
23
  const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
24
+ const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
25
+ const MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS = 1000;
26
+ const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
23
27
  // What errors from the block proposal handler result in slashing
24
28
  const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
25
29
  'state_mismatch',
26
- 'failed_txs'
30
+ 'failed_txs',
31
+ 'global_variables_mismatch',
32
+ 'invalid_proposal',
33
+ 'parent_block_wrong_slot',
34
+ 'in_hash_mismatch'
27
35
  ];
36
+ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
37
+ // enabled
38
+ ['invalid_fee_asset_price_modifier']: true,
39
+ ['checkpoint_header_mismatch']: true,
40
+ // These late mismatches should normally be caught by earlier checks, but if reached after validating the local
41
+ // checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
42
+ ['archive_mismatch']: true,
43
+ ['out_hash_mismatch']: true,
44
+ ['no_blocks_for_slot']: true,
45
+ ['too_many_blocks_in_checkpoint']: true,
46
+ ['checkpoint_validation_failed']: true,
47
+ ['last_block_archive_mismatch']: true,
48
+ // disabled
49
+ ['invalid_signature']: false,
50
+ ['last_block_not_found']: false,
51
+ ['block_fetch_error']: false,
52
+ ['checkpoint_already_published']: false
53
+ };
28
54
  /**
29
55
  * Validator Client
30
56
  */ export class ValidatorClient extends EventEmitter {
@@ -52,14 +78,19 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
52
78
  epochCacheUpdateLoop;
53
79
  /** Tracks the last epoch in which each attester successfully submitted at least one attestation. */ lastAttestedEpochByAttester;
54
80
  proposersOfInvalidBlocks;
81
+ slotsWithInvalidProposals;
82
+ invalidCheckpointProposalOffenseKeys;
83
+ badAttestationOffenseKeys;
84
+ slotsWithProposalEquivocation;
55
85
  /** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
56
86
  constructor(keyStore, epochCache, p2pClient, proposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, slashingProtectionSigner, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
57
- super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.proposalHandler = proposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.slashingProtectionSigner = slashingProtectionSigner, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.lastAttestedEpochByAttester = new Map(), this.proposersOfInvalidBlocks = new Set();
87
+ super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.proposalHandler = proposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.slashingProtectionSigner = slashingProtectionSigner, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.lastAttestedEpochByAttester = new Map(), this.proposersOfInvalidBlocks = FifoSet.withLimit(MAX_PROPOSERS_OF_INVALID_BLOCKS), this.slotsWithInvalidProposals = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS), this.invalidCheckpointProposalOffenseKeys = FifoSet.withLimit(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS), this.badAttestationOffenseKeys = FifoSet.withLimit(MAX_TRACKED_BAD_ATTESTATIONS), this.slotsWithProposalEquivocation = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
58
88
  // Create child logger with fisherman prefix if in fisherman mode
59
89
  this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
60
90
  this.tracer = telemetry.getTracer('Validator');
61
91
  this.metrics = new ValidatorMetrics(telemetry);
62
- this.validationService = new ValidationService(keyStore, this.log.createChild('validation-service'));
92
+ this.validationService = new ValidationService(keyStore, this.getSignatureContext(), this.log.createChild('validation-service'));
93
+ this.proposalHandler.setCheckpointProposalValidationFailureCallback((proposal, result, proposalInfo)=>this.handleInvalidCheckpointProposal(proposal, result, proposalInfo));
63
94
  // Refresh epoch cache every second to trigger alert if participation in committee changes
64
95
  this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), this.log, 1000);
65
96
  const myAddresses = this.getValidatorAddresses();
@@ -109,13 +140,19 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
109
140
  this.log.error(`Error updating epoch committee`, err);
110
141
  }
111
142
  }
112
- static async new(config, checkpointsBuilder, worldState, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, keyStoreManager, blobClient, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), slashingProtectionDb) {
143
+ static async new(config, checkpointsBuilder, worldState, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, keyStoreManager, blobClient, reexecutionTracker, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), slashingProtectionDb) {
113
144
  const metrics = new ValidatorMetrics(telemetry);
114
145
  const blockProposalValidator = new BlockProposalValidator(epochCache, {
115
146
  txsPermitted: !config.disableTransactions,
116
- maxTxsPerBlock: config.validateMaxTxsPerBlock
147
+ maxTxsPerBlock: config.validateMaxTxsPerBlock,
148
+ maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
149
+ skipSlotValidation: config.skipProposalSlotValidation,
150
+ signatureContext: {
151
+ chainId: config.l1ChainId,
152
+ rollupAddress: config.rollupAddress
153
+ }
117
154
  });
118
- const proposalHandler = new ProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, metrics, dateProvider, telemetry, undefined);
155
+ const proposalHandler = new ProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, reexecutionTracker, metrics, dateProvider, telemetry, undefined);
119
156
  const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
120
157
  let slashingProtectionSigner;
121
158
  if (slashingProtectionDb) {
@@ -156,6 +193,12 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
156
193
  signWithAddress(addr, msg, context) {
157
194
  return this.keyStore.signTypedDataWithAddress(addr, msg, context);
158
195
  }
196
+ getSignatureContext() {
197
+ return {
198
+ chainId: this.config.l1ChainId,
199
+ rollupAddress: this.config.rollupAddress
200
+ };
201
+ }
159
202
  getCoinbaseForAttestor(attestor) {
160
203
  return this.keyStore.getCoinbaseAddress(attestor);
161
204
  }
@@ -165,16 +208,23 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
165
208
  getConfig() {
166
209
  return this.config;
167
210
  }
211
+ hasProposalEquivocation(slotNumber) {
212
+ return this.slotsWithProposalEquivocation.has(slotNumber);
213
+ }
214
+ hasInvalidProposals(slotNumber) {
215
+ return this.slotsWithInvalidProposals.has(slotNumber);
216
+ }
168
217
  updateConfig(config) {
169
218
  this.config = {
170
219
  ...this.config,
171
220
  ...config
172
221
  };
222
+ this.proposalHandler.updateConfig(config);
173
223
  }
174
224
  reloadKeystore(newManager) {
175
225
  const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
176
226
  this.keyStore = new HAKeyStore(newAdapter, this.slashingProtectionSigner);
177
- this.validationService = new ValidationService(this.keyStore, this.log.createChild('validation-service'));
227
+ this.validationService = new ValidationService(this.keyStore, this.getSignatureContext(), this.log.createChild('validation-service'));
178
228
  }
179
229
  async start() {
180
230
  if (this.epochCacheUpdateLoop.isRunning()) {
@@ -216,6 +266,9 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
216
266
  this.p2pClient.registerDuplicateAttestationCallback((info)=>{
217
267
  this.handleDuplicateAttestation(info);
218
268
  });
269
+ this.p2pClient.registerCheckpointAttestationCallback((attestation)=>{
270
+ this.handleCheckpointAttestation(attestation);
271
+ });
219
272
  const myAddresses = this.getValidatorAddresses();
220
273
  this.p2pClient.registerThisValidatorAddresses(myAddresses);
221
274
  await this.p2pClient.addReqRespSubProtocol(ReqRespSubProtocol.AUTH, this.handleAuthRequest.bind(this));
@@ -255,11 +308,8 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
255
308
  txHashes: proposal.txHashes.map((t)=>t.toString()),
256
309
  fishermanMode: this.config.fishermanMode || false
257
310
  });
258
- // Reexecute txs if we are part of the committee, or if slashing is enabled, or if we are configured to always reexecute.
259
- // In fisherman mode, we always reexecute to validate proposals.
260
- const { slashBroadcastedInvalidBlockPenalty, alwaysReexecuteBlockProposals, fishermanMode } = this.config;
261
- const shouldReexecute = fishermanMode || slashBroadcastedInvalidBlockPenalty > 0n || partOfCommittee || alwaysReexecuteBlockProposals || this.blobClient.canUpload();
262
- const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !!shouldReexecute && !escapeHatchOpen);
311
+ // Reexecute outside the escape hatch so slashing observers can detect invalid proposals even when penalties are 0.
312
+ const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !escapeHatchOpen);
263
313
  if (!validationResult.isValid) {
264
314
  const reason = validationResult.reason || 'unknown';
265
315
  this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo);
@@ -277,10 +327,14 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
277
327
  // Node issues so we can't validate
278
328
  this.metrics.incFailedAttestationsNodeIssue(1, reason, partOfCommittee);
279
329
  }
280
- // Slash invalid block proposals (can happen even when not in committee)
281
- if (!escapeHatchOpen && validationResult.reason && SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason) && slashBroadcastedInvalidBlockPenalty > 0n) {
282
- this.log.warn(`Slashing proposer for invalid block proposal`, proposalInfo);
330
+ if (!escapeHatchOpen && validationResult.reason && SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason)) {
331
+ this.log.info(`Detected invalid block proposal offense`, {
332
+ ...proposalInfo,
333
+ amount: this.config.slashBroadcastedInvalidBlockPenalty,
334
+ offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL)
335
+ });
283
336
  this.slashInvalidBlock(proposal);
337
+ this.markInvalidProposalSlot(proposal.slotNumber);
284
338
  }
285
339
  return false;
286
340
  }
@@ -309,6 +363,10 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
309
363
  this.log.warn(`Escape hatch open for slot ${proposalSlotNumber}, skipping checkpoint attestation handling`);
310
364
  return undefined;
311
365
  }
366
+ // Early-out for equivocation: refuses if we've already attested to a higher slot.
367
+ if (!this.shouldAttestToSlot(proposalSlotNumber)) {
368
+ return undefined;
369
+ }
312
370
  // Ignore proposals from ourselves (may happen in HA setups)
313
371
  if (proposer && this.getValidatorAddresses().some((addr)=>addr.equals(proposer))) {
314
372
  this.log.debug(`Ignoring block proposal from self for slot ${proposalSlotNumber}`, {
@@ -420,7 +478,9 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
420
478
  * Uploads blobs for a checkpoint to the filestore (fire and forget).
421
479
  */ async uploadBlobsForCheckpoint(proposal, proposalInfo) {
422
480
  try {
423
- const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
481
+ const lastBlockHeader = (await this.blockSource.getBlockData({
482
+ archive: proposal.archive
483
+ }))?.header;
424
484
  if (!lastBlockHeader) {
425
485
  this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
426
486
  return;
@@ -448,11 +508,6 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
448
508
  this.log.warn(`Cannot slash proposal with invalid signature`);
449
509
  return;
450
510
  }
451
- // Trim the set if it's too big.
452
- if (this.proposersOfInvalidBlocks.size > MAX_PROPOSERS_OF_INVALID_BLOCKS) {
453
- // remove oldest proposer. `values` is guaranteed to be in insertion order.
454
- this.proposersOfInvalidBlocks.delete(this.proposersOfInvalidBlocks.values().next().value);
455
- }
456
511
  this.proposersOfInvalidBlocks.add(proposer.toString());
457
512
  this.emit(WANT_TO_SLASH_EVENT, [
458
513
  {
@@ -463,17 +518,95 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
463
518
  }
464
519
  ]);
465
520
  }
521
+ handleInvalidCheckpointProposal(proposal, result, proposalInfo) {
522
+ if (!SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
523
+ return;
524
+ }
525
+ this.markInvalidProposalSlot(proposal.slotNumber);
526
+ if (this.slashInvalidCheckpointProposal(proposal)) {
527
+ this.log.info(`Detected invalid checkpoint proposal offense`, {
528
+ ...proposalInfo,
529
+ reason: result.reason,
530
+ amount: this.config.slashBroadcastedInvalidCheckpointProposalPenalty,
531
+ offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL)
532
+ });
533
+ }
534
+ }
535
+ slashInvalidCheckpointProposal(proposal) {
536
+ const proposer = proposal.getSender();
537
+ if (!proposer) {
538
+ this.log.warn(`Cannot slash checkpoint proposal with invalid signature`, {
539
+ slotNumber: proposal.slotNumber,
540
+ archive: proposal.archive.toString()
541
+ });
542
+ return false;
543
+ }
544
+ const offenseType = OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL;
545
+ const offenseKey = `${proposer.toString()}:${offenseType}:${proposal.slotNumber}`;
546
+ if (!this.invalidCheckpointProposalOffenseKeys.addIfAbsent(offenseKey)) {
547
+ return false;
548
+ }
549
+ this.emit(WANT_TO_SLASH_EVENT, [
550
+ {
551
+ validator: proposer,
552
+ amount: this.config.slashBroadcastedInvalidCheckpointProposalPenalty,
553
+ offenseType,
554
+ epochOrSlot: BigInt(proposal.slotNumber)
555
+ }
556
+ ]);
557
+ return true;
558
+ }
559
+ markInvalidProposalSlot(slotNumber) {
560
+ this.slotsWithInvalidProposals.add(slotNumber);
561
+ }
562
+ handleCheckpointAttestation(attestation) {
563
+ const slotNumber = attestation.slotNumber;
564
+ if (!this.slotsWithInvalidProposals.has(slotNumber) || this.slotsWithProposalEquivocation.has(slotNumber)) {
565
+ return;
566
+ }
567
+ const attester = attestation.getSender();
568
+ if (!attester) {
569
+ this.log.warn(`Cannot slash checkpoint attestation with invalid signature`, {
570
+ slotNumber,
571
+ archive: attestation.archive.toString()
572
+ });
573
+ return;
574
+ }
575
+ this.slashAttestedToInvalidCheckpointProposal(slotNumber, attester);
576
+ }
577
+ slashAttestedToInvalidCheckpointProposal(slotNumber, attester) {
578
+ const offenseKey = `${attester.toString()}:${OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL}:${slotNumber}`;
579
+ if (!this.badAttestationOffenseKeys.addIfAbsent(offenseKey)) {
580
+ return;
581
+ }
582
+ this.log.info(`Detected attestation to invalid checkpoint proposal offense`, {
583
+ attester: attester.toString(),
584
+ slotNumber,
585
+ amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
586
+ offenseType: getOffenseTypeName(OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL)
587
+ });
588
+ this.emit(WANT_TO_SLASH_EVENT, [
589
+ {
590
+ validator: attester,
591
+ amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
592
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
593
+ epochOrSlot: BigInt(slotNumber)
594
+ }
595
+ ]);
596
+ }
466
597
  /**
467
598
  * Handle detection of a duplicate proposal (equivocation).
468
599
  * Emits a slash event when a proposer sends multiple proposals for the same position.
469
600
  */ handleDuplicateProposal(info) {
470
601
  const { slot, proposer, type } = info;
471
- this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
602
+ this.slotsWithProposalEquivocation.add(slot);
603
+ this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
472
604
  proposer: proposer.toString(),
473
605
  slot,
474
- type
606
+ type,
607
+ amount: this.config.slashDuplicateProposalPenalty,
608
+ offenseType: getOffenseTypeName(OffenseType.DUPLICATE_PROPOSAL)
475
609
  });
476
- // Emit slash event
477
610
  this.emit(WANT_TO_SLASH_EVENT, [
478
611
  {
479
612
  validator: proposer,
@@ -482,15 +615,23 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
482
615
  epochOrSlot: BigInt(slot)
483
616
  }
484
617
  ]);
618
+ this.emit(WANT_TO_CLEAR_SLASH_EVENT, [
619
+ {
620
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
621
+ epochOrSlot: BigInt(slot)
622
+ }
623
+ ]);
485
624
  }
486
625
  /**
487
626
  * Handle detection of a duplicate attestation (equivocation).
488
627
  * Emits a slash event when an attester signs attestations for different proposals at the same slot.
489
628
  */ handleDuplicateAttestation(info) {
490
629
  const { slot, attester } = info;
491
- this.log.warn(`Triggering slash event for duplicate attestation from ${attester.toString()} at slot ${slot}`, {
630
+ this.log.info(`Detected duplicate attestation offense from ${attester.toString()} at slot ${slot}`, {
492
631
  attester: attester.toString(),
493
- slot
632
+ slot,
633
+ amount: this.config.slashDuplicateAttestationPenalty,
634
+ offenseType: getOffenseTypeName(OffenseType.DUPLICATE_ATTESTATION)
494
635
  });
495
636
  this.emit(WANT_TO_SLASH_EVENT, [
496
637
  {
@@ -514,7 +655,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
514
655
  this.log.info(`Assembling block proposal for block ${blockHeader.globalVariables.blockNumber} slot ${blockHeader.globalVariables.slotNumber}`);
515
656
  const newProposal = await this.validationService.createBlockProposal(blockHeader, checkpointNumber, indexWithinCheckpoint, inHash, archive, txs, proposerAddress, {
516
657
  ...options,
517
- broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal
658
+ broadcastInvalidBlockProposal: options.broadcastInvalidBlockProposal || this.config.broadcastInvalidBlockProposal
518
659
  });
519
660
  this.lastProposedBlock = newProposal;
520
661
  return newProposal;
@@ -531,6 +672,13 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
531
672
  this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
532
673
  const newProposal = await this.validationService.createCheckpointProposal(checkpointHeader, archive, checkpointNumber, feeAssetPriceModifier, lastBlockProposal, proposerAddress, options);
533
674
  this.lastProposedCheckpoint = newProposal;
675
+ // Self-record this slot's outcome on the re-execution tracker. Proposers don't run their
676
+ // own proposals through `handleCheckpointProposal`, so without this call the proposer's
677
+ // sentinel would see no outcome for slots it proposed and would mis-attribute itself as
678
+ // inactive. We pass the locally-computed `archive` (not `newProposal.archive`, which may
679
+ // be intentionally corrupted under test-only flags); from the proposer's local-view
680
+ // perspective the work it just completed is valid by definition.
681
+ this.proposalHandler.recordOwnCheckpointProposalAsValid(checkpointHeader.slotNumber, archive, checkpointNumber);
534
682
  return newProposal;
535
683
  }
536
684
  async broadcastBlockProposal(proposal) {
@@ -566,27 +714,19 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
566
714
  throw new AttestationTimeoutError(0, required, slot);
567
715
  }
568
716
  await this.collectOwnAttestations(proposal, checkpointNumber);
569
- const proposalId = proposal.archive.toString();
717
+ const proposalPayloadHash = proposal.getPayloadHash();
570
718
  const myAddresses = this.getValidatorAddresses();
571
719
  let attestations = [];
572
720
  while(true){
573
- // Filter out attestations with a mismatching archive. This should NOT happen since we have verified
574
- // the proposer signature (ie our own) before accepting the attestation into the pool via the p2p client.
575
- const collectedAttestations = (await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalId)).filter((attestation)=>{
576
- if (!attestation.archive.equals(proposal.archive)) {
577
- this.log.warn(`Received attestation for slot ${slot} with mismatched archive from ${attestation.getSender()?.toString()}`, {
578
- attestationArchive: attestation.archive.toString(),
579
- proposalArchive: proposal.archive.toString()
580
- });
581
- return false;
582
- }
583
- return true;
584
- });
721
+ // The pool already filters by proposal payload hash; if any attestation slips through with a
722
+ // mismatched payload hash, drop it defensively. Equivocations are emitted as separate slash
723
+ // events from libp2p_service.
724
+ const collectedAttestations = await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalPayloadHash);
585
725
  // Log new attestations we collected
586
726
  const oldSenders = attestations.map((attestation)=>attestation.getSender());
587
727
  for (const collected of collectedAttestations){
588
728
  const collectedSender = collected.getSender();
589
- // Skip attestations with invalid signatures
729
+ // Skip attestations with invalid signatures. Should not happen as we don't add invalid attestations to our pool.
590
730
  if (!collectedSender) {
591
731
  this.log.warn(`Skipping attestation with invalid signature for slot ${slot}`);
592
732
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "0.0.1-commit.b2a5d0dd1",
3
+ "version": "0.0.1-commit.b3d3157a",
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.b2a5d0dd1",
68
- "@aztec/blob-lib": "0.0.1-commit.b2a5d0dd1",
69
- "@aztec/constants": "0.0.1-commit.b2a5d0dd1",
70
- "@aztec/epoch-cache": "0.0.1-commit.b2a5d0dd1",
71
- "@aztec/ethereum": "0.0.1-commit.b2a5d0dd1",
72
- "@aztec/foundation": "0.0.1-commit.b2a5d0dd1",
73
- "@aztec/node-keystore": "0.0.1-commit.b2a5d0dd1",
74
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.b2a5d0dd1",
75
- "@aztec/p2p": "0.0.1-commit.b2a5d0dd1",
76
- "@aztec/protocol-contracts": "0.0.1-commit.b2a5d0dd1",
77
- "@aztec/prover-client": "0.0.1-commit.b2a5d0dd1",
78
- "@aztec/simulator": "0.0.1-commit.b2a5d0dd1",
79
- "@aztec/slasher": "0.0.1-commit.b2a5d0dd1",
80
- "@aztec/stdlib": "0.0.1-commit.b2a5d0dd1",
81
- "@aztec/telemetry-client": "0.0.1-commit.b2a5d0dd1",
82
- "@aztec/validator-ha-signer": "0.0.1-commit.b2a5d0dd1",
67
+ "@aztec/blob-client": "0.0.1-commit.b3d3157a",
68
+ "@aztec/blob-lib": "0.0.1-commit.b3d3157a",
69
+ "@aztec/constants": "0.0.1-commit.b3d3157a",
70
+ "@aztec/epoch-cache": "0.0.1-commit.b3d3157a",
71
+ "@aztec/ethereum": "0.0.1-commit.b3d3157a",
72
+ "@aztec/foundation": "0.0.1-commit.b3d3157a",
73
+ "@aztec/node-keystore": "0.0.1-commit.b3d3157a",
74
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.b3d3157a",
75
+ "@aztec/p2p": "0.0.1-commit.b3d3157a",
76
+ "@aztec/protocol-contracts": "0.0.1-commit.b3d3157a",
77
+ "@aztec/prover-client": "0.0.1-commit.b3d3157a",
78
+ "@aztec/simulator": "0.0.1-commit.b3d3157a",
79
+ "@aztec/slasher": "0.0.1-commit.b3d3157a",
80
+ "@aztec/stdlib": "0.0.1-commit.b3d3157a",
81
+ "@aztec/telemetry-client": "0.0.1-commit.b3d3157a",
82
+ "@aztec/validator-ha-signer": "0.0.1-commit.b3d3157a",
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.b2a5d0dd1",
90
- "@aztec/world-state": "0.0.1-commit.b2a5d0dd1",
89
+ "@aztec/archiver": "0.0.1-commit.b3d3157a",
90
+ "@aztec/world-state": "0.0.1-commit.b3d3157a",
91
91
  "@electric-sql/pglite": "^0.3.14",
92
92
  "@jest/globals": "^30.0.0",
93
93
  "@types/jest": "^30.0.0",
package/src/config.ts CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  booleanConfigHelper,
4
4
  getConfigFromMappings,
5
5
  numberConfigHelper,
6
+ optionalNumberConfigHelper,
6
7
  secretValueConfigHelper,
7
8
  } from '@aztec/foundation/config';
8
9
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -30,6 +31,12 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
30
31
  .map(address => EthAddress.fromString(address.trim())),
31
32
  defaultValue: [],
32
33
  },
34
+ l1ChainId: {
35
+ env: 'L1_CHAIN_ID',
36
+ description: 'The chain ID of the ethereum host.',
37
+ parseEnv: (val: string) => +val,
38
+ defaultValue: 31337,
39
+ },
33
40
  disableValidator: {
34
41
  env: 'VALIDATOR_DISABLED',
35
42
  description: 'Do not run the validator',
@@ -72,25 +79,29 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
72
79
  description: 'Agree to attest to equivocated checkpoint proposals (for testing purposes only)',
73
80
  ...booleanConfigHelper(false),
74
81
  },
82
+ skipProposalSlotValidation: {
83
+ description: 'Accept proposal validation regardless of slot timing (for testing only)',
84
+ ...booleanConfigHelper(false),
85
+ },
75
86
  validateMaxL2BlockGas: {
76
87
  env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
77
88
  description: 'Maximum L2 block gas for validation. Proposals exceeding this limit are rejected.',
78
- parseEnv: (val: string) => parseInt(val, 10),
89
+ ...optionalNumberConfigHelper(),
79
90
  },
80
91
  validateMaxDABlockGas: {
81
92
  env: 'VALIDATOR_MAX_DA_BLOCK_GAS',
82
93
  description: 'Maximum DA block gas for validation. Proposals exceeding this limit are rejected.',
83
- parseEnv: (val: string) => parseInt(val, 10),
94
+ ...optionalNumberConfigHelper(),
84
95
  },
85
96
  validateMaxTxsPerBlock: {
86
97
  env: 'VALIDATOR_MAX_TX_PER_BLOCK',
87
98
  description: 'Maximum transactions per block for validation. Proposals exceeding this limit are rejected.',
88
- parseEnv: (val: string) => parseInt(val, 10),
99
+ ...optionalNumberConfigHelper(),
89
100
  },
90
101
  validateMaxTxsPerCheckpoint: {
91
102
  env: 'VALIDATOR_MAX_TX_PER_CHECKPOINT',
92
103
  description: 'Maximum transactions per checkpoint for validation. Proposals exceeding this limit are rejected.',
93
- parseEnv: (val: string) => parseInt(val, 10),
104
+ ...optionalNumberConfigHelper(),
94
105
  },
95
106
  ...localSignerConfigMappings,
96
107
  ...validatorHASignerConfigMappings,