@aztec/epoch-cache 4.0.0-nightly.20250907 → 4.0.0-nightly.20260107

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/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type L1ContractsConfig, type L1ReaderConfig } from '@aztec/ethereum';
2
- export type EpochCacheConfig = Pick<L1ReaderConfig & L1ContractsConfig, 'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'aztecSlotDuration' | 'ethereumSlotDuration' | 'aztecEpochDuration'>;
1
+ import { type L1ContractsConfig } from '@aztec/ethereum/config';
2
+ import { type L1ReaderConfig } from '@aztec/ethereum/l1-reader';
3
+ export type EpochCacheConfig = Pick<L1ReaderConfig & L1ContractsConfig, 'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'ethereumSlotDuration'>;
3
4
  export declare function getEpochCacheConfigEnvVars(): EpochCacheConfig;
4
- //# sourceMappingURL=config.d.ts.map
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLGlCQUFpQixFQUErQixNQUFNLHdCQUF3QixDQUFDO0FBQzdGLE9BQU8sRUFBRSxLQUFLLGNBQWMsRUFBNEIsTUFBTSwyQkFBMkIsQ0FBQztBQUUxRixNQUFNLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUNqQyxjQUFjLEdBQUcsaUJBQWlCLEVBQ2xDLFdBQVcsR0FBRyxXQUFXLEdBQUcsdUJBQXVCLEdBQUcsc0JBQXNCLENBQzdFLENBQUM7QUFFRix3QkFBZ0IsMEJBQTBCLElBQUksZ0JBQWdCLENBRTdEIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAGpB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,cAAc,GAAG,iBAAiB,EAChC,WAAW,GACX,WAAW,GACX,uBAAuB,GACvB,mBAAmB,GACnB,sBAAsB,GACtB,oBAAoB,CACvB,CAAC;AAEF,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAA+B,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EAAE,KAAK,cAAc,EAA4B,MAAM,2BAA2B,CAAC;AAE1F,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,cAAc,GAAG,iBAAiB,EAClC,WAAW,GAAG,WAAW,GAAG,uBAAuB,GAAG,sBAAsB,CAC7E,CAAC;AAEF,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D"}
package/dest/config.js CHANGED
@@ -1,4 +1,5 @@
1
- import { getL1ContractsConfigEnvVars, getL1ReaderConfigFromEnv } from '@aztec/ethereum';
1
+ import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
2
+ import { getL1ReaderConfigFromEnv } from '@aztec/ethereum/l1-reader';
2
3
  export function getEpochCacheConfigEnvVars() {
3
4
  return {
4
5
  ...getL1ReaderConfigFromEnv(),
@@ -1,32 +1,33 @@
1
- import { RollupContract } from '@aztec/ethereum';
1
+ import { RollupContract } from '@aztec/ethereum/contracts';
2
+ import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import { DateProvider } from '@aztec/foundation/timer';
4
5
  import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
5
6
  import { type EpochCacheConfig } from './config.js';
6
7
  export type EpochAndSlot = {
7
- epoch: bigint;
8
- slot: bigint;
8
+ epoch: EpochNumber;
9
+ slot: SlotNumber;
9
10
  ts: bigint;
10
11
  };
11
12
  export type EpochCommitteeInfo = {
12
13
  committee: EthAddress[] | undefined;
13
14
  seed: bigint;
14
- epoch: bigint;
15
+ epoch: EpochNumber;
15
16
  };
16
- export type SlotTag = 'now' | 'next' | bigint;
17
+ export type SlotTag = 'now' | 'next' | SlotNumber;
17
18
  export interface EpochCacheInterface {
18
19
  getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
19
20
  getEpochAndSlotNow(): EpochAndSlot;
20
21
  getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
21
22
  now: bigint;
22
23
  };
23
- getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}`;
24
- computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint;
24
+ getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
25
+ computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
25
26
  getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
26
27
  currentProposer: EthAddress | undefined;
27
28
  nextProposer: EthAddress | undefined;
28
- currentSlot: bigint;
29
- nextSlot: bigint;
29
+ currentSlot: SlotNumber;
30
+ nextSlot: SlotNumber;
30
31
  }>;
31
32
  getRegisteredValidators(): Promise<EthAddress[]>;
32
33
  isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
@@ -45,16 +46,22 @@ export declare class EpochCache implements EpochCacheInterface {
45
46
  private rollup;
46
47
  private readonly l1constants;
47
48
  private readonly dateProvider;
48
- private readonly config;
49
- private cache;
49
+ protected readonly config: {
50
+ cacheSize: number;
51
+ validatorRefreshIntervalSeconds: number;
52
+ };
53
+ protected cache: Map<EpochNumber, EpochCommitteeInfo>;
50
54
  private allValidators;
51
55
  private lastValidatorRefresh;
52
56
  private readonly log;
53
- constructor(rollup: RollupContract, initialEpoch?: bigint, initialValidators?: EthAddress[] | undefined, initialSampleSeed?: bigint, l1constants?: L1RollupConstants, dateProvider?: DateProvider, config?: {
57
+ constructor(rollup: RollupContract, l1constants: L1RollupConstants & {
58
+ lagInEpochsForValidatorSet: number;
59
+ lagInEpochsForRandao: number;
60
+ }, dateProvider?: DateProvider, config?: {
54
61
  cacheSize: number;
55
62
  validatorRefreshIntervalSeconds: number;
56
63
  });
57
- static create(rollupAddress: EthAddress, config?: EpochCacheConfig, deps?: {
64
+ static create(rollupOrAddress: EthAddress | RollupContract, config?: EpochCacheConfig, deps?: {
58
65
  dateProvider?: DateProvider;
59
66
  }): Promise<EpochCache>;
60
67
  getL1Constants(): L1RollupConstants;
@@ -67,7 +74,7 @@ export declare class EpochCache implements EpochCacheInterface {
67
74
  now: bigint;
68
75
  };
69
76
  private getEpochAndSlotAtTimestamp;
70
- getCommitteeForEpoch(epoch: bigint): Promise<EpochCommitteeInfo>;
77
+ getCommitteeForEpoch(epoch: EpochNumber): Promise<EpochCommitteeInfo>;
71
78
  /**
72
79
  * Get the current validator set
73
80
  * @param nextSlot - If true, get the validator set for the next slot.
@@ -79,8 +86,8 @@ export declare class EpochCache implements EpochCacheInterface {
79
86
  /**
80
87
  * Get the ABI encoding of the proposer index - see ValidatorSelectionLib.sol computeProposerIndex
81
88
  */
82
- getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}`;
83
- computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint;
89
+ getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
90
+ computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
84
91
  /**
85
92
  * Returns the current and next proposer's attester address
86
93
  *
@@ -88,29 +95,29 @@ export declare class EpochCache implements EpochCacheInterface {
88
95
  * which can be the next slot. If this is the case, then it will send proposals early.
89
96
  */
90
97
  getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
91
- currentSlot: bigint;
92
- nextSlot: bigint;
98
+ currentSlot: SlotNumber;
99
+ nextSlot: SlotNumber;
93
100
  currentProposer: EthAddress | undefined;
94
101
  nextProposer: EthAddress | undefined;
95
102
  }>;
96
103
  /**
97
- * Get the proposer attester address in the next slot
104
+ * Get the proposer attester address in the given L2 slot
98
105
  * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
99
106
  * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
100
107
  */
101
- getProposerAttesterAddressInNextSlot(): Promise<EthAddress | undefined>;
108
+ getProposerAttesterAddressInSlot(slot: SlotNumber): Promise<EthAddress | undefined>;
102
109
  /**
103
- * Get the proposer attester address at a given epoch and slot
104
- * @param when - The epoch and slot to get the proposer attester address at
110
+ * Get the proposer attester address in the next slot
105
111
  * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
106
112
  * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
107
113
  */
114
+ getProposerAttesterAddressInNextSlot(): Promise<EthAddress | undefined>;
108
115
  private getProposerAttesterAddressAt;
109
- getProposerFromEpochCommittee(epochCommitteeInfo: EpochCommitteeInfo, slot: bigint): EthAddress | undefined;
116
+ getProposerFromEpochCommittee(epochCommitteeInfo: EpochCommitteeInfo, slot: SlotNumber): EthAddress | undefined;
110
117
  /** Check if a validator is in the given slot's committee */
111
118
  isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
112
119
  /** From the set of given addresses, return all that are on the committee for the given slot */
113
120
  filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
114
121
  getRegisteredValidators(): Promise<EthAddress[]>;
115
122
  }
116
- //# sourceMappingURL=epoch_cache.d.ts.map
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfY2FjaGUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9lcG9jaF9jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQW9CLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDMUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQ0wsS0FBSyxpQkFBaUIsRUFPdkIsTUFBTSw2QkFBNkIsQ0FBQztBQUlyQyxPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBOEIsTUFBTSxhQUFhLENBQUM7QUFFaEYsTUFBTSxNQUFNLFlBQVksR0FBRztJQUN6QixLQUFLLEVBQUUsV0FBVyxDQUFDO0lBQ25CLElBQUksRUFBRSxVQUFVLENBQUM7SUFDakIsRUFBRSxFQUFFLE1BQU0sQ0FBQztDQUNaLENBQUM7QUFFRixNQUFNLE1BQU0sa0JBQWtCLEdBQUc7SUFDL0IsU0FBUyxFQUFFLFVBQVUsRUFBRSxHQUFHLFNBQVMsQ0FBQztJQUNwQyxJQUFJLEVBQUUsTUFBTSxDQUFDO0lBQ2IsS0FBSyxFQUFFLFdBQVcsQ0FBQztDQUNwQixDQUFDO0FBRUYsTUFBTSxNQUFNLE9BQU8sR0FBRyxLQUFLLEdBQUcsTUFBTSxHQUFHLFVBQVUsQ0FBQztBQUVsRCxNQUFNLFdBQVcsbUJBQW1CO0lBQ2xDLFlBQVksQ0FBQyxJQUFJLEVBQUUsT0FBTyxHQUFHLFNBQVMsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNyRSxrQkFBa0IsSUFBSSxZQUFZLENBQUM7SUFDbkMsMkJBQTJCLElBQUksWUFBWSxHQUFHO1FBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQTtLQUFFLENBQUM7SUFDOUQsd0JBQXdCLENBQUMs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
@@ -1 +1 @@
1
- {"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,cAAc,EAAuB,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAEL,KAAK,iBAAiB,EAOvB,MAAM,6BAA6B,CAAC;AAIrC,OAAO,EAAE,KAAK,gBAAgB,EAA8B,MAAM,aAAa,CAAC;AAEhF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,kBAAkB,IAAI,YAAY,CAAC;IACnC,2BAA2B,IAAI,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAAC;IACnF,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtF,6CAA6C,IAAI,OAAO,CAAC;QACvD,eAAe,EAAE,UAAU,GAAG,SAAS,CAAC;QACxC,YAAY,EAAE,UAAU,GAAG,SAAS,CAAC;QACrC,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,uBAAuB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACjD,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CACnF;AAED;;;;;;;;GAQG;AACH,qBAAa,UAAW,YAAW,mBAAmB;IAOlD,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZzB,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuC;gBAGjD,MAAM,EAAE,cAAc,EAC9B,YAAY,GAAE,MAAW,EACzB,iBAAiB,GAAE,UAAU,EAAE,GAAG,SAAqB,EACvD,iBAAiB,GAAE,MAAW,EACb,WAAW,GAAE,iBAA0C,EACvD,YAAY,GAAE,YAAiC,EAC/C,MAAM;;;KAAyD;WAWrE,MAAM,CACjB,aAAa,EAAE,UAAU,EACzB,MAAM,CAAC,EAAE,gBAAgB,EACzB,IAAI,GAAE;QAAE,YAAY,CAAC,EAAE,YAAY,CAAA;KAAO;IAyCrC,cAAc,IAAI,iBAAiB;IAInC,kBAAkB,IAAI,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE;IAKpD,YAAY,IAAI,MAAM;IAI7B,OAAO,CAAC,qBAAqB;IAMtB,2BAA2B,IAAI,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE;IAMpE,OAAO,CAAC,0BAA0B;IAS3B,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKvE;;;;OAIG;IACU,YAAY,CAAC,IAAI,GAAE,OAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAsB7E,OAAO,CAAC,oBAAoB;YAUd,gBAAgB;IAO9B;;OAEG;IACH,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE;IAW3E,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAQ5F;;;;;OAKG;IACG,6CAA6C,IAAI,OAAO,CAAC;QAC7D,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,UAAU,GAAG,SAAS,CAAC;QACxC,YAAY,EAAE,UAAU,GAAG,SAAS,CAAC;KACtC,CAAC;IAYF;;;;OAIG;IACH,oCAAoC,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAMvE;;;;;OAKG;YACW,4BAA4B;IAanC,6BAA6B,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAclH,4DAA4D;IACtD,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ3E,+FAA+F;IACzF,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IASjF,uBAAuB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;CAUvD"}
1
+ {"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import { NoCommitteeError, RollupContract, createEthereumChain } from '@aztec/ethereum';
1
+ import { createEthereumChain } from '@aztec/ethereum/chain';
2
+ import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import { DateProvider } from '@aztec/foundation/timer';
5
- import { EmptyL1RollupConstants, getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampForSlot, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
6
+ import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampForSlot, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
6
7
  import { createPublicClient, encodeAbiParameters, fallback, http, keccak256 } from 'viem';
7
8
  import { getEpochCacheConfigEnvVars } from './config.js';
8
9
  /**
@@ -18,11 +19,12 @@ import { getEpochCacheConfigEnvVars } from './config.js';
18
19
  l1constants;
19
20
  dateProvider;
20
21
  config;
22
+ // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
21
23
  cache;
22
24
  allValidators;
23
25
  lastValidatorRefresh;
24
26
  log;
25
- constructor(rollup, initialEpoch = 0n, initialValidators = undefined, initialSampleSeed = 0n, l1constants = EmptyL1RollupConstants, dateProvider = new DateProvider(), config = {
27
+ constructor(rollup, l1constants, dateProvider = new DateProvider(), config = {
26
28
  cacheSize: 12,
27
29
  validatorRefreshIntervalSeconds: 60
28
30
  }){
@@ -34,44 +36,47 @@ import { getEpochCacheConfigEnvVars } from './config.js';
34
36
  this.allValidators = new Set();
35
37
  this.lastValidatorRefresh = 0;
36
38
  this.log = createLogger('epoch-cache');
37
- this.cache.set(initialEpoch, {
38
- epoch: initialEpoch,
39
- committee: initialValidators,
40
- seed: initialSampleSeed
41
- });
42
- this.log.debug(`Initialized EpochCache with ${initialValidators?.length ?? 'no'} validators`, {
43
- l1constants,
44
- initialValidators,
45
- initialSampleSeed,
46
- initialEpoch
39
+ this.log.debug(`Initialized EpochCache`, {
40
+ l1constants
47
41
  });
48
42
  }
49
- static async create(rollupAddress, config, deps = {}) {
43
+ static async create(rollupOrAddress, config, deps = {}) {
50
44
  config = config ?? getEpochCacheConfigEnvVars();
51
- const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
52
- const publicClient = createPublicClient({
53
- chain: chain.chainInfo,
54
- transport: fallback(config.l1RpcUrls.map((url)=>http(url))),
55
- pollingInterval: config.viemPollingIntervalMS
56
- });
57
- const rollup = new RollupContract(publicClient, rollupAddress.toString());
58
- const [l1StartBlock, l1GenesisTime, initialValidators, sampleSeed, epochNumber, proofSubmissionEpochs] = await Promise.all([
45
+ // Load the rollup contract if we were given an address
46
+ let rollup;
47
+ if ('address' in rollupOrAddress) {
48
+ rollup = rollupOrAddress;
49
+ } else {
50
+ const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
51
+ const publicClient = createPublicClient({
52
+ chain: chain.chainInfo,
53
+ transport: fallback(config.l1RpcUrls.map((url)=>http(url, {
54
+ batch: false
55
+ }))),
56
+ pollingInterval: config.viemPollingIntervalMS
57
+ });
58
+ rollup = new RollupContract(publicClient, rollupOrAddress.toString());
59
+ }
60
+ const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, slotDuration, epochDuration, lagInEpochsForValidatorSet, lagInEpochsForRandao] = await Promise.all([
59
61
  rollup.getL1StartBlock(),
60
62
  rollup.getL1GenesisTime(),
61
- rollup.getCurrentEpochCommittee(),
62
- rollup.getCurrentSampleSeed(),
63
- rollup.getEpochNumber(),
64
- rollup.getProofSubmissionEpochs()
63
+ rollup.getProofSubmissionEpochs(),
64
+ rollup.getSlotDuration(),
65
+ rollup.getEpochDuration(),
66
+ rollup.getLagInEpochsForValidatorSet(),
67
+ rollup.getLagInEpochsForRandao()
65
68
  ]);
66
69
  const l1RollupConstants = {
67
70
  l1StartBlock,
68
71
  l1GenesisTime,
69
72
  proofSubmissionEpochs: Number(proofSubmissionEpochs),
70
- slotDuration: config.aztecSlotDuration,
71
- epochDuration: config.aztecEpochDuration,
72
- ethereumSlotDuration: config.ethereumSlotDuration
73
+ slotDuration: Number(slotDuration),
74
+ epochDuration: Number(epochDuration),
75
+ ethereumSlotDuration: config.ethereumSlotDuration,
76
+ lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
77
+ lagInEpochsForRandao: Number(lagInEpochsForRandao)
73
78
  };
74
- return new EpochCache(rollup, epochNumber, initialValidators?.map((v)=>EthAddress.fromString(v)), sampleSeed, l1RollupConstants, deps.dateProvider);
79
+ return new EpochCache(rollup, l1RollupConstants, deps.dateProvider);
75
80
  }
76
81
  getL1Constants() {
77
82
  return this.l1constants;
@@ -148,14 +153,21 @@ import { getEpochCacheConfigEnvVars } from './config.js';
148
153
  }
149
154
  async computeCommittee(when) {
150
155
  const { ts, epoch } = when;
151
- const [committeeHex, seed] = await Promise.all([
156
+ const [committee, seedBuffer, l1Timestamp] = await Promise.all([
152
157
  this.rollup.getCommitteeAt(ts),
153
- this.rollup.getSampleSeedAt(ts)
158
+ this.rollup.getSampleSeedAt(ts),
159
+ this.rollup.client.getBlock({
160
+ includeTransactions: false
161
+ }).then((b)=>b.timestamp)
154
162
  ]);
155
- const committee = committeeHex?.map((v)=>EthAddress.fromString(v));
163
+ const { lagInEpochsForValidatorSet, epochDuration, slotDuration } = this.l1constants;
164
+ const sub = BigInt(lagInEpochsForValidatorSet) * BigInt(epochDuration) * BigInt(slotDuration);
165
+ if (ts - sub > l1Timestamp) {
166
+ throw new Error(`Cannot query committee for future epoch ${epoch} with timestamp ${ts} (current L1 time is ${l1Timestamp}). Check your Ethereum node is synced.`);
167
+ }
156
168
  return {
157
169
  committee,
158
- seed,
170
+ seed: seedBuffer.toBigInt(),
159
171
  epoch
160
172
  };
161
173
  }
@@ -176,8 +188,8 @@ import { getEpochCacheConfigEnvVars } from './config.js';
176
188
  name: 'seed'
177
189
  }
178
190
  ], [
179
- epoch,
180
- slot,
191
+ BigInt(epoch),
192
+ BigInt(slot),
181
193
  seed
182
194
  ]);
183
195
  }
@@ -204,6 +216,14 @@ import { getEpochCacheConfigEnvVars } from './config.js';
204
216
  };
205
217
  }
206
218
  /**
219
+ * Get the proposer attester address in the given L2 slot
220
+ * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
221
+ * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
222
+ */ getProposerAttesterAddressInSlot(slot) {
223
+ const epochAndSlot = this.getEpochAndSlotAtSlot(slot);
224
+ return this.getProposerAttesterAddressAt(epochAndSlot);
225
+ }
226
+ /**
207
227
  * Get the proposer attester address in the next slot
208
228
  * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
209
229
  * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
@@ -254,9 +274,9 @@ import { getEpochCacheConfigEnvVars } from './config.js';
254
274
  const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
255
275
  if (validatorRefreshTime < this.dateProvider.now()) {
256
276
  const currentSet = await this.rollup.getAttesters();
257
- this.allValidators = new Set(currentSet);
277
+ this.allValidators = new Set(currentSet.map((v)=>v.toString()));
258
278
  this.lastValidatorRefresh = this.dateProvider.now();
259
279
  }
260
- return Array.from(this.allValidators.keys().map((v)=>EthAddress.fromString(v)));
280
+ return Array.from(this.allValidators.keys()).map((v)=>EthAddress.fromString(v));
261
281
  }
262
282
  }
package/dest/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './epoch_cache.js';
2
2
  export * from './config.js';
3
- //# sourceMappingURL=index.d.ts.map
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsYUFBYSxDQUFDIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/epoch-cache",
3
- "version": "4.0.0-nightly.20250907",
3
+ "version": "4.0.0-nightly.20260107",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -15,10 +15,10 @@
15
15
  "tsconfig": "./tsconfig.json"
16
16
  },
17
17
  "scripts": {
18
- "build": "yarn clean && tsc -b",
19
- "build:dev": "tsc -b --watch",
18
+ "build": "yarn clean && ../scripts/tsc.sh",
19
+ "build:dev": "../scripts/tsc.sh --watch",
20
20
  "clean": "rm -rf ./dest .tsbuildinfo",
21
- "start:dev": "tsc-watch -p tsconfig.json --onSuccess 'yarn start'",
21
+ "start:dev": "concurrently -k \"tsgo -b -w\" \"nodemon --watch dest --exec yarn start\"",
22
22
  "start": "node ./dest/index.js",
23
23
  "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
24
24
  },
@@ -26,22 +26,23 @@
26
26
  "../package.common.json"
27
27
  ],
28
28
  "dependencies": {
29
- "@aztec/ethereum": "4.0.0-nightly.20250907",
30
- "@aztec/foundation": "4.0.0-nightly.20250907",
31
- "@aztec/l1-artifacts": "4.0.0-nightly.20250907",
32
- "@aztec/stdlib": "4.0.0-nightly.20250907",
29
+ "@aztec/ethereum": "4.0.0-nightly.20260107",
30
+ "@aztec/foundation": "4.0.0-nightly.20260107",
31
+ "@aztec/l1-artifacts": "4.0.0-nightly.20260107",
32
+ "@aztec/stdlib": "4.0.0-nightly.20260107",
33
33
  "@viem/anvil": "^0.0.10",
34
34
  "dotenv": "^16.0.3",
35
35
  "get-port": "^7.1.0",
36
36
  "jest-mock-extended": "^4.0.0",
37
37
  "tslib": "^2.4.0",
38
- "viem": "2.23.7",
38
+ "viem": "npm:@aztec/viem@2.38.2",
39
39
  "zod": "^3.23.8"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@jest/globals": "^30.0.0",
43
43
  "@types/jest": "^30.0.0",
44
44
  "@types/node": "^22.15.17",
45
+ "@typescript/native-preview": "7.0.0-dev.20251126.1",
45
46
  "jest": "^30.0.0",
46
47
  "ts-node": "^10.9.1",
47
48
  "typescript": "^5.3.3"
package/src/config.ts CHANGED
@@ -1,18 +1,9 @@
1
- import {
2
- type L1ContractsConfig,
3
- type L1ReaderConfig,
4
- getL1ContractsConfigEnvVars,
5
- getL1ReaderConfigFromEnv,
6
- } from '@aztec/ethereum';
1
+ import { type L1ContractsConfig, getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
2
+ import { type L1ReaderConfig, getL1ReaderConfigFromEnv } from '@aztec/ethereum/l1-reader';
7
3
 
8
4
  export type EpochCacheConfig = Pick<
9
5
  L1ReaderConfig & L1ContractsConfig,
10
- | 'l1RpcUrls'
11
- | 'l1ChainId'
12
- | 'viemPollingIntervalMS'
13
- | 'aztecSlotDuration'
14
- | 'ethereumSlotDuration'
15
- | 'aztecEpochDuration'
6
+ 'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'ethereumSlotDuration'
16
7
  >;
17
8
 
18
9
  export function getEpochCacheConfigEnvVars(): EpochCacheConfig {
@@ -1,9 +1,10 @@
1
- import { NoCommitteeError, RollupContract, createEthereumChain } from '@aztec/ethereum';
1
+ import { createEthereumChain } from '@aztec/ethereum/chain';
2
+ import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts';
3
+ import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
4
  import { EthAddress } from '@aztec/foundation/eth-address';
3
5
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
6
  import { DateProvider } from '@aztec/foundation/timer';
5
7
  import {
6
- EmptyL1RollupConstants,
7
8
  type L1RollupConstants,
8
9
  getEpochAtSlot,
9
10
  getEpochNumberAtTimestamp,
@@ -18,30 +19,30 @@ import { createPublicClient, encodeAbiParameters, fallback, http, keccak256 } fr
18
19
  import { type EpochCacheConfig, getEpochCacheConfigEnvVars } from './config.js';
19
20
 
20
21
  export type EpochAndSlot = {
21
- epoch: bigint;
22
- slot: bigint;
22
+ epoch: EpochNumber;
23
+ slot: SlotNumber;
23
24
  ts: bigint;
24
25
  };
25
26
 
26
27
  export type EpochCommitteeInfo = {
27
28
  committee: EthAddress[] | undefined;
28
29
  seed: bigint;
29
- epoch: bigint;
30
+ epoch: EpochNumber;
30
31
  };
31
32
 
32
- export type SlotTag = 'now' | 'next' | bigint;
33
+ export type SlotTag = 'now' | 'next' | SlotNumber;
33
34
 
34
35
  export interface EpochCacheInterface {
35
36
  getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
36
37
  getEpochAndSlotNow(): EpochAndSlot;
37
38
  getEpochAndSlotInNextL1Slot(): EpochAndSlot & { now: bigint };
38
- getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}`;
39
- computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint;
39
+ getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
40
+ computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
40
41
  getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
41
42
  currentProposer: EthAddress | undefined;
42
43
  nextProposer: EthAddress | undefined;
43
- currentSlot: bigint;
44
- nextSlot: bigint;
44
+ currentSlot: SlotNumber;
45
+ nextSlot: SlotNumber;
45
46
  }>;
46
47
  getRegisteredValidators(): Promise<EthAddress[]>;
47
48
  isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
@@ -58,71 +59,77 @@ export interface EpochCacheInterface {
58
59
  * Note: This class is very dependent on the system clock being in sync.
59
60
  */
60
61
  export class EpochCache implements EpochCacheInterface {
61
- private cache: Map<bigint, EpochCommitteeInfo> = new Map();
62
+ // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
63
+ protected cache: Map<EpochNumber, EpochCommitteeInfo> = new Map();
62
64
  private allValidators: Set<string> = new Set();
63
65
  private lastValidatorRefresh = 0;
64
66
  private readonly log: Logger = createLogger('epoch-cache');
65
67
 
66
68
  constructor(
67
69
  private rollup: RollupContract,
68
- initialEpoch: bigint = 0n,
69
- initialValidators: EthAddress[] | undefined = undefined,
70
- initialSampleSeed: bigint = 0n,
71
- private readonly l1constants: L1RollupConstants = EmptyL1RollupConstants,
70
+ private readonly l1constants: L1RollupConstants & {
71
+ lagInEpochsForValidatorSet: number;
72
+ lagInEpochsForRandao: number;
73
+ },
72
74
  private readonly dateProvider: DateProvider = new DateProvider(),
73
- private readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60 },
75
+ protected readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60 },
74
76
  ) {
75
- this.cache.set(initialEpoch, { epoch: initialEpoch, committee: initialValidators, seed: initialSampleSeed });
76
- this.log.debug(`Initialized EpochCache with ${initialValidators?.length ?? 'no'} validators`, {
77
+ this.log.debug(`Initialized EpochCache`, {
77
78
  l1constants,
78
- initialValidators,
79
- initialSampleSeed,
80
- initialEpoch,
81
79
  });
82
80
  }
83
81
 
84
82
  static async create(
85
- rollupAddress: EthAddress,
83
+ rollupOrAddress: EthAddress | RollupContract,
86
84
  config?: EpochCacheConfig,
87
85
  deps: { dateProvider?: DateProvider } = {},
88
86
  ) {
89
87
  config = config ?? getEpochCacheConfigEnvVars();
90
88
 
91
- const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
92
- const publicClient = createPublicClient({
93
- chain: chain.chainInfo,
94
- transport: fallback(config.l1RpcUrls.map(url => http(url))),
95
- pollingInterval: config.viemPollingIntervalMS,
96
- });
89
+ // Load the rollup contract if we were given an address
90
+ let rollup: RollupContract;
91
+ if ('address' in rollupOrAddress) {
92
+ rollup = rollupOrAddress;
93
+ } else {
94
+ const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
95
+ const publicClient = createPublicClient({
96
+ chain: chain.chainInfo,
97
+ transport: fallback(config.l1RpcUrls.map(url => http(url, { batch: false }))),
98
+ pollingInterval: config.viemPollingIntervalMS,
99
+ });
100
+ rollup = new RollupContract(publicClient, rollupOrAddress.toString());
101
+ }
97
102
 
98
- const rollup = new RollupContract(publicClient, rollupAddress.toString());
99
- const [l1StartBlock, l1GenesisTime, initialValidators, sampleSeed, epochNumber, proofSubmissionEpochs] =
100
- await Promise.all([
101
- rollup.getL1StartBlock(),
102
- rollup.getL1GenesisTime(),
103
- rollup.getCurrentEpochCommittee(),
104
- rollup.getCurrentSampleSeed(),
105
- rollup.getEpochNumber(),
106
- rollup.getProofSubmissionEpochs(),
107
- ] as const);
108
-
109
- const l1RollupConstants: L1RollupConstants = {
103
+ const [
104
+ l1StartBlock,
105
+ l1GenesisTime,
106
+ proofSubmissionEpochs,
107
+ slotDuration,
108
+ epochDuration,
109
+ lagInEpochsForValidatorSet,
110
+ lagInEpochsForRandao,
111
+ ] = await Promise.all([
112
+ rollup.getL1StartBlock(),
113
+ rollup.getL1GenesisTime(),
114
+ rollup.getProofSubmissionEpochs(),
115
+ rollup.getSlotDuration(),
116
+ rollup.getEpochDuration(),
117
+ rollup.getLagInEpochsForValidatorSet(),
118
+ rollup.getLagInEpochsForRandao(),
119
+ ] as const);
120
+
121
+ const l1RollupConstants = {
110
122
  l1StartBlock,
111
123
  l1GenesisTime,
112
124
  proofSubmissionEpochs: Number(proofSubmissionEpochs),
113
- slotDuration: config.aztecSlotDuration,
114
- epochDuration: config.aztecEpochDuration,
125
+ slotDuration: Number(slotDuration),
126
+ epochDuration: Number(epochDuration),
115
127
  ethereumSlotDuration: config.ethereumSlotDuration,
128
+ lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
129
+ lagInEpochsForRandao: Number(lagInEpochsForRandao),
116
130
  };
117
131
 
118
- return new EpochCache(
119
- rollup,
120
- epochNumber,
121
- initialValidators?.map(v => EthAddress.fromString(v)),
122
- sampleSeed,
123
- l1RollupConstants,
124
- deps.dateProvider,
125
- );
132
+ return new EpochCache(rollup, l1RollupConstants, deps.dateProvider);
126
133
  }
127
134
 
128
135
  public getL1Constants(): L1RollupConstants {
@@ -138,7 +145,7 @@ export class EpochCache implements EpochCacheInterface {
138
145
  return BigInt(Math.floor(this.dateProvider.now() / 1000));
139
146
  }
140
147
 
141
- private getEpochAndSlotAtSlot(slot: bigint): EpochAndSlot {
148
+ private getEpochAndSlotAtSlot(slot: SlotNumber): EpochAndSlot {
142
149
  const epoch = getEpochAtSlot(slot, this.l1constants);
143
150
  const ts = getTimestampRangeForEpoch(epoch, this.l1constants)[0];
144
151
  return { epoch, ts, slot };
@@ -159,7 +166,7 @@ export class EpochCache implements EpochCacheInterface {
159
166
  };
160
167
  }
161
168
 
162
- public getCommitteeForEpoch(epoch: bigint): Promise<EpochCommitteeInfo> {
169
+ public getCommitteeForEpoch(epoch: EpochNumber): Promise<EpochCommitteeInfo> {
163
170
  const [startSlot] = getSlotRangeForEpoch(epoch, this.l1constants);
164
171
  return this.getCommittee(startSlot);
165
172
  }
@@ -201,28 +208,38 @@ export class EpochCache implements EpochCacheInterface {
201
208
  }
202
209
  }
203
210
 
204
- private async computeCommittee(when: { epoch: bigint; ts: bigint }): Promise<EpochCommitteeInfo> {
211
+ private async computeCommittee(when: { epoch: EpochNumber; ts: bigint }): Promise<EpochCommitteeInfo> {
205
212
  const { ts, epoch } = when;
206
- const [committeeHex, seed] = await Promise.all([this.rollup.getCommitteeAt(ts), this.rollup.getSampleSeedAt(ts)]);
207
- const committee = committeeHex?.map((v: `0x${string}`) => EthAddress.fromString(v));
208
- return { committee, seed, epoch };
213
+ const [committee, seedBuffer, l1Timestamp] = await Promise.all([
214
+ this.rollup.getCommitteeAt(ts),
215
+ this.rollup.getSampleSeedAt(ts),
216
+ this.rollup.client.getBlock({ includeTransactions: false }).then(b => b.timestamp),
217
+ ]);
218
+ const { lagInEpochsForValidatorSet, epochDuration, slotDuration } = this.l1constants;
219
+ const sub = BigInt(lagInEpochsForValidatorSet) * BigInt(epochDuration) * BigInt(slotDuration);
220
+ if (ts - sub > l1Timestamp) {
221
+ throw new Error(
222
+ `Cannot query committee for future epoch ${epoch} with timestamp ${ts} (current L1 time is ${l1Timestamp}). Check your Ethereum node is synced.`,
223
+ );
224
+ }
225
+ return { committee, seed: seedBuffer.toBigInt(), epoch };
209
226
  }
210
227
 
211
228
  /**
212
229
  * Get the ABI encoding of the proposer index - see ValidatorSelectionLib.sol computeProposerIndex
213
230
  */
214
- getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}` {
231
+ getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}` {
215
232
  return encodeAbiParameters(
216
233
  [
217
234
  { type: 'uint256', name: 'epoch' },
218
235
  { type: 'uint256', name: 'slot' },
219
236
  { type: 'uint256', name: 'seed' },
220
237
  ],
221
- [epoch, slot, seed],
238
+ [BigInt(epoch), BigInt(slot), seed],
222
239
  );
223
240
  }
224
241
 
225
- public computeProposerIndex(slot: bigint, epoch: bigint, seed: bigint, size: bigint): bigint {
242
+ public computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint {
226
243
  // if committe size is 0, then mod 1 is 0
227
244
  if (size === 0n) {
228
245
  return 0n;
@@ -236,9 +253,9 @@ export class EpochCache implements EpochCacheInterface {
236
253
  * We return the next proposer's attester address as the node will check if it is the proposer at the next ethereum block,
237
254
  * which can be the next slot. If this is the case, then it will send proposals early.
238
255
  */
239
- async getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
240
- currentSlot: bigint;
241
- nextSlot: bigint;
256
+ public async getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
257
+ currentSlot: SlotNumber;
258
+ nextSlot: SlotNumber;
242
259
  currentProposer: EthAddress | undefined;
243
260
  nextProposer: EthAddress | undefined;
244
261
  }> {
@@ -253,14 +270,23 @@ export class EpochCache implements EpochCacheInterface {
253
270
  };
254
271
  }
255
272
 
273
+ /**
274
+ * Get the proposer attester address in the given L2 slot
275
+ * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
276
+ * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
277
+ */
278
+ public getProposerAttesterAddressInSlot(slot: SlotNumber): Promise<EthAddress | undefined> {
279
+ const epochAndSlot = this.getEpochAndSlotAtSlot(slot);
280
+ return this.getProposerAttesterAddressAt(epochAndSlot);
281
+ }
282
+
256
283
  /**
257
284
  * Get the proposer attester address in the next slot
258
285
  * @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
259
286
  * If the committee is empty (i.e. target committee size is 0, and anyone can propose), we return undefined.
260
287
  */
261
- getProposerAttesterAddressInNextSlot(): Promise<EthAddress | undefined> {
288
+ public getProposerAttesterAddressInNextSlot(): Promise<EthAddress | undefined> {
262
289
  const epochAndSlot = this.getEpochAndSlotInNextL1Slot();
263
-
264
290
  return this.getProposerAttesterAddressAt(epochAndSlot);
265
291
  }
266
292
 
@@ -283,7 +309,10 @@ export class EpochCache implements EpochCacheInterface {
283
309
  return committee[Number(proposerIndex)];
284
310
  }
285
311
 
286
- public getProposerFromEpochCommittee(epochCommitteeInfo: EpochCommitteeInfo, slot: bigint): EthAddress | undefined {
312
+ public getProposerFromEpochCommittee(
313
+ epochCommitteeInfo: EpochCommitteeInfo,
314
+ slot: SlotNumber,
315
+ ): EthAddress | undefined {
287
316
  if (!epochCommitteeInfo.committee || epochCommitteeInfo.committee.length === 0) {
288
317
  return undefined;
289
318
  }
@@ -321,9 +350,9 @@ export class EpochCache implements EpochCacheInterface {
321
350
  const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
322
351
  if (validatorRefreshTime < this.dateProvider.now()) {
323
352
  const currentSet = await this.rollup.getAttesters();
324
- this.allValidators = new Set(currentSet);
353
+ this.allValidators = new Set(currentSet.map(v => v.toString()));
325
354
  this.lastValidatorRefresh = this.dateProvider.now();
326
355
  }
327
- return Array.from(this.allValidators.keys().map(v => EthAddress.fromString(v)));
356
+ return Array.from(this.allValidators.keys()).map(v => EthAddress.fromString(v));
328
357
  }
329
358
  }