@aztec/epoch-cache 0.0.1-commit.d431d1c → 0.0.1-commit.d939eb5aa

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.
@@ -0,0 +1,198 @@
1
+ import { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
3
+ import { PROPOSER_PIPELINING_SLOT_OFFSET } from '../epoch_cache.js';
4
+ /** Default L1 constants for testing. */ const DEFAULT_L1_CONSTANTS = {
5
+ l1StartBlock: 0n,
6
+ l1GenesisTime: 0n,
7
+ slotDuration: 24,
8
+ epochDuration: 16,
9
+ ethereumSlotDuration: 12,
10
+ proofSubmissionEpochs: 2,
11
+ targetCommitteeSize: 48,
12
+ rollupManaLimit: Number.MAX_SAFE_INTEGER
13
+ };
14
+ /**
15
+ * A test implementation of EpochCacheInterface that allows manual configuration
16
+ * of committee, proposer, slot, and escape hatch state for use in tests.
17
+ *
18
+ * Unlike the real EpochCache, this class doesn't require any RPC connections
19
+ * or mock setup. Simply use the setter methods to configure the test state.
20
+ */ export class TestEpochCache {
21
+ committee = [];
22
+ proposerAddress;
23
+ currentSlot = SlotNumber(0);
24
+ escapeHatchOpen = false;
25
+ seed = 0n;
26
+ registeredValidators = [];
27
+ l1Constants;
28
+ proposerPipeliningEnabled = false;
29
+ constructor(l1Constants = {}){
30
+ this.l1Constants = {
31
+ ...DEFAULT_L1_CONSTANTS,
32
+ ...l1Constants
33
+ };
34
+ }
35
+ /**
36
+ * Sets the committee members. Used in validation and attestation flows.
37
+ * @param committee - Array of committee member addresses.
38
+ */ setCommittee(committee) {
39
+ this.committee = committee;
40
+ return this;
41
+ }
42
+ /**
43
+ * Sets the proposer address returned by getProposerAttesterAddressInSlot.
44
+ * @param proposer - The address of the current proposer.
45
+ */ setProposer(proposer) {
46
+ this.proposerAddress = proposer;
47
+ return this;
48
+ }
49
+ /**
50
+ * Sets the current slot number.
51
+ * @param slot - The slot number to set.
52
+ */ setCurrentSlot(slot) {
53
+ this.currentSlot = slot;
54
+ return this;
55
+ }
56
+ /**
57
+ * Sets whether the escape hatch is open.
58
+ * @param open - True if escape hatch should be open.
59
+ */ setEscapeHatchOpen(open) {
60
+ this.escapeHatchOpen = open;
61
+ return this;
62
+ }
63
+ /**
64
+ * Sets the randomness seed used for proposer selection.
65
+ * @param seed - The seed value.
66
+ */ setSeed(seed) {
67
+ this.seed = seed;
68
+ return this;
69
+ }
70
+ /**
71
+ * Sets the list of registered validators (all validators, not just committee).
72
+ * @param validators - Array of validator addresses.
73
+ */ setRegisteredValidators(validators) {
74
+ this.registeredValidators = validators;
75
+ return this;
76
+ }
77
+ /**
78
+ * Sets the L1 constants used for epoch/slot calculations.
79
+ * @param constants - Partial constants to override defaults.
80
+ */ setL1Constants(constants) {
81
+ this.l1Constants = {
82
+ ...this.l1Constants,
83
+ ...constants
84
+ };
85
+ return this;
86
+ }
87
+ getL1Constants() {
88
+ return this.l1Constants;
89
+ }
90
+ setProposerPipeliningEnabled(enabled) {
91
+ this.proposerPipeliningEnabled = enabled;
92
+ }
93
+ getCommittee(_slot) {
94
+ const epoch = getEpochAtSlot(this.currentSlot, this.l1Constants);
95
+ return Promise.resolve({
96
+ committee: this.committee,
97
+ epoch,
98
+ seed: this.seed,
99
+ isEscapeHatchOpen: this.escapeHatchOpen
100
+ });
101
+ }
102
+ getSlotNow() {
103
+ return this.currentSlot;
104
+ }
105
+ getTargetSlot() {
106
+ return this.proposerPipeliningEnabled ? SlotNumber(this.currentSlot + PROPOSER_PIPELINING_SLOT_OFFSET) : this.currentSlot;
107
+ }
108
+ getEpochNow() {
109
+ return getEpochAtSlot(this.currentSlot, this.l1Constants);
110
+ }
111
+ getTargetEpoch() {
112
+ return getEpochAtSlot(this.getTargetSlot(), this.l1Constants);
113
+ }
114
+ isProposerPipeliningEnabled() {
115
+ return this.proposerPipeliningEnabled;
116
+ }
117
+ pipeliningOffset() {
118
+ return this.proposerPipeliningEnabled ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
119
+ }
120
+ getEpochAndSlotNow() {
121
+ const epochNow = getEpochAtSlot(this.currentSlot, this.l1Constants);
122
+ const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
123
+ return {
124
+ epoch: epochNow,
125
+ slot: this.currentSlot,
126
+ ts,
127
+ nowMs: ts * 1000n
128
+ };
129
+ }
130
+ getEpochAndSlotInNextL1Slot() {
131
+ const nowTs = getTimestampRangeForEpoch(getEpochAtSlot(this.currentSlot, this.l1Constants), this.l1Constants)[0];
132
+ const nextSlotTs = nowTs + BigInt(this.l1Constants.ethereumSlotDuration);
133
+ const nextSlot = getSlotAtTimestamp(nextSlotTs, this.l1Constants);
134
+ const epochNow = getEpochAtSlot(nextSlot, this.l1Constants);
135
+ const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
136
+ return {
137
+ epoch: epochNow,
138
+ slot: nextSlot,
139
+ ts,
140
+ nowSeconds: nowTs
141
+ };
142
+ }
143
+ getTargetEpochAndSlotInNextL1Slot() {
144
+ const result = this.getEpochAndSlotInNextL1Slot();
145
+ const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
146
+ const targetSlot = SlotNumber(result.slot + offset);
147
+ return {
148
+ ...result,
149
+ slot: targetSlot,
150
+ epoch: getEpochAtSlot(targetSlot, this.l1Constants)
151
+ };
152
+ }
153
+ getProposerIndexEncoding(epoch, slot, seed) {
154
+ // Simple encoding for testing purposes
155
+ return `0x${epoch.toString(16).padStart(64, '0')}${slot.toString(16).padStart(64, '0')}${seed.toString(16).padStart(64, '0')}`;
156
+ }
157
+ computeProposerIndex(slot, _epoch, _seed, size) {
158
+ if (size === 0n) {
159
+ return 0n;
160
+ }
161
+ return BigInt(slot) % size;
162
+ }
163
+ getCurrentAndNextSlot() {
164
+ const currentSlot = this.getSlotNow();
165
+ const next = this.getEpochAndSlotInNextL1Slot();
166
+ return {
167
+ currentSlot,
168
+ nextSlot: next.slot
169
+ };
170
+ }
171
+ getTargetAndNextSlot() {
172
+ const targetSlot = this.getTargetSlot();
173
+ const next = this.getTargetEpochAndSlotInNextL1Slot();
174
+ return {
175
+ targetSlot,
176
+ nextSlot: next.slot
177
+ };
178
+ }
179
+ getProposerAttesterAddressInSlot(_slot) {
180
+ return Promise.resolve(this.proposerAddress);
181
+ }
182
+ getRegisteredValidators() {
183
+ return Promise.resolve(this.registeredValidators);
184
+ }
185
+ isInCommittee(_slot, validator) {
186
+ return Promise.resolve(this.committee.some((v)=>v.equals(validator)));
187
+ }
188
+ filterInCommittee(_slot, validators) {
189
+ const committeeSet = new Set(this.committee.map((v)=>v.toString()));
190
+ return Promise.resolve(validators.filter((v)=>committeeSet.has(v.toString())));
191
+ }
192
+ isEscapeHatchOpen(_epoch) {
193
+ return Promise.resolve(this.escapeHatchOpen);
194
+ }
195
+ isEscapeHatchOpenAtSlot(_slot) {
196
+ return Promise.resolve(this.escapeHatchOpen);
197
+ }
198
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/epoch-cache",
3
- "version": "0.0.1-commit.d431d1c",
3
+ "version": "0.0.1-commit.d939eb5aa",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -26,11 +26,10 @@
26
26
  "../package.common.json"
27
27
  ],
28
28
  "dependencies": {
29
- "@aztec/ethereum": "0.0.1-commit.d431d1c",
30
- "@aztec/foundation": "0.0.1-commit.d431d1c",
31
- "@aztec/l1-artifacts": "0.0.1-commit.d431d1c",
32
- "@aztec/stdlib": "0.0.1-commit.d431d1c",
33
- "@viem/anvil": "^0.0.10",
29
+ "@aztec/ethereum": "0.0.1-commit.d939eb5aa",
30
+ "@aztec/foundation": "0.0.1-commit.d939eb5aa",
31
+ "@aztec/l1-artifacts": "0.0.1-commit.d939eb5aa",
32
+ "@aztec/stdlib": "0.0.1-commit.d939eb5aa",
34
33
  "dotenv": "^16.0.3",
35
34
  "get-port": "^7.1.0",
36
35
  "jest-mock-extended": "^4.0.0",
package/src/config.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  import { type L1ContractsConfig, getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
2
2
  import { type L1ReaderConfig, getL1ReaderConfigFromEnv } from '@aztec/ethereum/l1-reader';
3
+ import { type PipelineConfig, getPipelineConfigEnvVars } from '@aztec/stdlib/config';
3
4
 
4
5
  export type EpochCacheConfig = Pick<
5
- L1ReaderConfig & L1ContractsConfig,
6
- 'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'ethereumSlotDuration'
6
+ L1ReaderConfig & L1ContractsConfig & PipelineConfig,
7
+ | 'l1RpcUrls'
8
+ | 'l1ChainId'
9
+ | 'viemPollingIntervalMS'
10
+ | 'ethereumSlotDuration'
11
+ | 'l1HttpTimeoutMS'
12
+ | 'enableProposerPipelining'
7
13
  >;
8
14
 
9
15
  export function getEpochCacheConfigEnvVars(): EpochCacheConfig {
10
- return { ...getL1ReaderConfigFromEnv(), ...getL1ContractsConfigEnvVars() };
16
+ return { ...getL1ReaderConfigFromEnv(), ...getL1ContractsConfigEnvVars(), ...getPipelineConfigEnvVars() };
11
17
  }