@aztec/epoch-cache 0.0.1-commit.c2595eba → 0.0.1-commit.c2eed6949
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 +3 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -1
- package/dest/epoch_cache.d.ts +40 -6
- package/dest/epoch_cache.d.ts.map +1 -1
- package/dest/epoch_cache.js +80 -34
- package/dest/test/test_epoch_cache.d.ts +18 -3
- package/dest/test/test_epoch_cache.d.ts.map +1 -1
- package/dest/test/test_epoch_cache.js +57 -12
- package/package.json +5 -6
- package/src/config.ts +9 -3
- package/src/epoch_cache.ts +97 -27
- package/src/test/test_epoch_cache.ts +81 -12
package/dest/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type L1ContractsConfig } from '@aztec/ethereum/config';
|
|
2
2
|
import { type L1ReaderConfig } from '@aztec/ethereum/l1-reader';
|
|
3
|
-
|
|
3
|
+
import { type PipelineConfig } from '@aztec/stdlib/config';
|
|
4
|
+
export type EpochCacheConfig = Pick<L1ReaderConfig & L1ContractsConfig & PipelineConfig, 'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'ethereumSlotDuration' | 'l1HttpTimeoutMS' | 'enableProposerPipelining'>;
|
|
4
5
|
export declare function getEpochCacheConfigEnvVars(): EpochCacheConfig;
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLGlCQUFpQixFQUErQixNQUFNLHdCQUF3QixDQUFDO0FBQzdGLE9BQU8sRUFBRSxLQUFLLGNBQWMsRUFBNEIsTUFBTSwyQkFBMkIsQ0FBQztBQUMxRixPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQTRCLE1BQU0sc0JBQXNCLENBQUM7QUFFckYsTUFBTSxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FDakMsY0FBYyxHQUFHLGlCQUFpQixHQUFHLGNBQWMsRUFDakQsV0FBVyxHQUNYLFdBQVcsR0FDWCx1QkFBdUIsR0FDdkIsc0JBQXNCLEdBQ3RCLGlCQUFpQixHQUNqQiwwQkFBMEIsQ0FDN0IsQ0FBQztBQUVGLHdCQUFnQiwwQkFBMEIsSUFBSSxnQkFBZ0IsQ0FFN0QifQ==
|
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAC1F,OAAO,EAAE,KAAK,cAAc,EAA4B,MAAM,sBAAsB,CAAC;AAErF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,cAAc,GAAG,iBAAiB,GAAG,cAAc,EACjD,WAAW,GACX,WAAW,GACX,uBAAuB,GACvB,sBAAsB,GACtB,iBAAiB,GACjB,0BAA0B,CAC7B,CAAC;AAEF,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D"}
|
package/dest/config.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
|
|
2
2
|
import { getL1ReaderConfigFromEnv } from '@aztec/ethereum/l1-reader';
|
|
3
|
+
import { getPipelineConfigEnvVars } from '@aztec/stdlib/config';
|
|
3
4
|
export function getEpochCacheConfigEnvVars() {
|
|
4
5
|
return {
|
|
5
6
|
...getL1ReaderConfigFromEnv(),
|
|
6
|
-
...getL1ContractsConfigEnvVars()
|
|
7
|
+
...getL1ContractsConfigEnvVars(),
|
|
8
|
+
...getPipelineConfigEnvVars()
|
|
7
9
|
};
|
|
8
10
|
}
|
package/dest/epoch_cache.d.ts
CHANGED
|
@@ -4,9 +4,12 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
4
4
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
5
5
|
import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
6
6
|
import { type EpochCacheConfig } from './config.js';
|
|
7
|
+
/** When proposer pipelining is enabled, the proposer builds one slot ahead. */
|
|
8
|
+
export declare const PROPOSER_PIPELINING_SLOT_OFFSET = 1;
|
|
9
|
+
/** Flat return type for compound epoch/slot getters. */
|
|
7
10
|
export type EpochAndSlot = {
|
|
8
|
-
epoch: EpochNumber;
|
|
9
11
|
slot: SlotNumber;
|
|
12
|
+
epoch: EpochNumber;
|
|
10
13
|
ts: bigint;
|
|
11
14
|
};
|
|
12
15
|
export type EpochCommitteeInfo = {
|
|
@@ -19,22 +22,38 @@ export type EpochCommitteeInfo = {
|
|
|
19
22
|
export type SlotTag = 'now' | 'next' | SlotNumber;
|
|
20
23
|
export interface EpochCacheInterface {
|
|
21
24
|
getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
|
|
25
|
+
getSlotNow(): SlotNumber;
|
|
26
|
+
getTargetSlot(): SlotNumber;
|
|
27
|
+
getEpochNow(): EpochNumber;
|
|
28
|
+
getTargetEpoch(): EpochNumber;
|
|
22
29
|
getEpochAndSlotNow(): EpochAndSlot & {
|
|
23
30
|
nowMs: bigint;
|
|
24
31
|
};
|
|
25
32
|
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
26
|
-
|
|
33
|
+
nowSeconds: bigint;
|
|
34
|
+
};
|
|
35
|
+
/** Returns epoch/slot info for the next L1 slot with pipeline offset applied. */
|
|
36
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
37
|
+
nowSeconds: bigint;
|
|
27
38
|
};
|
|
39
|
+
isProposerPipeliningEnabled(): boolean;
|
|
40
|
+
isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean>;
|
|
41
|
+
isEscapeHatchOpenAtSlot(slot: SlotTag): Promise<boolean>;
|
|
28
42
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
|
|
29
43
|
computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
|
|
30
44
|
getCurrentAndNextSlot(): {
|
|
31
45
|
currentSlot: SlotNumber;
|
|
32
46
|
nextSlot: SlotNumber;
|
|
33
47
|
};
|
|
48
|
+
getTargetAndNextSlot(): {
|
|
49
|
+
targetSlot: SlotNumber;
|
|
50
|
+
nextSlot: SlotNumber;
|
|
51
|
+
};
|
|
34
52
|
getProposerAttesterAddressInSlot(slot: SlotNumber): Promise<EthAddress | undefined>;
|
|
35
53
|
getRegisteredValidators(): Promise<EthAddress[]>;
|
|
36
54
|
isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
|
|
37
55
|
filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
|
|
56
|
+
getL1Constants(): L1RollupConstants;
|
|
38
57
|
}
|
|
39
58
|
/**
|
|
40
59
|
* Epoch cache
|
|
@@ -52,29 +71,39 @@ export declare class EpochCache implements EpochCacheInterface {
|
|
|
52
71
|
protected readonly config: {
|
|
53
72
|
cacheSize: number;
|
|
54
73
|
validatorRefreshIntervalSeconds: number;
|
|
74
|
+
enableProposerPipelining: boolean;
|
|
55
75
|
};
|
|
56
76
|
protected cache: Map<EpochNumber, EpochCommitteeInfo>;
|
|
57
77
|
private allValidators;
|
|
58
78
|
private lastValidatorRefresh;
|
|
59
79
|
private readonly log;
|
|
80
|
+
protected enableProposerPipelining: boolean;
|
|
60
81
|
constructor(rollup: RollupContract, l1constants: L1RollupConstants & {
|
|
61
82
|
lagInEpochsForValidatorSet: number;
|
|
62
83
|
lagInEpochsForRandao: number;
|
|
63
84
|
}, dateProvider?: DateProvider, config?: {
|
|
64
85
|
cacheSize: number;
|
|
65
86
|
validatorRefreshIntervalSeconds: number;
|
|
87
|
+
enableProposerPipelining: boolean;
|
|
66
88
|
});
|
|
67
89
|
static create(rollupOrAddress: EthAddress | RollupContract, config?: EpochCacheConfig, deps?: {
|
|
68
90
|
dateProvider?: DateProvider;
|
|
69
91
|
}): Promise<EpochCache>;
|
|
70
92
|
getL1Constants(): L1RollupConstants;
|
|
93
|
+
isProposerPipeliningEnabled(): boolean;
|
|
94
|
+
getSlotNow(): SlotNumber;
|
|
95
|
+
getTargetSlot(): SlotNumber;
|
|
96
|
+
getEpochNow(): EpochNumber;
|
|
97
|
+
getTargetEpoch(): EpochNumber;
|
|
71
98
|
getEpochAndSlotNow(): EpochAndSlot & {
|
|
72
99
|
nowMs: bigint;
|
|
73
100
|
};
|
|
74
|
-
nowInSeconds(): bigint;
|
|
75
101
|
private getEpochAndSlotAtSlot;
|
|
76
102
|
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
77
|
-
|
|
103
|
+
nowSeconds: bigint;
|
|
104
|
+
};
|
|
105
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
106
|
+
nowSeconds: bigint;
|
|
78
107
|
};
|
|
79
108
|
private getEpochAndSlotAtTimestamp;
|
|
80
109
|
getCommitteeForEpoch(epoch: EpochNumber): Promise<EpochCommitteeInfo>;
|
|
@@ -105,11 +134,16 @@ export declare class EpochCache implements EpochCacheInterface {
|
|
|
105
134
|
*/
|
|
106
135
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
|
|
107
136
|
computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
|
|
108
|
-
/** Returns the current and next L2 slot
|
|
137
|
+
/** Returns the current and next L2 slot in next eth L1 Slot. */
|
|
109
138
|
getCurrentAndNextSlot(): {
|
|
110
139
|
currentSlot: SlotNumber;
|
|
111
140
|
nextSlot: SlotNumber;
|
|
112
141
|
};
|
|
142
|
+
/** Returns the taget and next L2 slot in the next L1 slot */
|
|
143
|
+
getTargetAndNextSlot(): {
|
|
144
|
+
targetSlot: SlotNumber;
|
|
145
|
+
nextSlot: SlotNumber;
|
|
146
|
+
};
|
|
113
147
|
/**
|
|
114
148
|
* Get the proposer attester address in the given L2 slot
|
|
115
149
|
* @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
|
|
@@ -130,4 +164,4 @@ export declare class EpochCache implements EpochCacheInterface {
|
|
|
130
164
|
filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
|
|
131
165
|
getRegisteredValidators(): Promise<EthAddress[]>;
|
|
132
166
|
}
|
|
133
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
167
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfY2FjaGUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9lcG9jaF9jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQW9CLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDMUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQ0wsS0FBSyxpQkFBaUIsRUFPdkIsTUFBTSw2QkFBNkIsQ0FBQztBQUlyQyxPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBOEIsTUFBTSxhQUFhLENBQUM7QUFFaEYsK0VBQStFO0FBQy9FLGVBQU8sTUFBTSwrQkFBK0IsSUFBSSxDQUFDO0FBRWpELHdEQUF3RDtBQUN4RCxNQUFNLE1BQU0sWUFBWSxHQUFHO0lBQ3pCLElBQUksRUFBRSxVQUFVLENBQUM7SUFDakIsS0FBSyxFQUFFLFdBQVcsQ0FBQztJQUNuQixFQUFFLEVBQUUsTUFBTSxDQUFDO0NBQ1osQ0FBQztBQUVGLE1BQU0sTUFBTSxrQkFBa0IsR0FBRztJQUMvQixTQUFTLEVBQUUsVUFBVSxFQUFFLEdBQUcsU0FBUyxDQUFDO0lBQ3BDLElBQUksRUFBRSxNQUFNLENBQUM7SUFDYixLQUFLLEVBQUUsV0FBVyxDQUFDO0lBQ25CLCtEQUErRDtJQUMvRCxpQkFBaUIsRUFBRSxPQUFPLENBQUM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sTUFBTSxPQUFPLEdBQUcsS0FBSyxHQUFHLE1BQU0sR0FBRyxVQUFVLENBQUM7QUFFbEQsTUFBTSxXQUFXLG1CQUFtQjtJQUNsQyxZQUFZLENBQUMsSUFBSSxFQUFFLE9BQU8sR0FBRyxTQUFTLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDckUsVUFB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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"epoch_cache.d.ts","sourceRoot":"","sources":["../src/epoch_cache.ts"],"names":[],"mappings":"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"}
|
package/dest/epoch_cache.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
2
3
|
import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts';
|
|
4
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
7
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
6
|
-
import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampForSlot
|
|
7
|
-
import { createPublicClient, encodeAbiParameters,
|
|
8
|
+
import { getEpochAtSlot, getEpochNumberAtTimestamp, getNextL1SlotTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
9
|
+
import { createPublicClient, encodeAbiParameters, keccak256 } from 'viem';
|
|
8
10
|
import { getEpochCacheConfigEnvVars } from './config.js';
|
|
11
|
+
/** When proposer pipelining is enabled, the proposer builds one slot ahead. */ export const PROPOSER_PIPELINING_SLOT_OFFSET = 1;
|
|
9
12
|
/**
|
|
10
13
|
* Epoch cache
|
|
11
14
|
*
|
|
@@ -24,9 +27,11 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
24
27
|
allValidators;
|
|
25
28
|
lastValidatorRefresh;
|
|
26
29
|
log;
|
|
30
|
+
enableProposerPipelining;
|
|
27
31
|
constructor(rollup, l1constants, dateProvider = new DateProvider(), config = {
|
|
28
32
|
cacheSize: 12,
|
|
29
|
-
validatorRefreshIntervalSeconds: 60
|
|
33
|
+
validatorRefreshIntervalSeconds: 60,
|
|
34
|
+
enableProposerPipelining: false
|
|
30
35
|
}){
|
|
31
36
|
this.rollup = rollup;
|
|
32
37
|
this.l1constants = l1constants;
|
|
@@ -36,8 +41,10 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
36
41
|
this.allValidators = new Set();
|
|
37
42
|
this.lastValidatorRefresh = 0;
|
|
38
43
|
this.log = createLogger('epoch-cache');
|
|
44
|
+
this.enableProposerPipelining = this.config.enableProposerPipelining;
|
|
39
45
|
this.log.debug(`Initialized EpochCache`, {
|
|
40
|
-
l1constants
|
|
46
|
+
l1constants,
|
|
47
|
+
enableProposerPipelining: this.enableProposerPipelining
|
|
41
48
|
});
|
|
42
49
|
}
|
|
43
50
|
static async create(rollupOrAddress, config, deps = {}) {
|
|
@@ -50,21 +57,23 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
50
57
|
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
51
58
|
const publicClient = createPublicClient({
|
|
52
59
|
chain: chain.chainInfo,
|
|
53
|
-
transport:
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, {
|
|
61
|
+
timeout: config.l1HttpTimeoutMS
|
|
62
|
+
}),
|
|
56
63
|
pollingInterval: config.viemPollingIntervalMS
|
|
57
64
|
});
|
|
58
65
|
rollup = new RollupContract(publicClient, rollupOrAddress.toString());
|
|
59
66
|
}
|
|
60
|
-
const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, slotDuration, epochDuration, lagInEpochsForValidatorSet, lagInEpochsForRandao] = await Promise.all([
|
|
67
|
+
const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, slotDuration, epochDuration, lagInEpochsForValidatorSet, lagInEpochsForRandao, targetCommitteeSize, rollupManaLimit] = await Promise.all([
|
|
61
68
|
rollup.getL1StartBlock(),
|
|
62
69
|
rollup.getL1GenesisTime(),
|
|
63
70
|
rollup.getProofSubmissionEpochs(),
|
|
64
71
|
rollup.getSlotDuration(),
|
|
65
72
|
rollup.getEpochDuration(),
|
|
66
73
|
rollup.getLagInEpochsForValidatorSet(),
|
|
67
|
-
rollup.getLagInEpochsForRandao()
|
|
74
|
+
rollup.getLagInEpochsForRandao(),
|
|
75
|
+
rollup.getTargetCommitteeSize(),
|
|
76
|
+
rollup.getManaLimit()
|
|
68
77
|
]);
|
|
69
78
|
const l1RollupConstants = {
|
|
70
79
|
l1StartBlock,
|
|
@@ -74,13 +83,36 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
74
83
|
epochDuration: Number(epochDuration),
|
|
75
84
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
76
85
|
lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
|
|
77
|
-
lagInEpochsForRandao: Number(lagInEpochsForRandao)
|
|
86
|
+
lagInEpochsForRandao: Number(lagInEpochsForRandao),
|
|
87
|
+
targetCommitteeSize: Number(targetCommitteeSize),
|
|
88
|
+
rollupManaLimit: Number(rollupManaLimit)
|
|
78
89
|
};
|
|
79
|
-
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider
|
|
90
|
+
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider, {
|
|
91
|
+
cacheSize: 12,
|
|
92
|
+
validatorRefreshIntervalSeconds: 60,
|
|
93
|
+
enableProposerPipelining: config.enableProposerPipelining
|
|
94
|
+
});
|
|
80
95
|
}
|
|
81
96
|
getL1Constants() {
|
|
82
97
|
return this.l1constants;
|
|
83
98
|
}
|
|
99
|
+
isProposerPipeliningEnabled() {
|
|
100
|
+
return this.enableProposerPipelining;
|
|
101
|
+
}
|
|
102
|
+
getSlotNow() {
|
|
103
|
+
return this.getEpochAndSlotNow().slot;
|
|
104
|
+
}
|
|
105
|
+
getTargetSlot() {
|
|
106
|
+
const slotNow = this.getSlotNow();
|
|
107
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
108
|
+
return SlotNumber(slotNow + offset);
|
|
109
|
+
}
|
|
110
|
+
getEpochNow() {
|
|
111
|
+
return this.getEpochAndSlotNow().epoch;
|
|
112
|
+
}
|
|
113
|
+
getTargetEpoch() {
|
|
114
|
+
return getEpochAtSlot(this.getTargetSlot(), this.l1constants);
|
|
115
|
+
}
|
|
84
116
|
getEpochAndSlotNow() {
|
|
85
117
|
const nowMs = BigInt(this.dateProvider.now());
|
|
86
118
|
const nowSeconds = nowMs / 1000n;
|
|
@@ -89,32 +121,37 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
89
121
|
nowMs
|
|
90
122
|
};
|
|
91
123
|
}
|
|
92
|
-
nowInSeconds() {
|
|
93
|
-
return BigInt(Math.floor(this.dateProvider.now() / 1000));
|
|
94
|
-
}
|
|
95
124
|
getEpochAndSlotAtSlot(slot) {
|
|
96
|
-
|
|
97
|
-
const ts = getTimestampRangeForEpoch(epoch, this.l1constants)[0];
|
|
98
|
-
return {
|
|
99
|
-
epoch,
|
|
100
|
-
ts,
|
|
101
|
-
slot
|
|
102
|
-
};
|
|
125
|
+
return this.getEpochAndSlotAtTimestamp(getTimestampForSlot(slot, this.l1constants));
|
|
103
126
|
}
|
|
104
127
|
getEpochAndSlotInNextL1Slot() {
|
|
105
|
-
const
|
|
106
|
-
const nextSlotTs =
|
|
128
|
+
const nowSeconds = this.dateProvider.nowInSeconds();
|
|
129
|
+
const nextSlotTs = getNextL1SlotTimestamp(nowSeconds, this.l1constants);
|
|
107
130
|
return {
|
|
108
131
|
...this.getEpochAndSlotAtTimestamp(nextSlotTs),
|
|
109
|
-
|
|
132
|
+
nowSeconds: BigInt(nowSeconds)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
getTargetEpochAndSlotInNextL1Slot() {
|
|
136
|
+
if (!this.isProposerPipeliningEnabled()) {
|
|
137
|
+
return this.getEpochAndSlotInNextL1Slot();
|
|
138
|
+
}
|
|
139
|
+
const result = this.getEpochAndSlotInNextL1Slot();
|
|
140
|
+
const offset = PROPOSER_PIPELINING_SLOT_OFFSET;
|
|
141
|
+
const targetSlot = SlotNumber(result.slot + offset);
|
|
142
|
+
return {
|
|
143
|
+
...result,
|
|
144
|
+
slot: targetSlot,
|
|
145
|
+
epoch: getEpochAtSlot(targetSlot, this.l1constants)
|
|
110
146
|
};
|
|
111
147
|
}
|
|
112
148
|
getEpochAndSlotAtTimestamp(ts) {
|
|
113
149
|
const slot = getSlotAtTimestamp(ts, this.l1constants);
|
|
150
|
+
const epoch = getEpochNumberAtTimestamp(ts, this.l1constants);
|
|
114
151
|
return {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
slot
|
|
152
|
+
slot,
|
|
153
|
+
epoch,
|
|
154
|
+
ts: getTimestampForSlot(slot, this.l1constants)
|
|
118
155
|
};
|
|
119
156
|
}
|
|
120
157
|
getCommitteeForEpoch(epoch) {
|
|
@@ -140,7 +177,7 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
140
177
|
* This is a lightweight helper intended for callers that already have a slot number and only
|
|
141
178
|
* need the escape hatch flag (without pulling full committee info).
|
|
142
179
|
*/ async isEscapeHatchOpenAtSlot(slot = 'now') {
|
|
143
|
-
const epoch = slot === 'now' ? this.
|
|
180
|
+
const epoch = slot === 'now' ? this.getEpochNow() : slot === 'next' ? this.getEpochAndSlotInNextL1Slot().epoch : getEpochAtSlot(slot, this.l1constants);
|
|
144
181
|
return await this.isEscapeHatchOpen(epoch);
|
|
145
182
|
}
|
|
146
183
|
/**
|
|
@@ -225,11 +262,19 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
225
262
|
}
|
|
226
263
|
return BigInt(keccak256(this.getProposerIndexEncoding(epoch, slot, seed))) % size;
|
|
227
264
|
}
|
|
228
|
-
/** Returns the current and next L2 slot
|
|
229
|
-
const
|
|
265
|
+
/** Returns the current and next L2 slot in next eth L1 Slot. */ getCurrentAndNextSlot() {
|
|
266
|
+
const currentSlot = this.getSlotNow();
|
|
230
267
|
const next = this.getEpochAndSlotInNextL1Slot();
|
|
231
268
|
return {
|
|
232
|
-
currentSlot
|
|
269
|
+
currentSlot,
|
|
270
|
+
nextSlot: next.slot
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/** Returns the taget and next L2 slot in the next L1 slot */ getTargetAndNextSlot() {
|
|
274
|
+
const targetSlot = this.getTargetSlot();
|
|
275
|
+
const next = this.getTargetEpochAndSlotInNextL1Slot();
|
|
276
|
+
return {
|
|
277
|
+
targetSlot,
|
|
233
278
|
nextSlot: next.slot
|
|
234
279
|
};
|
|
235
280
|
}
|
|
@@ -290,10 +335,11 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
290
335
|
async getRegisteredValidators() {
|
|
291
336
|
const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
|
|
292
337
|
const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
|
|
293
|
-
|
|
294
|
-
|
|
338
|
+
const now = this.dateProvider.now();
|
|
339
|
+
if (validatorRefreshTime < now) {
|
|
340
|
+
const currentSet = await this.rollup.getAttesters(BigInt(Math.floor(now / 1000)));
|
|
295
341
|
this.allValidators = new Set(currentSet.map((v)=>v.toString()));
|
|
296
|
-
this.lastValidatorRefresh =
|
|
342
|
+
this.lastValidatorRefresh = now;
|
|
297
343
|
}
|
|
298
344
|
return Array.from(this.allValidators.keys()).map((v)=>EthAddress.fromString(v));
|
|
299
345
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
4
|
-
import type
|
|
4
|
+
import { type EpochAndSlot, type EpochCacheInterface, type EpochCommitteeInfo, type SlotTag } from '../epoch_cache.js';
|
|
5
5
|
/**
|
|
6
6
|
* A test implementation of EpochCacheInterface that allows manual configuration
|
|
7
7
|
* of committee, proposer, slot, and escape hatch state for use in tests.
|
|
@@ -17,6 +17,7 @@ export declare class TestEpochCache implements EpochCacheInterface {
|
|
|
17
17
|
private seed;
|
|
18
18
|
private registeredValidators;
|
|
19
19
|
private l1Constants;
|
|
20
|
+
private proposerPipeliningEnabled;
|
|
20
21
|
constructor(l1Constants?: Partial<L1RollupConstants>);
|
|
21
22
|
/**
|
|
22
23
|
* Sets the committee members. Used in validation and attestation flows.
|
|
@@ -54,12 +55,21 @@ export declare class TestEpochCache implements EpochCacheInterface {
|
|
|
54
55
|
*/
|
|
55
56
|
setL1Constants(constants: Partial<L1RollupConstants>): this;
|
|
56
57
|
getL1Constants(): L1RollupConstants;
|
|
58
|
+
setProposerPipeliningEnabled(enabled: boolean): void;
|
|
57
59
|
getCommittee(_slot?: SlotTag): Promise<EpochCommitteeInfo>;
|
|
60
|
+
getSlotNow(): SlotNumber;
|
|
61
|
+
getTargetSlot(): SlotNumber;
|
|
62
|
+
getEpochNow(): EpochNumber;
|
|
63
|
+
getTargetEpoch(): EpochNumber;
|
|
64
|
+
isProposerPipeliningEnabled(): boolean;
|
|
58
65
|
getEpochAndSlotNow(): EpochAndSlot & {
|
|
59
66
|
nowMs: bigint;
|
|
60
67
|
};
|
|
61
68
|
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
62
|
-
|
|
69
|
+
nowSeconds: bigint;
|
|
70
|
+
};
|
|
71
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
72
|
+
nowSeconds: bigint;
|
|
63
73
|
};
|
|
64
74
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
|
|
65
75
|
computeProposerIndex(slot: SlotNumber, _epoch: EpochNumber, _seed: bigint, size: bigint): bigint;
|
|
@@ -67,10 +77,15 @@ export declare class TestEpochCache implements EpochCacheInterface {
|
|
|
67
77
|
currentSlot: SlotNumber;
|
|
68
78
|
nextSlot: SlotNumber;
|
|
69
79
|
};
|
|
80
|
+
getTargetAndNextSlot(): {
|
|
81
|
+
targetSlot: SlotNumber;
|
|
82
|
+
nextSlot: SlotNumber;
|
|
83
|
+
};
|
|
70
84
|
getProposerAttesterAddressInSlot(_slot: SlotNumber): Promise<EthAddress | undefined>;
|
|
71
85
|
getRegisteredValidators(): Promise<EthAddress[]>;
|
|
72
86
|
isInCommittee(_slot: SlotTag, validator: EthAddress): Promise<boolean>;
|
|
73
87
|
filterInCommittee(_slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
|
|
88
|
+
isEscapeHatchOpen(_epoch: EpochNumber): Promise<boolean>;
|
|
74
89
|
isEscapeHatchOpenAtSlot(_slot?: SlotTag): Promise<boolean>;
|
|
75
90
|
}
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
91
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdF9lcG9jaF9jYWNoZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3QvdGVzdF9lcG9jaF9jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUMzRCxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBR3JFLE9BQU8sRUFDTCxLQUFLLFlBQVksRUFDakIsS0FBSyxtQkFBbUIsRUFDeEIsS0FBSyxrQkFBa0IsRUFFdkIsS0FBSyxPQUFPLEVBQ2IsTUFBTSxtQkFBbUIsQ0FBQztBQWMzQjs7Ozs7O0dBTUc7QUFDSCxxQkFBYSxjQUFlLFlBQVcsbUJBQW1CO0lBQ3hELE9BQU8sQ0FBQyxTQUFTLENBQW9CO0lBQ3JDLE9BQU8sQ0FBQyxlQUFlLENBQXlCO0lBQ2hELE9BQU8sQ0FBQyxXQUFXLENBQTZCO0lBQ2hELE9BQU8sQ0FBQyxlQUFlLENBQWtCO0lBQ3pDLE9BQU8sQ0FBQyxJQUFJLENBQWM7SUFDMUIsT0FBTyxDQUFDLG9CQUFvQixDQUFvQjtJQUNoRCxPQUFPLENBQUMsV0FBVyxDQUFvQjtJQUN2QyxPQUFPLENBQUMseUJBQXlCLENBQVM7SUFFMUMsWUFBWSxXQUFXLEdBQUUsT0FBTyxDQUFDLGlCQUFpQixDQUFNLEVBRXZEO0lBRUQ7OztPQUdHO0lBQ0gsWUFBWSxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLENBRzFDO0lBRUQ7OztPQUdHO0lBQ0gsV0FBVyxDQUFDLFFBQVEsRUFBRSxVQUFVLEdBQUcsU0FBUyxHQUFHLElBQUksQ0FHbEQ7SUFFRDs7O09BR0c7SUFDSCxjQUFjLENBQUMsSUFBSSxFQUFFLFVBQVUsR0FBRyxJQUFJLENBR3JDO0lBRUQ7OztPQUdHO0lBQ0gsa0JBQWtCLENBQUMsSUFBSSxFQUFFLE9BQU8sR0FBRyxJQUFJLENBR3RDO0lBRUQ7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLElBQUksRUFBRSxNQUFNLEdBQUcsSUFBSSxDQUcxQjtJQUVEOzs7T0FHRztJQUNILHVCQUF1QixDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLENBR3REO0lBRUQ7OztPQUdHO0lBQ0gsY0FBYyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxJQUFJLENBRzFEO0lBRUQsY0FBYyxJQUFJLGlCQUFpQixDQUVsQztJQUVELDRCQUE0QixDQUFDLE9BQU8sRUFBRSxPQUFPLEdBQUcsSUFBSSxDQUVuRDtJQUVELFlBQVksQ0FBQyxLQUFLLENBQUMsRUFBRSxPQUFPLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBUXpEO0lBRUQsVUFBVSxJQUFJLFVBQVUsQ0FFdkI7SUFFRCxhQUFhLElBQUksVUFBVSxDQUkxQjtJQUVELFdBQVcsSUFBSSxXQUFXLENBRXpCO0lBRUQsY0FBYyxJQUFJLFdBQVcsQ0FFNUI7SUFFRCwyQkFBMkIsSUFBSSxPQUFPLENBRXJDO0lBRUQsa0JBQWtCLElBQUksWUFBWSxHQUFHO1FBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQTtLQUFFLENBU3JEO0lBRUQsMkJBQTJCLElBQUksWUFBWSxHQUFHO1FBQUUsVUFBVSxFQUFFLE1BQU0sQ0FBQTtLQUFFLENBWW5FO0lBRUQsaUNBQWlDLElBQUksWUFBWSxHQUFHO1FBQUUsVUFBVSxFQUFFLE1BQU0sQ0FBQTtLQUFFLENBS3pFO0lBRUQsd0JBQXdCLENBQUMsS0FBSyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxNQUFNLEdBQUcsS0FBSyxNQUFNLEVBQUUsQ0FHMUY7SUFFRCxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSxHQUFHLE1BQU0sQ0FLL0Y7SUFFRCxxQkFBcUIsSUFBSTtRQUFFLFdBQVcsRUFBRSxVQUFVLENBQUM7UUFBQyxRQUFRLEVBQUUsVUFBVSxDQUFBO0tBQUUsQ0FRekU7SUFFRCxvQkFBb0IsSUFBSTtRQUFFLFVBQVUsRUFBRSxVQUFVLENBQUM7UUFBQyxRQUFRLEVBQUUsVUFBVSxDQUFBO0tBQUUsQ0FRdkU7SUFFRCxnQ0FBZ0MsQ0FBQyxLQUFLLEVBQUUsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRW5GO0lBRUQsdUJBQXVCLElBQUksT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBRS9DO0lBRUQsYUFBYSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBRXJFO0lBRUQsaUJBQWlCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBR2pGO0lBRUQsaUJBQWlCLENBQUMsTUFBTSxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBRXZEO0lBRUQsdUJBQXVCLENBQUMsS0FBSyxDQUFDLEVBQUUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FFekQ7Q0FDRiJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test_epoch_cache.d.ts","sourceRoot":"","sources":["../../src/test/test_epoch_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"test_epoch_cache.d.ts","sourceRoot":"","sources":["../../src/test/test_epoch_cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
3
|
+
import { PROPOSER_PIPELINING_SLOT_OFFSET } from '../epoch_cache.js';
|
|
3
4
|
/** Default L1 constants for testing. */ const DEFAULT_L1_CONSTANTS = {
|
|
4
5
|
l1StartBlock: 0n,
|
|
5
6
|
l1GenesisTime: 0n,
|
|
6
7
|
slotDuration: 24,
|
|
7
8
|
epochDuration: 16,
|
|
8
9
|
ethereumSlotDuration: 12,
|
|
9
|
-
proofSubmissionEpochs: 2
|
|
10
|
+
proofSubmissionEpochs: 2,
|
|
11
|
+
targetCommitteeSize: 48,
|
|
12
|
+
rollupManaLimit: Number.MAX_SAFE_INTEGER
|
|
10
13
|
};
|
|
11
14
|
/**
|
|
12
15
|
* A test implementation of EpochCacheInterface that allows manual configuration
|
|
@@ -22,6 +25,7 @@ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@
|
|
|
22
25
|
seed = 0n;
|
|
23
26
|
registeredValidators = [];
|
|
24
27
|
l1Constants;
|
|
28
|
+
proposerPipeliningEnabled = false;
|
|
25
29
|
constructor(l1Constants = {}){
|
|
26
30
|
this.l1Constants = {
|
|
27
31
|
...DEFAULT_L1_CONSTANTS,
|
|
@@ -83,6 +87,9 @@ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@
|
|
|
83
87
|
getL1Constants() {
|
|
84
88
|
return this.l1Constants;
|
|
85
89
|
}
|
|
90
|
+
setProposerPipeliningEnabled(enabled) {
|
|
91
|
+
this.proposerPipeliningEnabled = enabled;
|
|
92
|
+
}
|
|
86
93
|
getCommittee(_slot) {
|
|
87
94
|
const epoch = getEpochAtSlot(this.currentSlot, this.l1Constants);
|
|
88
95
|
return Promise.resolve({
|
|
@@ -92,27 +99,52 @@ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@
|
|
|
92
99
|
isEscapeHatchOpen: this.escapeHatchOpen
|
|
93
100
|
});
|
|
94
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
|
+
}
|
|
95
117
|
getEpochAndSlotNow() {
|
|
96
|
-
const
|
|
97
|
-
const ts = getTimestampRangeForEpoch(
|
|
118
|
+
const epochNow = getEpochAtSlot(this.currentSlot, this.l1Constants);
|
|
119
|
+
const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
|
|
98
120
|
return {
|
|
99
|
-
epoch,
|
|
121
|
+
epoch: epochNow,
|
|
100
122
|
slot: this.currentSlot,
|
|
101
123
|
ts,
|
|
102
124
|
nowMs: ts * 1000n
|
|
103
125
|
};
|
|
104
126
|
}
|
|
105
127
|
getEpochAndSlotInNextL1Slot() {
|
|
106
|
-
const
|
|
107
|
-
const nextSlotTs =
|
|
128
|
+
const nowTs = getTimestampRangeForEpoch(getEpochAtSlot(this.currentSlot, this.l1Constants), this.l1Constants)[0];
|
|
129
|
+
const nextSlotTs = nowTs + BigInt(this.l1Constants.ethereumSlotDuration);
|
|
108
130
|
const nextSlot = getSlotAtTimestamp(nextSlotTs, this.l1Constants);
|
|
109
|
-
const
|
|
110
|
-
const ts = getTimestampRangeForEpoch(
|
|
131
|
+
const epochNow = getEpochAtSlot(nextSlot, this.l1Constants);
|
|
132
|
+
const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
|
|
111
133
|
return {
|
|
112
|
-
epoch,
|
|
134
|
+
epoch: epochNow,
|
|
113
135
|
slot: nextSlot,
|
|
114
136
|
ts,
|
|
115
|
-
|
|
137
|
+
nowSeconds: nowTs
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
getTargetEpochAndSlotInNextL1Slot() {
|
|
141
|
+
const result = this.getEpochAndSlotInNextL1Slot();
|
|
142
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
143
|
+
const targetSlot = SlotNumber(result.slot + offset);
|
|
144
|
+
return {
|
|
145
|
+
...result,
|
|
146
|
+
slot: targetSlot,
|
|
147
|
+
epoch: getEpochAtSlot(targetSlot, this.l1Constants)
|
|
116
148
|
};
|
|
117
149
|
}
|
|
118
150
|
getProposerIndexEncoding(epoch, slot, seed) {
|
|
@@ -126,9 +158,19 @@ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@
|
|
|
126
158
|
return BigInt(slot) % size;
|
|
127
159
|
}
|
|
128
160
|
getCurrentAndNextSlot() {
|
|
161
|
+
const currentSlot = this.getSlotNow();
|
|
162
|
+
const next = this.getEpochAndSlotInNextL1Slot();
|
|
163
|
+
return {
|
|
164
|
+
currentSlot,
|
|
165
|
+
nextSlot: next.slot
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
getTargetAndNextSlot() {
|
|
169
|
+
const targetSlot = this.getTargetSlot();
|
|
170
|
+
const next = this.getTargetEpochAndSlotInNextL1Slot();
|
|
129
171
|
return {
|
|
130
|
-
|
|
131
|
-
nextSlot:
|
|
172
|
+
targetSlot,
|
|
173
|
+
nextSlot: next.slot
|
|
132
174
|
};
|
|
133
175
|
}
|
|
134
176
|
getProposerAttesterAddressInSlot(_slot) {
|
|
@@ -144,6 +186,9 @@ import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@
|
|
|
144
186
|
const committeeSet = new Set(this.committee.map((v)=>v.toString()));
|
|
145
187
|
return Promise.resolve(validators.filter((v)=>committeeSet.has(v.toString())));
|
|
146
188
|
}
|
|
189
|
+
isEscapeHatchOpen(_epoch) {
|
|
190
|
+
return Promise.resolve(this.escapeHatchOpen);
|
|
191
|
+
}
|
|
147
192
|
isEscapeHatchOpenAtSlot(_slot) {
|
|
148
193
|
return Promise.resolve(this.escapeHatchOpen);
|
|
149
194
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/epoch-cache",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.c2eed6949",
|
|
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.
|
|
30
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
31
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
32
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
33
|
-
"@viem/anvil": "^0.0.10",
|
|
29
|
+
"@aztec/ethereum": "0.0.1-commit.c2eed6949",
|
|
30
|
+
"@aztec/foundation": "0.0.1-commit.c2eed6949",
|
|
31
|
+
"@aztec/l1-artifacts": "0.0.1-commit.c2eed6949",
|
|
32
|
+
"@aztec/stdlib": "0.0.1-commit.c2eed6949",
|
|
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
|
-
|
|
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
|
}
|
package/src/epoch_cache.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
2
3
|
import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts';
|
|
3
4
|
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -8,19 +9,23 @@ import {
|
|
|
8
9
|
type L1RollupConstants,
|
|
9
10
|
getEpochAtSlot,
|
|
10
11
|
getEpochNumberAtTimestamp,
|
|
12
|
+
getNextL1SlotTimestamp,
|
|
11
13
|
getSlotAtTimestamp,
|
|
12
14
|
getSlotRangeForEpoch,
|
|
13
15
|
getTimestampForSlot,
|
|
14
|
-
getTimestampRangeForEpoch,
|
|
15
16
|
} from '@aztec/stdlib/epoch-helpers';
|
|
16
17
|
|
|
17
|
-
import { createPublicClient, encodeAbiParameters,
|
|
18
|
+
import { createPublicClient, encodeAbiParameters, keccak256 } from 'viem';
|
|
18
19
|
|
|
19
20
|
import { type EpochCacheConfig, getEpochCacheConfigEnvVars } from './config.js';
|
|
20
21
|
|
|
22
|
+
/** When proposer pipelining is enabled, the proposer builds one slot ahead. */
|
|
23
|
+
export const PROPOSER_PIPELINING_SLOT_OFFSET = 1;
|
|
24
|
+
|
|
25
|
+
/** Flat return type for compound epoch/slot getters. */
|
|
21
26
|
export type EpochAndSlot = {
|
|
22
|
-
epoch: EpochNumber;
|
|
23
27
|
slot: SlotNumber;
|
|
28
|
+
epoch: EpochNumber;
|
|
24
29
|
ts: bigint;
|
|
25
30
|
};
|
|
26
31
|
|
|
@@ -36,15 +41,26 @@ export type SlotTag = 'now' | 'next' | SlotNumber;
|
|
|
36
41
|
|
|
37
42
|
export interface EpochCacheInterface {
|
|
38
43
|
getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
|
|
44
|
+
getSlotNow(): SlotNumber;
|
|
45
|
+
getTargetSlot(): SlotNumber;
|
|
46
|
+
getEpochNow(): EpochNumber;
|
|
47
|
+
getTargetEpoch(): EpochNumber;
|
|
39
48
|
getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint };
|
|
40
|
-
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
49
|
+
getEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint };
|
|
50
|
+
/** Returns epoch/slot info for the next L1 slot with pipeline offset applied. */
|
|
51
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint };
|
|
52
|
+
isProposerPipeliningEnabled(): boolean;
|
|
53
|
+
isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean>;
|
|
54
|
+
isEscapeHatchOpenAtSlot(slot: SlotTag): Promise<boolean>;
|
|
41
55
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
|
|
42
56
|
computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
|
|
43
57
|
getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber };
|
|
58
|
+
getTargetAndNextSlot(): { targetSlot: SlotNumber; nextSlot: SlotNumber };
|
|
44
59
|
getProposerAttesterAddressInSlot(slot: SlotNumber): Promise<EthAddress | undefined>;
|
|
45
60
|
getRegisteredValidators(): Promise<EthAddress[]>;
|
|
46
61
|
isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
|
|
47
62
|
filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
|
|
63
|
+
getL1Constants(): L1RollupConstants;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
/**
|
|
@@ -63,6 +79,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
63
79
|
private lastValidatorRefresh = 0;
|
|
64
80
|
private readonly log: Logger = createLogger('epoch-cache');
|
|
65
81
|
|
|
82
|
+
protected enableProposerPipelining: boolean;
|
|
83
|
+
|
|
66
84
|
constructor(
|
|
67
85
|
private rollup: RollupContract,
|
|
68
86
|
private readonly l1constants: L1RollupConstants & {
|
|
@@ -70,10 +88,12 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
70
88
|
lagInEpochsForRandao: number;
|
|
71
89
|
},
|
|
72
90
|
private readonly dateProvider: DateProvider = new DateProvider(),
|
|
73
|
-
protected readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60 },
|
|
91
|
+
protected readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60, enableProposerPipelining: false },
|
|
74
92
|
) {
|
|
93
|
+
this.enableProposerPipelining = this.config.enableProposerPipelining;
|
|
75
94
|
this.log.debug(`Initialized EpochCache`, {
|
|
76
95
|
l1constants,
|
|
96
|
+
enableProposerPipelining: this.enableProposerPipelining,
|
|
77
97
|
});
|
|
78
98
|
}
|
|
79
99
|
|
|
@@ -92,7 +112,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
92
112
|
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
93
113
|
const publicClient = createPublicClient({
|
|
94
114
|
chain: chain.chainInfo,
|
|
95
|
-
transport:
|
|
115
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
96
116
|
pollingInterval: config.viemPollingIntervalMS,
|
|
97
117
|
});
|
|
98
118
|
rollup = new RollupContract(publicClient, rollupOrAddress.toString());
|
|
@@ -106,6 +126,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
106
126
|
epochDuration,
|
|
107
127
|
lagInEpochsForValidatorSet,
|
|
108
128
|
lagInEpochsForRandao,
|
|
129
|
+
targetCommitteeSize,
|
|
130
|
+
rollupManaLimit,
|
|
109
131
|
] = await Promise.all([
|
|
110
132
|
rollup.getL1StartBlock(),
|
|
111
133
|
rollup.getL1GenesisTime(),
|
|
@@ -114,6 +136,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
114
136
|
rollup.getEpochDuration(),
|
|
115
137
|
rollup.getLagInEpochsForValidatorSet(),
|
|
116
138
|
rollup.getLagInEpochsForRandao(),
|
|
139
|
+
rollup.getTargetCommitteeSize(),
|
|
140
|
+
rollup.getManaLimit(),
|
|
117
141
|
] as const);
|
|
118
142
|
|
|
119
143
|
const l1RollupConstants = {
|
|
@@ -125,43 +149,77 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
125
149
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
126
150
|
lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
|
|
127
151
|
lagInEpochsForRandao: Number(lagInEpochsForRandao),
|
|
152
|
+
targetCommitteeSize: Number(targetCommitteeSize),
|
|
153
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
128
154
|
};
|
|
129
155
|
|
|
130
|
-
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider
|
|
156
|
+
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider, {
|
|
157
|
+
cacheSize: 12,
|
|
158
|
+
validatorRefreshIntervalSeconds: 60,
|
|
159
|
+
enableProposerPipelining: config.enableProposerPipelining,
|
|
160
|
+
});
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
public getL1Constants(): L1RollupConstants {
|
|
134
164
|
return this.l1constants;
|
|
135
165
|
}
|
|
136
166
|
|
|
167
|
+
public isProposerPipeliningEnabled(): boolean {
|
|
168
|
+
return this.enableProposerPipelining;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public getSlotNow(): SlotNumber {
|
|
172
|
+
return this.getEpochAndSlotNow().slot;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public getTargetSlot(): SlotNumber {
|
|
176
|
+
const slotNow = this.getSlotNow();
|
|
177
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
178
|
+
return SlotNumber(slotNow + offset);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public getEpochNow(): EpochNumber {
|
|
182
|
+
return this.getEpochAndSlotNow().epoch;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public getTargetEpoch(): EpochNumber {
|
|
186
|
+
return getEpochAtSlot(this.getTargetSlot(), this.l1constants);
|
|
187
|
+
}
|
|
188
|
+
|
|
137
189
|
public getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
|
|
138
190
|
const nowMs = BigInt(this.dateProvider.now());
|
|
139
191
|
const nowSeconds = nowMs / 1000n;
|
|
140
192
|
return { ...this.getEpochAndSlotAtTimestamp(nowSeconds), nowMs };
|
|
141
193
|
}
|
|
142
194
|
|
|
143
|
-
|
|
144
|
-
return
|
|
195
|
+
private getEpochAndSlotAtSlot(slot: SlotNumber): EpochAndSlot {
|
|
196
|
+
return this.getEpochAndSlotAtTimestamp(getTimestampForSlot(slot, this.l1constants));
|
|
145
197
|
}
|
|
146
198
|
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
return {
|
|
199
|
+
public getEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
200
|
+
const nowSeconds = this.dateProvider.nowInSeconds();
|
|
201
|
+
const nextSlotTs = getNextL1SlotTimestamp(nowSeconds, this.l1constants);
|
|
202
|
+
return { ...this.getEpochAndSlotAtTimestamp(nextSlotTs), nowSeconds: BigInt(nowSeconds) };
|
|
151
203
|
}
|
|
152
204
|
|
|
153
|
-
public
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
205
|
+
public getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
206
|
+
if (!this.isProposerPipeliningEnabled()) {
|
|
207
|
+
return this.getEpochAndSlotInNextL1Slot();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const result = this.getEpochAndSlotInNextL1Slot();
|
|
211
|
+
const offset = PROPOSER_PIPELINING_SLOT_OFFSET;
|
|
212
|
+
const targetSlot = SlotNumber(result.slot + offset);
|
|
213
|
+
return { ...result, slot: targetSlot, epoch: getEpochAtSlot(targetSlot, this.l1constants) };
|
|
157
214
|
}
|
|
158
215
|
|
|
159
216
|
private getEpochAndSlotAtTimestamp(ts: bigint): EpochAndSlot {
|
|
160
217
|
const slot = getSlotAtTimestamp(ts, this.l1constants);
|
|
218
|
+
const epoch = getEpochNumberAtTimestamp(ts, this.l1constants);
|
|
161
219
|
return {
|
|
162
|
-
epoch: getEpochNumberAtTimestamp(ts, this.l1constants),
|
|
163
|
-
ts: getTimestampForSlot(slot, this.l1constants),
|
|
164
220
|
slot,
|
|
221
|
+
epoch,
|
|
222
|
+
ts: getTimestampForSlot(slot, this.l1constants),
|
|
165
223
|
};
|
|
166
224
|
}
|
|
167
225
|
|
|
@@ -194,7 +252,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
194
252
|
public async isEscapeHatchOpenAtSlot(slot: SlotTag = 'now'): Promise<boolean> {
|
|
195
253
|
const epoch =
|
|
196
254
|
slot === 'now'
|
|
197
|
-
? this.
|
|
255
|
+
? this.getEpochNow()
|
|
198
256
|
: slot === 'next'
|
|
199
257
|
? this.getEpochAndSlotInNextL1Slot().epoch
|
|
200
258
|
: getEpochAtSlot(slot, this.l1constants);
|
|
@@ -229,7 +287,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
229
287
|
return epochData;
|
|
230
288
|
}
|
|
231
289
|
|
|
232
|
-
private getEpochAndTimestamp(slot: SlotTag = 'now') {
|
|
290
|
+
private getEpochAndTimestamp(slot: SlotTag = 'now'): { epoch: EpochNumber; ts: bigint } {
|
|
233
291
|
if (slot === 'now') {
|
|
234
292
|
return this.getEpochAndSlotNow();
|
|
235
293
|
} else if (slot === 'next') {
|
|
@@ -279,13 +337,24 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
279
337
|
return BigInt(keccak256(this.getProposerIndexEncoding(epoch, slot, seed))) % size;
|
|
280
338
|
}
|
|
281
339
|
|
|
282
|
-
/** Returns the current and next L2 slot
|
|
340
|
+
/** Returns the current and next L2 slot in next eth L1 Slot. */
|
|
283
341
|
public getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
284
|
-
const
|
|
342
|
+
const currentSlot = this.getSlotNow();
|
|
285
343
|
const next = this.getEpochAndSlotInNextL1Slot();
|
|
286
344
|
|
|
287
345
|
return {
|
|
288
|
-
currentSlot
|
|
346
|
+
currentSlot,
|
|
347
|
+
nextSlot: next.slot,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Returns the taget and next L2 slot in the next L1 slot */
|
|
352
|
+
public getTargetAndNextSlot(): { targetSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
353
|
+
const targetSlot = this.getTargetSlot();
|
|
354
|
+
const next = this.getTargetEpochAndSlotInNextL1Slot();
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
targetSlot,
|
|
289
358
|
nextSlot: next.slot,
|
|
290
359
|
};
|
|
291
360
|
}
|
|
@@ -368,10 +437,11 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
368
437
|
async getRegisteredValidators(): Promise<EthAddress[]> {
|
|
369
438
|
const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
|
|
370
439
|
const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
|
|
371
|
-
|
|
372
|
-
|
|
440
|
+
const now = this.dateProvider.now();
|
|
441
|
+
if (validatorRefreshTime < now) {
|
|
442
|
+
const currentSet = await this.rollup.getAttesters(BigInt(Math.floor(now / 1000)));
|
|
373
443
|
this.allValidators = new Set(currentSet.map(v => v.toString()));
|
|
374
|
-
this.lastValidatorRefresh =
|
|
444
|
+
this.lastValidatorRefresh = now;
|
|
375
445
|
}
|
|
376
446
|
return Array.from(this.allValidators.keys()).map(v => EthAddress.fromString(v));
|
|
377
447
|
}
|
|
@@ -3,7 +3,13 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
4
4
|
import { getEpochAtSlot, getSlotAtTimestamp, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
type EpochAndSlot,
|
|
8
|
+
type EpochCacheInterface,
|
|
9
|
+
type EpochCommitteeInfo,
|
|
10
|
+
PROPOSER_PIPELINING_SLOT_OFFSET,
|
|
11
|
+
type SlotTag,
|
|
12
|
+
} from '../epoch_cache.js';
|
|
7
13
|
|
|
8
14
|
/** Default L1 constants for testing. */
|
|
9
15
|
const DEFAULT_L1_CONSTANTS: L1RollupConstants = {
|
|
@@ -13,6 +19,8 @@ const DEFAULT_L1_CONSTANTS: L1RollupConstants = {
|
|
|
13
19
|
epochDuration: 16,
|
|
14
20
|
ethereumSlotDuration: 12,
|
|
15
21
|
proofSubmissionEpochs: 2,
|
|
22
|
+
targetCommitteeSize: 48,
|
|
23
|
+
rollupManaLimit: Number.MAX_SAFE_INTEGER,
|
|
16
24
|
};
|
|
17
25
|
|
|
18
26
|
/**
|
|
@@ -30,6 +38,7 @@ export class TestEpochCache implements EpochCacheInterface {
|
|
|
30
38
|
private seed: bigint = 0n;
|
|
31
39
|
private registeredValidators: EthAddress[] = [];
|
|
32
40
|
private l1Constants: L1RollupConstants;
|
|
41
|
+
private proposerPipeliningEnabled = false;
|
|
33
42
|
|
|
34
43
|
constructor(l1Constants: Partial<L1RollupConstants> = {}) {
|
|
35
44
|
this.l1Constants = { ...DEFAULT_L1_CONSTANTS, ...l1Constants };
|
|
@@ -102,6 +111,10 @@ export class TestEpochCache implements EpochCacheInterface {
|
|
|
102
111
|
return this.l1Constants;
|
|
103
112
|
}
|
|
104
113
|
|
|
114
|
+
setProposerPipeliningEnabled(enabled: boolean): void {
|
|
115
|
+
this.proposerPipeliningEnabled = enabled;
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
getCommittee(_slot?: SlotTag): Promise<EpochCommitteeInfo> {
|
|
106
119
|
const epoch = getEpochAtSlot(this.currentSlot, this.l1Constants);
|
|
107
120
|
return Promise.resolve({
|
|
@@ -112,19 +125,58 @@ export class TestEpochCache implements EpochCacheInterface {
|
|
|
112
125
|
});
|
|
113
126
|
}
|
|
114
127
|
|
|
128
|
+
getSlotNow(): SlotNumber {
|
|
129
|
+
return this.currentSlot;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getTargetSlot(): SlotNumber {
|
|
133
|
+
return this.proposerPipeliningEnabled
|
|
134
|
+
? SlotNumber(this.currentSlot + PROPOSER_PIPELINING_SLOT_OFFSET)
|
|
135
|
+
: this.currentSlot;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getEpochNow(): EpochNumber {
|
|
139
|
+
return getEpochAtSlot(this.currentSlot, this.l1Constants);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getTargetEpoch(): EpochNumber {
|
|
143
|
+
return getEpochAtSlot(this.getTargetSlot(), this.l1Constants);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
isProposerPipeliningEnabled(): boolean {
|
|
147
|
+
return this.proposerPipeliningEnabled;
|
|
148
|
+
}
|
|
149
|
+
|
|
115
150
|
getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
|
|
116
|
-
const
|
|
117
|
-
const ts = getTimestampRangeForEpoch(
|
|
118
|
-
return {
|
|
151
|
+
const epochNow = getEpochAtSlot(this.currentSlot, this.l1Constants);
|
|
152
|
+
const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
|
|
153
|
+
return {
|
|
154
|
+
epoch: epochNow,
|
|
155
|
+
slot: this.currentSlot,
|
|
156
|
+
ts,
|
|
157
|
+
nowMs: ts * 1000n,
|
|
158
|
+
};
|
|
119
159
|
}
|
|
120
160
|
|
|
121
|
-
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
122
|
-
const
|
|
123
|
-
const nextSlotTs =
|
|
161
|
+
getEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
162
|
+
const nowTs = getTimestampRangeForEpoch(getEpochAtSlot(this.currentSlot, this.l1Constants), this.l1Constants)[0];
|
|
163
|
+
const nextSlotTs = nowTs + BigInt(this.l1Constants.ethereumSlotDuration);
|
|
124
164
|
const nextSlot = getSlotAtTimestamp(nextSlotTs, this.l1Constants);
|
|
125
|
-
const
|
|
126
|
-
const ts = getTimestampRangeForEpoch(
|
|
127
|
-
return {
|
|
165
|
+
const epochNow = getEpochAtSlot(nextSlot, this.l1Constants);
|
|
166
|
+
const ts = getTimestampRangeForEpoch(epochNow, this.l1Constants)[0];
|
|
167
|
+
return {
|
|
168
|
+
epoch: epochNow,
|
|
169
|
+
slot: nextSlot,
|
|
170
|
+
ts,
|
|
171
|
+
nowSeconds: nowTs,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
176
|
+
const result = this.getEpochAndSlotInNextL1Slot();
|
|
177
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
178
|
+
const targetSlot = SlotNumber(result.slot + offset);
|
|
179
|
+
return { ...result, slot: targetSlot, epoch: getEpochAtSlot(targetSlot, this.l1Constants) };
|
|
128
180
|
}
|
|
129
181
|
|
|
130
182
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}` {
|
|
@@ -140,9 +192,22 @@ export class TestEpochCache implements EpochCacheInterface {
|
|
|
140
192
|
}
|
|
141
193
|
|
|
142
194
|
getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
195
|
+
const currentSlot = this.getSlotNow();
|
|
196
|
+
const next = this.getEpochAndSlotInNextL1Slot();
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
currentSlot,
|
|
200
|
+
nextSlot: next.slot,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
getTargetAndNextSlot(): { targetSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
205
|
+
const targetSlot = this.getTargetSlot();
|
|
206
|
+
const next = this.getTargetEpochAndSlotInNextL1Slot();
|
|
207
|
+
|
|
143
208
|
return {
|
|
144
|
-
|
|
145
|
-
nextSlot:
|
|
209
|
+
targetSlot,
|
|
210
|
+
nextSlot: next.slot,
|
|
146
211
|
};
|
|
147
212
|
}
|
|
148
213
|
|
|
@@ -163,6 +228,10 @@ export class TestEpochCache implements EpochCacheInterface {
|
|
|
163
228
|
return Promise.resolve(validators.filter(v => committeeSet.has(v.toString())));
|
|
164
229
|
}
|
|
165
230
|
|
|
231
|
+
isEscapeHatchOpen(_epoch: EpochNumber): Promise<boolean> {
|
|
232
|
+
return Promise.resolve(this.escapeHatchOpen);
|
|
233
|
+
}
|
|
234
|
+
|
|
166
235
|
isEscapeHatchOpenAtSlot(_slot?: SlotTag): Promise<boolean> {
|
|
167
236
|
return Promise.resolve(this.escapeHatchOpen);
|
|
168
237
|
}
|