@aztec/sequencer-client 0.0.1-commit.6d3c34e → 0.0.1-commit.7035c9bd6
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 +12 -7
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +56 -17
- package/dest/config.d.ts +26 -7
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +47 -30
- package/dest/global_variable_builder/global_builder.d.ts +2 -4
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +7 -6
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +35 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +106 -42
- package/dest/publisher/index.d.ts +2 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
- package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +59 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/index.js +2 -0
- package/dest/publisher/sequencer-publisher-factory.d.ts +11 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +27 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +12 -4
- package/dest/publisher/sequencer-publisher.d.ts +30 -10
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +362 -56
- package/dest/sequencer/checkpoint_proposal_job.d.ts +42 -11
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +322 -122
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/events.d.ts +2 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/index.d.ts +1 -2
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -1
- package/dest/sequencer/metrics.d.ts +21 -5
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +122 -30
- package/dest/sequencer/sequencer.d.ts +43 -20
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +151 -82
- package/dest/sequencer/timetable.d.ts +4 -6
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +7 -11
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/index.d.ts +3 -5
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +23 -19
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +67 -38
- package/dest/test/utils.d.ts +8 -8
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +12 -11
- package/package.json +29 -28
- package/src/client/sequencer-client.ts +77 -18
- package/src/config.ts +66 -41
- package/src/global_variable_builder/global_builder.ts +6 -5
- package/src/index.ts +1 -6
- package/src/publisher/config.ts +121 -43
- package/src/publisher/index.ts +3 -0
- package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +55 -0
- package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
- package/src/publisher/l1_tx_failed_store/index.ts +3 -0
- package/src/publisher/sequencer-publisher-factory.ts +38 -6
- package/src/publisher/sequencer-publisher-metrics.ts +7 -3
- package/src/publisher/sequencer-publisher.ts +360 -69
- package/src/sequencer/checkpoint_proposal_job.ts +449 -142
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/index.ts +0 -1
- package/src/sequencer/metrics.ts +138 -32
- package/src/sequencer/sequencer.ts +200 -91
- package/src/sequencer/timetable.ts +13 -12
- package/src/sequencer/types.ts +1 -1
- package/src/test/index.ts +2 -4
- package/src/test/mock_checkpoint_builder.ts +122 -78
- package/src/test/utils.ts +24 -14
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/src/sequencer/block_builder.ts +0 -216
|
@@ -370,7 +370,7 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _initProto;
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _initProto;
|
|
374
374
|
import { getKzg } from '@aztec/blob-lib';
|
|
375
375
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
376
376
|
import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
@@ -380,7 +380,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
380
380
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
381
381
|
import { createLogger } from '@aztec/foundation/log';
|
|
382
382
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
383
|
-
import {
|
|
383
|
+
import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
384
384
|
import { SequencerConfigSchema } from '@aztec/stdlib/interfaces/server';
|
|
385
385
|
import { pickFromSchema } from '@aztec/stdlib/schemas';
|
|
386
386
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
@@ -396,6 +396,8 @@ import { SequencerState } from './utils.js';
|
|
|
396
396
|
export { SequencerState };
|
|
397
397
|
_dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpointProposal'), _dec2 = trackSpan('Seqeuencer.tryVoteWhenSyncFails', ({ slot })=>({
|
|
398
398
|
[Attributes.SLOT_NUMBER]: slot
|
|
399
|
+
})), _dec3 = trackSpan('Sequencer.tryVoteWhenEscapeHatchOpen', ({ slot })=>({
|
|
400
|
+
[Attributes.SLOT_NUMBER]: slot
|
|
399
401
|
}));
|
|
400
402
|
/**
|
|
401
403
|
* Sequencer client
|
|
@@ -436,24 +438,23 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
436
438
|
_dec2,
|
|
437
439
|
2,
|
|
438
440
|
"tryVoteWhenSyncFails"
|
|
441
|
+
],
|
|
442
|
+
[
|
|
443
|
+
_dec3,
|
|
444
|
+
2,
|
|
445
|
+
"tryVoteWhenEscapeHatchOpen"
|
|
439
446
|
]
|
|
440
447
|
], []));
|
|
441
448
|
}
|
|
442
449
|
runningPromise;
|
|
443
450
|
state;
|
|
444
451
|
metrics;
|
|
445
|
-
/** The last slot for which we attempted to
|
|
452
|
+
/** The last slot for which we attempted to perform our voting duties with degraded block production */ lastSlotForFallbackVote;
|
|
453
|
+
/** The last slot for which we logged "no committee" warning, to avoid spam */ lastSlotForNoCommitteeWarning;
|
|
446
454
|
/** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */ lastSlotForCheckpointProposalJob;
|
|
447
455
|
/** Last successful checkpoint proposed */ lastCheckpointProposed;
|
|
448
456
|
/** The last epoch for which we logged strategy comparison in fisherman mode. */ lastEpochForStrategyComparison;
|
|
449
457
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */ timetable;
|
|
450
|
-
// This shouldn't be here as this gets re-created each time we build/propose a block.
|
|
451
|
-
// But we have a number of tests that abuse/rely on this class having a permanent publisher.
|
|
452
|
-
// As long as those tests only configure a single publisher they will continue to work.
|
|
453
|
-
// This will get re-assigned every time the sequencer goes to build a new block to a publisher that is valid
|
|
454
|
-
// for the block proposer.
|
|
455
|
-
// TODO(palla/mbps): Remove this field and fix tests
|
|
456
|
-
publisher;
|
|
457
458
|
/** Config for the sequencer */ config;
|
|
458
459
|
constructor(publisherFactory, validatorClient, globalsBuilder, p2pClient, worldState, slasherClient, l2BlockSource, l1ToL2MessageSource, checkpointsBuilder, l1Constants, dateProvider, epochCache, rollupContract, config, telemetry = getTelemetryClient(), log = createLogger('sequencer')){
|
|
459
460
|
super(), this.publisherFactory = publisherFactory, this.validatorClient = validatorClient, this.globalsBuilder = globalsBuilder, this.p2pClient = p2pClient, this.worldState = worldState, this.slasherClient = slasherClient, this.l2BlockSource = l2BlockSource, this.l1ToL2MessageSource = l1ToL2MessageSource, this.checkpointsBuilder = checkpointsBuilder, this.l1Constants = l1Constants, this.dateProvider = dateProvider, this.epochCache = epochCache, this.rollupContract = rollupContract, this.telemetry = telemetry, this.log = log, this.state = (_initProto(this), SequencerState.STOPPED), this.config = DefaultSequencerConfig;
|
|
@@ -466,7 +467,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
466
467
|
}
|
|
467
468
|
/** Updates sequencer config by the defined values and updates the timetable */ updateConfig(config) {
|
|
468
469
|
const filteredConfig = pickFromSchema(config, SequencerConfigSchema);
|
|
469
|
-
this.log.info(`Updated sequencer config`, omit(filteredConfig, '
|
|
470
|
+
this.log.info(`Updated sequencer config`, omit(filteredConfig, 'txPublicSetupAllowListExtend'));
|
|
470
471
|
this.config = merge(this.config, filteredConfig);
|
|
471
472
|
this.timetable = new SequencerTimetable({
|
|
472
473
|
ethereumSlotDuration: this.l1Constants.ethereumSlotDuration,
|
|
@@ -477,9 +478,8 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
477
478
|
enforce: this.config.enforceTimeTable
|
|
478
479
|
}, this.metrics, this.log);
|
|
479
480
|
}
|
|
480
|
-
/** Initializes the sequencer (precomputes tables
|
|
481
|
+
/** Initializes the sequencer (precomputes tables). Takes about 3s. */ init() {
|
|
481
482
|
getKzg();
|
|
482
|
-
this.publisher = (await this.publisherFactory.create(undefined)).publisher;
|
|
483
483
|
}
|
|
484
484
|
/** Starts the sequencer and moves to IDLE state. */ start() {
|
|
485
485
|
this.runningPromise = new RunningPromise(this.safeWork.bind(this), this.log, this.config.sequencerPollingIntervalMS);
|
|
@@ -494,7 +494,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
494
494
|
this.setState(SequencerState.STOPPING, undefined, {
|
|
495
495
|
force: true
|
|
496
496
|
});
|
|
497
|
-
this.
|
|
497
|
+
this.publisherFactory.interruptAll();
|
|
498
498
|
await this.runningPromise?.stop();
|
|
499
499
|
this.setState(SequencerState.STOPPED, undefined, {
|
|
500
500
|
force: true
|
|
@@ -509,7 +509,6 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
509
509
|
error: err
|
|
510
510
|
});
|
|
511
511
|
if (err instanceof SequencerTooSlowError) {
|
|
512
|
-
// TODO(palla/mbps): Add missing states
|
|
513
512
|
// Log as warn only if we had to abort halfway through the block proposal
|
|
514
513
|
const logLvl = [
|
|
515
514
|
SequencerState.INITIALIZING_CHECKPOINT,
|
|
@@ -540,9 +539,10 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
540
539
|
* - Submit checkpoint
|
|
541
540
|
*/ async work() {
|
|
542
541
|
this.setState(SequencerState.SYNCHRONIZING, undefined);
|
|
543
|
-
const { slot, ts,
|
|
542
|
+
const { slot, ts, nowSeconds, epoch } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
543
|
+
const { slot: targetSlot, epoch: targetEpoch } = this.epochCache.getTargetEpochAndSlotInNextL1Slot();
|
|
544
544
|
// Check if we are synced and it's our slot, grab a publisher, check previous block invalidation, etc
|
|
545
|
-
const checkpointProposalJob = await this.prepareCheckpointProposal(slot, ts,
|
|
545
|
+
const checkpointProposalJob = await this.prepareCheckpointProposal(slot, targetSlot, epoch, targetEpoch, ts, nowSeconds);
|
|
546
546
|
if (!checkpointProposalJob) {
|
|
547
547
|
return;
|
|
548
548
|
}
|
|
@@ -552,10 +552,10 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
552
552
|
if (checkpoint) {
|
|
553
553
|
this.lastCheckpointProposed = checkpoint;
|
|
554
554
|
}
|
|
555
|
-
// Log fee strategy comparison if on fisherman
|
|
556
|
-
if (this.config.fishermanMode && (this.lastEpochForStrategyComparison === undefined ||
|
|
557
|
-
this.logStrategyComparison(
|
|
558
|
-
this.lastEpochForStrategyComparison =
|
|
555
|
+
// Log fee strategy comparison if on fisherman (uses target epoch since we mirror the proposer's perspective)
|
|
556
|
+
if (this.config.fishermanMode && (this.lastEpochForStrategyComparison === undefined || targetEpoch > this.lastEpochForStrategyComparison)) {
|
|
557
|
+
this.logStrategyComparison(targetEpoch, checkpointProposalJob.getPublisher());
|
|
558
|
+
this.lastEpochForStrategyComparison = targetEpoch;
|
|
559
559
|
}
|
|
560
560
|
return checkpoint;
|
|
561
561
|
}
|
|
@@ -563,17 +563,17 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
563
563
|
* Prepares the checkpoint proposal by performing all necessary checks and setup.
|
|
564
564
|
* This is the initial step in the main loop.
|
|
565
565
|
* @returns CheckpointProposalJob if successful, undefined if we are not yet synced or are not the proposer.
|
|
566
|
-
*/ async prepareCheckpointProposal(slot, ts,
|
|
567
|
-
// Check we have not already processed this slot (cheapest check)
|
|
566
|
+
*/ async prepareCheckpointProposal(slot, targetSlot, epoch, targetEpoch, ts, nowSeconds) {
|
|
567
|
+
// Check we have not already processed this target slot (cheapest check)
|
|
568
568
|
// We only check this if enforce timetable is set, since we want to keep processing the same slot if we are not
|
|
569
569
|
// running against actual time (eg when we use sandbox-style automining)
|
|
570
|
-
if (this.lastSlotForCheckpointProposalJob && this.lastSlotForCheckpointProposalJob >=
|
|
571
|
-
this.log.trace(`
|
|
570
|
+
if (this.lastSlotForCheckpointProposalJob && this.lastSlotForCheckpointProposalJob >= targetSlot && this.config.enforceTimeTable) {
|
|
571
|
+
this.log.trace(`Target slot ${targetSlot} has already been processed`);
|
|
572
572
|
return undefined;
|
|
573
573
|
}
|
|
574
|
-
// But if we have already proposed for this slot,
|
|
575
|
-
if (this.lastCheckpointProposed && this.lastCheckpointProposed.header.slotNumber >=
|
|
576
|
-
this.log.trace(`Slot ${
|
|
574
|
+
// But if we have already proposed for this slot, then we definitely have to skip it, automining or not
|
|
575
|
+
if (this.lastCheckpointProposed && this.lastCheckpointProposed.header.slotNumber >= targetSlot) {
|
|
576
|
+
this.log.trace(`Slot ${targetSlot} has already been published as checkpoint ${this.lastCheckpointProposed.number}`);
|
|
577
577
|
return undefined;
|
|
578
578
|
}
|
|
579
579
|
// Check all components are synced to latest as seen by the archiver (queries all subsystems)
|
|
@@ -584,36 +584,58 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
584
584
|
if (!syncedTo) {
|
|
585
585
|
await this.tryVoteWhenSyncFails({
|
|
586
586
|
slot,
|
|
587
|
+
targetSlot,
|
|
587
588
|
ts
|
|
588
589
|
});
|
|
589
590
|
return undefined;
|
|
590
591
|
}
|
|
592
|
+
// If escape hatch is open for the target epoch, do not start checkpoint proposal work and do not attempt invalidations.
|
|
593
|
+
// Still perform governance/slashing voting (as proposer) once per slot.
|
|
594
|
+
// When pipelining, we check the target epoch (slot+1's epoch) since that's the epoch we're building for.
|
|
595
|
+
const isEscapeHatchOpen = await this.epochCache.isEscapeHatchOpen(targetEpoch);
|
|
596
|
+
if (isEscapeHatchOpen) {
|
|
597
|
+
this.setState(SequencerState.PROPOSER_CHECK, slot);
|
|
598
|
+
const [canPropose, proposer] = await this.checkCanPropose(targetSlot);
|
|
599
|
+
if (canPropose) {
|
|
600
|
+
await this.tryVoteWhenEscapeHatchOpen({
|
|
601
|
+
slot,
|
|
602
|
+
proposer
|
|
603
|
+
});
|
|
604
|
+
} else {
|
|
605
|
+
this.log.trace(`Escape hatch open but we are not proposer, skipping vote-only actions`, {
|
|
606
|
+
slot,
|
|
607
|
+
epoch,
|
|
608
|
+
proposer
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
return undefined;
|
|
612
|
+
}
|
|
591
613
|
// Next checkpoint follows from the last synced one
|
|
592
614
|
const checkpointNumber = CheckpointNumber(syncedTo.checkpointNumber + 1);
|
|
593
615
|
const logCtx = {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
syncedToL2Slot: getSlotAtTimestamp(syncedTo.l1Timestamp, this.l1Constants),
|
|
616
|
+
nowSeconds,
|
|
617
|
+
syncedToL2Slot: syncedTo.syncedL2Slot,
|
|
597
618
|
slot,
|
|
619
|
+
targetSlot,
|
|
598
620
|
slotTs: ts,
|
|
599
621
|
checkpointNumber,
|
|
600
622
|
isPendingChainValid: pick(syncedTo.pendingChainValidationStatus, 'valid', 'reason', 'invalidIndex')
|
|
601
623
|
};
|
|
602
|
-
// Check that we are a proposer for the
|
|
624
|
+
// Check that we are a proposer for the target slot.
|
|
603
625
|
this.setState(SequencerState.PROPOSER_CHECK, slot);
|
|
604
|
-
const [canPropose, proposer] = await this.checkCanPropose(
|
|
626
|
+
const [canPropose, proposer] = await this.checkCanPropose(targetSlot);
|
|
605
627
|
// If we are not a proposer check if we should invalidate an invalid checkpoint, and bail
|
|
606
628
|
if (!canPropose) {
|
|
607
629
|
await this.considerInvalidatingCheckpoint(syncedTo, slot);
|
|
608
630
|
return undefined;
|
|
609
631
|
}
|
|
610
|
-
// Check that the slot is not taken by a block already (should never happen, since only us can propose for this slot)
|
|
611
|
-
if (syncedTo.
|
|
612
|
-
this.log.warn(`Cannot propose block at
|
|
632
|
+
// Check that the target slot is not taken by a block already (should never happen, since only us can propose for this slot)
|
|
633
|
+
if (syncedTo.blockData && syncedTo.blockData.header.getSlot() >= targetSlot) {
|
|
634
|
+
this.log.warn(`Cannot propose block at target slot ${targetSlot} since that slot was taken by block ${syncedTo.blockNumber}`, {
|
|
613
635
|
...logCtx,
|
|
614
|
-
block: syncedTo.
|
|
636
|
+
block: syncedTo.blockData.header.toInspect()
|
|
615
637
|
});
|
|
616
|
-
this.metrics.
|
|
638
|
+
this.metrics.recordCheckpointPrecheckFailed('slot_already_taken');
|
|
617
639
|
return undefined;
|
|
618
640
|
}
|
|
619
641
|
// We now need to get ourselves a publisher.
|
|
@@ -623,7 +645,6 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
623
645
|
const proposerForPublisher = this.config.fishermanMode ? undefined : proposer;
|
|
624
646
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposerForPublisher);
|
|
625
647
|
this.log.verbose(`Created publisher at address ${publisher.getSenderAddress()} for attestor ${attestorAddress}`);
|
|
626
|
-
this.publisher = publisher;
|
|
627
648
|
// In fisherman mode, set the actual proposer's address for simulations
|
|
628
649
|
if (this.config.fishermanMode && proposer) {
|
|
629
650
|
publisher.setProposerAddressForSimulation(proposer);
|
|
@@ -631,29 +652,31 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
631
652
|
}
|
|
632
653
|
// Prepare invalidation request if the pending chain is invalid (returns undefined if no need)
|
|
633
654
|
const invalidateCheckpoint = await publisher.simulateInvalidateCheckpoint(syncedTo.pendingChainValidationStatus);
|
|
634
|
-
// Check with the rollup contract if we can indeed propose at the
|
|
655
|
+
// Check with the rollup contract if we can indeed propose at the target slot. This check should not fail
|
|
635
656
|
// if all the previous checks are good, but we do it just in case.
|
|
636
|
-
const canProposeCheck = await publisher.
|
|
657
|
+
const canProposeCheck = await publisher.canProposeAt(syncedTo.archive, proposer ?? EthAddress.ZERO, {
|
|
658
|
+
...invalidateCheckpoint
|
|
659
|
+
});
|
|
637
660
|
if (canProposeCheck === undefined) {
|
|
638
661
|
this.log.warn(`Cannot propose checkpoint ${checkpointNumber} at slot ${slot} due to failed rollup contract check`, logCtx);
|
|
639
662
|
this.emit('proposer-rollup-check-failed', {
|
|
640
663
|
reason: 'Rollup contract check failed',
|
|
641
664
|
slot
|
|
642
665
|
});
|
|
643
|
-
this.metrics.
|
|
666
|
+
this.metrics.recordCheckpointPrecheckFailed('rollup_contract_check_failed');
|
|
644
667
|
return undefined;
|
|
645
668
|
}
|
|
646
|
-
if (canProposeCheck.slot !==
|
|
647
|
-
this.log.warn(`Cannot propose block due to slot mismatch with rollup contract (this can be caused by a clock out of sync). Expected slot ${
|
|
669
|
+
if (canProposeCheck.slot !== targetSlot) {
|
|
670
|
+
this.log.warn(`Cannot propose block due to slot mismatch with rollup contract (this can be caused by a clock out of sync). Expected slot ${targetSlot} but got ${canProposeCheck.slot}.`, {
|
|
648
671
|
...logCtx,
|
|
649
672
|
rollup: canProposeCheck,
|
|
650
|
-
expectedSlot:
|
|
673
|
+
expectedSlot: targetSlot
|
|
651
674
|
});
|
|
652
675
|
this.emit('proposer-rollup-check-failed', {
|
|
653
676
|
reason: 'Slot mismatch',
|
|
654
677
|
slot
|
|
655
678
|
});
|
|
656
|
-
this.metrics.
|
|
679
|
+
this.metrics.recordCheckpointPrecheckFailed('slot_mismatch');
|
|
657
680
|
return undefined;
|
|
658
681
|
}
|
|
659
682
|
if (canProposeCheck.checkpointNumber !== checkpointNumber) {
|
|
@@ -666,19 +689,26 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
666
689
|
reason: 'Block mismatch',
|
|
667
690
|
slot
|
|
668
691
|
});
|
|
669
|
-
this.metrics.
|
|
692
|
+
this.metrics.recordCheckpointPrecheckFailed('block_number_mismatch');
|
|
670
693
|
return undefined;
|
|
671
694
|
}
|
|
672
|
-
this.lastSlotForCheckpointProposalJob =
|
|
673
|
-
this.
|
|
695
|
+
this.lastSlotForCheckpointProposalJob = targetSlot;
|
|
696
|
+
await this.p2pClient.prepareForSlot(targetSlot);
|
|
697
|
+
this.log.info(`Preparing checkpoint proposal ${checkpointNumber} for target slot ${targetSlot} during wall-clock slot ${slot}`, {
|
|
674
698
|
...logCtx,
|
|
675
|
-
proposer
|
|
699
|
+
proposer,
|
|
700
|
+
pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled()
|
|
676
701
|
});
|
|
677
702
|
// Create and return the checkpoint proposal job
|
|
678
|
-
return this.createCheckpointProposalJob(slot, checkpointNumber, syncedTo.blockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint);
|
|
703
|
+
return this.createCheckpointProposalJob(slot, targetSlot, epoch, targetEpoch, checkpointNumber, syncedTo.blockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint);
|
|
679
704
|
}
|
|
680
|
-
createCheckpointProposalJob(slot, checkpointNumber, syncedToBlockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint) {
|
|
681
|
-
return new CheckpointProposalJob(slot, checkpointNumber, syncedToBlockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint, this.validatorClient, this.globalsBuilder, this.p2pClient, this.worldState, this.l1ToL2MessageSource, this.checkpointsBuilder, this.l2BlockSource, this.l1Constants, this.config, this.timetable, this.slasherClient, this.epochCache, this.dateProvider, this.metrics, this, this.setState.bind(this), this.
|
|
705
|
+
createCheckpointProposalJob(slot, targetSlot, epoch, targetEpoch, checkpointNumber, syncedToBlockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint) {
|
|
706
|
+
return new CheckpointProposalJob(slot, targetSlot, epoch, targetEpoch, checkpointNumber, syncedToBlockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint, this.validatorClient, this.globalsBuilder, this.p2pClient, this.worldState, this.l1ToL2MessageSource, this.l2BlockSource, this.checkpointsBuilder, this.l2BlockSource, this.l1Constants, this.config, this.timetable, this.slasherClient, this.epochCache, this.dateProvider, this.metrics, this, this.setState.bind(this), this.tracer, this.log.getBindings());
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Returns the current sequencer state.
|
|
710
|
+
*/ getState() {
|
|
711
|
+
return this.state;
|
|
682
712
|
}
|
|
683
713
|
/**
|
|
684
714
|
* Internal helper for setting the sequencer state and checks if we have enough time left in the slot to transition to the new state.
|
|
@@ -720,16 +750,15 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
720
750
|
* Returns whether all dependencies have caught up.
|
|
721
751
|
* We don't check against the previous block submitted since it may have been reorg'd out.
|
|
722
752
|
*/ async checkSync(args) {
|
|
723
|
-
// Check that the archiver
|
|
753
|
+
// Check that the archiver has fully synced the L2 slot before the one we want to propose in.
|
|
724
754
|
// TODO(#14766): Archiver reports L1 timestamp based on L1 blocks seen, which means that a missed L1 block will
|
|
725
755
|
// cause the archiver L1 timestamp to fall behind, and cause this sequencer to start processing one L1 slot later.
|
|
726
|
-
const
|
|
727
|
-
const { slot
|
|
728
|
-
if (
|
|
756
|
+
const syncedL2Slot = await this.l2BlockSource.getSyncedL2SlotNumber();
|
|
757
|
+
const { slot } = args;
|
|
758
|
+
if (syncedL2Slot === undefined || syncedL2Slot + 1 < slot) {
|
|
729
759
|
this.log.debug(`Cannot propose block at next L2 slot ${slot} due to pending sync from L1`, {
|
|
730
760
|
slot,
|
|
731
|
-
|
|
732
|
-
l1Timestamp
|
|
761
|
+
syncedL2Slot
|
|
733
762
|
});
|
|
734
763
|
return undefined;
|
|
735
764
|
}
|
|
@@ -765,41 +794,44 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
765
794
|
checkpointNumber: CheckpointNumber.ZERO,
|
|
766
795
|
blockNumber: BlockNumber.ZERO,
|
|
767
796
|
archive,
|
|
768
|
-
|
|
797
|
+
syncedL2Slot,
|
|
769
798
|
pendingChainValidationStatus
|
|
770
799
|
};
|
|
771
800
|
}
|
|
772
|
-
const
|
|
773
|
-
if (!
|
|
801
|
+
const blockData = await this.l2BlockSource.getBlockData(blockNumber);
|
|
802
|
+
if (!blockData) {
|
|
774
803
|
// this shouldn't really happen because a moment ago we checked that all components were in sync
|
|
775
|
-
this.log.error(`Failed to get L2 block ${blockNumber} from the archiver with all components in sync`);
|
|
804
|
+
this.log.error(`Failed to get L2 block data ${blockNumber} from the archiver with all components in sync`);
|
|
776
805
|
return undefined;
|
|
777
806
|
}
|
|
778
807
|
return {
|
|
779
|
-
|
|
780
|
-
blockNumber:
|
|
781
|
-
checkpointNumber:
|
|
782
|
-
archive:
|
|
783
|
-
|
|
808
|
+
blockData,
|
|
809
|
+
blockNumber: blockData.header.getBlockNumber(),
|
|
810
|
+
checkpointNumber: blockData.checkpointNumber,
|
|
811
|
+
archive: blockData.archive.root,
|
|
812
|
+
syncedL2Slot,
|
|
784
813
|
pendingChainValidationStatus
|
|
785
814
|
};
|
|
786
815
|
}
|
|
787
816
|
/**
|
|
788
817
|
* Checks if we are the proposer for the next slot.
|
|
789
818
|
* @returns True if we can propose, and the proposer address (undefined if anyone can propose)
|
|
790
|
-
*/ async checkCanPropose(
|
|
819
|
+
*/ async checkCanPropose(targetSlot) {
|
|
791
820
|
let proposer;
|
|
792
821
|
try {
|
|
793
|
-
proposer = await this.epochCache.getProposerAttesterAddressInSlot(
|
|
822
|
+
proposer = await this.epochCache.getProposerAttesterAddressInSlot(targetSlot);
|
|
794
823
|
} catch (e) {
|
|
795
824
|
if (e instanceof NoCommitteeError) {
|
|
796
|
-
this.
|
|
825
|
+
if (this.lastSlotForNoCommitteeWarning !== targetSlot) {
|
|
826
|
+
this.lastSlotForNoCommitteeWarning = targetSlot;
|
|
827
|
+
this.log.warn(`Cannot propose at target slot ${targetSlot} since the committee does not exist on L1`);
|
|
828
|
+
}
|
|
797
829
|
return [
|
|
798
830
|
false,
|
|
799
831
|
undefined
|
|
800
832
|
];
|
|
801
833
|
}
|
|
802
|
-
this.log.error(`Error getting proposer for slot ${
|
|
834
|
+
this.log.error(`Error getting proposer for target slot ${targetSlot}`, e);
|
|
803
835
|
return [
|
|
804
836
|
false,
|
|
805
837
|
undefined
|
|
@@ -822,7 +854,8 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
822
854
|
const validatorAddresses = this.validatorClient.getValidatorAddresses();
|
|
823
855
|
const weAreProposer = validatorAddresses.some((addr)=>addr.equals(proposer));
|
|
824
856
|
if (!weAreProposer) {
|
|
825
|
-
this.log.debug(`Cannot propose at slot ${
|
|
857
|
+
this.log.debug(`Cannot propose at target slot ${targetSlot} since we are not a proposer`, {
|
|
858
|
+
targetSlot,
|
|
826
859
|
validatorAddresses,
|
|
827
860
|
proposer
|
|
828
861
|
});
|
|
@@ -831,6 +864,10 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
831
864
|
proposer
|
|
832
865
|
];
|
|
833
866
|
}
|
|
867
|
+
this.log.debug(`We are the proposer for target slot ${targetSlot}`, {
|
|
868
|
+
targetSlot,
|
|
869
|
+
proposer
|
|
870
|
+
});
|
|
834
871
|
return [
|
|
835
872
|
true,
|
|
836
873
|
proposer
|
|
@@ -840,9 +877,9 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
840
877
|
* Tries to vote on slashing actions and governance when the sync check fails but we're past the max time for initializing a proposal.
|
|
841
878
|
* This allows the sequencer to participate in governance/slashing votes even when it cannot build blocks.
|
|
842
879
|
*/ async tryVoteWhenSyncFails(args) {
|
|
843
|
-
const { slot } = args;
|
|
880
|
+
const { slot, targetSlot } = args;
|
|
844
881
|
// Prevent duplicate attempts in the same slot
|
|
845
|
-
if (this.
|
|
882
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
846
883
|
this.log.trace(`Already attempted to vote in slot ${slot} (skipping)`);
|
|
847
884
|
return;
|
|
848
885
|
}
|
|
@@ -863,7 +900,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
863
900
|
maxAllowedTime
|
|
864
901
|
});
|
|
865
902
|
// Check if we're a proposer or proposal is open
|
|
866
|
-
const [canPropose, proposer] = await this.checkCanPropose(
|
|
903
|
+
const [canPropose, proposer] = await this.checkCanPropose(targetSlot);
|
|
867
904
|
if (!canPropose) {
|
|
868
905
|
this.log.trace(`Cannot vote in slot ${slot} since we are not a proposer`, {
|
|
869
906
|
slot,
|
|
@@ -872,15 +909,15 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
872
909
|
return;
|
|
873
910
|
}
|
|
874
911
|
// Mark this slot as attempted
|
|
875
|
-
this.
|
|
912
|
+
this.lastSlotForFallbackVote = slot;
|
|
876
913
|
// Get a publisher for voting
|
|
877
914
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
878
915
|
this.log.debug(`Attempting to vote despite sync failure at slot ${slot}`, {
|
|
879
916
|
attestorAddress,
|
|
880
917
|
slot
|
|
881
918
|
});
|
|
882
|
-
// Enqueue governance and slashing votes
|
|
883
|
-
const voter = new CheckpointVoter(
|
|
919
|
+
// Enqueue governance and slashing votes (voter uses the target slot for L1 submission)
|
|
920
|
+
const voter = new CheckpointVoter(targetSlot, publisher, attestorAddress, this.validatorClient, this.slasherClient, this.l1Constants, this.config, this.metrics, this.log);
|
|
884
921
|
const votesPromises = voter.enqueueVotes();
|
|
885
922
|
const votes = await Promise.all(votesPromises);
|
|
886
923
|
if (votes.every((p)=>!p)) {
|
|
@@ -893,12 +930,41 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
893
930
|
await publisher.sendRequests();
|
|
894
931
|
}
|
|
895
932
|
/**
|
|
896
|
-
*
|
|
933
|
+
* Tries to vote on slashing actions and governance proposals when escape hatch is open.
|
|
934
|
+
* This allows the sequencer to participate in voting without performing checkpoint proposal work.
|
|
935
|
+
*/ async tryVoteWhenEscapeHatchOpen(args) {
|
|
936
|
+
const { slot, proposer } = args;
|
|
937
|
+
// Prevent duplicate attempts in the same slot
|
|
938
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
939
|
+
this.log.trace(`Already attempted to vote in slot ${slot} (escape hatch open, skipping)`);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
// Mark this slot as attempted
|
|
943
|
+
this.lastSlotForFallbackVote = slot;
|
|
944
|
+
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
945
|
+
this.log.debug(`Escape hatch open for slot ${slot}, attempting vote-only actions`, {
|
|
946
|
+
slot,
|
|
947
|
+
attestorAddress
|
|
948
|
+
});
|
|
949
|
+
const voter = new CheckpointVoter(slot, publisher, attestorAddress, this.validatorClient, this.slasherClient, this.l1Constants, this.config, this.metrics, this.log);
|
|
950
|
+
const votesPromises = voter.enqueueVotes();
|
|
951
|
+
const votes = await Promise.all(votesPromises);
|
|
952
|
+
if (votes.every((p)=>!p)) {
|
|
953
|
+
this.log.debug(`No votes to enqueue for slot ${slot} (escape hatch open)`);
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
this.log.info(`Voting in slot ${slot} (escape hatch open)`, {
|
|
957
|
+
slot
|
|
958
|
+
});
|
|
959
|
+
await publisher.sendRequests();
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Considers invalidating a block if the pending chain is invalid. Depends on how long the invalid block
|
|
897
963
|
* has been there without being invalidated and whether the sequencer is in the committee or not. We always
|
|
898
964
|
* have the proposer try to invalidate, but if they fail, the sequencers in the committee are expected to try,
|
|
899
965
|
* and if they fail, any sequencer will try as well.
|
|
900
966
|
*/ async considerInvalidatingCheckpoint(syncedTo, currentSlot) {
|
|
901
|
-
const { pendingChainValidationStatus,
|
|
967
|
+
const { pendingChainValidationStatus, syncedL2Slot } = syncedTo;
|
|
902
968
|
if (pendingChainValidationStatus.valid) {
|
|
903
969
|
return;
|
|
904
970
|
}
|
|
@@ -909,7 +975,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
909
975
|
const { secondsBeforeInvalidatingBlockAsCommitteeMember, secondsBeforeInvalidatingBlockAsNonCommitteeMember } = this.config;
|
|
910
976
|
const logData = {
|
|
911
977
|
invalidL1Timestamp: invalidCheckpointTimestamp,
|
|
912
|
-
|
|
978
|
+
syncedL2Slot,
|
|
913
979
|
invalidCheckpoint: pendingChainValidationStatus.checkpoint,
|
|
914
980
|
secondsBeforeInvalidatingBlockAsCommitteeMember,
|
|
915
981
|
secondsBeforeInvalidatingBlockAsNonCommitteeMember,
|
|
@@ -1000,6 +1066,9 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
|
|
|
1000
1066
|
getValidatorAddresses() {
|
|
1001
1067
|
return this.validatorClient?.getValidatorAddresses();
|
|
1002
1068
|
}
|
|
1069
|
+
/** Updates the publisher factory's node keystore adapter after a keystore reload. */ updatePublisherNodeKeyStore(adapter) {
|
|
1070
|
+
this.publisherFactory.updateNodeKeyStore(adapter);
|
|
1071
|
+
}
|
|
1003
1072
|
getConfig() {
|
|
1004
1073
|
return this.config;
|
|
1005
1074
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
1
2
|
import type { SequencerMetrics } from './metrics.js';
|
|
2
3
|
import { SequencerState } from './utils.js';
|
|
3
|
-
export declare const MIN_EXECUTION_TIME = 2;
|
|
4
|
-
export declare const CHECKPOINT_INITIALIZATION_TIME = 1;
|
|
5
|
-
export declare const CHECKPOINT_ASSEMBLE_TIME = 1;
|
|
6
4
|
export declare class SequencerTimetable {
|
|
7
5
|
private readonly metrics?;
|
|
8
|
-
private readonly log
|
|
6
|
+
private readonly log?;
|
|
9
7
|
/**
|
|
10
8
|
* How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
|
|
11
9
|
* assuming an execution time equal to `minExecutionTime`, subtracted from the slot duration. This means that, if the proposer
|
|
@@ -59,7 +57,7 @@ export declare class SequencerTimetable {
|
|
|
59
57
|
p2pPropagationTime?: number;
|
|
60
58
|
blockDurationMs?: number;
|
|
61
59
|
enforce: boolean;
|
|
62
|
-
}, metrics?: SequencerMetrics | undefined, log?:
|
|
60
|
+
}, metrics?: SequencerMetrics | undefined, log?: Logger | undefined);
|
|
63
61
|
getMaxAllowedTime(state: Extract<SequencerState, SequencerState.STOPPED | SequencerState.IDLE | SequencerState.SYNCHRONIZING>): undefined;
|
|
64
62
|
getMaxAllowedTime(state: Exclude<SequencerState, SequencerState.STOPPED | SequencerState.IDLE | SequencerState.SYNCHRONIZING>): number;
|
|
65
63
|
getMaxAllowedTime(state: SequencerState): number | undefined;
|
|
@@ -87,4 +85,4 @@ export declare class SequencerTimetable {
|
|
|
87
85
|
isLastBlock: boolean;
|
|
88
86
|
};
|
|
89
87
|
}
|
|
90
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
88
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXRhYmxlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL3RpbWV0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQVNwRCxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTVDLHFCQUFhLGtCQUFrQjtJQXFFM0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUM7SUFyRXZCOzs7O09BSUc7SUFDSCxTQUFnQixrQkFBa0IsRUFBRSxNQUFNLENBQUM7SUFFM0M7Ozs7T0FJRztJQUNILFNBQWdCLG9CQUFvQixFQUFFLE1BQU0sQ0FBQztJQUU3Qzs7Ozs7T0FLRztJQUNILFNBQWdCLDBCQUEwQixFQUFFLE1BQU0sQ0FBQztJQUVuRDs7OztPQUlHO0lBQ0gsU0FBZ0IsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDO0lBRXpDOzs7T0FHRztJQUNILFNBQWdCLGdCQUFnQixFQUFFLE1BQU0sQ0FBc0I7SUFFOUQsdURBQXVEO0lBQ3ZELFNBQWdCLDRCQUE0QixFQUFFLE1BQU0sQ0FBa0M7SUFFdEYsbUdBQW1HO0lBQ25HLFNBQWdCLGtCQUFrQixFQUFFLE1BQU0sQ0FBQztJQUUzQyxtRkFBbUY7SUFDbkYsU0FBZ0Isc0JBQXNCLEVBQUUsTUFBTSxDQUE0QjtJQUUxRSx3Q0FBd0M7SUFDeEMsU0FBZ0Isb0JBQW9CLEVBQUUsTUFBTSxDQUFDO0lBRTdDLGtGQUFrRjtJQUNsRixTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMsNERBQTREO0lBQzVELFNBQWdCLE9BQU8sRUFBRSxPQUFPLENBQUM7SUFFakMsb0dBQW9HO0lBQ3BHLFNBQWdCLGFBQWEsRUFBRSxNQUFNLEdBQUcsU0FBUyxDQUFDO0lBRWxELDRFQUE0RTtJQUM1RSxTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMsWUFDRSxJQUFJLEVBQUU7UUFDSixvQkFBb0IsRUFBRSxNQUFNLENBQUM7UUFDN0IsaUJBQWlCLEVBQUUsTUFBTSxDQUFDO1FBQzFCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztRQUN6QixrQkFBa0IsQ0FBQyxFQUFFLE1BQU0sQ0FBQztRQUM1QixlQUFlLENBQUMsRUFBRSxNQUFNLENBQUM7UUFDekIsT0FBTyxFQUFFLE9BQU8sQ0FBQztLQUNsQixFQUNnQixPQUFPLENBQUMsOEJBQWtCLEVBQzFCLEdBQUcsQ0FBQyxvQkFBUSxFQTJFOUI7SUFFTSxpQkFBaUIsQ0FDdEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLE9BQU8sR0FBRyxjQUFjLENBQUMsSUFBSSxHQUFHLGNBQWMsQ0FBQyxhQUFhLENBQUMsR0FDMUcsU0FBUyxDQUFDO0lBQ04saUJBQWlCLENBQ3RCLEtBQUssRUFBRSxPQUFPLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxPQUFPLEdBQUcsY0FBYyxDQUFDLElBQUksR0FBRyxjQUFjLENBQUMsYUFBYSxDQUFDLEdBQzFHLE1BQU0sQ0FBQztJQUNILGlCQUFpQixDQUFDLEtBQUssRUFBRSxjQUFjLEdBQUcsTUFBTSxHQUFHLFNBQVMsQ0FBQztJQTJCN0QsY0FBYyxDQUFDLFFBQVEsRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLE1BQU0sUUFpQnRFO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxpQkFBaUIsQ0FDdEIsZUFBZSxFQUFFLE1BQU0sR0FFckI7UUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDO1FBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQztRQUFDLFdBQVcsRUFBRSxJQUFJLENBQUE7S0FBRSxHQUMxRDtRQUFFLFFBQVEsRUFBRSxLQUFLLENBQUM7UUFBQyxRQUFRLEVBQUUsU0FBUyxDQUFDO1FBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQTtLQUFFLEdBQzVEO1FBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQztRQUFDLFFBQVEsRUFBRSxNQUFNLENBQUM7UUFBQyxXQUFXLEVBQUUsT0FBTyxDQUFBO0tBQUUsQ0F3RGhFO0NBQ0YifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timetable.d.ts","sourceRoot":"","sources":["../../src/sequencer/timetable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"timetable.d.ts","sourceRoot":"","sources":["../../src/sequencer/timetable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AASpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,kBAAkB;IAqE3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;IArEvB;;;;OAIG;IACH,SAAgB,kBAAkB,EAAE,MAAM,CAAC;IAE3C;;;;OAIG;IACH,SAAgB,oBAAoB,EAAE,MAAM,CAAC;IAE7C;;;;;OAKG;IACH,SAAgB,0BAA0B,EAAE,MAAM,CAAC;IAEnD;;;;OAIG;IACH,SAAgB,gBAAgB,EAAE,MAAM,CAAC;IAEzC;;;OAGG;IACH,SAAgB,gBAAgB,EAAE,MAAM,CAAsB;IAE9D,uDAAuD;IACvD,SAAgB,4BAA4B,EAAE,MAAM,CAAkC;IAEtF,mGAAmG;IACnG,SAAgB,kBAAkB,EAAE,MAAM,CAAC;IAE3C,mFAAmF;IACnF,SAAgB,sBAAsB,EAAE,MAAM,CAA4B;IAE1E,wCAAwC;IACxC,SAAgB,oBAAoB,EAAE,MAAM,CAAC;IAE7C,kFAAkF;IAClF,SAAgB,iBAAiB,EAAE,MAAM,CAAC;IAE1C,4DAA4D;IAC5D,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC,oGAAoG;IACpG,SAAgB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAElD,4EAA4E;IAC5E,SAAgB,iBAAiB,EAAE,MAAM,CAAC;IAE1C,YACE,IAAI,EAAE;QACJ,oBAAoB,EAAE,MAAM,CAAC;QAC7B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,OAAO,EAAE,OAAO,CAAC;KAClB,EACgB,OAAO,CAAC,8BAAkB,EAC1B,GAAG,CAAC,oBAAQ,EA2E9B;IAEM,iBAAiB,CACtB,KAAK,EAAE,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,IAAI,GAAG,cAAc,CAAC,aAAa,CAAC,GAC1G,SAAS,CAAC;IACN,iBAAiB,CACtB,KAAK,EAAE,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,IAAI,GAAG,cAAc,CAAC,aAAa,CAAC,GAC1G,MAAM,CAAC;IACH,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC;IA2B7D,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,QAiBtE;IAED;;;;;;;;OAQG;IACI,iBAAiB,CACtB,eAAe,EAAE,MAAM,GAErB;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,GAC1D;QAAE,QAAQ,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAC;QAAC,WAAW,EAAE,KAAK,CAAA;KAAE,GAC5D;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAwDhE;CACF"}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
|
|
1
|
+
import { CHECKPOINT_ASSEMBLE_TIME, CHECKPOINT_INITIALIZATION_TIME, DEFAULT_P2P_PROPAGATION_TIME, MIN_EXECUTION_TIME } from '@aztec/stdlib/timetable';
|
|
3
2
|
import { SequencerTooSlowError } from './errors.js';
|
|
4
3
|
import { SequencerState } from './utils.js';
|
|
5
|
-
export const MIN_EXECUTION_TIME = 2;
|
|
6
|
-
export const CHECKPOINT_INITIALIZATION_TIME = 1;
|
|
7
|
-
export const CHECKPOINT_ASSEMBLE_TIME = 1;
|
|
8
4
|
export class SequencerTimetable {
|
|
9
5
|
metrics;
|
|
10
6
|
log;
|
|
@@ -41,7 +37,7 @@ export class SequencerTimetable {
|
|
|
41
37
|
/** Whether assertTimeLeft will throw if not enough time. */ enforce;
|
|
42
38
|
/** Duration per block when building multiple blocks per slot (undefined = single block per slot) */ blockDuration;
|
|
43
39
|
/** Maximum number of blocks that can be built in this slot configuration */ maxNumberOfBlocks;
|
|
44
|
-
constructor(opts, metrics, log
|
|
40
|
+
constructor(opts, metrics, log){
|
|
45
41
|
this.metrics = metrics;
|
|
46
42
|
this.log = log;
|
|
47
43
|
this.minExecutionTime = MIN_EXECUTION_TIME;
|
|
@@ -84,7 +80,7 @@ export class SequencerTimetable {
|
|
|
84
80
|
this.checkpointFinalizationTime;
|
|
85
81
|
const initializeDeadline = this.aztecSlotDuration - minWorkToDo;
|
|
86
82
|
this.initializeDeadline = initializeDeadline;
|
|
87
|
-
this.log
|
|
83
|
+
this.log?.info(`Sequencer timetable initialized with ${this.maxNumberOfBlocks} blocks per slot (${this.enforce ? 'enforced' : 'not enforced'})`, {
|
|
88
84
|
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
89
85
|
aztecSlotDuration: this.aztecSlotDuration,
|
|
90
86
|
l1PublishingTime: this.l1PublishingTime,
|
|
@@ -141,7 +137,7 @@ export class SequencerTimetable {
|
|
|
141
137
|
throw new SequencerTooSlowError(newState, maxAllowedTime, secondsIntoSlot);
|
|
142
138
|
}
|
|
143
139
|
this.metrics?.recordStateTransitionBufferMs(Math.floor(bufferSeconds * 1000), newState);
|
|
144
|
-
this.log
|
|
140
|
+
this.log?.trace(`Enough time to transition to ${newState}`, {
|
|
145
141
|
maxAllowedTime,
|
|
146
142
|
secondsIntoSlot
|
|
147
143
|
});
|
|
@@ -175,7 +171,7 @@ export class SequencerTimetable {
|
|
|
175
171
|
const available = (maxAllowed - secondsIntoSlot) / 2; // Split remaining time: half for execution, half for re-execution
|
|
176
172
|
const canStart = available >= this.minExecutionTime;
|
|
177
173
|
const deadline = secondsIntoSlot + available;
|
|
178
|
-
this.log
|
|
174
|
+
this.log?.verbose(`${canStart ? 'Can' : 'Cannot'} start single-block checkpoint at ${secondsIntoSlot}s into slot`, {
|
|
179
175
|
secondsIntoSlot,
|
|
180
176
|
maxAllowed,
|
|
181
177
|
available,
|
|
@@ -197,7 +193,7 @@ export class SequencerTimetable {
|
|
|
197
193
|
if (timeUntilDeadline >= this.minExecutionTime) {
|
|
198
194
|
// Found an available sub-slot! Is this the last one?
|
|
199
195
|
const isLastBlock = subSlot === this.maxNumberOfBlocks;
|
|
200
|
-
this.log
|
|
196
|
+
this.log?.verbose(`Can start ${isLastBlock ? 'last block' : 'block'} in sub-slot ${subSlot} with deadline ${deadline}s`, {
|
|
201
197
|
secondsIntoSlot,
|
|
202
198
|
deadline,
|
|
203
199
|
timeUntilDeadline,
|
|
@@ -212,7 +208,7 @@ export class SequencerTimetable {
|
|
|
212
208
|
}
|
|
213
209
|
}
|
|
214
210
|
// No sub-slots available with enough time
|
|
215
|
-
this.log
|
|
211
|
+
this.log?.verbose(`No time left to start any more blocks`, {
|
|
216
212
|
secondsIntoSlot,
|
|
217
213
|
maxBlocks: this.maxNumberOfBlocks,
|
|
218
214
|
initializationOffset: this.initializationOffset
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
2
|
-
export type SequencerRollupConstants = Pick<L1RollupConstants, 'ethereumSlotDuration' | 'l1GenesisTime' | 'slotDuration'>;
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
2
|
+
export type SequencerRollupConstants = Pick<L1RollupConstants, 'ethereumSlotDuration' | 'l1GenesisTime' | 'slotDuration' | 'rollupManaLimit'>;
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXF1ZW5jZXIvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVyRSxNQUFNLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxDQUN6QyxpQkFBaUIsRUFDakIsc0JBQXNCLEdBQUcsZUFBZSxHQUFHLGNBQWMsR0FBRyxpQkFBaUIsQ0FDOUUsQ0FBQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sequencer/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,iBAAiB,EACjB,sBAAsB,GAAG,eAAe,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sequencer/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,iBAAiB,EACjB,sBAAsB,GAAG,eAAe,GAAG,cAAc,GAAG,iBAAiB,CAC9E,CAAC"}
|