@aztec/epoch-cache 1.2.1 → 2.0.0-nightly.20250814

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.
@@ -13,8 +13,9 @@ export type EpochCommitteeInfo = {
13
13
  seed: bigint;
14
14
  epoch: bigint;
15
15
  };
16
+ export type SlotTag = 'now' | 'next' | bigint;
16
17
  export interface EpochCacheInterface {
17
- getCommittee(slot: 'now' | 'next' | bigint | undefined): Promise<EpochCommitteeInfo>;
18
+ getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
18
19
  getEpochAndSlotNow(): EpochAndSlot;
19
20
  getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
20
21
  now: bigint;
@@ -27,7 +28,9 @@ export interface EpochCacheInterface {
27
28
  currentSlot: bigint;
28
29
  nextSlot: bigint;
29
30
  }>;
30
- isInCommittee(validator: EthAddress): Promise<boolean>;
31
+ getRegisteredValidators(): Promise<EthAddress[]>;
32
+ isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
33
+ filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
31
34
  }
32
35
  /**
33
36
  * Epoch cache
@@ -44,9 +47,12 @@ export declare class EpochCache implements EpochCacheInterface {
44
47
  private readonly dateProvider;
45
48
  private readonly config;
46
49
  private cache;
50
+ private allValidators;
51
+ private lastValidatorRefresh;
47
52
  private readonly log;
48
53
  constructor(rollup: RollupContract, initialEpoch?: bigint, initialValidators?: EthAddress[] | undefined, initialSampleSeed?: bigint, l1constants?: L1RollupConstants, dateProvider?: DateProvider, config?: {
49
54
  cacheSize: number;
55
+ validatorRefreshIntervalSeconds: number;
50
56
  });
51
57
  static create(rollupAddress: EthAddress, config?: EpochCacheConfig, deps?: {
52
58
  dateProvider?: DateProvider;
@@ -67,7 +73,7 @@ export declare class EpochCache implements EpochCacheInterface {
67
73
  * @param nextSlot - If true, get the validator set for the next slot.
68
74
  * @returns The current validator set.
69
75
  */
70
- getCommittee(slot?: 'now' | 'next' | bigint): Promise<EpochCommitteeInfo>;
76
+ getCommittee(slot?: SlotTag): Promise<EpochCommitteeInfo>;
71
77
  private getEpochAndTimestamp;
72
78
  private computeCommittee;
73
79
  /**
@@ -100,10 +106,11 @@ export declare class EpochCache implements EpochCacheInterface {
100
106
  * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
101
107
  */
102
108
  private getProposerAttesterAddressAt;
103
- /**
104
- * Check if a validator is in the current epoch's committee
105
- */
106
- isInCommittee(validator: EthAddress): Promise<boolean>;
107
- filterInCommittee(validators: EthAddress[]): Promise<EthAddress[]>;
109
+ getProposerFromEpochCommittee(epochCommitteeInfo: EpochCommitteeInfo, slot: bigint): EthAddress | undefined;
110
+ /** Check if a validator is in the given slot's committee */
111
+ isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
112
+ /** From the set of given addresses, return all that are on the committee for the given slot */
113
+ filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
114
+ getRegisteredValidators(): Promise<EthAddress[]>;
108
115
  }
109
116
  //# sourceMappingURL=epoch_cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"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"}
@@ -19,15 +19,20 @@ import { getEpochCacheConfigEnvVars } from './config.js';
19
19
  dateProvider;
20
20
  config;
21
21
  cache;
22
+ allValidators;
23
+ lastValidatorRefresh;
22
24
  log;
23
25
  constructor(rollup, initialEpoch = 0n, initialValidators = undefined, initialSampleSeed = 0n, l1constants = EmptyL1RollupConstants, dateProvider = new DateProvider(), config = {
24
- cacheSize: 12
26
+ cacheSize: 12,
27
+ validatorRefreshIntervalSeconds: 60
25
28
  }){
26
29
  this.rollup = rollup;
27
30
  this.l1constants = l1constants;
28
31
  this.dateProvider = dateProvider;
29
32
  this.config = config;
30
33
  this.cache = new Map();
34
+ this.allValidators = new Set();
35
+ this.lastValidatorRefresh = 0;
31
36
  this.log = createLogger('epoch-cache');
32
37
  this.cache.set(initialEpoch, {
33
38
  epoch: initialEpoch,
@@ -222,21 +227,36 @@ import { getEpochCacheConfigEnvVars } from './config.js';
222
227
  const proposerIndex = this.computeProposerIndex(slot, epoch, seed, BigInt(committee.length));
223
228
  return committee[Number(proposerIndex)];
224
229
  }
225
- /**
226
- * Check if a validator is in the current epoch's committee
227
- */ async isInCommittee(validator) {
228
- const { committee } = await this.getCommittee();
230
+ getProposerFromEpochCommittee(epochCommitteeInfo, slot) {
231
+ if (!epochCommitteeInfo.committee || epochCommitteeInfo.committee.length === 0) {
232
+ return undefined;
233
+ }
234
+ const proposerIndex = this.computeProposerIndex(slot, epochCommitteeInfo.epoch, epochCommitteeInfo.seed, BigInt(epochCommitteeInfo.committee.length));
235
+ return epochCommitteeInfo.committee[Number(proposerIndex)];
236
+ }
237
+ /** Check if a validator is in the given slot's committee */ async isInCommittee(slot, validator) {
238
+ const { committee } = await this.getCommittee(slot);
229
239
  if (!committee) {
230
240
  return false;
231
241
  }
232
242
  return committee.some((v)=>v.equals(validator));
233
243
  }
234
- async filterInCommittee(validators) {
235
- const { committee } = await this.getCommittee();
244
+ /** From the set of given addresses, return all that are on the committee for the given slot */ async filterInCommittee(slot, validators) {
245
+ const { committee } = await this.getCommittee(slot);
236
246
  if (!committee) {
237
247
  return [];
238
248
  }
239
249
  const committeeSet = new Set(committee.map((v)=>v.toString()));
240
250
  return validators.filter((v)=>committeeSet.has(v.toString()));
241
251
  }
252
+ async getRegisteredValidators() {
253
+ const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
254
+ const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
255
+ if (validatorRefreshTime < this.dateProvider.now()) {
256
+ const currentSet = await this.rollup.getAttesters();
257
+ this.allValidators = new Set(currentSet);
258
+ this.lastValidatorRefresh = this.dateProvider.now();
259
+ }
260
+ return Array.from(this.allValidators.keys().map((v)=>EthAddress.fromString(v)));
261
+ }
242
262
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/epoch-cache",
3
- "version": "1.2.1",
3
+ "version": "2.0.0-nightly.20250814",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -26,10 +26,10 @@
26
26
  "../package.common.json"
27
27
  ],
28
28
  "dependencies": {
29
- "@aztec/ethereum": "1.2.1",
30
- "@aztec/foundation": "1.2.1",
31
- "@aztec/l1-artifacts": "1.2.1",
32
- "@aztec/stdlib": "1.2.1",
29
+ "@aztec/ethereum": "2.0.0-nightly.20250814",
30
+ "@aztec/foundation": "2.0.0-nightly.20250814",
31
+ "@aztec/l1-artifacts": "2.0.0-nightly.20250814",
32
+ "@aztec/stdlib": "2.0.0-nightly.20250814",
33
33
  "@viem/anvil": "^0.0.10",
34
34
  "dotenv": "^16.0.3",
35
35
  "get-port": "^7.1.0",
@@ -29,8 +29,10 @@ export type EpochCommitteeInfo = {
29
29
  epoch: bigint;
30
30
  };
31
31
 
32
+ export type SlotTag = 'now' | 'next' | bigint;
33
+
32
34
  export interface EpochCacheInterface {
33
- getCommittee(slot: 'now' | 'next' | bigint | undefined): Promise<EpochCommitteeInfo>;
35
+ getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
34
36
  getEpochAndSlotNow(): EpochAndSlot;
35
37
  getEpochAndSlotInNextL1Slot(): EpochAndSlot & { now: bigint };
36
38
  getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}`;
@@ -41,7 +43,9 @@ export interface EpochCacheInterface {
41
43
  currentSlot: bigint;
42
44
  nextSlot: bigint;
43
45
  }>;
44
- isInCommittee(validator: EthAddress): Promise<boolean>;
46
+ getRegisteredValidators(): Promise<EthAddress[]>;
47
+ isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
48
+ filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
45
49
  }
46
50
 
47
51
  /**
@@ -55,6 +59,8 @@ export interface EpochCacheInterface {
55
59
  */
56
60
  export class EpochCache implements EpochCacheInterface {
57
61
  private cache: Map<bigint, EpochCommitteeInfo> = new Map();
62
+ private allValidators: Set<string> = new Set();
63
+ private lastValidatorRefresh = 0;
58
64
  private readonly log: Logger = createLogger('epoch-cache');
59
65
 
60
66
  constructor(
@@ -64,7 +70,7 @@ export class EpochCache implements EpochCacheInterface {
64
70
  initialSampleSeed: bigint = 0n,
65
71
  private readonly l1constants: L1RollupConstants = EmptyL1RollupConstants,
66
72
  private readonly dateProvider: DateProvider = new DateProvider(),
67
- private readonly config = { cacheSize: 12 },
73
+ private readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60 },
68
74
  ) {
69
75
  this.cache.set(initialEpoch, { epoch: initialEpoch, committee: initialValidators, seed: initialSampleSeed });
70
76
  this.log.debug(`Initialized EpochCache with ${initialValidators?.length ?? 'no'} validators`, {
@@ -163,7 +169,7 @@ export class EpochCache implements EpochCacheInterface {
163
169
  * @param nextSlot - If true, get the validator set for the next slot.
164
170
  * @returns The current validator set.
165
171
  */
166
- public async getCommittee(slot: 'now' | 'next' | bigint = 'now'): Promise<EpochCommitteeInfo> {
172
+ public async getCommittee(slot: SlotTag = 'now'): Promise<EpochCommitteeInfo> {
167
173
  const { epoch, ts } = this.getEpochAndTimestamp(slot);
168
174
 
169
175
  if (this.cache.has(epoch)) {
@@ -185,7 +191,7 @@ export class EpochCache implements EpochCacheInterface {
185
191
  return epochData;
186
192
  }
187
193
 
188
- private getEpochAndTimestamp(slot: 'now' | 'next' | bigint = 'now') {
194
+ private getEpochAndTimestamp(slot: SlotTag = 'now') {
189
195
  if (slot === 'now') {
190
196
  return this.getEpochAndSlotNow();
191
197
  } else if (slot === 'next') {
@@ -216,7 +222,7 @@ export class EpochCache implements EpochCacheInterface {
216
222
  );
217
223
  }
218
224
 
219
- computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint {
225
+ public computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint {
220
226
  // if committe size is 0, then mod 1 is 0
221
227
  if (size === 0n) {
222
228
  return 0n;
@@ -277,23 +283,47 @@ export class EpochCache implements EpochCacheInterface {
277
283
  return committee[Number(proposerIndex)];
278
284
  }
279
285
 
280
- /**
281
- * Check if a validator is in the current epoch's committee
282
- */
283
- async isInCommittee(validator: EthAddress): Promise<boolean> {
284
- const { committee } = await this.getCommittee();
286
+ public getProposerFromEpochCommittee(epochCommitteeInfo: EpochCommitteeInfo, slot: bigint): EthAddress | undefined {
287
+ if (!epochCommitteeInfo.committee || epochCommitteeInfo.committee.length === 0) {
288
+ return undefined;
289
+ }
290
+ const proposerIndex = this.computeProposerIndex(
291
+ slot,
292
+ epochCommitteeInfo.epoch,
293
+ epochCommitteeInfo.seed,
294
+ BigInt(epochCommitteeInfo.committee.length),
295
+ );
296
+
297
+ return epochCommitteeInfo.committee[Number(proposerIndex)];
298
+ }
299
+
300
+ /** Check if a validator is in the given slot's committee */
301
+ async isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean> {
302
+ const { committee } = await this.getCommittee(slot);
285
303
  if (!committee) {
286
304
  return false;
287
305
  }
288
306
  return committee.some(v => v.equals(validator));
289
307
  }
290
308
 
291
- async filterInCommittee(validators: EthAddress[]): Promise<EthAddress[]> {
292
- const { committee } = await this.getCommittee();
309
+ /** From the set of given addresses, return all that are on the committee for the given slot */
310
+ async filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]> {
311
+ const { committee } = await this.getCommittee(slot);
293
312
  if (!committee) {
294
313
  return [];
295
314
  }
296
315
  const committeeSet = new Set(committee.map(v => v.toString()));
297
316
  return validators.filter(v => committeeSet.has(v.toString()));
298
317
  }
318
+
319
+ async getRegisteredValidators(): Promise<EthAddress[]> {
320
+ const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
321
+ const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
322
+ if (validatorRefreshTime < this.dateProvider.now()) {
323
+ const currentSet = await this.rollup.getAttesters();
324
+ this.allValidators = new Set(currentSet);
325
+ this.lastValidatorRefresh = this.dateProvider.now();
326
+ }
327
+ return Array.from(this.allValidators.keys().map(v => EthAddress.fromString(v)));
328
+ }
299
329
  }