@aztec/sequencer-client 0.0.1-commit.88c5703d4 → 0.0.1-commit.88e6f9396
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 +1 -13
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +21 -67
- package/dest/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -4
- package/dest/publisher/sequencer-publisher.d.ts +6 -4
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +13 -7
- 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 +57 -45
- 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 +28 -86
- package/src/config.ts +4 -3
- package/src/publisher/sequencer-publisher.ts +17 -9
- 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 +82 -51
- 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
|
-
DefaultSequencerConfig,
|
|
24
|
-
type SequencerClientConfig,
|
|
25
|
-
getPublisherConfigFromSequencerConfig,
|
|
26
|
-
} from '../config.js';
|
|
22
|
+
import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
|
|
27
23
|
import { 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.
|
|
@@ -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
|
));
|
|
@@ -160,12 +156,7 @@ export class SequencerClient {
|
|
|
160
156
|
const l1PublishingTimeBasedOnChain = isAnvilTestChain(config.l1ChainId) ? 1 : ethereumSlotDuration;
|
|
161
157
|
const l1PublishingTime = config.l1PublishingTime ?? l1PublishingTimeBasedOnChain;
|
|
162
158
|
|
|
163
|
-
const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock
|
|
164
|
-
config,
|
|
165
|
-
rollupManaLimit,
|
|
166
|
-
l1PublishingTime,
|
|
167
|
-
log,
|
|
168
|
-
);
|
|
159
|
+
const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock } = capPerBlockLimits(config, rollupManaLimit, log);
|
|
169
160
|
|
|
170
161
|
const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration, rollupManaLimit };
|
|
171
162
|
|
|
@@ -183,7 +174,7 @@ export class SequencerClient {
|
|
|
183
174
|
deps.dateProvider,
|
|
184
175
|
epochCache,
|
|
185
176
|
rollupContract,
|
|
186
|
-
{ ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock
|
|
177
|
+
{ ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock },
|
|
187
178
|
telemetryClient,
|
|
188
179
|
log,
|
|
189
180
|
);
|
|
@@ -248,88 +239,39 @@ export class SequencerClient {
|
|
|
248
239
|
}
|
|
249
240
|
|
|
250
241
|
/**
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* Otherwise, derives it as (checkpointLimit / maxBlocks) * multiplier, capped at the checkpoint limit.
|
|
242
|
+
* Caps operator-provided per-block limits at checkpoint-level limits.
|
|
243
|
+
* Returns undefined for any limit the operator didn't set — the checkpoint builder handles redistribution.
|
|
254
244
|
*/
|
|
255
|
-
|
|
245
|
+
function capPerBlockLimits(
|
|
256
246
|
config: SequencerClientConfig,
|
|
257
247
|
rollupManaLimit: number,
|
|
258
|
-
l1PublishingTime: number,
|
|
259
248
|
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));
|
|
249
|
+
): { maxL2BlockGas: number | undefined; maxDABlockGas: number | undefined; maxTxsPerBlock: number | undefined } {
|
|
250
|
+
let maxL2BlockGas = config.maxL2BlockGas;
|
|
251
|
+
if (maxL2BlockGas !== undefined && maxL2BlockGas > rollupManaLimit) {
|
|
252
|
+
log.warn(`Provided MAX_L2_BLOCK_GAS ${maxL2BlockGas} exceeds rollup mana limit ${rollupManaLimit} (capping)`);
|
|
253
|
+
maxL2BlockGas = rollupManaLimit;
|
|
285
254
|
}
|
|
286
255
|
|
|
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));
|
|
256
|
+
let maxDABlockGas = config.maxDABlockGas;
|
|
257
|
+
if (maxDABlockGas !== undefined && maxDABlockGas > MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT) {
|
|
258
|
+
log.warn(
|
|
259
|
+
`Provided MAX_DA_BLOCK_GAS ${maxDABlockGas} exceeds DA checkpoint limit ${MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT} (capping)`,
|
|
260
|
+
);
|
|
261
|
+
maxDABlockGas = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT;
|
|
301
262
|
}
|
|
302
263
|
|
|
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),
|
|
264
|
+
let maxTxsPerBlock = config.maxTxsPerBlock;
|
|
265
|
+
if (
|
|
266
|
+
maxTxsPerBlock !== undefined &&
|
|
267
|
+
config.maxTxsPerCheckpoint !== undefined &&
|
|
268
|
+
maxTxsPerBlock > config.maxTxsPerCheckpoint
|
|
269
|
+
) {
|
|
270
|
+
log.warn(
|
|
271
|
+
`Provided MAX_TX_PER_BLOCK ${maxTxsPerBlock} exceeds MAX_TX_PER_CHECKPOINT ${config.maxTxsPerCheckpoint} (capping)`,
|
|
319
272
|
);
|
|
320
|
-
|
|
321
|
-
maxTxsPerBlock = defaultMaxTxsPerBlock;
|
|
273
|
+
maxTxsPerBlock = config.maxTxsPerCheckpoint;
|
|
322
274
|
}
|
|
323
275
|
|
|
324
|
-
|
|
325
|
-
maxL2BlockGas,
|
|
326
|
-
maxDABlockGas,
|
|
327
|
-
maxTxsPerBlock,
|
|
328
|
-
rollupManaLimit,
|
|
329
|
-
daCheckpointLimit,
|
|
330
|
-
maxNumberOfBlocks,
|
|
331
|
-
multiplier,
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock, maxBlocksPerCheckpoint: maxNumberOfBlocks };
|
|
276
|
+
return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock };
|
|
335
277
|
}
|
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
|
|
|
@@ -133,6 +133,7 @@ export class SequencerPublisher {
|
|
|
133
133
|
|
|
134
134
|
protected log: Logger;
|
|
135
135
|
protected ethereumSlotDuration: bigint;
|
|
136
|
+
protected aztecSlotDuration: bigint;
|
|
136
137
|
|
|
137
138
|
private blobClient: BlobClientInterface;
|
|
138
139
|
|
|
@@ -166,7 +167,7 @@ export class SequencerPublisher {
|
|
|
166
167
|
|
|
167
168
|
constructor(
|
|
168
169
|
private config: Pick<SequencerPublisherConfig, 'fishermanMode' | 'l1TxFailedStore'> &
|
|
169
|
-
Pick<L1ContractsConfig, 'ethereumSlotDuration'> & { l1ChainId: number },
|
|
170
|
+
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'> & { l1ChainId: number },
|
|
170
171
|
deps: {
|
|
171
172
|
telemetry?: TelemetryClient;
|
|
172
173
|
blobClient: BlobClientInterface;
|
|
@@ -185,6 +186,7 @@ export class SequencerPublisher {
|
|
|
185
186
|
) {
|
|
186
187
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
187
188
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
189
|
+
this.aztecSlotDuration = BigInt(config.aztecSlotDuration);
|
|
188
190
|
this.epochCache = deps.epochCache;
|
|
189
191
|
this.lastActions = deps.lastActions;
|
|
190
192
|
|
|
@@ -286,7 +288,7 @@ export class SequencerPublisher {
|
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
public getCurrentL2Slot(): SlotNumber {
|
|
289
|
-
return this.epochCache.
|
|
291
|
+
return this.epochCache.getSlotNow();
|
|
290
292
|
}
|
|
291
293
|
|
|
292
294
|
/**
|
|
@@ -399,8 +401,8 @@ export class SequencerPublisher {
|
|
|
399
401
|
// @note - we can only have one blob config per bundle
|
|
400
402
|
// find requests with gas and blob configs
|
|
401
403
|
// See https://github.com/AztecProtocol/aztec-packages/issues/11513
|
|
402
|
-
const gasConfigs =
|
|
403
|
-
const blobConfigs =
|
|
404
|
+
const gasConfigs = validRequests.filter(request => request.gasConfig).map(request => request.gasConfig);
|
|
405
|
+
const blobConfigs = validRequests.filter(request => request.blobConfig).map(request => request.blobConfig);
|
|
404
406
|
|
|
405
407
|
if (blobConfigs.length > 1) {
|
|
406
408
|
throw new Error('Multiple blob configs found');
|
|
@@ -596,20 +598,23 @@ export class SequencerPublisher {
|
|
|
596
598
|
}
|
|
597
599
|
|
|
598
600
|
/**
|
|
599
|
-
* @notice Will call `
|
|
601
|
+
* @notice Will call `canProposeAt` to make sure that it is possible to propose
|
|
600
602
|
* @param tipArchive - The archive to check
|
|
601
603
|
* @returns The slot and block number if it is possible to propose, undefined otherwise
|
|
602
604
|
*/
|
|
603
|
-
public
|
|
605
|
+
public canProposeAt(
|
|
604
606
|
tipArchive: Fr,
|
|
605
607
|
msgSender: EthAddress,
|
|
606
|
-
opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
608
|
+
opts: { forcePendingCheckpointNumber?: CheckpointNumber; pipelined?: boolean } = {},
|
|
607
609
|
) {
|
|
608
610
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
609
611
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
610
612
|
|
|
613
|
+
const pipelined = opts.pipelined ?? this.epochCache.isProposerPipeliningEnabled();
|
|
614
|
+
const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
|
|
615
|
+
|
|
611
616
|
return this.rollupContract
|
|
612
|
-
.
|
|
617
|
+
.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), this.ethereumSlotDuration, slotOffset, {
|
|
613
618
|
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber,
|
|
614
619
|
})
|
|
615
620
|
.catch(err => {
|
|
@@ -623,6 +628,7 @@ export class SequencerPublisher {
|
|
|
623
628
|
return undefined;
|
|
624
629
|
});
|
|
625
630
|
}
|
|
631
|
+
|
|
626
632
|
/**
|
|
627
633
|
* @notice Will simulate `validateHeader` to make sure that the block header is valid
|
|
628
634
|
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header.
|
|
@@ -811,7 +817,9 @@ export class SequencerPublisher {
|
|
|
811
817
|
attestationsAndSignersSignature: Signature,
|
|
812
818
|
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
813
819
|
): Promise<bigint> {
|
|
814
|
-
|
|
820
|
+
// Anchor the simulation timestamp to the checkpoint's own slot start time
|
|
821
|
+
// rather than the current L1 block timestamp, which may overshoot into the next slot if the build ran late.
|
|
822
|
+
const ts = checkpoint.header.timestamp;
|
|
815
823
|
const blobFields = checkpoint.toBlobFields();
|
|
816
824
|
const blobs = await getBlobsPerL1Block(blobFields);
|
|
817
825
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|