@aztec/slasher 0.0.1-commit.6d63667d → 0.0.1-commit.86469d5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { EpochCache } from '@aztec/epoch-cache';
2
- import { EpochNumber } from '@aztec/foundation/branded-types';
2
+ import type { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { L2Block, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
4
- import type { ICheckpointsBuilder, ITxProvider, SlasherConfig } from '@aztec/stdlib/interfaces/server';
4
+ import type { ICheckpointsBuilder, ITxProvider, MerkleTreeWriteOperations, SlasherConfig } from '@aztec/stdlib/interfaces/server';
5
5
  import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
6
6
  import { type Watcher, type WatcherEmitter } from '../watcher.js';
7
7
  declare const EpochPruneWatcherPenaltiesConfigKeys: readonly ["slashPrunePenalty", "slashDataWithholdingPenalty"];
@@ -29,11 +29,10 @@ export declare class EpochPruneWatcher extends EpochPruneWatcher_base implements
29
29
  private handlePruneL2Blocks;
30
30
  private emitSlashForEpoch;
31
31
  private processPruneL2Blocks;
32
- validateBlocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void>;
33
- private validateCheckpoint;
34
- private validateBlockInCheckpoint;
32
+ validateBlocks(blocks: L2Block[]): Promise<void>;
33
+ validateBlock(blockFromL1: L2Block, previousCheckpointOutHashes: Fr[], fork: MerkleTreeWriteOperations): Promise<void>;
35
34
  private getValidatorsForEpoch;
36
35
  private validatorsToSlashingArgs;
37
36
  }
38
37
  export {};
39
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBZSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUkzRSxPQUFPLEVBRUwsT0FBTyxFQUNQLEtBQUsseUJBQXlCLEVBRy9CLE1BQU0scUJBQXFCLENBQUM7QUFFN0IsT0FBTyxLQUFLLEVBRVYsbUJBQW1CLEVBQ25CLFdBQVcsRUFFWCxhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxtQkFBbUIsRUFBNEIsTUFBTSx5QkFBeUIsQ0FBQztBQVk3RixPQUFPLEVBQTZDLEtBQUssT0FBTyxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdHLFFBQUEsTUFBTSxvQ0FBb0MsK0RBQWdFLENBQUM7QUFFM0csS0FBSywwQkFBMEIsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsT0FBTyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7O0FBRTdHOzs7OztHQUtHO0FBQ0gscUJBQWEsaUJBQWtCLFNBQVEsc0JBQTJDLFlBQVcsT0FBTztJQVNoRyxPQUFPLENBQUMsYUFBYTtJQUNyQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxrQkFBa0I7SUFaNUIsT0FBTyxDQUFDLEdBQUcsQ0FBK0M7SUFHMUQsT0FBTyxDQUFDLHdCQUF3QixDQUF1QztJQUV2RSxPQUFPLENBQUMsU0FBUyxDQUE2QjtJQUU5QyxZQUNVLGFBQWEsRUFBRSx5QkFBeUIsRUFDeEMsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLGlCQUFpQixDQUFDLEVBQ2hELGtCQUFrQixFQUFFLG1CQUFtQixFQUMvQyxTQUFTLEVBQUUsMEJBQTBCLEVBT3RDO0lBRU0sS0FBSyxrQkFHWDtJQUVNLElBQUksa0JBR1Y7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBR3hEO0lBRUQsT0FBTyxDQUFDLG1CQUFtQjtZQU9iLGlCQUFpQjtZQVdqQixvQkFBb0I7SUF3QnJCLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEVBQUUsV0FBVyxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBK0J0RjtZQUVhLGtCQUFrQjtZQXNDbEIseUJBQXlCO1lBOEJ6QixxQkFBcUI7SUFTbkMsT0FBTyxDQUFDLHdCQUF3QjtDQWdCakMifQ==
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBR2hELE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXpELE9BQU8sRUFFTCxPQUFPLEVBQ1AsS0FBSyx5QkFBeUIsRUFHL0IsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEtBQUssRUFDVixtQkFBbUIsRUFDbkIsV0FBVyxFQUNYLHlCQUF5QixFQUN6QixhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxtQkFBbUIsRUFBNEIsTUFBTSx5QkFBeUIsQ0FBQztBQVk3RixPQUFPLEVBQTZDLEtBQUssT0FBTyxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdHLFFBQUEsTUFBTSxvQ0FBb0MsK0RBQWdFLENBQUM7QUFFM0csS0FBSywwQkFBMEIsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsT0FBTyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7O0FBRTdHOzs7OztHQUtHO0FBQ0gscUJBQWEsaUJBQWtCLFNBQVEsc0JBQTJDLFlBQVcsT0FBTztJQVNoRyxPQUFPLENBQUMsYUFBYTtJQUNyQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxrQkFBa0I7SUFaNUIsT0FBTyxDQUFDLEdBQUcsQ0FBK0M7SUFHMUQsT0FBTyxDQUFDLHdCQUF3QixDQUF1QztJQUV2RSxPQUFPLENBQUMsU0FBUyxDQUE2QjtJQUU5QyxZQUNVLGFBQWEsRUFBRSx5QkFBeUIsRUFDeEMsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLGlCQUFpQixDQUFDLEVBQ2hELGtCQUFrQixFQUFFLG1CQUFtQixFQUMvQyxTQUFTLEVBQUUsMEJBQTBCLEVBT3RDO0lBRU0sS0FBSyxrQkFHWDtJQUVNLElBQUksa0JBR1Y7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBR3hEO0lBRUQsT0FBTyxDQUFDLG1CQUFtQjtZQU9iLGlCQUFpQjtZQVdqQixvQkFBb0I7SUF3QnJCLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWtCNUQ7SUFFWSxhQUFhLENBQ3hCLFdBQVcsRUFBRSxPQUFPLEVBQ3BCLDJCQUEyQixFQUFFLEVBQUUsRUFBRSxFQUNqQyxJQUFJLEVBQUUseUJBQXlCLEdBQzlCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0E4Q2Y7WUFFYSxxQkFBcUI7SUFTbkMsT0FBTyxDQUFDLHdCQUF3QjtDQWdCakMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAe,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAI3E,OAAO,EAEL,OAAO,EACP,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAEV,mBAAmB,EACnB,WAAW,EAEX,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,yBAAyB,CAAC;AAY7F,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,oCAAoC,+DAAgE,CAAC;AAE3G,KAAK,0BAA0B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE7G;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAZ5B,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,wBAAwB,CAAuC;IAEvE,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACU,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,kBAAkB,EAAE,mBAAmB,EAC/C,SAAS,EAAE,0BAA0B,EAOtC;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAGV;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAGxD;IAED,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAWjB,oBAAoB;IAwBrB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BtF;YAEa,kBAAkB;YAsClB,yBAAyB;YA8BzB,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
1
+ {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEzD,OAAO,EAEL,OAAO,EACP,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,yBAAyB,CAAC;AAY7F,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,oCAAoC,+DAAgE,CAAC;AAE3G,KAAK,0BAA0B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE7G;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAZ5B,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,wBAAwB,CAAuC;IAEvE,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACU,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,kBAAkB,EAAE,mBAAmB,EAC/C,SAAS,EAAE,0BAA0B,EAOtC;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAGV;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAGxD;IAED,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAWjB,oBAAoB;IAwBrB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5D;IAEY,aAAa,CACxB,WAAW,EAAE,OAAO,EACpB,2BAA2B,EAAE,EAAE,EAAE,EACjC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA8Cf;YAEa,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
@@ -1,5 +1,5 @@
1
- import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import { chunkBy, merge, pick } from '@aztec/foundation/collection';
1
+ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
+ import { merge, pick } from '@aztec/foundation/collection';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { L2BlockSourceEvents } from '@aztec/stdlib/block';
5
5
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
@@ -67,7 +67,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
67
67
  this.log.info(`Detected chain prune. Validating epoch ${epochNumber} with blocks ${epochBlocks[0]?.number} to ${epochBlocks[epochBlocks.length - 1]?.number}.`, {
68
68
  blocks: epochBlocks.map((b)=>b.toBlockInfo())
69
69
  });
70
- await this.validateBlocks(epochBlocks, epochNumber);
70
+ await this.validateBlocks(epochBlocks);
71
71
  this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
72
72
  await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
73
73
  } catch (error) {
@@ -81,26 +81,19 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
81
81
  }
82
82
  }
83
83
  }
84
- async validateBlocks(blocks, epochNumber) {
84
+ async validateBlocks(blocks) {
85
85
  if (blocks.length === 0) {
86
86
  return;
87
87
  }
88
- // Sort blocks by block number and group by checkpoint
89
- const sortedBlocks = [
90
- ...blocks
91
- ].sort((a, b)=>a.number - b.number);
92
- const blocksByCheckpoint = chunkBy(sortedBlocks, (b)=>b.checkpointNumber);
93
- // Get prior checkpoints in the epoch (in case this was a partial prune) to extract the out hashes
94
- const priorCheckpointOutHashes = (await this.l2BlockSource.getCheckpointsForEpoch(epochNumber)).filter((c)=>c.number < sortedBlocks[0].checkpointNumber).map((c)=>c.getCheckpointOutHash());
95
- let previousCheckpointOutHashes = [
96
- ...priorCheckpointOutHashes
97
- ];
98
- const fork = await this.checkpointsBuilder.getFork(BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1));
88
+ let previousCheckpointOutHashes = [];
89
+ const fork = await this.checkpointsBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
99
90
  try {
100
- for (const checkpointBlocks of blocksByCheckpoint){
101
- await this.validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork);
102
- // Compute checkpoint out hash from all blocks in this checkpoint
103
- const checkpointOutHash = computeCheckpointOutHash(checkpointBlocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs)));
91
+ for (const block of blocks){
92
+ await this.validateBlock(block, previousCheckpointOutHashes, fork);
93
+ // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
94
+ const checkpointOutHash = computeCheckpointOutHash([
95
+ block.body.txEffects.map((tx)=>tx.l2ToL1Msgs)
96
+ ]);
104
97
  previousCheckpointOutHashes = [
105
98
  ...previousCheckpointOutHashes,
106
99
  checkpointOutHash
@@ -110,29 +103,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
110
103
  await fork.close();
111
104
  }
112
105
  }
113
- async validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork) {
114
- const checkpointNumber = checkpointBlocks[0].checkpointNumber;
115
- this.log.debug(`Validating pruned checkpoint ${checkpointNumber} with ${checkpointBlocks.length} blocks`);
116
- // Get L1ToL2Messages once for the entire checkpoint
117
- const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
118
- // Build checkpoint constants from first block's global variables
119
- const gv = checkpointBlocks[0].header.globalVariables;
120
- const constants = {
121
- chainId: gv.chainId,
122
- version: gv.version,
123
- slotNumber: gv.slotNumber,
124
- coinbase: gv.coinbase,
125
- feeRecipient: gv.feeRecipient,
126
- gasFees: gv.gasFees
127
- };
128
- // Start checkpoint builder once for all blocks in this checkpoint
129
- const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
130
- // Validate all blocks in the checkpoint sequentially
131
- for (const block of checkpointBlocks){
132
- await this.validateBlockInCheckpoint(block, checkpointBuilder);
133
- }
134
- }
135
- async validateBlockInCheckpoint(blockFromL1, checkpointBuilder) {
106
+ async validateBlock(blockFromL1, previousCheckpointOutHashes, fork) {
136
107
  this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
137
108
  const txHashes = blockFromL1.body.txEffects.map((txEffect)=>txEffect.txHash);
138
109
  // We load txs from the mempool directly, since the TxCollector running in the background has already been
@@ -142,7 +113,19 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
142
113
  if (missingTxs && missingTxs.length > 0) {
143
114
  throw new TransactionsNotAvailableError(missingTxs);
144
115
  }
116
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
117
+ const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
145
118
  const gv = blockFromL1.header.globalVariables;
119
+ const constants = {
120
+ chainId: gv.chainId,
121
+ version: gv.version,
122
+ slotNumber: gv.slotNumber,
123
+ coinbase: gv.coinbase,
124
+ feeRecipient: gv.feeRecipient,
125
+ gasFees: gv.gasFees
126
+ };
127
+ // Use checkpoint builder to validate the block
128
+ const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
146
129
  const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {});
147
130
  if (numTxs !== txs.length) {
148
131
  // This should be detected by state mismatch, but this makes it easier to debug.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/slasher",
3
- "version": "0.0.1-commit.6d63667d",
3
+ "version": "0.0.1-commit.86469d5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -56,20 +56,20 @@
56
56
  ]
57
57
  },
58
58
  "dependencies": {
59
- "@aztec/epoch-cache": "0.0.1-commit.6d63667d",
60
- "@aztec/ethereum": "0.0.1-commit.6d63667d",
61
- "@aztec/foundation": "0.0.1-commit.6d63667d",
62
- "@aztec/kv-store": "0.0.1-commit.6d63667d",
63
- "@aztec/l1-artifacts": "0.0.1-commit.6d63667d",
64
- "@aztec/stdlib": "0.0.1-commit.6d63667d",
65
- "@aztec/telemetry-client": "0.0.1-commit.6d63667d",
59
+ "@aztec/epoch-cache": "0.0.1-commit.86469d5",
60
+ "@aztec/ethereum": "0.0.1-commit.86469d5",
61
+ "@aztec/foundation": "0.0.1-commit.86469d5",
62
+ "@aztec/kv-store": "0.0.1-commit.86469d5",
63
+ "@aztec/l1-artifacts": "0.0.1-commit.86469d5",
64
+ "@aztec/stdlib": "0.0.1-commit.86469d5",
65
+ "@aztec/telemetry-client": "0.0.1-commit.86469d5",
66
66
  "source-map-support": "^0.5.21",
67
67
  "tslib": "^2.4.0",
68
68
  "viem": "npm:@aztec/viem@2.38.2",
69
69
  "zod": "^3.23.8"
70
70
  },
71
71
  "devDependencies": {
72
- "@aztec/aztec.js": "0.0.1-commit.6d63667d",
72
+ "@aztec/aztec.js": "0.0.1-commit.86469d5",
73
73
  "@jest/globals": "^30.0.0",
74
74
  "@types/jest": "^30.0.0",
75
75
  "@types/node": "^22.15.17",
@@ -1,6 +1,6 @@
1
1
  import { EpochCache } from '@aztec/epoch-cache';
2
- import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
3
- import { chunkBy, merge, pick } from '@aztec/foundation/collection';
2
+ import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
3
+ import { merge, pick } from '@aztec/foundation/collection';
4
4
  import type { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { type Logger, createLogger } from '@aztec/foundation/log';
6
6
  import {
@@ -12,7 +12,6 @@ import {
12
12
  } from '@aztec/stdlib/block';
13
13
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
14
14
  import type {
15
- ICheckpointBlockBuilder,
16
15
  ICheckpointsBuilder,
17
16
  ITxProvider,
18
17
  MerkleTreeWriteOperations,
@@ -107,7 +106,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
107
106
  { blocks: epochBlocks.map(b => b.toBlockInfo()) },
108
107
  );
109
108
 
110
- await this.validateBlocks(epochBlocks, epochNumber);
109
+ await this.validateBlocks(epochBlocks);
111
110
  this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
112
111
  await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
113
112
  } catch (error) {
@@ -122,32 +121,19 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
122
121
  }
123
122
  }
124
123
 
125
- public async validateBlocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void> {
124
+ public async validateBlocks(blocks: L2Block[]): Promise<void> {
126
125
  if (blocks.length === 0) {
127
126
  return;
128
127
  }
129
128
 
130
- // Sort blocks by block number and group by checkpoint
131
- const sortedBlocks = [...blocks].sort((a, b) => a.number - b.number);
132
- const blocksByCheckpoint = chunkBy(sortedBlocks, b => b.checkpointNumber);
133
-
134
- // Get prior checkpoints in the epoch (in case this was a partial prune) to extract the out hashes
135
- const priorCheckpointOutHashes = (await this.l2BlockSource.getCheckpointsForEpoch(epochNumber))
136
- .filter(c => c.number < sortedBlocks[0].checkpointNumber)
137
- .map(c => c.getCheckpointOutHash());
138
- let previousCheckpointOutHashes: Fr[] = [...priorCheckpointOutHashes];
139
-
140
- const fork = await this.checkpointsBuilder.getFork(
141
- BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1),
142
- );
129
+ let previousCheckpointOutHashes: Fr[] = [];
130
+ const fork = await this.checkpointsBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
143
131
  try {
144
- for (const checkpointBlocks of blocksByCheckpoint) {
145
- await this.validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork);
132
+ for (const block of blocks) {
133
+ await this.validateBlock(block, previousCheckpointOutHashes, fork);
146
134
 
147
- // Compute checkpoint out hash from all blocks in this checkpoint
148
- const checkpointOutHash = computeCheckpointOutHash(
149
- checkpointBlocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
150
- );
135
+ // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
136
+ const checkpointOutHash = computeCheckpointOutHash([block.body.txEffects.map(tx => tx.l2ToL1Msgs)]);
151
137
  previousCheckpointOutHashes = [...previousCheckpointOutHashes, checkpointOutHash];
152
138
  }
153
139
  } finally {
@@ -155,19 +141,25 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
155
141
  }
156
142
  }
157
143
 
158
- private async validateCheckpoint(
159
- checkpointBlocks: L2Block[],
144
+ public async validateBlock(
145
+ blockFromL1: L2Block,
160
146
  previousCheckpointOutHashes: Fr[],
161
147
  fork: MerkleTreeWriteOperations,
162
148
  ): Promise<void> {
163
- const checkpointNumber = checkpointBlocks[0].checkpointNumber;
164
- this.log.debug(`Validating pruned checkpoint ${checkpointNumber} with ${checkpointBlocks.length} blocks`);
149
+ this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
150
+ const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
151
+ // We load txs from the mempool directly, since the TxCollector running in the background has already been
152
+ // trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
153
+ // it's likely that they are not available in the network at all.
154
+ const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
165
155
 
166
- // Get L1ToL2Messages once for the entire checkpoint
167
- const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
156
+ if (missingTxs && missingTxs.length > 0) {
157
+ throw new TransactionsNotAvailableError(missingTxs);
158
+ }
168
159
 
169
- // Build checkpoint constants from first block's global variables
170
- const gv = checkpointBlocks[0].header.globalVariables;
160
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
161
+ const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
162
+ const gv = blockFromL1.header.globalVariables;
171
163
  const constants: CheckpointGlobalVariables = {
172
164
  chainId: gv.chainId,
173
165
  version: gv.version,
@@ -177,7 +169,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
177
169
  gasFees: gv.gasFees,
178
170
  };
179
171
 
180
- // Start checkpoint builder once for all blocks in this checkpoint
172
+ // Use checkpoint builder to validate the block
181
173
  const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(
182
174
  checkpointNumber,
183
175
  constants,
@@ -187,28 +179,6 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
187
179
  this.log.getBindings(),
188
180
  );
189
181
 
190
- // Validate all blocks in the checkpoint sequentially
191
- for (const block of checkpointBlocks) {
192
- await this.validateBlockInCheckpoint(block, checkpointBuilder);
193
- }
194
- }
195
-
196
- private async validateBlockInCheckpoint(
197
- blockFromL1: L2Block,
198
- checkpointBuilder: ICheckpointBlockBuilder,
199
- ): Promise<void> {
200
- this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
201
- const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
202
- // We load txs from the mempool directly, since the TxCollector running in the background has already been
203
- // trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
204
- // it's likely that they are not available in the network at all.
205
- const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
206
-
207
- if (missingTxs && missingTxs.length > 0) {
208
- throw new TransactionsNotAvailableError(missingTxs);
209
- }
210
-
211
- const gv = blockFromL1.header.globalVariables;
212
182
  const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {});
213
183
 
214
184
  if (numTxs !== txs.length) {