@aztec/epoch-cache 0.0.1-commit.f146247c → 0.0.1-commit.f1b29a41e
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 +84 -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 +101 -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 target 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfY2FjaGUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9lcG9jaF9jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQW9CLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDMUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQ0wsS0FBSyxpQkFBaUIsRUFRdkIsTUFBTSw2QkFBNkIsQ0FBQztBQUlyQyxPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBOEIsTUFBTSxhQUFhLENBQUM7QUFFaEYsK0VBQStFO0FBQy9FLGVBQU8sTUFBTSwrQkFBK0IsSUFBSSxDQUFDO0FBRWpELHdEQUF3RDtBQUN4RCxNQUFNLE1BQU0sWUFBWSxHQUFHO0lBQ3pCLElBQUksRUFBRSxVQUFVLENBQUM7SUFDakIsS0FBSyxFQUFFLFdBQVcsQ0FBQztJQUNuQixFQUFFLEVBQUUsTUFBTSxDQUFDO0NBQ1osQ0FBQztBQUVGLE1BQU0sTUFBTSxrQkFBa0IsR0FBRztJQUMvQixTQUFTLEVBQUUsVUFBVSxFQUFFLEdBQUcsU0FBUyxDQUFDO0lBQ3BDLElBQUksRUFBRSxNQUFNLENBQUM7SUFDYixLQUFLLEVBQUUsV0FBVyxDQUFDO0lBQ25CLCtEQUErRDtJQUMvRCxpQkFBaUIsRUFBRSxPQUFPLENBQUM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sTUFBTSxPQUFPLEdBQUcsS0FBSyxHQUFHLE1BQU0sR0FBRyxVQUFVLENBQUM7QUFFbEQsTUFBTSxXQUFXLG1CQUFtQjtJQUNsQyxZQUFZLENBQUMsSUFBSSxFQUFFLE9BQU8sR0FBRyxTQUFTLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDckUsVUFB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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, getSlotAtNextL1Block, 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,14 +262,26 @@ 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,
|
|
233
270
|
nextSlot: next.slot
|
|
234
271
|
};
|
|
235
272
|
}
|
|
273
|
+
/** Returns the target and next L2 slot in the next L1 slot. */ getTargetAndNextSlot() {
|
|
274
|
+
const nowSeconds = BigInt(this.dateProvider.nowInSeconds());
|
|
275
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
276
|
+
const currentSlot = getSlotAtTimestamp(nowSeconds, this.l1constants);
|
|
277
|
+
const targetSlot = SlotNumber(currentSlot + offset);
|
|
278
|
+
const nextL2SlotOnL1 = getSlotAtNextL1Block(nowSeconds, this.l1constants);
|
|
279
|
+
const nextSlot = SlotNumber(nextL2SlotOnL1 + offset);
|
|
280
|
+
return {
|
|
281
|
+
targetSlot,
|
|
282
|
+
nextSlot
|
|
283
|
+
};
|
|
284
|
+
}
|
|
236
285
|
/**
|
|
237
286
|
* Get the proposer attester address in the given L2 slot
|
|
238
287
|
* @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
|
|
@@ -290,10 +339,11 @@ import { getEpochCacheConfigEnvVars } from './config.js';
|
|
|
290
339
|
async getRegisteredValidators() {
|
|
291
340
|
const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
|
|
292
341
|
const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
|
|
293
|
-
|
|
294
|
-
|
|
342
|
+
const now = this.dateProvider.now();
|
|
343
|
+
if (validatorRefreshTime < now) {
|
|
344
|
+
const currentSet = await this.rollup.getAttesters(BigInt(Math.floor(now / 1000)));
|
|
295
345
|
this.allValidators = new Set(currentSet.map((v)=>v.toString()));
|
|
296
|
-
this.lastValidatorRefresh =
|
|
346
|
+
this.lastValidatorRefresh = now;
|
|
297
347
|
}
|
|
298
348
|
return Array.from(this.allValidators.keys()).map((v)=>EthAddress.fromString(v));
|
|
299
349
|
}
|
|
@@ -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.f1b29a41e",
|
|
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.f1b29a41e",
|
|
30
|
+
"@aztec/foundation": "0.0.1-commit.f1b29a41e",
|
|
31
|
+
"@aztec/l1-artifacts": "0.0.1-commit.f1b29a41e",
|
|
32
|
+
"@aztec/stdlib": "0.0.1-commit.f1b29a41e",
|
|
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,24 @@ import {
|
|
|
8
9
|
type L1RollupConstants,
|
|
9
10
|
getEpochAtSlot,
|
|
10
11
|
getEpochNumberAtTimestamp,
|
|
12
|
+
getNextL1SlotTimestamp,
|
|
13
|
+
getSlotAtNextL1Block,
|
|
11
14
|
getSlotAtTimestamp,
|
|
12
15
|
getSlotRangeForEpoch,
|
|
13
16
|
getTimestampForSlot,
|
|
14
|
-
getTimestampRangeForEpoch,
|
|
15
17
|
} from '@aztec/stdlib/epoch-helpers';
|
|
16
18
|
|
|
17
|
-
import { createPublicClient, encodeAbiParameters,
|
|
19
|
+
import { createPublicClient, encodeAbiParameters, keccak256 } from 'viem';
|
|
18
20
|
|
|
19
21
|
import { type EpochCacheConfig, getEpochCacheConfigEnvVars } from './config.js';
|
|
20
22
|
|
|
23
|
+
/** When proposer pipelining is enabled, the proposer builds one slot ahead. */
|
|
24
|
+
export const PROPOSER_PIPELINING_SLOT_OFFSET = 1;
|
|
25
|
+
|
|
26
|
+
/** Flat return type for compound epoch/slot getters. */
|
|
21
27
|
export type EpochAndSlot = {
|
|
22
|
-
epoch: EpochNumber;
|
|
23
28
|
slot: SlotNumber;
|
|
29
|
+
epoch: EpochNumber;
|
|
24
30
|
ts: bigint;
|
|
25
31
|
};
|
|
26
32
|
|
|
@@ -36,15 +42,26 @@ export type SlotTag = 'now' | 'next' | SlotNumber;
|
|
|
36
42
|
|
|
37
43
|
export interface EpochCacheInterface {
|
|
38
44
|
getCommittee(slot: SlotTag | undefined): Promise<EpochCommitteeInfo>;
|
|
45
|
+
getSlotNow(): SlotNumber;
|
|
46
|
+
getTargetSlot(): SlotNumber;
|
|
47
|
+
getEpochNow(): EpochNumber;
|
|
48
|
+
getTargetEpoch(): EpochNumber;
|
|
39
49
|
getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint };
|
|
40
|
-
getEpochAndSlotInNextL1Slot(): EpochAndSlot & {
|
|
50
|
+
getEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint };
|
|
51
|
+
/** Returns epoch/slot info for the next L1 slot with pipeline offset applied. */
|
|
52
|
+
getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint };
|
|
53
|
+
isProposerPipeliningEnabled(): boolean;
|
|
54
|
+
isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean>;
|
|
55
|
+
isEscapeHatchOpenAtSlot(slot: SlotTag): Promise<boolean>;
|
|
41
56
|
getProposerIndexEncoding(epoch: EpochNumber, slot: SlotNumber, seed: bigint): `0x${string}`;
|
|
42
57
|
computeProposerIndex(slot: SlotNumber, epoch: EpochNumber, seed: bigint, size: bigint): bigint;
|
|
43
58
|
getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber };
|
|
59
|
+
getTargetAndNextSlot(): { targetSlot: SlotNumber; nextSlot: SlotNumber };
|
|
44
60
|
getProposerAttesterAddressInSlot(slot: SlotNumber): Promise<EthAddress | undefined>;
|
|
45
61
|
getRegisteredValidators(): Promise<EthAddress[]>;
|
|
46
62
|
isInCommittee(slot: SlotTag, validator: EthAddress): Promise<boolean>;
|
|
47
63
|
filterInCommittee(slot: SlotTag, validators: EthAddress[]): Promise<EthAddress[]>;
|
|
64
|
+
getL1Constants(): L1RollupConstants;
|
|
48
65
|
}
|
|
49
66
|
|
|
50
67
|
/**
|
|
@@ -63,6 +80,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
63
80
|
private lastValidatorRefresh = 0;
|
|
64
81
|
private readonly log: Logger = createLogger('epoch-cache');
|
|
65
82
|
|
|
83
|
+
protected enableProposerPipelining: boolean;
|
|
84
|
+
|
|
66
85
|
constructor(
|
|
67
86
|
private rollup: RollupContract,
|
|
68
87
|
private readonly l1constants: L1RollupConstants & {
|
|
@@ -70,10 +89,12 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
70
89
|
lagInEpochsForRandao: number;
|
|
71
90
|
},
|
|
72
91
|
private readonly dateProvider: DateProvider = new DateProvider(),
|
|
73
|
-
protected readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60 },
|
|
92
|
+
protected readonly config = { cacheSize: 12, validatorRefreshIntervalSeconds: 60, enableProposerPipelining: false },
|
|
74
93
|
) {
|
|
94
|
+
this.enableProposerPipelining = this.config.enableProposerPipelining;
|
|
75
95
|
this.log.debug(`Initialized EpochCache`, {
|
|
76
96
|
l1constants,
|
|
97
|
+
enableProposerPipelining: this.enableProposerPipelining,
|
|
77
98
|
});
|
|
78
99
|
}
|
|
79
100
|
|
|
@@ -92,7 +113,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
92
113
|
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
93
114
|
const publicClient = createPublicClient({
|
|
94
115
|
chain: chain.chainInfo,
|
|
95
|
-
transport:
|
|
116
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
96
117
|
pollingInterval: config.viemPollingIntervalMS,
|
|
97
118
|
});
|
|
98
119
|
rollup = new RollupContract(publicClient, rollupOrAddress.toString());
|
|
@@ -106,6 +127,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
106
127
|
epochDuration,
|
|
107
128
|
lagInEpochsForValidatorSet,
|
|
108
129
|
lagInEpochsForRandao,
|
|
130
|
+
targetCommitteeSize,
|
|
131
|
+
rollupManaLimit,
|
|
109
132
|
] = await Promise.all([
|
|
110
133
|
rollup.getL1StartBlock(),
|
|
111
134
|
rollup.getL1GenesisTime(),
|
|
@@ -114,6 +137,8 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
114
137
|
rollup.getEpochDuration(),
|
|
115
138
|
rollup.getLagInEpochsForValidatorSet(),
|
|
116
139
|
rollup.getLagInEpochsForRandao(),
|
|
140
|
+
rollup.getTargetCommitteeSize(),
|
|
141
|
+
rollup.getManaLimit(),
|
|
117
142
|
] as const);
|
|
118
143
|
|
|
119
144
|
const l1RollupConstants = {
|
|
@@ -125,43 +150,77 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
125
150
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
126
151
|
lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
|
|
127
152
|
lagInEpochsForRandao: Number(lagInEpochsForRandao),
|
|
153
|
+
targetCommitteeSize: Number(targetCommitteeSize),
|
|
154
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
128
155
|
};
|
|
129
156
|
|
|
130
|
-
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider
|
|
157
|
+
return new EpochCache(rollup, l1RollupConstants, deps.dateProvider, {
|
|
158
|
+
cacheSize: 12,
|
|
159
|
+
validatorRefreshIntervalSeconds: 60,
|
|
160
|
+
enableProposerPipelining: config.enableProposerPipelining,
|
|
161
|
+
});
|
|
131
162
|
}
|
|
132
163
|
|
|
133
164
|
public getL1Constants(): L1RollupConstants {
|
|
134
165
|
return this.l1constants;
|
|
135
166
|
}
|
|
136
167
|
|
|
168
|
+
public isProposerPipeliningEnabled(): boolean {
|
|
169
|
+
return this.enableProposerPipelining;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public getSlotNow(): SlotNumber {
|
|
173
|
+
return this.getEpochAndSlotNow().slot;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public getTargetSlot(): SlotNumber {
|
|
177
|
+
const slotNow = this.getSlotNow();
|
|
178
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
179
|
+
return SlotNumber(slotNow + offset);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public getEpochNow(): EpochNumber {
|
|
183
|
+
return this.getEpochAndSlotNow().epoch;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public getTargetEpoch(): EpochNumber {
|
|
187
|
+
return getEpochAtSlot(this.getTargetSlot(), this.l1constants);
|
|
188
|
+
}
|
|
189
|
+
|
|
137
190
|
public getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
|
|
138
191
|
const nowMs = BigInt(this.dateProvider.now());
|
|
139
192
|
const nowSeconds = nowMs / 1000n;
|
|
140
193
|
return { ...this.getEpochAndSlotAtTimestamp(nowSeconds), nowMs };
|
|
141
194
|
}
|
|
142
195
|
|
|
143
|
-
|
|
144
|
-
return
|
|
196
|
+
private getEpochAndSlotAtSlot(slot: SlotNumber): EpochAndSlot {
|
|
197
|
+
return this.getEpochAndSlotAtTimestamp(getTimestampForSlot(slot, this.l1constants));
|
|
145
198
|
}
|
|
146
199
|
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
return {
|
|
200
|
+
public getEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
201
|
+
const nowSeconds = this.dateProvider.nowInSeconds();
|
|
202
|
+
const nextSlotTs = getNextL1SlotTimestamp(nowSeconds, this.l1constants);
|
|
203
|
+
return { ...this.getEpochAndSlotAtTimestamp(nextSlotTs), nowSeconds: BigInt(nowSeconds) };
|
|
151
204
|
}
|
|
152
205
|
|
|
153
|
-
public
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
206
|
+
public getTargetEpochAndSlotInNextL1Slot(): EpochAndSlot & { nowSeconds: bigint } {
|
|
207
|
+
if (!this.isProposerPipeliningEnabled()) {
|
|
208
|
+
return this.getEpochAndSlotInNextL1Slot();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const result = this.getEpochAndSlotInNextL1Slot();
|
|
212
|
+
const offset = PROPOSER_PIPELINING_SLOT_OFFSET;
|
|
213
|
+
const targetSlot = SlotNumber(result.slot + offset);
|
|
214
|
+
return { ...result, slot: targetSlot, epoch: getEpochAtSlot(targetSlot, this.l1constants) };
|
|
157
215
|
}
|
|
158
216
|
|
|
159
217
|
private getEpochAndSlotAtTimestamp(ts: bigint): EpochAndSlot {
|
|
160
218
|
const slot = getSlotAtTimestamp(ts, this.l1constants);
|
|
219
|
+
const epoch = getEpochNumberAtTimestamp(ts, this.l1constants);
|
|
161
220
|
return {
|
|
162
|
-
epoch: getEpochNumberAtTimestamp(ts, this.l1constants),
|
|
163
|
-
ts: getTimestampForSlot(slot, this.l1constants),
|
|
164
221
|
slot,
|
|
222
|
+
epoch,
|
|
223
|
+
ts: getTimestampForSlot(slot, this.l1constants),
|
|
165
224
|
};
|
|
166
225
|
}
|
|
167
226
|
|
|
@@ -194,7 +253,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
194
253
|
public async isEscapeHatchOpenAtSlot(slot: SlotTag = 'now'): Promise<boolean> {
|
|
195
254
|
const epoch =
|
|
196
255
|
slot === 'now'
|
|
197
|
-
? this.
|
|
256
|
+
? this.getEpochNow()
|
|
198
257
|
: slot === 'next'
|
|
199
258
|
? this.getEpochAndSlotInNextL1Slot().epoch
|
|
200
259
|
: getEpochAtSlot(slot, this.l1constants);
|
|
@@ -229,7 +288,7 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
229
288
|
return epochData;
|
|
230
289
|
}
|
|
231
290
|
|
|
232
|
-
private getEpochAndTimestamp(slot: SlotTag = 'now') {
|
|
291
|
+
private getEpochAndTimestamp(slot: SlotTag = 'now'): { epoch: EpochNumber; ts: bigint } {
|
|
233
292
|
if (slot === 'now') {
|
|
234
293
|
return this.getEpochAndSlotNow();
|
|
235
294
|
} else if (slot === 'next') {
|
|
@@ -279,17 +338,31 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
279
338
|
return BigInt(keccak256(this.getProposerIndexEncoding(epoch, slot, seed))) % size;
|
|
280
339
|
}
|
|
281
340
|
|
|
282
|
-
/** Returns the current and next L2 slot
|
|
341
|
+
/** Returns the current and next L2 slot in next eth L1 Slot. */
|
|
283
342
|
public getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
284
|
-
const
|
|
343
|
+
const currentSlot = this.getSlotNow();
|
|
285
344
|
const next = this.getEpochAndSlotInNextL1Slot();
|
|
286
345
|
|
|
287
346
|
return {
|
|
288
|
-
currentSlot
|
|
347
|
+
currentSlot,
|
|
289
348
|
nextSlot: next.slot,
|
|
290
349
|
};
|
|
291
350
|
}
|
|
292
351
|
|
|
352
|
+
/** Returns the target and next L2 slot in the next L1 slot. */
|
|
353
|
+
public getTargetAndNextSlot(): { targetSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
354
|
+
const nowSeconds = BigInt(this.dateProvider.nowInSeconds());
|
|
355
|
+
const offset = this.isProposerPipeliningEnabled() ? PROPOSER_PIPELINING_SLOT_OFFSET : 0;
|
|
356
|
+
|
|
357
|
+
const currentSlot = getSlotAtTimestamp(nowSeconds, this.l1constants);
|
|
358
|
+
const targetSlot = SlotNumber(currentSlot + offset);
|
|
359
|
+
|
|
360
|
+
const nextL2SlotOnL1 = getSlotAtNextL1Block(nowSeconds, this.l1constants);
|
|
361
|
+
const nextSlot = SlotNumber(nextL2SlotOnL1 + offset);
|
|
362
|
+
|
|
363
|
+
return { targetSlot, nextSlot };
|
|
364
|
+
}
|
|
365
|
+
|
|
293
366
|
/**
|
|
294
367
|
* Get the proposer attester address in the given L2 slot
|
|
295
368
|
* @returns The proposer attester address. If the committee does not exist, we throw a NoCommitteeError.
|
|
@@ -368,10 +441,11 @@ export class EpochCache implements EpochCacheInterface {
|
|
|
368
441
|
async getRegisteredValidators(): Promise<EthAddress[]> {
|
|
369
442
|
const validatorRefreshIntervalMs = this.config.validatorRefreshIntervalSeconds * 1000;
|
|
370
443
|
const validatorRefreshTime = this.lastValidatorRefresh + validatorRefreshIntervalMs;
|
|
371
|
-
|
|
372
|
-
|
|
444
|
+
const now = this.dateProvider.now();
|
|
445
|
+
if (validatorRefreshTime < now) {
|
|
446
|
+
const currentSet = await this.rollup.getAttesters(BigInt(Math.floor(now / 1000)));
|
|
373
447
|
this.allValidators = new Set(currentSet.map(v => v.toString()));
|
|
374
|
-
this.lastValidatorRefresh =
|
|
448
|
+
this.lastValidatorRefresh = now;
|
|
375
449
|
}
|
|
376
450
|
return Array.from(this.allValidators.keys()).map(v => EthAddress.fromString(v));
|
|
377
451
|
}
|
|
@@ -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
|
}
|