@aztec/validator-client 5.0.0-nightly.20260505 → 5.0.0-nightly.20260514

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/dest/factory.js CHANGED
@@ -10,7 +10,7 @@ export function createProposalHandler(config, deps) {
10
10
  maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
11
11
  signatureContext: {
12
12
  chainId: config.l1ChainId,
13
- rollupAddress: config.l1Contracts.rollupAddress
13
+ rollupAddress: config.rollupAddress
14
14
  }
15
15
  });
16
16
  return new ProposalHandler(deps.checkpointsBuilder, deps.worldState, deps.blockSource, deps.l1ToL2MessageSource, deps.p2pClient.getTxProvider(), blockProposalValidator, deps.epochCache, config, deps.blobClient, metrics, deps.dateProvider, deps.telemetry, undefined);
@@ -56,7 +56,9 @@ export declare class ProposalHandler {
56
56
  private dateProvider;
57
57
  private log;
58
58
  readonly tracer: Tracer;
59
- /** Cached last checkpoint validation result to avoid double-validation on validator nodes. */
59
+ /** Cached last checkpoint validation result to avoid double-validation on validator nodes.
60
+ * Keyed by signed-payload hash so two proposals at the same (slot, archive) but with a
61
+ * different `feeAssetPriceModifier` (or any other signed field) are validated independently. */
60
62
  private lastCheckpointValidationResult?;
61
63
  /** Archiver reference for setting proposed checkpoints (pipelining). Set via register(). */
62
64
  private archiver?;
@@ -105,4 +107,4 @@ export declare class ProposalHandler {
105
107
  private setProposedCheckpointFromBlocks;
106
108
  }
107
109
  export {};
108
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUdyRSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFjLE1BQU0saUNBQWlDLENBQUM7QUFFNUYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBR3JELE9BQU8sRUFBRSxZQUFZLEVBQVMsTUFBTSx5QkFBeUIsQ0FBQztBQUM5RCxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ25FLE9BQU8sS0FBSyxFQUFhLE9BQU8sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFJMUYsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLHlCQUF5QixFQUFFLHNCQUFzQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdEgsT0FBTyxFQUNMLEtBQUssbUJBQW1CLEVBR3pCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUF5QixzQkFBc0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXRHLE9BQU8sS0FBSyxFQUE2QixRQUFRLEVBQUUsRUFBRSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFRaEYsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFF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
110
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUdyRSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsV0FBVyxFQUNYLGdCQUFnQixFQUdqQixNQUFNLGlDQUFpQyxDQUFDO0FBRXpDLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVwRCxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdyRCxPQUFPLEVBQUUsWUFBWSxFQUFTLE1BQU0seUJBQXlCLENBQUM7QUFDOUQsT0FBTyxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUM5QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNuRSxPQUFPLEtBQUssRUFBYSxPQUFPLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBSTFGLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSx5QkFBeUIsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3RILE9BQU8sRUFDTCxLQUFLLG1CQUFtQixFQUd6QixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBeUIsc0JBQXNCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUV0RyxPQUFPLEtBQUssRUFBNkIsUUFBUSxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBUWhGLE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFB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
@@ -1 +1 @@
1
- {"version":3,"file":"proposal_handler.d.ts","sourceRoot":"","sources":["../src/proposal_handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAc,MAAM,iCAAiC,CAAC;AAE5F,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAS,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAa,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAI1F,OAAO,KAAK,EAAE,WAAW,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACtH,OAAO,EACL,KAAK,mBAAmB,EAGzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,aAAa,EAAyB,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEtG,OAAO,KAAK,EAA6B,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAQhF,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAsB,MAAM,yBAAyB,CAAC;AAEhG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,oCAAoC,GAC5C,kBAAkB,GAClB,wBAAwB,GACxB,yBAAyB,GACzB,yBAAyB,GACzB,kBAAkB,GAClB,2BAA2B,GAC3B,6BAA6B,GAC7B,mBAAmB,GACnB,gBAAgB,GAChB,YAAY,GACZ,wBAAwB,GACxB,SAAS,GACT,eAAe,CAAC;AAEpB,KAAK,2BAA2B,GAAG;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,EAAE,WAAW,CAAC;IACzB,iBAAiB,CAAC,EAAE,2BAA2B,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,oCAAoC,CAAC;IAC7C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,2BAA2B,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oCAAoC,GAAG,oCAAoC,CAAC;AAExH,MAAM,MAAM,kCAAkC,GAC1C;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,gBAAgB,EAAE,gBAAgB,CAAA;CAAE,GACrD;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAMvC,yFAAyF;AACzF,qBAAa,eAAe;IAiBxB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,OAAO,CAAC;IAChB,OAAO,CAAC,YAAY;IAEpB,OAAO,CAAC,GAAG;IA5Bb,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,8FAA8F;IAC9F,OAAO,CAAC,8BAA8B,CAAC,CAIrC;IAEF,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,CAA6D;IAE9E,0FAA0F;IAC1F,OAAO,CAAC,wBAAwB,CAAC,CAAiB;IAElD,YACU,kBAAkB,EAAE,0BAA0B,EAC9C,UAAU,EAAE,sBAAsB,EAClC,WAAW,EAAE,aAAa,GAAG,WAAW,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,WAAW,EACvB,sBAAsB,EAAE,sBAAsB,EAC9C,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,yBAAyB,EACjC,UAAU,EAAE,mBAAmB,EAC/B,OAAO,CAAC,8BAAkB,EAC1B,YAAY,GAAE,YAAiC,EACvD,SAAS,GAAE,eAAsC,EACzC,GAAG,yCAA6C,EAMzD;IAED;;;;;;OAMG;IACH,QAAQ,CACN,SAAS,EAAE,GAAG,EACd,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,uBAAuB,GAAG,gBAAgB,CAAC,EACrE,wBAAwB,CAAC,EAAE,MAAM,MAAM,EAAE,GACxC,eAAe,CA+EjB;IAEK,mBAAmB,CACvB,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAAC,6BAA6B,CAAC,CA6JxC;YAEa,cAAc;IAmC5B,OAAO,CAAC,uBAAuB;IA0C/B;;;;OAIG;IACH,OAAO,CAAC,iCAAiC;IA4EzC,OAAO,CAAC,sBAAsB;YAYhB,sBAAsB;IAoCpC,OAAO,CAAC,yBAAyB;IAgB3B,qBAAqB,CACzB,QAAQ,EAAE,aAAa,EACvB,WAAW,EAAE,WAAW,EACxB,gBAAgB,EAAE,gBAAgB,EAClC,GAAG,EAAE,EAAE,EAAE,EACT,cAAc,EAAE,EAAE,EAAE,EACpB,2BAA2B,EAAE,EAAE,EAAE,GAChC,OAAO,CAAC,2BAA2B,CAAC,CAmHtC;IAED;;;;OAIG;IACG,wBAAwB,CAC5B,QAAQ,EAAE,sBAAsB,EAChC,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,kCAAkC,CAAC,CAuC7C;IAED;;;OAGG;IACG,0BAA0B,CAC9B,QAAQ,EAAE,sBAAsB,EAChC,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,kCAAkC,CAAC,CAmJ7C;IAED,yDAAyD;IACzD,OAAO,CAAC,0BAA0B;IAalC,6FAA6F;IAC7F,SAAS,CAAC,2BAA2B,CAAC,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI,CAInG;IAED,uDAAuD;IACvD,UAAgB,wBAAwB,CAAC,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB/G;YAOa,mCAAmC;YA4BnC,+BAA+B;CAsC9C"}
1
+ {"version":3,"file":"proposal_handler.d.ts","sourceRoot":"","sources":["../src/proposal_handler.ts"],"names":[],"mappings":"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"}
@@ -73,7 +73,7 @@ import { TimeoutError } from '@aztec/foundation/error';
73
73
  import { createLogger } from '@aztec/foundation/log';
74
74
  import { retryUntil } from '@aztec/foundation/retry';
75
75
  import { DateProvider, Timer } from '@aztec/foundation/timer';
76
- import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
76
+ import { getPreviousCheckpointOutHashes, validateCheckpoint } from '@aztec/stdlib/checkpoint';
77
77
  import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
78
78
  import { Gas } from '@aztec/stdlib/gas';
79
79
  import { accumulateCheckpointOutHashes, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
@@ -94,7 +94,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
94
94
  dateProvider;
95
95
  log;
96
96
  tracer;
97
- /** Cached last checkpoint validation result to avoid double-validation on validator nodes. */ lastCheckpointValidationResult;
97
+ /** Cached last checkpoint validation result to avoid double-validation on validator nodes.
98
+ * Keyed by signed-payload hash so two proposals at the same (slot, archive) but with a
99
+ * different `feeAssetPriceModifier` (or any other signed field) are validated independently. */ lastCheckpointValidationResult;
98
100
  /** Archiver reference for setting proposed checkpoints (pipelining). Set via register(). */ archiver;
99
101
  /** Returns current validator addresses for own-proposal detection. Set via register(). */ getOwnValidatorAddresses;
100
102
  constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:proposal-handler')){
@@ -269,7 +271,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
269
271
  const blockNumber = parentBlock === 'genesis' ? BlockNumber(INITIAL_L2_BLOCK_NUM) : BlockNumber(parentBlock.header.getBlockNumber() + 1);
270
272
  proposalInfo.blockNumber = blockNumber;
271
273
  // Check that this block number does not exist already
272
- const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
274
+ const existingBlock = await this.blockSource.getBlockData({
275
+ number: blockNumber
276
+ });
273
277
  if (existingBlock) {
274
278
  this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
275
279
  return {
@@ -331,9 +335,18 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
331
335
  reason: 'txs_not_available'
332
336
  };
333
337
  }
334
- // Collect the out hashes of all the checkpoints before this one in the same epoch
338
+ // Collect the out hashes of all the checkpoints before this one in the same epoch.
339
+ // Mirror the proposer-side fallback: under pipelining the immediately-preceding cp may not
340
+ // yet be on L1, in which case the helper grafts the locally-known proposed cp's outHash.
335
341
  const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
336
- const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
342
+ const previousCheckpointOutHashes = await getPreviousCheckpointOutHashes({
343
+ blockSource: this.blockSource,
344
+ epoch,
345
+ checkpointNumber,
346
+ l1Constants: this.epochCache.getL1Constants(),
347
+ pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled(),
348
+ log: this.log
349
+ });
337
350
  // Try re-executing the transactions in the proposal if needed
338
351
  let reexecutionResult;
339
352
  try {
@@ -374,7 +387,11 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
374
387
  const currentTime = this.dateProvider.now();
375
388
  const timeoutDurationMs = deadline.getTime() - currentTime;
376
389
  try {
377
- return await this.blockSource.getBlockDataByArchive(parentArchive) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(()=>this.blockSource.syncImmediate().then(()=>this.blockSource.getBlockDataByArchive(parentArchive)), 'force archiver sync', timeoutDurationMs / 1000, 0.5));
390
+ return await this.blockSource.getBlockData({
391
+ archive: parentArchive
392
+ }) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(()=>this.blockSource.syncImmediate().then(()=>this.blockSource.getBlockData({
393
+ archive: parentArchive
394
+ })), 'force archiver sync', timeoutDurationMs / 1000, 0.5));
378
395
  } catch (err) {
379
396
  if (err instanceof TimeoutError) {
380
397
  this.log.debug(`Timed out getting parent block by archive root`, {
@@ -673,8 +690,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
673
690
  * Used by both the all-nodes callback (via register) and the validator client (via delegation).
674
691
  */ async handleCheckpointProposal(proposal, proposalInfo) {
675
692
  const slot = proposal.slotNumber;
676
- // Check cache: same archive+slot means we already validated this proposal
677
- if (this.lastCheckpointValidationResult && this.lastCheckpointValidationResult.archive.equals(proposal.archive) && this.lastCheckpointValidationResult.slotNumber === slot) {
693
+ const payloadHash = proposal.getPayloadHash();
694
+ // Check cache: same signed-payload hash means we already validated this exact proposal.
695
+ if (this.lastCheckpointValidationResult && this.lastCheckpointValidationResult.payloadHash === payloadHash) {
678
696
  this.log.debug(`Returning cached validation result for checkpoint proposal at slot ${slot}`, proposalInfo);
679
697
  return this.lastCheckpointValidationResult.result;
680
698
  }
@@ -686,8 +704,7 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
686
704
  reason: 'invalid_signature'
687
705
  };
688
706
  this.lastCheckpointValidationResult = {
689
- archive: proposal.archive,
690
- slotNumber: slot,
707
+ payloadHash,
691
708
  result
692
709
  };
693
710
  return result;
@@ -699,16 +716,14 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
699
716
  reason: 'invalid_fee_asset_price_modifier'
700
717
  };
701
718
  this.lastCheckpointValidationResult = {
702
- archive: proposal.archive,
703
- slotNumber: slot,
719
+ payloadHash,
704
720
  result
705
721
  };
706
722
  return result;
707
723
  }
708
724
  const result = await this.validateCheckpointProposal(proposal, proposalInfo);
709
725
  this.lastCheckpointValidationResult = {
710
- archive: proposal.archive,
711
- slotNumber: slot,
726
+ payloadHash,
712
727
  result
713
728
  };
714
729
  // Upload blobs to filestore if validation passed (fire and forget)
@@ -737,7 +752,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
737
752
  try {
738
753
  lastBlockHeader = await retryUntil(async ()=>{
739
754
  await this.blockSource.syncImmediate();
740
- return this.blockSource.getBlockHeaderByArchive(proposal.archive);
755
+ return (await this.blockSource.getBlockData({
756
+ archive: proposal.archive
757
+ }))?.header;
741
758
  }, `waiting for block with archive ${proposal.archive.toString()} for slot ${slot}`, timeoutSeconds, 0.5);
742
759
  } catch (err) {
743
760
  if (err instanceof TimeoutError) {
@@ -799,9 +816,17 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
799
816
  const checkpointNumber = firstBlock.checkpointNumber;
800
817
  // Get L1-to-L2 messages for this checkpoint
801
818
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
802
- // Collect the out hashes of all the checkpoints before this one in the same epoch
819
+ // Collect the out hashes of all the checkpoints before this one in the same epoch.
820
+ // See note on the analogous block-proposal site: the helper handles pipelining lag.
803
821
  const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
804
- const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
822
+ const previousCheckpointOutHashes = await getPreviousCheckpointOutHashes({
823
+ blockSource: this.blockSource,
824
+ epoch,
825
+ checkpointNumber,
826
+ l1Constants: this.epochCache.getL1Constants(),
827
+ pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled(),
828
+ log: this.log
829
+ });
805
830
  // Fork world state at the block before the first block
806
831
  const parentBlockNumber = BlockNumber(firstBlock.number - 1);
807
832
  const fork = _ts_add_disposable_resource(env, await this.checkpointsBuilder.getFork(parentBlockNumber), true);
@@ -902,7 +927,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
902
927
  }
903
928
  /** Uploads blobs for a checkpoint to the filestore. */ async uploadBlobsForCheckpoint(proposal, proposalInfo) {
904
929
  try {
905
- const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
930
+ const lastBlockHeader = (await this.blockSource.getBlockData({
931
+ archive: proposal.archive
932
+ }))?.header;
906
933
  if (!lastBlockHeader) {
907
934
  this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
908
935
  return;
@@ -932,7 +959,9 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
932
959
  if (!this.archiver) {
933
960
  return false;
934
961
  }
935
- const blockData = await this.blockSource.getBlockDataByArchive(proposal.archive);
962
+ const blockData = await this.blockSource.getBlockData({
963
+ archive: proposal.archive
964
+ });
936
965
  if (!blockData) {
937
966
  this.log.debug(`Block data not found for checkpoint proposal archive, cannot set proposed checkpoint`, {
938
967
  archive: proposal.archive.toString()
@@ -957,14 +986,18 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
957
986
  if (!this.archiver) {
958
987
  return false;
959
988
  }
960
- let blockData = await this.blockSource.getBlockDataByArchive(proposal.archive);
989
+ let blockData = await this.blockSource.getBlockData({
990
+ archive: proposal.archive
991
+ });
961
992
  if (!blockData) {
962
993
  // The checkpoint proposal often arrives before the last block finishes re-execution.
963
994
  // Retry until we find the data or give up at the end of the slot.
964
995
  const nextSlot = this.epochCache.getSlotNow() + 1;
965
996
  const timeOfNextSlot = getTimestampForSlot(SlotNumber(nextSlot), await this.archiver.getL1Constants());
966
997
  const timeoutSeconds = Math.max(1, Number(timeOfNextSlot) - Math.floor(this.dateProvider.now() / 1000));
967
- blockData = await retryUntil(()=>this.blockSource.getBlockDataByArchive(proposal.archive), 'block data for own checkpoint proposal', timeoutSeconds, 0.25).catch(()=>undefined);
998
+ blockData = await retryUntil(()=>this.blockSource.getBlockData({
999
+ archive: proposal.archive
1000
+ }), 'block data for own checkpoint proposal', timeoutSeconds, 0.25).catch(()=>undefined);
968
1001
  }
969
1002
  if (blockData) {
970
1003
  await this.archiver.addProposedCheckpoint({
@@ -54,6 +54,9 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
54
54
  /** Tracks the last epoch in which each attester successfully submitted at least one attestation. */
55
55
  private lastAttestedEpochByAttester;
56
56
  private proposersOfInvalidBlocks;
57
+ private slotsWithInvalidBlockProposals;
58
+ private slotsWithProposalEquivocation;
59
+ private badAttestationOffenseKeys;
57
60
  /** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
58
61
  private lastAttestedProposal?;
59
62
  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);
@@ -97,6 +100,9 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
97
100
  */
98
101
  protected uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void>;
99
102
  private slashInvalidBlock;
103
+ private markInvalidProposalSlot;
104
+ private handleCheckpointAttestation;
105
+ private slashAttestedToInvalidCheckpointProposal;
100
106
  /**
101
107
  * Handle detection of a duplicate proposal (equivocation).
102
108
  * Emits a slash event when a proposer sends multiple proposals for the same position.
@@ -107,6 +113,8 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
107
113
  * Emits a slash event when an attester signs attestations for different proposals at the same slot.
108
114
  */
109
115
  private handleDuplicateAttestation;
116
+ private getSlotKey;
117
+ private addToBoundedSet;
110
118
  createBlockProposal(blockHeader: BlockHeader, checkpointNumber: CheckpointNumber, indexWithinCheckpoint: IndexWithinCheckpoint, inHash: Fr, archive: Fr, txs: Tx[], proposerAddress: EthAddress | undefined, options?: BlockProposalOptions): Promise<BlockProposal>;
111
119
  createCheckpointProposal(checkpointHeader: CheckpointHeader, archive: Fr, checkpointNumber: CheckpointNumber, feeAssetPriceModifier: bigint, lastBlockProposal: BlockProposal | undefined, proposerAddress: EthAddress | undefined, options?: CheckpointProposalOptions): Promise<CheckpointProposal>;
112
120
  broadcastBlockProposal(proposal: BlockProposal): Promise<void>;
@@ -116,4 +124,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
116
124
  private handleAuthRequest;
117
125
  }
118
126
  export {};
119
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFBb0MsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRyxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkcsT0FBTyxLQUFLLEVBQ1YsV0FBVyxFQUNYLFNBQVMsRUFDVCx5QkFBeUIsRUFDekIsc0JBQXNCLEVBQ3ZCLE1BQU0saUNBQWlDLENBQUM7QUFDekMsT0FB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
127
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFJTCxLQUFLLE9BQU8sRUFDWixLQUFLLGNBQWMsRUFDcEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkcsT0FBTyxLQUFLLEVBQ1YsV0FBVyxFQUNYLFNBQVMsRUFDVCx5QkFBeUIsRUFDekIsc0JBQXNCLEVBQ3ZCLE1BQU0saUNBQWlDLENBQUM7QUFDekMsT0FB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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":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAe,qBAAqB,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AACnH,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGhF,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAmD,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE/F,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,+BAA+B,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEvG,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAsB,MAAM,yBAAyB,CAAC;AAMhG,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAClH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAGxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EAA6C,eAAe,EAAE,MAAM,uBAAuB,CAAC;;AAcnG;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBAA2C,YAAW,SAAS,EAAE,OAAO;IA4BzG,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,wBAAwB;IAChC,OAAO,CAAC,YAAY;IAtCtB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,GAAG,CAAS;IAEpB,OAAO,CAAC,qBAAqB,CAAS;IAEtC,wFAAwF;IACxF,OAAO,CAAC,iBAAiB,CAAC,CAAgB;IAE1C,sDAAsD;IACtD,OAAO,CAAC,sBAAsB,CAAC,CAAqB;IAEpD,OAAO,CAAC,+BAA+B,CAA0B;IACjE,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,oGAAoG;IACpG,OAAO,CAAC,2BAA2B,CAAuC;IAE1E,OAAO,CAAC,wBAAwB,CAA0B;IAC1D,OAAO,CAAC,8BAA8B,CAA0B;IAChE,OAAO,CAAC,6BAA6B,CAA0B;IAC/D,OAAO,CAAC,yBAAyB,CAA0B;IAE3D,mFAAmF;IACnF,OAAO,CAAC,oBAAoB,CAAC,CAAyB;IAEtD,SAAS,aACC,QAAQ,EAAE,yBAAyB,EACnC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,aAAa,EAC1B,kBAAkB,EAAE,0BAA0B,EAC9C,UAAU,EAAE,sBAAsB,EAClC,mBAAmB,EAAE,mBAAmB,EACxC,MAAM,EAAE,yBAAyB,EACjC,UAAU,EAAE,mBAAmB,EAC/B,wBAAwB,EAAE,iBAAiB,EAC3C,YAAY,GAAE,YAAiC,EACvD,SAAS,GAAE,eAAsC,EACjD,GAAG,SAA4B,EAqBhC;IAED,OAAc,6BAA6B,CAAC,eAAe,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,QAuB5F;YAEa,0BAA0B;IA4BxC,OAAa,GAAG,CACd,MAAM,EAAE,yBAAyB,EACjC,kBAAkB,EAAE,0BAA0B,EAC9C,UAAU,EAAE,sBAAsB,EAClC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,WAAW,EAAE,aAAa,GAAG,WAAW,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,WAAW,EACvB,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,mBAAmB,EAC/B,YAAY,GAAE,YAAiC,EAC/C,SAAS,GAAE,eAAsC,EACjD,oBAAoB,CAAC,EAAE,0BAA0B,4BA0ElD;IAEM,qBAAqB,iBAI3B;IAEM,kBAAkB,oBAExB;IAEM,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,cAAc,sBAEzF;IAED,OAAO,CAAC,mBAAmB;IAOpB,sBAAsB,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,CAE9D;IAEM,0BAA0B,CAAC,QAAQ,EAAE,UAAU,GAAG,YAAY,CAEpE;IAEM,SAAS,IAAI,yBAAyB,CAE5C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,QAE7D;IAEM,cAAc,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAQvD;IAEY,KAAK,kBAmBjB;IAEY,IAAI,kBAGhB;IAED,0CAA0C;IAC7B,gBAAgB,kBAsC5B;IAED;;;;OAIG;IACG,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0G7F;IAED;;;;;OAKG;IACG,0BAA0B,CAC9B,QAAQ,EAAE,sBAAsB,EAChC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,qBAAqB,EAAE,GAAG,SAAS,CAAC,CAwG9C;IAED;;;OAGG;IACH,OAAO,CAAC,kBAAkB;YAiBZ,wCAAwC;IAmBtD;;OAEG;IACH,UAAgB,wBAAwB,CAAC,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/G;IAED,OAAO,CAAC,iBAAiB;IA2BzB,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,wCAAwC;IAyBhD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA6B/B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAkBlC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAWjB,mBAAmB,CACvB,WAAW,EAAE,WAAW,EACxB,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB,EAC5C,MAAM,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,EACX,GAAG,EAAE,EAAE,EAAE,EACT,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAiCxB;IAEK,wBAAwB,CAC5B,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,EAAE,EACX,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,MAAM,EAC7B,iBAAiB,EAAE,aAAa,GAAG,SAAS,EAC5C,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,kBAAkB,CAAC,CA0B7B;IAEK,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnE;IAEK,0BAA0B,CAC9B,sBAAsB,EAAE,+BAA+B,EACvD,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,UAAU,EAChB,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,SAAS,CAAC,CAOpB;IAEK,sBAAsB,CAC1B,QAAQ,EAAE,kBAAkB,EAC5B,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAiBlC;IAEK,mBAAmB,CACvB,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,IAAI,EACd,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAuDlC;YAEa,iBAAiB;CAwBhC"}
package/dest/validator.js CHANGED
@@ -5,7 +5,7 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
5
5
  import { sleep } from '@aztec/foundation/sleep';
6
6
  import { DateProvider } from '@aztec/foundation/timer';
7
7
  import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
8
- import { OffenseType, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
8
+ import { OffenseType, WANT_TO_CLEAR_SLASH_EVENT, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
9
9
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
10
10
  import { AttestationTimeoutError } from '@aztec/stdlib/validators';
11
11
  import { getTelemetryClient } from '@aztec/telemetry-client';
@@ -20,6 +20,8 @@ import { ProposalHandler } from './proposal_handler.js';
20
20
  // We maintain a set of proposers who have proposed invalid blocks.
21
21
  // Just cap the set to avoid unbounded growth.
22
22
  const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
23
+ const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
24
+ const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
23
25
  // What errors from the block proposal handler result in slashing
24
26
  const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
25
27
  'state_mismatch',
@@ -52,9 +54,12 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
52
54
  epochCacheUpdateLoop;
53
55
  /** Tracks the last epoch in which each attester successfully submitted at least one attestation. */ lastAttestedEpochByAttester;
54
56
  proposersOfInvalidBlocks;
57
+ slotsWithInvalidBlockProposals;
58
+ slotsWithProposalEquivocation;
59
+ badAttestationOffenseKeys;
55
60
  /** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
56
61
  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();
62
+ 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(), this.slotsWithInvalidBlockProposals = new Set(), this.slotsWithProposalEquivocation = new Set(), this.badAttestationOffenseKeys = new Set();
58
63
  // Create child logger with fisherman prefix if in fisherman mode
59
64
  this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
60
65
  this.tracer = telemetry.getTracer('Validator');
@@ -117,7 +122,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
117
122
  maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
118
123
  signatureContext: {
119
124
  chainId: config.l1ChainId,
120
- rollupAddress: config.l1Contracts.rollupAddress
125
+ rollupAddress: config.rollupAddress
121
126
  }
122
127
  });
123
128
  const proposalHandler = new ProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, metrics, dateProvider, telemetry, undefined);
@@ -164,7 +169,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
164
169
  getSignatureContext() {
165
170
  return {
166
171
  chainId: this.config.l1ChainId,
167
- rollupAddress: this.config.l1Contracts.rollupAddress
172
+ rollupAddress: this.config.rollupAddress
168
173
  };
169
174
  }
170
175
  getCoinbaseForAttestor(attestor) {
@@ -227,6 +232,9 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
227
232
  this.p2pClient.registerDuplicateAttestationCallback((info)=>{
228
233
  this.handleDuplicateAttestation(info);
229
234
  });
235
+ this.p2pClient.registerCheckpointAttestationCallback((attestation)=>{
236
+ this.handleCheckpointAttestation(attestation);
237
+ });
230
238
  const myAddresses = this.getValidatorAddresses();
231
239
  this.p2pClient.registerThisValidatorAddresses(myAddresses);
232
240
  await this.p2pClient.addReqRespSubProtocol(ReqRespSubProtocol.AUTH, this.handleAuthRequest.bind(this));
@@ -268,8 +276,8 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
268
276
  });
269
277
  // Reexecute txs if we are part of the committee, or if slashing is enabled, or if we are configured to always reexecute.
270
278
  // In fisherman mode, we always reexecute to validate proposals.
271
- const { slashBroadcastedInvalidBlockPenalty, alwaysReexecuteBlockProposals, fishermanMode } = this.config;
272
- const shouldReexecute = fishermanMode || slashBroadcastedInvalidBlockPenalty > 0n || partOfCommittee || alwaysReexecuteBlockProposals || this.blobClient.canUpload();
279
+ const { slashBroadcastedInvalidBlockPenalty, slashAttestInvalidCheckpointProposalPenalty, alwaysReexecuteBlockProposals, fishermanMode } = this.config;
280
+ const shouldReexecute = fishermanMode || slashBroadcastedInvalidBlockPenalty > 0n || slashAttestInvalidCheckpointProposalPenalty > 0n || partOfCommittee || alwaysReexecuteBlockProposals || this.blobClient.canUpload();
273
281
  const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !!shouldReexecute && !escapeHatchOpen);
274
282
  if (!validationResult.isValid) {
275
283
  const reason = validationResult.reason || 'unknown';
@@ -288,10 +296,14 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
288
296
  // Node issues so we can't validate
289
297
  this.metrics.incFailedAttestationsNodeIssue(1, reason, partOfCommittee);
290
298
  }
291
- // Slash invalid block proposals (can happen even when not in committee)
292
- if (!escapeHatchOpen && validationResult.reason && SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason) && slashBroadcastedInvalidBlockPenalty > 0n) {
293
- this.log.warn(`Slashing proposer for invalid block proposal`, proposalInfo);
294
- this.slashInvalidBlock(proposal);
299
+ if (!escapeHatchOpen && validationResult.reason && SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason)) {
300
+ if (slashBroadcastedInvalidBlockPenalty > 0n) {
301
+ this.log.warn(`Slashing proposer for invalid block proposal`, proposalInfo);
302
+ this.slashInvalidBlock(proposal);
303
+ }
304
+ if (slashAttestInvalidCheckpointProposalPenalty > 0n) {
305
+ this.markInvalidProposalSlot(proposal.slotNumber);
306
+ }
295
307
  }
296
308
  return false;
297
309
  }
@@ -431,7 +443,9 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
431
443
  * Uploads blobs for a checkpoint to the filestore (fire and forget).
432
444
  */ async uploadBlobsForCheckpoint(proposal, proposalInfo) {
433
445
  try {
434
- const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
446
+ const lastBlockHeader = (await this.blockSource.getBlockData({
447
+ archive: proposal.archive
448
+ }))?.header;
435
449
  if (!lastBlockHeader) {
436
450
  this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
437
451
  return;
@@ -474,11 +488,54 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
474
488
  }
475
489
  ]);
476
490
  }
491
+ markInvalidProposalSlot(slotNumber) {
492
+ const slotKey = this.getSlotKey(slotNumber);
493
+ this.addToBoundedSet(this.slotsWithInvalidBlockProposals, slotKey, MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
494
+ }
495
+ handleCheckpointAttestation(attestation) {
496
+ const slotNumber = attestation.slotNumber;
497
+ const slotKey = this.getSlotKey(slotNumber);
498
+ if (!this.slotsWithInvalidBlockProposals.has(slotKey) || this.slotsWithProposalEquivocation.has(slotKey)) {
499
+ return;
500
+ }
501
+ const attester = attestation.getSender();
502
+ if (!attester) {
503
+ this.log.warn(`Cannot slash checkpoint attestation with invalid signature`, {
504
+ slotNumber,
505
+ archive: attestation.archive.toString()
506
+ });
507
+ return;
508
+ }
509
+ this.slashAttestedToInvalidCheckpointProposal(slotNumber, attester);
510
+ }
511
+ slashAttestedToInvalidCheckpointProposal(slotNumber, attester) {
512
+ if (this.config.slashAttestInvalidCheckpointProposalPenalty <= 0n) {
513
+ return;
514
+ }
515
+ const offenseKey = `${this.getSlotKey(slotNumber)}:${attester.toString()}`;
516
+ if (!this.addToBoundedSet(this.badAttestationOffenseKeys, offenseKey, MAX_TRACKED_BAD_ATTESTATIONS)) {
517
+ return;
518
+ }
519
+ this.log.warn(`Slashing attester for attesting to invalid checkpoint proposal`, {
520
+ attester: attester.toString(),
521
+ slotNumber
522
+ });
523
+ this.emit(WANT_TO_SLASH_EVENT, [
524
+ {
525
+ validator: attester,
526
+ amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
527
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
528
+ epochOrSlot: BigInt(slotNumber)
529
+ }
530
+ ]);
531
+ }
477
532
  /**
478
533
  * Handle detection of a duplicate proposal (equivocation).
479
534
  * Emits a slash event when a proposer sends multiple proposals for the same position.
480
535
  */ handleDuplicateProposal(info) {
481
536
  const { slot, proposer, type } = info;
537
+ const slotKey = this.getSlotKey(slot);
538
+ this.addToBoundedSet(this.slotsWithProposalEquivocation, slotKey, MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
482
539
  this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
483
540
  proposer: proposer.toString(),
484
541
  slot,
@@ -493,6 +550,12 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
493
550
  epochOrSlot: BigInt(slot)
494
551
  }
495
552
  ]);
553
+ this.emit(WANT_TO_CLEAR_SLASH_EVENT, [
554
+ {
555
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
556
+ epochOrSlot: BigInt(slot)
557
+ }
558
+ ]);
496
559
  }
497
560
  /**
498
561
  * Handle detection of a duplicate attestation (equivocation).
@@ -512,6 +575,19 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
512
575
  }
513
576
  ]);
514
577
  }
578
+ getSlotKey(slot) {
579
+ return slot.toString();
580
+ }
581
+ addToBoundedSet(set, value, maxSize) {
582
+ if (set.has(value)) {
583
+ return false;
584
+ }
585
+ if (set.size >= maxSize) {
586
+ set.delete(set.values().next().value);
587
+ }
588
+ set.add(value);
589
+ return true;
590
+ }
515
591
  async createBlockProposal(blockHeader, checkpointNumber, indexWithinCheckpoint, inHash, archive, txs, proposerAddress, options = {}) {
516
592
  // Validate that we're not creating a proposal for an older or equal position
517
593
  if (this.lastProposedBlock) {
@@ -577,27 +653,19 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
577
653
  throw new AttestationTimeoutError(0, required, slot);
578
654
  }
579
655
  await this.collectOwnAttestations(proposal, checkpointNumber);
580
- const proposalId = proposal.archive.toString();
656
+ const proposalPayloadHash = proposal.getPayloadHash();
581
657
  const myAddresses = this.getValidatorAddresses();
582
658
  let attestations = [];
583
659
  while(true){
584
- // Filter out attestations with a mismatching archive. This should NOT happen since we have verified
585
- // the proposer signature (ie our own) before accepting the attestation into the pool via the p2p client.
586
- const collectedAttestations = (await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalId)).filter((attestation)=>{
587
- if (!attestation.archive.equals(proposal.archive)) {
588
- this.log.warn(`Received attestation for slot ${slot} with mismatched archive from ${attestation.getSender()?.toString()}`, {
589
- attestationArchive: attestation.archive.toString(),
590
- proposalArchive: proposal.archive.toString()
591
- });
592
- return false;
593
- }
594
- return true;
595
- });
660
+ // The pool already filters by proposal payload hash; if any attestation slips through with a
661
+ // mismatched payload hash, drop it defensively. Equivocations are emitted as separate slash
662
+ // events from libp2p_service.
663
+ const collectedAttestations = await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalPayloadHash);
596
664
  // Log new attestations we collected
597
665
  const oldSenders = attestations.map((attestation)=>attestation.getSender());
598
666
  for (const collected of collectedAttestations){
599
667
  const collectedSender = collected.getSender();
600
- // Skip attestations with invalid signatures
668
+ // Skip attestations with invalid signatures. Should not happen as we don't add invalid attestations to our pool.
601
669
  if (!collectedSender) {
602
670
  this.log.warn(`Skipping attestation with invalid signature for slot ${slot}`);
603
671
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/validator-client",
3
- "version": "5.0.0-nightly.20260505",
3
+ "version": "5.0.0-nightly.20260514",
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": "5.0.0-nightly.20260505",
68
- "@aztec/blob-lib": "5.0.0-nightly.20260505",
69
- "@aztec/constants": "5.0.0-nightly.20260505",
70
- "@aztec/epoch-cache": "5.0.0-nightly.20260505",
71
- "@aztec/ethereum": "5.0.0-nightly.20260505",
72
- "@aztec/foundation": "5.0.0-nightly.20260505",
73
- "@aztec/node-keystore": "5.0.0-nightly.20260505",
74
- "@aztec/noir-protocol-circuits-types": "5.0.0-nightly.20260505",
75
- "@aztec/p2p": "5.0.0-nightly.20260505",
76
- "@aztec/protocol-contracts": "5.0.0-nightly.20260505",
77
- "@aztec/prover-client": "5.0.0-nightly.20260505",
78
- "@aztec/simulator": "5.0.0-nightly.20260505",
79
- "@aztec/slasher": "5.0.0-nightly.20260505",
80
- "@aztec/stdlib": "5.0.0-nightly.20260505",
81
- "@aztec/telemetry-client": "5.0.0-nightly.20260505",
82
- "@aztec/validator-ha-signer": "5.0.0-nightly.20260505",
67
+ "@aztec/blob-client": "5.0.0-nightly.20260514",
68
+ "@aztec/blob-lib": "5.0.0-nightly.20260514",
69
+ "@aztec/constants": "5.0.0-nightly.20260514",
70
+ "@aztec/epoch-cache": "5.0.0-nightly.20260514",
71
+ "@aztec/ethereum": "5.0.0-nightly.20260514",
72
+ "@aztec/foundation": "5.0.0-nightly.20260514",
73
+ "@aztec/node-keystore": "5.0.0-nightly.20260514",
74
+ "@aztec/noir-protocol-circuits-types": "5.0.0-nightly.20260514",
75
+ "@aztec/p2p": "5.0.0-nightly.20260514",
76
+ "@aztec/protocol-contracts": "5.0.0-nightly.20260514",
77
+ "@aztec/prover-client": "5.0.0-nightly.20260514",
78
+ "@aztec/simulator": "5.0.0-nightly.20260514",
79
+ "@aztec/slasher": "5.0.0-nightly.20260514",
80
+ "@aztec/stdlib": "5.0.0-nightly.20260514",
81
+ "@aztec/telemetry-client": "5.0.0-nightly.20260514",
82
+ "@aztec/validator-ha-signer": "5.0.0-nightly.20260514",
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": "5.0.0-nightly.20260505",
90
- "@aztec/world-state": "5.0.0-nightly.20260505",
89
+ "@aztec/archiver": "5.0.0-nightly.20260514",
90
+ "@aztec/world-state": "5.0.0-nightly.20260514",
91
91
  "@electric-sql/pglite": "^0.3.14",
92
92
  "@jest/globals": "^30.0.0",
93
93
  "@types/jest": "^30.0.0",
package/src/factory.ts CHANGED
@@ -35,7 +35,7 @@ export function createProposalHandler(
35
35
  maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
36
36
  signatureContext: {
37
37
  chainId: config.l1ChainId,
38
- rollupAddress: config.l1Contracts.rollupAddress,
38
+ rollupAddress: config.rollupAddress,
39
39
  },
40
40
  });
41
41
  return new ProposalHandler(
@@ -4,7 +4,12 @@ import { type Blob, encodeCheckpointBlobDataFromBlocks, getBlobsPerL1Block } fro
4
4
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
5
5
  import type { EpochCache } from '@aztec/epoch-cache';
6
6
  import { validateFeeAssetPriceModifier } from '@aztec/ethereum/contracts';
7
- import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
7
+ import {
8
+ BlockNumber,
9
+ CheckpointNumber,
10
+ type CheckpointProposalHash,
11
+ SlotNumber,
12
+ } from '@aztec/foundation/branded-types';
8
13
  import { pick } from '@aztec/foundation/collection';
9
14
  import { Fr } from '@aztec/foundation/curves/bn254';
10
15
  import { TimeoutError } from '@aztec/foundation/error';
@@ -15,7 +20,7 @@ import { DateProvider, Timer } from '@aztec/foundation/timer';
15
20
  import type { P2P, PeerId } from '@aztec/p2p';
16
21
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
17
22
  import type { BlockData, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
18
- import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
23
+ import { getPreviousCheckpointOutHashes, validateCheckpoint } from '@aztec/stdlib/checkpoint';
19
24
  import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
20
25
  import { Gas } from '@aztec/stdlib/gas';
21
26
  import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
@@ -88,10 +93,11 @@ type CheckpointComputationResult =
88
93
  export class ProposalHandler {
89
94
  public readonly tracer: Tracer;
90
95
 
91
- /** Cached last checkpoint validation result to avoid double-validation on validator nodes. */
96
+ /** Cached last checkpoint validation result to avoid double-validation on validator nodes.
97
+ * Keyed by signed-payload hash so two proposals at the same (slot, archive) but with a
98
+ * different `feeAssetPriceModifier` (or any other signed field) are validated independently. */
92
99
  private lastCheckpointValidationResult?: {
93
- archive: Fr;
94
- slotNumber: SlotNumber;
100
+ payloadHash: CheckpointProposalHash;
95
101
  result: CheckpointProposalValidationResult;
96
102
  };
97
103
 
@@ -292,7 +298,7 @@ export class ProposalHandler {
292
298
  proposalInfo.blockNumber = blockNumber;
293
299
 
294
300
  // Check that this block number does not exist already
295
- const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
301
+ const existingBlock = await this.blockSource.getBlockData({ number: blockNumber });
296
302
  if (existingBlock) {
297
303
  this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
298
304
  return { isValid: false, blockNumber, reason: 'block_number_already_exists' };
@@ -341,11 +347,18 @@ export class ProposalHandler {
341
347
  return { isValid: false, blockNumber, reason: 'txs_not_available' };
342
348
  }
343
349
 
344
- // Collect the out hashes of all the checkpoints before this one in the same epoch
350
+ // Collect the out hashes of all the checkpoints before this one in the same epoch.
351
+ // Mirror the proposer-side fallback: under pipelining the immediately-preceding cp may not
352
+ // yet be on L1, in which case the helper grafts the locally-known proposed cp's outHash.
345
353
  const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
346
- const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
347
- .filter(c => c.checkpointNumber < checkpointNumber)
348
- .map(c => c.checkpointOutHash);
354
+ const previousCheckpointOutHashes = await getPreviousCheckpointOutHashes({
355
+ blockSource: this.blockSource,
356
+ epoch,
357
+ checkpointNumber,
358
+ l1Constants: this.epochCache.getL1Constants(),
359
+ pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled(),
360
+ log: this.log,
361
+ });
349
362
 
350
363
  // Try re-executing the transactions in the proposal if needed
351
364
  let reexecutionResult;
@@ -393,11 +406,12 @@ export class ProposalHandler {
393
406
 
394
407
  try {
395
408
  return (
396
- (await this.blockSource.getBlockDataByArchive(parentArchive)) ??
409
+ (await this.blockSource.getBlockData({ archive: parentArchive })) ??
397
410
  (timeoutDurationMs <= 0
398
411
  ? undefined
399
412
  : await retryUntil(
400
- () => this.blockSource.syncImmediate().then(() => this.blockSource.getBlockDataByArchive(parentArchive)),
413
+ () =>
414
+ this.blockSource.syncImmediate().then(() => this.blockSource.getBlockData({ archive: parentArchive })),
401
415
  'force archiver sync',
402
416
  timeoutDurationMs / 1000,
403
417
  0.5,
@@ -734,13 +748,10 @@ export class ProposalHandler {
734
748
  proposalInfo: LogData,
735
749
  ): Promise<CheckpointProposalValidationResult> {
736
750
  const slot = proposal.slotNumber;
751
+ const payloadHash = proposal.getPayloadHash();
737
752
 
738
- // Check cache: same archive+slot means we already validated this proposal
739
- if (
740
- this.lastCheckpointValidationResult &&
741
- this.lastCheckpointValidationResult.archive.equals(proposal.archive) &&
742
- this.lastCheckpointValidationResult.slotNumber === slot
743
- ) {
753
+ // Check cache: same signed-payload hash means we already validated this exact proposal.
754
+ if (this.lastCheckpointValidationResult && this.lastCheckpointValidationResult.payloadHash === payloadHash) {
744
755
  this.log.debug(`Returning cached validation result for checkpoint proposal at slot ${slot}`, proposalInfo);
745
756
  return this.lastCheckpointValidationResult.result;
746
757
  }
@@ -749,7 +760,7 @@ export class ProposalHandler {
749
760
  if (!proposer) {
750
761
  this.log.warn(`Received checkpoint proposal with invalid signature for slot ${proposal.slotNumber}`);
751
762
  const result: CheckpointProposalValidationResult = { isValid: false, reason: 'invalid_signature' };
752
- this.lastCheckpointValidationResult = { archive: proposal.archive, slotNumber: slot, result };
763
+ this.lastCheckpointValidationResult = { payloadHash, result };
753
764
  return result;
754
765
  }
755
766
 
@@ -758,12 +769,12 @@ export class ProposalHandler {
758
769
  `Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${proposal.slotNumber}`,
759
770
  );
760
771
  const result: CheckpointProposalValidationResult = { isValid: false, reason: 'invalid_fee_asset_price_modifier' };
761
- this.lastCheckpointValidationResult = { archive: proposal.archive, slotNumber: slot, result };
772
+ this.lastCheckpointValidationResult = { payloadHash, result };
762
773
  return result;
763
774
  }
764
775
 
765
776
  const result = await this.validateCheckpointProposal(proposal, proposalInfo);
766
- this.lastCheckpointValidationResult = { archive: proposal.archive, slotNumber: slot, result };
777
+ this.lastCheckpointValidationResult = { payloadHash, result };
767
778
 
768
779
  // Upload blobs to filestore if validation passed (fire and forget)
769
780
  if (result.isValid) {
@@ -794,7 +805,7 @@ export class ProposalHandler {
794
805
  lastBlockHeader = await retryUntil(
795
806
  async () => {
796
807
  await this.blockSource.syncImmediate();
797
- return this.blockSource.getBlockHeaderByArchive(proposal.archive);
808
+ return (await this.blockSource.getBlockData({ archive: proposal.archive }))?.header;
798
809
  },
799
810
  `waiting for block with archive ${proposal.archive.toString()} for slot ${slot}`,
800
811
  timeoutSeconds,
@@ -850,11 +861,17 @@ export class ProposalHandler {
850
861
  // Get L1-to-L2 messages for this checkpoint
851
862
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
852
863
 
853
- // Collect the out hashes of all the checkpoints before this one in the same epoch
864
+ // Collect the out hashes of all the checkpoints before this one in the same epoch.
865
+ // See note on the analogous block-proposal site: the helper handles pipelining lag.
854
866
  const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
855
- const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
856
- .filter(c => c.checkpointNumber < checkpointNumber)
857
- .map(c => c.checkpointOutHash);
867
+ const previousCheckpointOutHashes = await getPreviousCheckpointOutHashes({
868
+ blockSource: this.blockSource,
869
+ epoch,
870
+ checkpointNumber,
871
+ l1Constants: this.epochCache.getL1Constants(),
872
+ pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled(),
873
+ log: this.log,
874
+ });
858
875
 
859
876
  // Fork world state at the block before the first block
860
877
  const parentBlockNumber = BlockNumber(firstBlock.number - 1);
@@ -953,7 +970,7 @@ export class ProposalHandler {
953
970
  /** Uploads blobs for a checkpoint to the filestore. */
954
971
  protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
955
972
  try {
956
- const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
973
+ const lastBlockHeader = (await this.blockSource.getBlockData({ archive: proposal.archive }))?.header;
957
974
  if (!lastBlockHeader) {
958
975
  this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
959
976
  return;
@@ -987,7 +1004,7 @@ export class ProposalHandler {
987
1004
  if (!this.archiver) {
988
1005
  return false;
989
1006
  }
990
- const blockData = await this.blockSource.getBlockDataByArchive(proposal.archive);
1007
+ const blockData = await this.blockSource.getBlockData({ archive: proposal.archive });
991
1008
  if (!blockData) {
992
1009
  this.log.debug(`Block data not found for checkpoint proposal archive, cannot set proposed checkpoint`, {
993
1010
  archive: proposal.archive.toString(),
@@ -1015,7 +1032,7 @@ export class ProposalHandler {
1015
1032
  if (!this.archiver) {
1016
1033
  return false;
1017
1034
  }
1018
- let blockData = await this.blockSource.getBlockDataByArchive(proposal.archive);
1035
+ let blockData = await this.blockSource.getBlockData({ archive: proposal.archive });
1019
1036
 
1020
1037
  if (!blockData) {
1021
1038
  // The checkpoint proposal often arrives before the last block finishes re-execution.
@@ -1025,7 +1042,7 @@ export class ProposalHandler {
1025
1042
  const timeoutSeconds = Math.max(1, Number(timeOfNextSlot) - Math.floor(this.dateProvider.now() / 1000));
1026
1043
 
1027
1044
  blockData = await retryUntil(
1028
- () => this.blockSource.getBlockDataByArchive(proposal.archive),
1045
+ () => this.blockSource.getBlockData({ archive: proposal.archive }),
1029
1046
  'block data for own checkpoint proposal',
1030
1047
  timeoutSeconds,
1031
1048
  0.25,
package/src/validator.ts CHANGED
@@ -12,7 +12,13 @@ import { DateProvider } from '@aztec/foundation/timer';
12
12
  import type { KeystoreManager } from '@aztec/node-keystore';
13
13
  import type { DuplicateAttestationInfo, DuplicateProposalInfo, P2P, PeerId } from '@aztec/p2p';
14
14
  import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
15
- import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
15
+ import {
16
+ OffenseType,
17
+ WANT_TO_CLEAR_SLASH_EVENT,
18
+ WANT_TO_SLASH_EVENT,
19
+ type Watcher,
20
+ type WatcherEmitter,
21
+ } from '@aztec/slasher';
16
22
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
17
23
  import type { CommitteeAttestationsAndSigners, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
18
24
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
@@ -58,6 +64,8 @@ import { type BlockProposalValidationFailureReason, ProposalHandler } from './pr
58
64
  // We maintain a set of proposers who have proposed invalid blocks.
59
65
  // Just cap the set to avoid unbounded growth.
60
66
  const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
67
+ const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
68
+ const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
61
69
 
62
70
  // What errors from the block proposal handler result in slashing
63
71
  const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT: BlockProposalValidationFailureReason[] = [
@@ -88,6 +96,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
88
96
  private lastAttestedEpochByAttester: Map<string, EpochNumber> = new Map();
89
97
 
90
98
  private proposersOfInvalidBlocks: Set<string> = new Set();
99
+ private slotsWithInvalidBlockProposals: Set<string> = new Set();
100
+ private slotsWithProposalEquivocation: Set<string> = new Set();
101
+ private badAttestationOffenseKeys: Set<string> = new Set();
91
102
 
92
103
  /** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
93
104
  private lastAttestedProposal?: CheckpointProposalCore;
@@ -204,7 +215,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
204
215
  maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
205
216
  signatureContext: {
206
217
  chainId: config.l1ChainId,
207
- rollupAddress: config.l1Contracts.rollupAddress,
218
+ rollupAddress: config.rollupAddress,
208
219
  },
209
220
  });
210
221
  const proposalHandler = new ProposalHandler(
@@ -288,7 +299,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
288
299
  private getSignatureContext(): CoordinationSignatureContext {
289
300
  return {
290
301
  chainId: this.config.l1ChainId,
291
- rollupAddress: this.config.l1Contracts.rollupAddress,
302
+ rollupAddress: this.config.rollupAddress,
292
303
  };
293
304
  }
294
305
 
@@ -374,6 +385,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
374
385
  this.handleDuplicateAttestation(info);
375
386
  });
376
387
 
388
+ this.p2pClient.registerCheckpointAttestationCallback((attestation: CheckpointAttestation) => {
389
+ this.handleCheckpointAttestation(attestation);
390
+ });
391
+
377
392
  const myAddresses = this.getValidatorAddresses();
378
393
  this.p2pClient.registerThisValidatorAddresses(myAddresses);
379
394
 
@@ -422,10 +437,16 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
422
437
 
423
438
  // Reexecute txs if we are part of the committee, or if slashing is enabled, or if we are configured to always reexecute.
424
439
  // In fisherman mode, we always reexecute to validate proposals.
425
- const { slashBroadcastedInvalidBlockPenalty, alwaysReexecuteBlockProposals, fishermanMode } = this.config;
440
+ const {
441
+ slashBroadcastedInvalidBlockPenalty,
442
+ slashAttestInvalidCheckpointProposalPenalty,
443
+ alwaysReexecuteBlockProposals,
444
+ fishermanMode,
445
+ } = this.config;
426
446
  const shouldReexecute =
427
447
  fishermanMode ||
428
448
  slashBroadcastedInvalidBlockPenalty > 0n ||
449
+ slashAttestInvalidCheckpointProposalPenalty > 0n ||
429
450
  partOfCommittee ||
430
451
  alwaysReexecuteBlockProposals ||
431
452
  this.blobClient.canUpload();
@@ -457,15 +478,18 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
457
478
  this.metrics.incFailedAttestationsNodeIssue(1, reason, partOfCommittee);
458
479
  }
459
480
 
460
- // Slash invalid block proposals (can happen even when not in committee)
461
481
  if (
462
482
  !escapeHatchOpen &&
463
483
  validationResult.reason &&
464
- SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason) &&
465
- slashBroadcastedInvalidBlockPenalty > 0n
484
+ SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason)
466
485
  ) {
467
- this.log.warn(`Slashing proposer for invalid block proposal`, proposalInfo);
468
- this.slashInvalidBlock(proposal);
486
+ if (slashBroadcastedInvalidBlockPenalty > 0n) {
487
+ this.log.warn(`Slashing proposer for invalid block proposal`, proposalInfo);
488
+ this.slashInvalidBlock(proposal);
489
+ }
490
+ if (slashAttestInvalidCheckpointProposalPenalty > 0n) {
491
+ this.markInvalidProposalSlot(proposal.slotNumber);
492
+ }
469
493
  }
470
494
  return false;
471
495
  }
@@ -645,7 +669,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
645
669
  */
646
670
  protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
647
671
  try {
648
- const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
672
+ const lastBlockHeader = (await this.blockSource.getBlockData({ archive: proposal.archive }))?.header;
649
673
  if (!lastBlockHeader) {
650
674
  this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
651
675
  return;
@@ -696,12 +720,63 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
696
720
  ]);
697
721
  }
698
722
 
723
+ private markInvalidProposalSlot(slotNumber: SlotNumber): void {
724
+ const slotKey = this.getSlotKey(slotNumber);
725
+ this.addToBoundedSet(this.slotsWithInvalidBlockProposals, slotKey, MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
726
+ }
727
+
728
+ private handleCheckpointAttestation(attestation: CheckpointAttestation): void {
729
+ const slotNumber = attestation.slotNumber;
730
+ const slotKey = this.getSlotKey(slotNumber);
731
+ if (!this.slotsWithInvalidBlockProposals.has(slotKey) || this.slotsWithProposalEquivocation.has(slotKey)) {
732
+ return;
733
+ }
734
+
735
+ const attester = attestation.getSender();
736
+ if (!attester) {
737
+ this.log.warn(`Cannot slash checkpoint attestation with invalid signature`, {
738
+ slotNumber,
739
+ archive: attestation.archive.toString(),
740
+ });
741
+ return;
742
+ }
743
+
744
+ this.slashAttestedToInvalidCheckpointProposal(slotNumber, attester);
745
+ }
746
+
747
+ private slashAttestedToInvalidCheckpointProposal(slotNumber: SlotNumber, attester: EthAddress): void {
748
+ if (this.config.slashAttestInvalidCheckpointProposalPenalty <= 0n) {
749
+ return;
750
+ }
751
+
752
+ const offenseKey = `${this.getSlotKey(slotNumber)}:${attester.toString()}`;
753
+ if (!this.addToBoundedSet(this.badAttestationOffenseKeys, offenseKey, MAX_TRACKED_BAD_ATTESTATIONS)) {
754
+ return;
755
+ }
756
+
757
+ this.log.warn(`Slashing attester for attesting to invalid checkpoint proposal`, {
758
+ attester: attester.toString(),
759
+ slotNumber,
760
+ });
761
+
762
+ this.emit(WANT_TO_SLASH_EVENT, [
763
+ {
764
+ validator: attester,
765
+ amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
766
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
767
+ epochOrSlot: BigInt(slotNumber),
768
+ },
769
+ ]);
770
+ }
771
+
699
772
  /**
700
773
  * Handle detection of a duplicate proposal (equivocation).
701
774
  * Emits a slash event when a proposer sends multiple proposals for the same position.
702
775
  */
703
776
  private handleDuplicateProposal(info: DuplicateProposalInfo): void {
704
777
  const { slot, proposer, type } = info;
778
+ const slotKey = this.getSlotKey(slot);
779
+ this.addToBoundedSet(this.slotsWithProposalEquivocation, slotKey, MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
705
780
 
706
781
  this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
707
782
  proposer: proposer.toString(),
@@ -718,6 +793,13 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
718
793
  epochOrSlot: BigInt(slot),
719
794
  },
720
795
  ]);
796
+
797
+ this.emit(WANT_TO_CLEAR_SLASH_EVENT, [
798
+ {
799
+ offenseType: OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL,
800
+ epochOrSlot: BigInt(slot),
801
+ },
802
+ ]);
721
803
  }
722
804
 
723
805
  /**
@@ -742,6 +824,21 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
742
824
  ]);
743
825
  }
744
826
 
827
+ private getSlotKey(slot: SlotNumber): string {
828
+ return slot.toString();
829
+ }
830
+
831
+ private addToBoundedSet(set: Set<string>, value: string, maxSize: number): boolean {
832
+ if (set.has(value)) {
833
+ return false;
834
+ }
835
+ if (set.size >= maxSize) {
836
+ set.delete(set.values().next().value!);
837
+ }
838
+ set.add(value);
839
+ return true;
840
+ }
841
+
745
842
  async createBlockProposal(
746
843
  blockHeader: BlockHeader,
747
844
  checkpointNumber: CheckpointNumber,
@@ -881,33 +978,21 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
881
978
 
882
979
  await this.collectOwnAttestations(proposal, checkpointNumber);
883
980
 
884
- const proposalId = proposal.archive.toString();
981
+ const proposalPayloadHash = proposal.getPayloadHash();
885
982
  const myAddresses = this.getValidatorAddresses();
886
983
 
887
984
  let attestations: CheckpointAttestation[] = [];
888
985
  while (true) {
889
- // Filter out attestations with a mismatching archive. This should NOT happen since we have verified
890
- // the proposer signature (ie our own) before accepting the attestation into the pool via the p2p client.
891
- const collectedAttestations = (await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalId)).filter(
892
- attestation => {
893
- if (!attestation.archive.equals(proposal.archive)) {
894
- this.log.warn(
895
- `Received attestation for slot ${slot} with mismatched archive from ${attestation
896
- .getSender()
897
- ?.toString()}`,
898
- { attestationArchive: attestation.archive.toString(), proposalArchive: proposal.archive.toString() },
899
- );
900
- return false;
901
- }
902
- return true;
903
- },
904
- );
986
+ // The pool already filters by proposal payload hash; if any attestation slips through with a
987
+ // mismatched payload hash, drop it defensively. Equivocations are emitted as separate slash
988
+ // events from libp2p_service.
989
+ const collectedAttestations = await this.p2pClient.getCheckpointAttestationsForSlot(slot, proposalPayloadHash);
905
990
 
906
991
  // Log new attestations we collected
907
992
  const oldSenders = attestations.map(attestation => attestation.getSender());
908
993
  for (const collected of collectedAttestations) {
909
994
  const collectedSender = collected.getSender();
910
- // Skip attestations with invalid signatures
995
+ // Skip attestations with invalid signatures. Should not happen as we don't add invalid attestations to our pool.
911
996
  if (!collectedSender) {
912
997
  this.log.warn(`Skipping attestation with invalid signature for slot ${slot}`);
913
998
  continue;