@aztec/sequencer-client 0.0.1-commit.3e3d0c9cd → 0.0.1-commit.3fd054f6
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/client/sequencer-client.d.ts +4 -13
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +29 -80
- package/dest/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -4
- package/dest/global_variable_builder/global_builder.d.ts +13 -7
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +22 -22
- package/dest/global_variable_builder/index.d.ts +2 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/publisher/config.d.ts +13 -1
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +17 -2
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +2 -2
- package/dest/publisher/sequencer-publisher.d.ts +9 -4
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +22 -8
- package/dest/sequencer/checkpoint_proposal_job.d.ts +12 -4
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +122 -73
- package/dest/sequencer/events.d.ts +2 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +5 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +11 -0
- package/dest/sequencer/sequencer.d.ts +5 -5
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +60 -48
- package/dest/test/mock_checkpoint_builder.d.ts +4 -8
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/package.json +27 -27
- package/src/client/sequencer-client.ts +39 -103
- package/src/config.ts +4 -3
- package/src/global_variable_builder/global_builder.ts +22 -24
- package/src/global_variable_builder/index.ts +1 -1
- package/src/publisher/config.ts +32 -0
- package/src/publisher/sequencer-publisher-factory.ts +3 -3
- package/src/publisher/sequencer-publisher.ts +28 -10
- package/src/sequencer/checkpoint_proposal_job.ts +164 -82
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/metrics.ts +14 -0
- package/src/sequencer/sequencer.ts +85 -54
- package/src/test/mock_checkpoint_builder.ts +3 -3
|
@@ -19,15 +19,10 @@ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
|
19
19
|
import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
20
20
|
import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
21
21
|
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
type SequencerClientConfig,
|
|
25
|
-
getPublisherConfigFromSequencerConfig,
|
|
26
|
-
} from '../config.js';
|
|
27
|
-
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
22
|
+
import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
|
|
23
|
+
import type { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
28
24
|
import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
29
25
|
import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
30
|
-
import { SequencerTimetable } from '../sequencer/timetable.js';
|
|
31
26
|
|
|
32
27
|
/**
|
|
33
28
|
* Encapsulates the full sequencer and publisher.
|
|
@@ -70,7 +65,9 @@ export class SequencerClient {
|
|
|
70
65
|
dateProvider: DateProvider;
|
|
71
66
|
epochCache?: EpochCache;
|
|
72
67
|
l1TxUtils: L1TxUtils[];
|
|
68
|
+
funderL1TxUtils?: L1TxUtils;
|
|
73
69
|
nodeKeyStore: KeystoreManager;
|
|
70
|
+
globalVariableBuilder: GlobalVariableBuilder;
|
|
74
71
|
},
|
|
75
72
|
) {
|
|
76
73
|
const {
|
|
@@ -92,16 +89,14 @@ export class SequencerClient {
|
|
|
92
89
|
publicClient,
|
|
93
90
|
l1TxUtils.map(x => x.getSenderAddress()),
|
|
94
91
|
);
|
|
95
|
-
const publisherManager = new PublisherManager(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
);
|
|
92
|
+
const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config), {
|
|
93
|
+
bindings: log.getBindings(),
|
|
94
|
+
funder: deps.funderL1TxUtils,
|
|
95
|
+
});
|
|
100
96
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
101
|
-
const [l1GenesisTime, slotDuration,
|
|
97
|
+
const [l1GenesisTime, slotDuration, rollupManaLimit] = await Promise.all([
|
|
102
98
|
rollupContract.getL1GenesisTime(),
|
|
103
99
|
rollupContract.getSlotDuration(),
|
|
104
|
-
rollupContract.getVersion(),
|
|
105
100
|
rollupContract.getManaLimit().then(Number),
|
|
106
101
|
] as const);
|
|
107
102
|
|
|
@@ -118,6 +113,7 @@ export class SequencerClient {
|
|
|
118
113
|
l1ChainId: chainId,
|
|
119
114
|
viemPollingIntervalMS: config.viemPollingIntervalMS,
|
|
120
115
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
116
|
+
enableProposerPipelining: config.enableProposerPipelining,
|
|
121
117
|
},
|
|
122
118
|
{ dateProvider: deps.dateProvider },
|
|
123
119
|
));
|
|
@@ -144,13 +140,7 @@ export class SequencerClient {
|
|
|
144
140
|
|
|
145
141
|
const ethereumSlotDuration = config.ethereumSlotDuration;
|
|
146
142
|
|
|
147
|
-
const globalsBuilder =
|
|
148
|
-
...config,
|
|
149
|
-
l1GenesisTime,
|
|
150
|
-
slotDuration: Number(slotDuration),
|
|
151
|
-
ethereumSlotDuration,
|
|
152
|
-
rollupVersion,
|
|
153
|
-
});
|
|
143
|
+
const globalsBuilder = deps.globalVariableBuilder;
|
|
154
144
|
|
|
155
145
|
// When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
|
|
156
146
|
// Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
|
|
@@ -160,12 +150,7 @@ export class SequencerClient {
|
|
|
160
150
|
const l1PublishingTimeBasedOnChain = isAnvilTestChain(config.l1ChainId) ? 1 : ethereumSlotDuration;
|
|
161
151
|
const l1PublishingTime = config.l1PublishingTime ?? l1PublishingTimeBasedOnChain;
|
|
162
152
|
|
|
163
|
-
const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock
|
|
164
|
-
config,
|
|
165
|
-
rollupManaLimit,
|
|
166
|
-
l1PublishingTime,
|
|
167
|
-
log,
|
|
168
|
-
);
|
|
153
|
+
const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock } = capPerBlockLimits(config, rollupManaLimit, log);
|
|
169
154
|
|
|
170
155
|
const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration, rollupManaLimit };
|
|
171
156
|
|
|
@@ -183,7 +168,7 @@ export class SequencerClient {
|
|
|
183
168
|
deps.dateProvider,
|
|
184
169
|
epochCache,
|
|
185
170
|
rollupContract,
|
|
186
|
-
{ ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock
|
|
171
|
+
{ ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock },
|
|
187
172
|
telemetryClient,
|
|
188
173
|
log,
|
|
189
174
|
);
|
|
@@ -211,7 +196,7 @@ export class SequencerClient {
|
|
|
211
196
|
await this.validatorClient?.start();
|
|
212
197
|
this.sequencer.start();
|
|
213
198
|
this.l1Metrics?.start();
|
|
214
|
-
await this.publisherManager.
|
|
199
|
+
await this.publisherManager.start();
|
|
215
200
|
}
|
|
216
201
|
|
|
217
202
|
/**
|
|
@@ -220,7 +205,7 @@ export class SequencerClient {
|
|
|
220
205
|
public async stop() {
|
|
221
206
|
await this.sequencer.stop();
|
|
222
207
|
await this.validatorClient?.stop();
|
|
223
|
-
this.publisherManager.
|
|
208
|
+
await this.publisherManager.stop();
|
|
224
209
|
this.l1Metrics?.stop();
|
|
225
210
|
}
|
|
226
211
|
|
|
@@ -248,88 +233,39 @@ export class SequencerClient {
|
|
|
248
233
|
}
|
|
249
234
|
|
|
250
235
|
/**
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* Otherwise, derives it as (checkpointLimit / maxBlocks) * multiplier, capped at the checkpoint limit.
|
|
236
|
+
* Caps operator-provided per-block limits at checkpoint-level limits.
|
|
237
|
+
* Returns undefined for any limit the operator didn't set — the checkpoint builder handles redistribution.
|
|
254
238
|
*/
|
|
255
|
-
|
|
239
|
+
function capPerBlockLimits(
|
|
256
240
|
config: SequencerClientConfig,
|
|
257
241
|
rollupManaLimit: number,
|
|
258
|
-
l1PublishingTime: number,
|
|
259
242
|
log: ReturnType<typeof createLogger>,
|
|
260
|
-
): { maxL2BlockGas: number; maxDABlockGas: number; maxTxsPerBlock: number
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
p2pPropagationTime: config.attestationPropagationTime,
|
|
266
|
-
blockDurationMs: config.blockDurationMs,
|
|
267
|
-
enforce: config.enforceTimeTable ?? DefaultSequencerConfig.enforceTimeTable,
|
|
268
|
-
}).maxNumberOfBlocks;
|
|
269
|
-
|
|
270
|
-
const multiplier = config.perBlockAllocationMultiplier ?? DefaultSequencerConfig.perBlockAllocationMultiplier;
|
|
271
|
-
|
|
272
|
-
// Compute maxL2BlockGas
|
|
273
|
-
let maxL2BlockGas: number;
|
|
274
|
-
if (config.maxL2BlockGas !== undefined) {
|
|
275
|
-
if (config.maxL2BlockGas > rollupManaLimit) {
|
|
276
|
-
log.warn(
|
|
277
|
-
`Provided MAX_L2_BLOCK_GAS ${config.maxL2BlockGas} exceeds L1 rollup mana limit ${rollupManaLimit} (capping)`,
|
|
278
|
-
);
|
|
279
|
-
maxL2BlockGas = rollupManaLimit;
|
|
280
|
-
} else {
|
|
281
|
-
maxL2BlockGas = config.maxL2BlockGas;
|
|
282
|
-
}
|
|
283
|
-
} else {
|
|
284
|
-
maxL2BlockGas = Math.min(rollupManaLimit, Math.ceil((rollupManaLimit / maxNumberOfBlocks) * multiplier));
|
|
243
|
+
): { maxL2BlockGas: number | undefined; maxDABlockGas: number | undefined; maxTxsPerBlock: number | undefined } {
|
|
244
|
+
let maxL2BlockGas = config.maxL2BlockGas;
|
|
245
|
+
if (maxL2BlockGas !== undefined && maxL2BlockGas > rollupManaLimit) {
|
|
246
|
+
log.warn(`Provided MAX_L2_BLOCK_GAS ${maxL2BlockGas} exceeds rollup mana limit ${rollupManaLimit} (capping)`);
|
|
247
|
+
maxL2BlockGas = rollupManaLimit;
|
|
285
248
|
}
|
|
286
249
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
`Provided MAX_DA_BLOCK_GAS ${config.maxDABlockGas} exceeds DA checkpoint limit ${daCheckpointLimit} (capping)`,
|
|
294
|
-
);
|
|
295
|
-
maxDABlockGas = daCheckpointLimit;
|
|
296
|
-
} else {
|
|
297
|
-
maxDABlockGas = config.maxDABlockGas;
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
maxDABlockGas = Math.min(daCheckpointLimit, Math.ceil((daCheckpointLimit / maxNumberOfBlocks) * multiplier));
|
|
250
|
+
let maxDABlockGas = config.maxDABlockGas;
|
|
251
|
+
if (maxDABlockGas !== undefined && maxDABlockGas > MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT) {
|
|
252
|
+
log.warn(
|
|
253
|
+
`Provided MAX_DA_BLOCK_GAS ${maxDABlockGas} exceeds DA checkpoint limit ${MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT} (capping)`,
|
|
254
|
+
);
|
|
255
|
+
maxDABlockGas = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT;
|
|
301
256
|
}
|
|
302
257
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)
|
|
311
|
-
maxTxsPerBlock = config.maxTxsPerCheckpoint;
|
|
312
|
-
} else {
|
|
313
|
-
maxTxsPerBlock = config.maxTxsPerBlock;
|
|
314
|
-
}
|
|
315
|
-
} else if (config.maxTxsPerCheckpoint !== undefined) {
|
|
316
|
-
maxTxsPerBlock = Math.min(
|
|
317
|
-
config.maxTxsPerCheckpoint,
|
|
318
|
-
Math.ceil((config.maxTxsPerCheckpoint / maxNumberOfBlocks) * multiplier),
|
|
258
|
+
let maxTxsPerBlock = config.maxTxsPerBlock;
|
|
259
|
+
if (
|
|
260
|
+
maxTxsPerBlock !== undefined &&
|
|
261
|
+
config.maxTxsPerCheckpoint !== undefined &&
|
|
262
|
+
maxTxsPerBlock > config.maxTxsPerCheckpoint
|
|
263
|
+
) {
|
|
264
|
+
log.warn(
|
|
265
|
+
`Provided MAX_TX_PER_BLOCK ${maxTxsPerBlock} exceeds MAX_TX_PER_CHECKPOINT ${config.maxTxsPerCheckpoint} (capping)`,
|
|
319
266
|
);
|
|
320
|
-
|
|
321
|
-
maxTxsPerBlock = defaultMaxTxsPerBlock;
|
|
267
|
+
maxTxsPerBlock = config.maxTxsPerCheckpoint;
|
|
322
268
|
}
|
|
323
269
|
|
|
324
|
-
|
|
325
|
-
maxL2BlockGas,
|
|
326
|
-
maxDABlockGas,
|
|
327
|
-
maxTxsPerBlock,
|
|
328
|
-
rollupManaLimit,
|
|
329
|
-
daCheckpointLimit,
|
|
330
|
-
maxNumberOfBlocks,
|
|
331
|
-
multiplier,
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock, maxBlocksPerCheckpoint: maxNumberOfBlocks };
|
|
270
|
+
return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock };
|
|
335
271
|
}
|
package/src/config.ts
CHANGED
|
@@ -13,8 +13,10 @@ import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
|
|
|
13
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
14
14
|
import {
|
|
15
15
|
type ChainConfig,
|
|
16
|
+
type PipelineConfig,
|
|
16
17
|
type SequencerConfig,
|
|
17
18
|
chainConfigMappings,
|
|
19
|
+
pipelineConfigMappings,
|
|
18
20
|
sharedSequencerConfigMappings,
|
|
19
21
|
} from '@aztec/stdlib/config';
|
|
20
22
|
import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
|
|
@@ -68,6 +70,7 @@ export type SequencerClientConfig = SequencerPublisherConfig &
|
|
|
68
70
|
SequencerConfig &
|
|
69
71
|
L1ReaderConfig &
|
|
70
72
|
ChainConfig &
|
|
73
|
+
PipelineConfig &
|
|
71
74
|
Pick<P2PConfig, 'txPublicSetupAllowListExtend'> &
|
|
72
75
|
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
|
|
73
76
|
|
|
@@ -119,9 +122,6 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
119
122
|
'Redistribute remaining checkpoint budget evenly across remaining blocks instead of allowing a single block to consume the entire remaining budget.',
|
|
120
123
|
...booleanConfigHelper(DefaultSequencerConfig.redistributeCheckpointBudget),
|
|
121
124
|
},
|
|
122
|
-
maxBlocksPerCheckpoint: {
|
|
123
|
-
description: 'Computed max number of blocks per checkpoint from timetable.',
|
|
124
|
-
},
|
|
125
125
|
coinbase: {
|
|
126
126
|
env: 'COINBASE',
|
|
127
127
|
parseEnv: (val: string) => (val ? EthAddress.fromString(val) : undefined),
|
|
@@ -244,6 +244,7 @@ export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientCo
|
|
|
244
244
|
...sequencerTxSenderConfigMappings,
|
|
245
245
|
...sequencerPublisherConfigMappings,
|
|
246
246
|
...chainConfigMappings,
|
|
247
|
+
...pipelineConfigMappings,
|
|
247
248
|
...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration', 'aztecSlotDuration', 'aztecEpochDuration']),
|
|
248
249
|
};
|
|
249
250
|
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
-
import { makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
3
|
-
import type { L1ContractsConfig } from '@aztec/ethereum/config';
|
|
4
1
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
5
|
-
import type {
|
|
2
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
6
3
|
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
7
4
|
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
8
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
9
6
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
10
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
11
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
12
|
-
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
10
|
+
import { type L1RollupConstants, getNextL1SlotTimestamp, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
11
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
14
12
|
import type {
|
|
15
13
|
CheckpointGlobalVariables,
|
|
@@ -17,7 +15,12 @@ import type {
|
|
|
17
15
|
} from '@aztec/stdlib/tx';
|
|
18
16
|
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
/** Configuration for the GlobalVariableBuilder (excludes L1 client config). */
|
|
19
|
+
export type GlobalVariableBuilderConfig = {
|
|
20
|
+
l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
|
|
21
|
+
ethereumSlotDuration: number;
|
|
22
|
+
rollupVersion: bigint;
|
|
23
|
+
} & Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'>;
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
26
|
* Simple global variables builder.
|
|
@@ -28,7 +31,6 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
28
31
|
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
29
32
|
|
|
30
33
|
private readonly rollupContract: RollupContract;
|
|
31
|
-
private readonly publicClient: ViemPublicClient;
|
|
32
34
|
private readonly ethereumSlotDuration: number;
|
|
33
35
|
private readonly aztecSlotDuration: number;
|
|
34
36
|
private readonly l1GenesisTime: bigint;
|
|
@@ -37,28 +39,18 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
37
39
|
private version: Fr;
|
|
38
40
|
|
|
39
41
|
constructor(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
private readonly dateProvider: DateProvider,
|
|
43
|
+
private readonly publicClient: ViemPublicClient,
|
|
44
|
+
config: GlobalVariableBuilderConfig,
|
|
43
45
|
) {
|
|
44
|
-
const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
|
|
45
|
-
|
|
46
|
-
const chain = createEthereumChain(l1RpcUrls, chainId);
|
|
47
|
-
|
|
48
46
|
this.version = new Fr(config.rollupVersion);
|
|
49
|
-
this.chainId = new Fr(
|
|
47
|
+
this.chainId = new Fr(this.publicClient.chain!.id);
|
|
50
48
|
|
|
51
49
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
52
50
|
this.aztecSlotDuration = config.slotDuration;
|
|
53
51
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
54
52
|
|
|
55
|
-
this.
|
|
56
|
-
chain: chain.chainInfo,
|
|
57
|
-
transport: makeL1HttpTransport(chain.rpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
58
|
-
pollingInterval: config.viemPollingIntervalMS,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
this.rollupContract = new RollupContract(this.publicClient, l1Contracts.rollupAddress);
|
|
53
|
+
this.rollupContract = new RollupContract(this.publicClient, config.l1Contracts.rollupAddress);
|
|
62
54
|
}
|
|
63
55
|
|
|
64
56
|
/**
|
|
@@ -74,7 +66,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
74
66
|
const earliestTimestamp = await this.rollupContract.getTimestampForSlot(
|
|
75
67
|
SlotNumber.fromBigInt(BigInt(lastCheckpoint.slotNumber) + 1n),
|
|
76
68
|
);
|
|
77
|
-
const nextEthTimestamp =
|
|
69
|
+
const nextEthTimestamp = getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
70
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
71
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
72
|
+
});
|
|
78
73
|
const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
|
|
79
74
|
|
|
80
75
|
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
@@ -109,7 +104,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
109
104
|
const slot: SlotNumber =
|
|
110
105
|
maybeSlot ??
|
|
111
106
|
(await this.rollupContract.getSlotAt(
|
|
112
|
-
|
|
107
|
+
getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
108
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
109
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
110
|
+
}),
|
|
113
111
|
));
|
|
114
112
|
|
|
115
113
|
const checkpointGlobalVariables = await this.buildCheckpointGlobalVariables(coinbase, feeRecipient, slot);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { GlobalVariableBuilder } from './global_builder.js';
|
|
1
|
+
export { GlobalVariableBuilder, type GlobalVariableBuilderConfig } from './global_builder.js';
|
package/src/publisher/config.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type L1TxUtilsConfig, l1TxUtilsConfigMappings } from '@aztec/ethereum/l
|
|
|
4
4
|
import { type ConfigMappingsType, SecretValue, booleanConfigHelper } from '@aztec/foundation/config';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
|
|
7
|
+
import { parseEther } from 'viem';
|
|
8
|
+
|
|
7
9
|
/** Configuration of the transaction publisher. */
|
|
8
10
|
export type TxSenderConfig = L1ReaderConfig & {
|
|
9
11
|
/** The private key to be used by the publisher. */
|
|
@@ -50,13 +52,37 @@ export type PublisherConfig = L1TxUtilsConfig &
|
|
|
50
52
|
publisherForwarderAddress?: EthAddress;
|
|
51
53
|
/** Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path */
|
|
52
54
|
l1TxFailedStore?: string;
|
|
55
|
+
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
56
|
+
publisherFundingThreshold?: bigint;
|
|
57
|
+
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
58
|
+
publisherFundingAmount?: bigint;
|
|
53
59
|
};
|
|
54
60
|
|
|
61
|
+
/** Shared config mappings for publisher funding, used by both sequencer and prover publisher configs. */
|
|
62
|
+
const publisherFundingConfigMappings = {
|
|
63
|
+
publisherFundingThreshold: {
|
|
64
|
+
env: 'PUBLISHER_FUNDING_THRESHOLD' as const,
|
|
65
|
+
description:
|
|
66
|
+
'Min ETH balance below which a publisher gets funded. Specified in ether (e.g. 0.1). Unset = funding disabled.',
|
|
67
|
+
parseEnv: (val: string) => parseEther(val),
|
|
68
|
+
},
|
|
69
|
+
publisherFundingAmount: {
|
|
70
|
+
env: 'PUBLISHER_FUNDING_AMOUNT' as const,
|
|
71
|
+
description:
|
|
72
|
+
'Amount of ETH to send when funding a publisher. Specified in ether (e.g. 0.5). Unset = funding disabled.',
|
|
73
|
+
parseEnv: (val: string) => parseEther(val),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
55
77
|
export type ProverPublisherConfig = L1TxUtilsConfig &
|
|
56
78
|
BlobClientConfig & {
|
|
57
79
|
fishermanMode?: boolean;
|
|
58
80
|
proverPublisherAllowInvalidStates?: boolean;
|
|
59
81
|
proverPublisherForwarderAddress?: EthAddress;
|
|
82
|
+
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
83
|
+
publisherFundingThreshold?: bigint;
|
|
84
|
+
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
85
|
+
publisherFundingAmount?: bigint;
|
|
60
86
|
};
|
|
61
87
|
|
|
62
88
|
export type SequencerPublisherConfig = L1TxUtilsConfig &
|
|
@@ -66,6 +92,10 @@ export type SequencerPublisherConfig = L1TxUtilsConfig &
|
|
|
66
92
|
sequencerPublisherForwarderAddress?: EthAddress;
|
|
67
93
|
/** Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path */
|
|
68
94
|
l1TxFailedStore?: string;
|
|
95
|
+
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
96
|
+
publisherFundingThreshold?: bigint;
|
|
97
|
+
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
98
|
+
publisherFundingAmount?: bigint;
|
|
69
99
|
};
|
|
70
100
|
|
|
71
101
|
export function getPublisherConfigFromProverConfig(config: ProverPublisherConfig): PublisherConfig {
|
|
@@ -142,6 +172,7 @@ export const sequencerPublisherConfigMappings: ConfigMappingsType<SequencerPubli
|
|
|
142
172
|
env: 'L1_TX_FAILED_STORE',
|
|
143
173
|
description: 'Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path',
|
|
144
174
|
},
|
|
175
|
+
...publisherFundingConfigMappings,
|
|
145
176
|
};
|
|
146
177
|
|
|
147
178
|
export const proverPublisherConfigMappings: ConfigMappingsType<ProverPublisherConfig & L1TxUtilsConfig> = {
|
|
@@ -163,4 +194,5 @@ export const proverPublisherConfigMappings: ConfigMappingsType<ProverPublisherCo
|
|
|
163
194
|
description: 'Address of the forwarder contract to wrap all L1 transactions through (for testing purposes only)',
|
|
164
195
|
parseEnv: (val: string) => (val ? EthAddress.fromString(val) : undefined),
|
|
165
196
|
},
|
|
197
|
+
...publisherFundingConfigMappings,
|
|
166
198
|
};
|
|
@@ -117,8 +117,8 @@ export class SequencerPublisherFactory {
|
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
/**
|
|
121
|
-
public
|
|
122
|
-
this.deps.publisherManager.
|
|
120
|
+
/** Stops all publishers managed by this factory. Used during sequencer shutdown. */
|
|
121
|
+
public async stopAll(): Promise<void> {
|
|
122
|
+
await this.deps.publisherManager.stop();
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -42,6 +42,7 @@ import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
|
42
42
|
import { type ProposerSlashAction, encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
43
43
|
import { CommitteeAttestationsAndSigners, type ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
44
44
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
45
|
+
import { getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
45
46
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
46
47
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
47
48
|
import type { L1PublishCheckpointStats } from '@aztec/stdlib/stats';
|
|
@@ -133,6 +134,8 @@ export class SequencerPublisher {
|
|
|
133
134
|
|
|
134
135
|
protected log: Logger;
|
|
135
136
|
protected ethereumSlotDuration: bigint;
|
|
137
|
+
protected aztecSlotDuration: bigint;
|
|
138
|
+
private dateProvider: DateProvider;
|
|
136
139
|
|
|
137
140
|
private blobClient: BlobClientInterface;
|
|
138
141
|
|
|
@@ -166,7 +169,7 @@ export class SequencerPublisher {
|
|
|
166
169
|
|
|
167
170
|
constructor(
|
|
168
171
|
private config: Pick<SequencerPublisherConfig, 'fishermanMode' | 'l1TxFailedStore'> &
|
|
169
|
-
Pick<L1ContractsConfig, 'ethereumSlotDuration'> & { l1ChainId: number },
|
|
172
|
+
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'> & { l1ChainId: number },
|
|
170
173
|
deps: {
|
|
171
174
|
telemetry?: TelemetryClient;
|
|
172
175
|
blobClient: BlobClientInterface;
|
|
@@ -185,6 +188,8 @@ export class SequencerPublisher {
|
|
|
185
188
|
) {
|
|
186
189
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
187
190
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
191
|
+
this.aztecSlotDuration = BigInt(config.aztecSlotDuration);
|
|
192
|
+
this.dateProvider = deps.dateProvider;
|
|
188
193
|
this.epochCache = deps.epochCache;
|
|
189
194
|
this.lastActions = deps.lastActions;
|
|
190
195
|
|
|
@@ -286,7 +291,7 @@ export class SequencerPublisher {
|
|
|
286
291
|
}
|
|
287
292
|
|
|
288
293
|
public getCurrentL2Slot(): SlotNumber {
|
|
289
|
-
return this.epochCache.
|
|
294
|
+
return this.epochCache.getSlotNow();
|
|
290
295
|
}
|
|
291
296
|
|
|
292
297
|
/**
|
|
@@ -399,8 +404,8 @@ export class SequencerPublisher {
|
|
|
399
404
|
// @note - we can only have one blob config per bundle
|
|
400
405
|
// find requests with gas and blob configs
|
|
401
406
|
// See https://github.com/AztecProtocol/aztec-packages/issues/11513
|
|
402
|
-
const gasConfigs =
|
|
403
|
-
const blobConfigs =
|
|
407
|
+
const gasConfigs = validRequests.filter(request => request.gasConfig).map(request => request.gasConfig);
|
|
408
|
+
const blobConfigs = validRequests.filter(request => request.blobConfig).map(request => request.blobConfig);
|
|
404
409
|
|
|
405
410
|
if (blobConfigs.length > 1) {
|
|
406
411
|
throw new Error('Multiple blob configs found');
|
|
@@ -596,20 +601,24 @@ export class SequencerPublisher {
|
|
|
596
601
|
}
|
|
597
602
|
|
|
598
603
|
/**
|
|
599
|
-
* @notice Will call `
|
|
604
|
+
* @notice Will call `canProposeAt` to make sure that it is possible to propose
|
|
600
605
|
* @param tipArchive - The archive to check
|
|
601
606
|
* @returns The slot and block number if it is possible to propose, undefined otherwise
|
|
602
607
|
*/
|
|
603
|
-
public
|
|
608
|
+
public canProposeAt(
|
|
604
609
|
tipArchive: Fr,
|
|
605
610
|
msgSender: EthAddress,
|
|
606
|
-
opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
611
|
+
opts: { forcePendingCheckpointNumber?: CheckpointNumber; pipelined?: boolean } = {},
|
|
607
612
|
) {
|
|
608
613
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
609
614
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
610
615
|
|
|
616
|
+
const pipelined = opts.pipelined ?? this.epochCache.isProposerPipeliningEnabled();
|
|
617
|
+
const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
|
|
618
|
+
const nextL1SlotTs = this.getNextL1SlotTimestamp() + slotOffset;
|
|
619
|
+
|
|
611
620
|
return this.rollupContract
|
|
612
|
-
.
|
|
621
|
+
.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), nextL1SlotTs, {
|
|
613
622
|
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber,
|
|
614
623
|
})
|
|
615
624
|
.catch(err => {
|
|
@@ -623,6 +632,7 @@ export class SequencerPublisher {
|
|
|
623
632
|
return undefined;
|
|
624
633
|
});
|
|
625
634
|
}
|
|
635
|
+
|
|
626
636
|
/**
|
|
627
637
|
* @notice Will simulate `validateHeader` to make sure that the block header is valid
|
|
628
638
|
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header.
|
|
@@ -646,7 +656,7 @@ export class SequencerPublisher {
|
|
|
646
656
|
flags,
|
|
647
657
|
] as const;
|
|
648
658
|
|
|
649
|
-
const ts =
|
|
659
|
+
const ts = this.getNextL1SlotTimestamp();
|
|
650
660
|
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(
|
|
651
661
|
opts?.forcePendingCheckpointNumber,
|
|
652
662
|
);
|
|
@@ -811,7 +821,9 @@ export class SequencerPublisher {
|
|
|
811
821
|
attestationsAndSignersSignature: Signature,
|
|
812
822
|
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
813
823
|
): Promise<bigint> {
|
|
814
|
-
|
|
824
|
+
// Anchor the simulation timestamp to the checkpoint's own slot start time
|
|
825
|
+
// rather than the current L1 block timestamp, which may overshoot into the next slot if the build ran late.
|
|
826
|
+
const ts = checkpoint.header.timestamp;
|
|
815
827
|
const blobFields = checkpoint.toBlobFields();
|
|
816
828
|
const blobs = await getBlobsPerL1Block(blobFields);
|
|
817
829
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
@@ -1577,4 +1589,10 @@ export class SequencerPublisher {
|
|
|
1577
1589
|
},
|
|
1578
1590
|
});
|
|
1579
1591
|
}
|
|
1592
|
+
|
|
1593
|
+
/** Returns the timestamp to use when simulating L1 proposal calls */
|
|
1594
|
+
private getNextL1SlotTimestamp(): bigint {
|
|
1595
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
1596
|
+
return getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), l1Constants);
|
|
1597
|
+
}
|
|
1580
1598
|
}
|