@aztec/sequencer-client 0.0.1-commit.7035c9bd6 → 0.0.1-commit.71324e566

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.
Files changed (70) hide show
  1. package/dest/client/sequencer-client.d.ts +6 -1
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +11 -17
  4. package/dest/config.d.ts +1 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +8 -11
  7. package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
  8. package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
  9. package/dest/global_variable_builder/fee_predictor.js +128 -0
  10. package/dest/global_variable_builder/fee_provider.d.ts +21 -0
  11. package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
  12. package/dest/global_variable_builder/fee_provider.js +58 -0
  13. package/dest/global_variable_builder/global_builder.d.ts +15 -14
  14. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  15. package/dest/global_variable_builder/global_builder.js +16 -51
  16. package/dest/global_variable_builder/index.d.ts +4 -2
  17. package/dest/global_variable_builder/index.d.ts.map +1 -1
  18. package/dest/global_variable_builder/index.js +2 -0
  19. package/dest/publisher/config.d.ts +13 -1
  20. package/dest/publisher/config.d.ts.map +1 -1
  21. package/dest/publisher/config.js +19 -4
  22. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +3 -4
  23. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -1
  24. package/dest/publisher/sequencer-publisher-factory.d.ts +3 -5
  25. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  26. package/dest/publisher/sequencer-publisher-factory.js +2 -3
  27. package/dest/publisher/sequencer-publisher.d.ts +48 -42
  28. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  29. package/dest/publisher/sequencer-publisher.js +117 -109
  30. package/dest/sequencer/chain_state_overrides.d.ts +25 -0
  31. package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
  32. package/dest/sequencer/chain_state_overrides.js +39 -0
  33. package/dest/sequencer/checkpoint_proposal_job.d.ts +21 -10
  34. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  35. package/dest/sequencer/checkpoint_proposal_job.js +200 -134
  36. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
  37. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
  38. package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
  39. package/dest/sequencer/checkpoint_voter.d.ts +1 -2
  40. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
  41. package/dest/sequencer/checkpoint_voter.js +2 -5
  42. package/dest/sequencer/metrics.d.ts +5 -10
  43. package/dest/sequencer/metrics.d.ts.map +1 -1
  44. package/dest/sequencer/metrics.js +12 -20
  45. package/dest/sequencer/sequencer.d.ts +17 -4
  46. package/dest/sequencer/sequencer.d.ts.map +1 -1
  47. package/dest/sequencer/sequencer.js +76 -23
  48. package/dest/sequencer/timetable.d.ts +14 -1
  49. package/dest/sequencer/timetable.d.ts.map +1 -1
  50. package/dest/sequencer/timetable.js +45 -36
  51. package/package.json +27 -27
  52. package/src/client/sequencer-client.ts +16 -24
  53. package/src/config.ts +8 -11
  54. package/src/global_variable_builder/README.md +44 -0
  55. package/src/global_variable_builder/fee_predictor.ts +172 -0
  56. package/src/global_variable_builder/fee_provider.ts +75 -0
  57. package/src/global_variable_builder/global_builder.ts +26 -63
  58. package/src/global_variable_builder/index.ts +3 -1
  59. package/src/publisher/config.ts +38 -4
  60. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +3 -1
  61. package/src/publisher/sequencer-publisher-factory.ts +3 -6
  62. package/src/publisher/sequencer-publisher.ts +181 -155
  63. package/src/sequencer/README.md +83 -13
  64. package/src/sequencer/chain_state_overrides.ts +87 -0
  65. package/src/sequencer/checkpoint_proposal_job.ts +242 -154
  66. package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
  67. package/src/sequencer/checkpoint_voter.ts +1 -12
  68. package/src/sequencer/metrics.ts +15 -25
  69. package/src/sequencer/sequencer.ts +113 -25
  70. package/src/sequencer/timetable.ts +57 -45
@@ -373,7 +373,7 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
373
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
- import { NoCommitteeError } from '@aztec/ethereum/contracts';
376
+ import { NoCommitteeError, SimulationOverridesBuilder } from '@aztec/ethereum/contracts';
377
377
  import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
378
378
  import { merge, omit, pick } from '@aztec/foundation/collection';
379
379
  import { Fr } from '@aztec/foundation/curves/bn254';
@@ -388,6 +388,7 @@ import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-clie
388
388
  import EventEmitter from 'node:events';
389
389
  import { DefaultSequencerConfig } from '../config.js';
390
390
  import { CheckpointProposalJob } from './checkpoint_proposal_job.js';
391
+ import { CheckpointProposalJobMetrics } from './checkpoint_proposal_job_metrics.js';
391
392
  import { CheckpointVoter } from './checkpoint_voter.js';
392
393
  import { SequencerInterruptedError, SequencerTooSlowError } from './errors.js';
393
394
  import { SequencerMetrics } from './metrics.js';
@@ -449,11 +450,13 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
449
450
  runningPromise;
450
451
  state;
451
452
  metrics;
453
+ checkpointProposalJobMetrics;
452
454
  /** The last slot for which we attempted to perform our voting duties with degraded block production */ lastSlotForFallbackVote;
453
455
  /** The last slot for which we logged "no committee" warning, to avoid spam */ lastSlotForNoCommitteeWarning;
454
456
  /** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */ lastSlotForCheckpointProposalJob;
455
457
  /** Last successful checkpoint proposed */ lastCheckpointProposed;
456
458
  /** The last epoch for which we logged strategy comparison in fisherman mode. */ lastEpochForStrategyComparison;
459
+ /** The last checkpoint proposal job, tracked so we can await its pending L1 submission during shutdown. */ lastCheckpointProposalJob;
457
460
  /** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */ timetable;
458
461
  /** Config for the sequencer */ config;
459
462
  constructor(publisherFactory, validatorClient, globalsBuilder, p2pClient, worldState, slasherClient, l2BlockSource, l1ToL2MessageSource, checkpointsBuilder, l1Constants, dateProvider, epochCache, rollupContract, config, telemetry = getTelemetryClient(), log = createLogger('sequencer')){
@@ -463,19 +466,22 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
463
466
  this.log = log.createChild('[FISHERMAN]');
464
467
  }
465
468
  this.metrics = new SequencerMetrics(telemetry, this.rollupContract, 'Sequencer');
469
+ this.checkpointProposalJobMetrics = new CheckpointProposalJobMetrics(telemetry);
466
470
  this.updateConfig(config);
467
471
  }
468
472
  /** Updates sequencer config by the defined values and updates the timetable */ updateConfig(config) {
469
473
  const filteredConfig = pickFromSchema(config, SequencerConfigSchema);
470
474
  this.log.info(`Updated sequencer config`, omit(filteredConfig, 'txPublicSetupAllowListExtend'));
471
475
  this.config = merge(this.config, filteredConfig);
476
+ const p2pPropagationTime = this.config.attestationPropagationTime;
472
477
  this.timetable = new SequencerTimetable({
473
478
  ethereumSlotDuration: this.l1Constants.ethereumSlotDuration,
474
479
  aztecSlotDuration: this.aztecSlotDuration,
475
480
  l1PublishingTime: this.l1PublishingTime,
476
- p2pPropagationTime: this.config.attestationPropagationTime,
481
+ p2pPropagationTime,
477
482
  blockDurationMs: this.config.blockDurationMs,
478
- enforce: this.config.enforceTimeTable
483
+ enforce: this.config.enforceTimeTable,
484
+ pipelining: this.epochCache.isProposerPipeliningEnabled()
479
485
  }, this.metrics, this.log);
480
486
  }
481
487
  /** Initializes the sequencer (precomputes tables). Takes about 3s. */ init() {
@@ -489,13 +495,17 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
489
495
  this.runningPromise.start();
490
496
  this.log.info('Started sequencer');
491
497
  }
498
+ /** Triggers an immediate run of the sequencer, bypassing the polling interval. */ trigger() {
499
+ return this.runningPromise?.trigger();
500
+ }
492
501
  /** Stops the sequencer from building blocks and moves to STOPPED state. */ async stop() {
493
502
  this.log.info(`Stopping sequencer`);
494
503
  this.setState(SequencerState.STOPPING, undefined, {
495
504
  force: true
496
505
  });
497
- this.publisherFactory.interruptAll();
506
+ await this.publisherFactory.stopAll();
498
507
  await this.runningPromise?.stop();
508
+ await this.lastCheckpointProposalJob?.awaitPendingSubmission();
499
509
  this.setState(SequencerState.STOPPED, undefined, {
500
510
  force: true
501
511
  });
@@ -546,6 +556,8 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
546
556
  if (!checkpointProposalJob) {
547
557
  return;
548
558
  }
559
+ // Track the job so we can await its pending L1 submission during shutdown
560
+ this.lastCheckpointProposalJob = checkpointProposalJob;
549
561
  // Execute the checkpoint proposal job
550
562
  const checkpoint = await checkpointProposalJob.execute();
551
563
  // Update last checkpoint proposed (currently unused)
@@ -629,6 +641,13 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
629
641
  await this.considerInvalidatingCheckpoint(syncedTo, slot);
630
642
  return undefined;
631
643
  }
644
+ // Guard: don't exceed 1-deep pipeline. Without a proposed checkpoint, we can only build
645
+ // confirmed + 1. With a proposed checkpoint, we can build confirmed + 2.
646
+ const confirmedCkpt = syncedTo.checkpointedCheckpointNumber;
647
+ if (checkpointNumber > confirmedCkpt + 2) {
648
+ this.log.verbose(`Skipping slot ${targetSlot}: checkpoint ${checkpointNumber} exceeds max pipeline depth (confirmed=${confirmedCkpt})`);
649
+ return undefined;
650
+ }
632
651
  // Check that the target slot is not taken by a block already (should never happen, since only us can propose for this slot)
633
652
  if (syncedTo.blockData && syncedTo.blockData.header.getSlot() >= targetSlot) {
634
653
  this.log.warn(`Cannot propose block at target slot ${targetSlot} since that slot was taken by block ${syncedTo.blockNumber}`, {
@@ -651,12 +670,32 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
651
670
  this.log.debug(`Set proposer address ${proposer} for simulation in fisherman mode`);
652
671
  }
653
672
  // Prepare invalidation request if the pending chain is invalid (returns undefined if no need)
654
- const invalidateCheckpoint = await publisher.simulateInvalidateCheckpoint(syncedTo.pendingChainValidationStatus);
655
- // Check with the rollup contract if we can indeed propose at the target slot. This check should not fail
656
- // if all the previous checks are good, but we do it just in case.
657
- const canProposeCheck = await publisher.canProposeAt(syncedTo.archive, proposer ?? EthAddress.ZERO, {
658
- ...invalidateCheckpoint
659
- });
673
+ let invalidateCheckpoint = await publisher.simulateInvalidateCheckpoint(syncedTo.pendingChainValidationStatus);
674
+ // Determine the correct archive and L1 state overrides for the canProposeAt check.
675
+ // The L1 contract reads archives[proposedCheckpointNumber] and compares it with the provided archive.
676
+ // When invalidating or pipelining, the local archive may differ from L1's, so we adjust accordingly.
677
+ let archiveForCheck = syncedTo.archive;
678
+ const l1SimulationOverridesBuilder = new SimulationOverridesBuilder();
679
+ if (this.epochCache.isProposerPipeliningEnabled() && syncedTo.hasProposedCheckpoint) {
680
+ // Parent checkpoint hasn't landed on L1 yet. Override both the proposed checkpoint number
681
+ // and the archive at that checkpoint so L1 simulation sees the correct chain tip.
682
+ const parentCheckpointNumber = CheckpointNumber(checkpointNumber - 1);
683
+ l1SimulationOverridesBuilder.forPendingCheckpoint(parentCheckpointNumber).withPendingArchive(syncedTo.archive);
684
+ this.metrics.recordPipelineDepth(1);
685
+ this.log.verbose(`Building on top of proposed checkpoint (pending=${syncedTo.proposedCheckpointData?.checkpointNumber})`);
686
+ // Clear the invalidation - the proposed checkpoint should handle it.
687
+ invalidateCheckpoint = undefined;
688
+ } else if (invalidateCheckpoint) {
689
+ // After invalidation, L1 will roll back to checkpoint N-1. The archive at N-1 already
690
+ // exists on L1, so we just pass the matching archive (the lastArchive of the invalid checkpoint).
691
+ archiveForCheck = invalidateCheckpoint.lastArchive;
692
+ l1SimulationOverridesBuilder.forPendingCheckpoint(invalidateCheckpoint.forcePendingCheckpointNumber);
693
+ this.metrics.recordPipelineDepth(0);
694
+ } else {
695
+ this.metrics.recordPipelineDepth(0);
696
+ }
697
+ const simulationOverridesPlan = l1SimulationOverridesBuilder.build();
698
+ const canProposeCheck = await publisher.canProposeAt(archiveForCheck, proposer ?? EthAddress.ZERO, simulationOverridesPlan);
660
699
  if (canProposeCheck === undefined) {
661
700
  this.log.warn(`Cannot propose checkpoint ${checkpointNumber} at slot ${slot} due to failed rollup contract check`, logCtx);
662
701
  this.emit('proposer-rollup-check-failed', {
@@ -700,10 +739,10 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
700
739
  pipeliningEnabled: this.epochCache.isProposerPipeliningEnabled()
701
740
  });
702
741
  // Create and return the checkpoint proposal job
703
- return this.createCheckpointProposalJob(slot, targetSlot, epoch, targetEpoch, checkpointNumber, syncedTo.blockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint);
742
+ return this.createCheckpointProposalJob(slot, targetSlot, targetEpoch, checkpointNumber, syncedTo.blockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint, syncedTo.proposedCheckpointData);
704
743
  }
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());
744
+ createCheckpointProposalJob(slot, targetSlot, targetEpoch, checkpointNumber, syncedToBlockNumber, proposer, publisher, attestorAddress, invalidateCheckpoint, proposedCheckpointData) {
745
+ return new CheckpointProposalJob(slot, targetSlot, 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.checkpointProposalJobMetrics.createRecorder(), this, this.setState.bind(this), this.tracer, this.log.getBindings(), proposedCheckpointData);
707
746
  }
708
747
  /**
709
748
  * Returns the current sequencer state.
@@ -751,8 +790,8 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
751
790
  * We don't check against the previous block submitted since it may have been reorg'd out.
752
791
  */ async checkSync(args) {
753
792
  // Check that the archiver has fully synced the L2 slot before the one we want to propose in.
754
- // TODO(#14766): Archiver reports L1 timestamp based on L1 blocks seen, which means that a missed L1 block will
755
- // cause the archiver L1 timestamp to fall behind, and cause this sequencer to start processing one L1 slot later.
793
+ // The archiver reports sync progress via L1 block timestamps and synced checkpoint slots.
794
+ // See getSyncedL2SlotNumber for how missed L1 blocks are handled.
756
795
  const syncedL2Slot = await this.l2BlockSource.getSyncedL2SlotNumber();
757
796
  const { slot } = args;
758
797
  if (syncedL2Slot === undefined || syncedL2Slot + 1 < slot) {
@@ -767,22 +806,30 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
767
806
  number: syncSummary.latestBlockNumber,
768
807
  hash: syncSummary.latestBlockHash
769
808
  })),
770
- this.l2BlockSource.getL2Tips().then((t)=>t.proposed),
809
+ this.l2BlockSource.getL2Tips().then((t)=>({
810
+ proposed: t.proposed,
811
+ checkpointed: t.checkpointed,
812
+ proposedCheckpoint: t.proposedCheckpoint
813
+ })),
771
814
  this.p2pClient.getStatus().then((p2p)=>p2p.syncedToL2Block),
772
- this.l1ToL2MessageSource.getL2Tips().then((t)=>t.proposed),
773
- this.l2BlockSource.getPendingChainValidationStatus()
815
+ this.l1ToL2MessageSource.getL2Tips().then((t)=>({
816
+ proposed: t.proposed,
817
+ checkpointed: t.checkpointed
818
+ })),
819
+ this.l2BlockSource.getPendingChainValidationStatus(),
820
+ this.l2BlockSource.getProposedCheckpointOnly()
774
821
  ]);
775
- const [worldState, l2BlockSource, p2p, l1ToL2MessageSource, pendingChainValidationStatus] = syncedBlocks;
822
+ const [worldState, l2Tips, p2p, l1ToL2MessageSourceTips, pendingChainValidationStatus, proposedCheckpointData] = syncedBlocks;
776
823
  // Handle zero as a special case, since the block hash won't match across services if we're changing the prefilled data for the genesis block,
777
824
  // as the world state can compute the new genesis block hash, but other components use the hardcoded constant.
778
825
  // TODO(palla/mbps): Fix the above. All components should be able to handle dynamic genesis block hashes.
779
- const result = l2BlockSource.number === 0 && worldState.number === 0 && p2p.number === 0 && l1ToL2MessageSource.number === 0 || worldState.hash === l2BlockSource.hash && p2p.hash === l2BlockSource.hash && l1ToL2MessageSource.hash === l2BlockSource.hash;
826
+ const result = l2Tips.proposed.number === 0 && l2Tips.checkpointed.block.number === 0 && l2Tips.checkpointed.checkpoint.number === 0 && worldState.number === 0 && p2p.number === 0 && l1ToL2MessageSourceTips.proposed.number === 0 && l1ToL2MessageSourceTips.checkpointed.block.number === 0 && l1ToL2MessageSourceTips.checkpointed.checkpoint.number === 0 || worldState.hash === l2Tips.proposed.hash && p2p.hash === l2Tips.proposed.hash && l1ToL2MessageSourceTips.proposed.hash === l2Tips.proposed.hash && l1ToL2MessageSourceTips.checkpointed.block.hash === l2Tips.checkpointed.block.hash && l1ToL2MessageSourceTips.checkpointed.checkpoint.hash === l2Tips.checkpointed.checkpoint.hash;
780
827
  if (!result) {
781
828
  this.log.debug(`Sequencer sync check failed`, {
782
829
  worldState,
783
- l2BlockSource,
830
+ l2BlockSource: l2Tips.proposed,
784
831
  p2p,
785
- l1ToL2MessageSource
832
+ l1ToL2MessageSourceTips
786
833
  });
787
834
  return undefined;
788
835
  }
@@ -792,8 +839,10 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
792
839
  const archive = new Fr((await this.worldState.getCommitted().getTreeInfo(MerkleTreeId.ARCHIVE)).root);
793
840
  return {
794
841
  checkpointNumber: CheckpointNumber.ZERO,
842
+ checkpointedCheckpointNumber: CheckpointNumber.ZERO,
795
843
  blockNumber: BlockNumber.ZERO,
796
844
  archive,
845
+ hasProposedCheckpoint: false,
797
846
  syncedL2Slot,
798
847
  pendingChainValidationStatus
799
848
  };
@@ -804,11 +853,15 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
804
853
  this.log.error(`Failed to get L2 block data ${blockNumber} from the archiver with all components in sync`);
805
854
  return undefined;
806
855
  }
856
+ const hasProposedCheckpoint = l2Tips.proposedCheckpoint.checkpoint.number > l2Tips.checkpointed.checkpoint.number;
807
857
  return {
808
858
  blockData,
809
859
  blockNumber: blockData.header.getBlockNumber(),
810
860
  checkpointNumber: blockData.checkpointNumber,
861
+ checkpointedCheckpointNumber: l2Tips.checkpointed.checkpoint.number,
811
862
  archive: blockData.archive.root,
863
+ hasProposedCheckpoint,
864
+ proposedCheckpointData,
812
865
  syncedL2Slot,
813
866
  pendingChainValidationStatus
814
867
  };
@@ -864,7 +917,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
864
917
  proposer
865
918
  ];
866
919
  }
867
- this.log.debug(`We are the proposer for target slot ${targetSlot}`, {
920
+ this.log.info(`We are the proposer for pipeline slot ${targetSlot}`, {
868
921
  targetSlot,
869
922
  proposer
870
923
  });
@@ -4,6 +4,7 @@ import { SequencerState } from './utils.js';
4
4
  export declare class SequencerTimetable {
5
5
  private readonly metrics?;
6
6
  private readonly log?;
7
+ private readonly checkpointTiming;
7
8
  /**
8
9
  * How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
9
10
  * assuming an execution time equal to `minExecutionTime`, subtracted from the slot duration. This means that, if the proposer
@@ -50,6 +51,13 @@ export declare class SequencerTimetable {
50
51
  readonly blockDuration: number | undefined;
51
52
  /** Maximum number of blocks that can be built in this slot configuration */
52
53
  readonly maxNumberOfBlocks: number;
54
+ /** Whether pipelining is enabled (checkpoint finalization deferred to next slot). */
55
+ readonly pipelining: boolean;
56
+ /**
57
+ * How far into the target slot attestation collection can extend when pipelining.
58
+ * Covers validator re-execution (one block duration) plus one-way attestation return.
59
+ */
60
+ readonly pipeliningAttestationGracePeriod: number;
53
61
  constructor(opts: {
54
62
  ethereumSlotDuration: number;
55
63
  aztecSlotDuration: number;
@@ -57,7 +65,12 @@ export declare class SequencerTimetable {
57
65
  p2pPropagationTime?: number;
58
66
  blockDurationMs?: number;
59
67
  enforce: boolean;
68
+ pipelining?: boolean;
60
69
  }, metrics?: SequencerMetrics | undefined, log?: Logger | undefined);
70
+ getCheckpointAssemblyDeadline(): number;
71
+ getCheckpointAttestationDeadline(): number;
72
+ getCheckpointAttestationStartDeadline(): number;
73
+ getCheckpointPublishingDeadline(): number;
61
74
  getMaxAllowedTime(state: Extract<SequencerState, SequencerState.STOPPED | SequencerState.IDLE | SequencerState.SYNCHRONIZING>): undefined;
62
75
  getMaxAllowedTime(state: Exclude<SequencerState, SequencerState.STOPPED | SequencerState.IDLE | SequencerState.SYNCHRONIZING>): number;
63
76
  getMaxAllowedTime(state: SequencerState): number | undefined;
@@ -85,4 +98,4 @@ export declare class SequencerTimetable {
85
98
  isLastBlock: boolean;
86
99
  };
87
100
  }
88
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXRhYmxlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL3RpbWV0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQVNwRCxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTVDLHFCQUFhLGtCQUFrQjtJQXFFM0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUM7SUFyRXZCOzs7O09BSUc7SUFDSCxTQUFnQixrQkFBa0IsRUFBRSxNQUFNLENBQUM7SUFFM0M7Ozs7T0FJRztJQUNILFNBQWdCLG9CQUFvQixFQUFFLE1BQU0sQ0FBQztJQUU3Qzs7Ozs7T0FLRztJQUNILFNBQWdCLDBCQUEwQixFQUFFLE1BQU0sQ0FBQztJQUVuRDs7OztPQUlHO0lBQ0gsU0FBZ0IsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDO0lBRXpDOzs7T0FHRztJQUNILFNBQWdCLGdCQUFnQixFQUFFLE1BQU0sQ0FBc0I7SUFFOUQsdURBQXVEO0lBQ3ZELFNBQWdCLDRCQUE0QixFQUFFLE1BQU0sQ0FBa0M7SUFFdEYsbUdBQW1HO0lBQ25HLFNBQWdCLGtCQUFrQixFQUFFLE1BQU0sQ0FBQztJQUUzQyxtRkFBbUY7SUFDbkYsU0FBZ0Isc0JBQXNCLEVBQUUsTUFBTSxDQUE0QjtJQUUxRSx3Q0FBd0M7SUFDeEMsU0FBZ0Isb0JBQW9CLEVBQUUsTUFBTSxDQUFDO0lBRTdDLGtGQUFrRjtJQUNsRixTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMsNERBQTREO0lBQzVELFNBQWdCLE9BQU8sRUFBRSxPQUFPLENBQUM7SUFFakMsb0dBQW9HO0lBQ3BHLFNBQWdCLGFBQWEsRUFBRSxNQUFNLEdBQUcsU0FBUyxDQUFDO0lBRWxELDRFQUE0RTtJQUM1RSxTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMsWUFDRSxJQUFJLEVBQUU7UUFDSixvQkFBb0IsRUFBRSxNQUFNLENBQUM7UUFDN0IsaUJBQWlCLEVBQUUsTUFBTSxDQUFDO1FBQzFCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztRQUN6QixrQkFBa0IsQ0FBQyxFQUFFLE1BQU0sQ0FBQztRQUM1QixlQUFlLENBQUMsRUFBRSxNQUFNLENBQUM7UUFDekIsT0FBTyxFQUFFLE9BQU8sQ0FBQztLQUNsQixFQUNnQixPQUFPLENBQUMsOEJBQWtCLEVBQzFCLEdBQUcsQ0FBQyxvQkFBUSxFQTJFOUI7SUFFTSxpQkFBaUIsQ0FDdEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLE9BQU8sR0FBRyxjQUFjLENBQUMsSUFBSSxHQUFHLGNBQWMsQ0FBQyxhQUFhLENBQUMsR0FDMUcsU0FBUyxDQUFDO0lBQ04saUJBQWlCLENBQ3RCLEtBQUssRUFBRSxPQUFPLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxPQUFPLEdBQUcsY0FBYyxDQUFDLElBQUksR0FBRyxjQUFjLENBQUMsYUFBYSxDQUFDLEdBQzFHLE1BQU0sQ0FBQztJQUNILGlCQUFpQixDQUFDLEtBQUssRUFBRSxjQUFjLEdBQUcsTUFBTSxHQUFHLFNBQVMsQ0FBQztJQTJCN0QsY0FBYyxDQUFDLFFBQVEsRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLE1BQU0sUUFpQnRFO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxpQkFBaUIsQ0FDdEIsZUFBZSxFQUFFLE1BQU0sR0FFckI7UUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDO1FBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQztRQUFDLFdBQVcsRUFBRSxJQUFJLENBQUE7S0FBRSxHQUMxRDtRQUFFLFFBQVEsRUFBRSxLQUFLLENBQUM7UUFBQyxRQUFRLEVBQUUsU0FBUyxDQUFDO1FBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQTtLQUFFLEdBQzVEO1FBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQztRQUFDLFFBQVEsRUFBRSxNQUFNLENBQUM7UUFBQyxXQUFXLEVBQUUsT0FBTyxDQUFBO0tBQUUsQ0F3RGhFO0NBQ0YifQ==
101
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXRhYmxlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL3RpbWV0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQVdwRCxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTVDLHFCQUFhLGtCQUFrQjtJQWlGM0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUM7SUFqRnZCLE9BQU8sQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQW1CO0lBRXBEOzs7O09BSUc7SUFDSCxTQUFnQixrQkFBa0IsRUFBRSxNQUFNLENBQUM7SUFFM0M7Ozs7T0FJRztJQUNILFNBQWdCLG9CQUFvQixFQUFFLE1BQU0sQ0FBQztJQUU3Qzs7Ozs7T0FLRztJQUNILFNBQWdCLDBCQUEwQixFQUFFLE1BQU0sQ0FBQztJQUVuRDs7OztPQUlHO0lBQ0gsU0FBZ0IsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDO0lBRXpDOzs7T0FHRztJQUNILFNBQWdCLGdCQUFnQixFQUFFLE1BQU0sQ0FBc0I7SUFFOUQsdURBQXVEO0lBQ3ZELFNBQWdCLDRCQUE0QixFQUFFLE1BQU0sQ0FBa0M7SUFFdEYsbUdBQW1HO0lBQ25HLFNBQWdCLGtCQUFrQixFQUFFLE1BQU0sQ0FBQztJQUUzQyxtRkFBbUY7SUFDbkYsU0FBZ0Isc0JBQXNCLEVBQUUsTUFBTSxDQUE0QjtJQUUxRSx3Q0FBd0M7SUFDeEMsU0FBZ0Isb0JBQW9CLEVBQUUsTUFBTSxDQUFDO0lBRTdDLGtGQUFrRjtJQUNsRixTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMsNERBQTREO0lBQzVELFNBQWdCLE9BQU8sRUFBRSxPQUFPLENBQUM7SUFFakMsb0dBQW9HO0lBQ3BHLFNBQWdCLGFBQWEsRUFBRSxNQUFNLEdBQUcsU0FBUyxDQUFDO0lBRWxELDRFQUE0RTtJQUM1RSxTQUFnQixpQkFBaUIsRUFBRSxNQUFNLENBQUM7SUFFMUMscUZBQXFGO0lBQ3JGLFNBQWdCLFVBQVUsRUFBRSxPQUFPLENBQUM7SUFFcEM7OztPQUdHO0lBQ0gsU0FBZ0IsZ0NBQWdDLEVBQUUsTUFBTSxDQUFDO0lBRXpELFlBQ0UsSUFBSSxFQUFFO1FBQ0osb0JBQW9CLEVBQUUsTUFBTSxDQUFDO1FBQzdCLGlCQUFpQixFQUFFLE1BQU0sQ0FBQztRQUMxQixnQkFBZ0IsRUFBRSxNQUFNLENBQUM7UUFDekIsa0JBQWtCLENBQUMsRUFBRSxNQUFNLENBQUM7UUFDNUIsZUFBZSxDQUFDLEVBQUUsTUFBTSxDQUFDO1FBQ3pCLE9BQU8sRUFBRSxPQUFPLENBQUM7UUFDakIsVUFBVSxDQUFDLEVBQUUsT0FBTyxDQUFDO0tBQ3RCLEVBQ2dCLE9BQU8sQ0FBQyw4QkFBa0IsRUFDMUIsR0FBRyxDQUFDLG9CQUFRLEVBd0Q5QjtJQUVNLDZCQUE2QixJQUFJLE1BQU0sQ0FFN0M7SUFFTSxnQ0FBZ0MsSUFBSSxNQUFNLENBRWhEO0lBRU0scUNBQXFDLElBQUksTUFBTSxDQUVyRDtJQUVNLCtCQUErQixJQUFJLE1BQU0sQ0FFL0M7SUFFTSxpQkFBaUIsQ0FDdEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLE9BQU8sR0FBRyxjQUFjLENBQUMsSUFBSSxHQUFHLGNBQWMsQ0FBQyxhQUFhLENBQUMsR0FDMUcsU0FBUyxDQUFDO0lBQ04saUJBQWlCLENBQ3RCLEtBQUssRUFBRSxPQUFPLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxPQUFPLEdBQUcsY0FBYyxDQUFDLElBQUksR0FBRyxjQUFjLENBQUMsYUFBYSxDQUFDLEdBQzFHLE1BQU0sQ0FBQztJQUNILGlCQUFpQixDQUFDLEtBQUssRUFBRSxjQUFjLEdBQUcsTUFBTSxHQUFHLFNBQVMsQ0FBQztJQTRCN0QsY0FBYyxDQUFDLFFBQVEsRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLE1BQU0sUUFpQnRFO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxpQkFBaUIsQ0FDdEIsZUFBZSxFQUFFLE1BQU0sR0FFckI7UUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDO1FBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQztRQUFDLFdBQVcsRUFBRSxJQUFJLENBQUE7S0FBRSxHQUMxRDtRQUFFLFFBQVEsRUFBRSxLQUFLLENBQUM7UUFBQyxRQUFRLEVBQUUsU0FBUyxDQUFDO1FBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQTtLQUFFLEdBQzVEO1FBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQztRQUFDLFFBQVEsRUFBRSxNQUFNLENBQUM7UUFBQyxXQUFXLEVBQUUsT0FBTyxDQUFBO0tBQUUsQ0F3RGhFO0NBQ0YifQ==
@@ -1 +1 @@
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
+ {"version":3,"file":"timetable.d.ts","sourceRoot":"","sources":["../../src/sequencer/timetable.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
- import { CHECKPOINT_ASSEMBLE_TIME, CHECKPOINT_INITIALIZATION_TIME, DEFAULT_P2P_PROPAGATION_TIME, MIN_EXECUTION_TIME } from '@aztec/stdlib/timetable';
1
+ import { CHECKPOINT_ASSEMBLE_TIME, CHECKPOINT_INITIALIZATION_TIME, DEFAULT_P2P_PROPAGATION_TIME, MIN_EXECUTION_TIME, createCheckpointTimingModel } from '@aztec/stdlib/timetable';
2
2
  import { SequencerTooSlowError } from './errors.js';
3
3
  import { SequencerState } from './utils.js';
4
4
  export class SequencerTimetable {
5
5
  metrics;
6
6
  log;
7
+ checkpointTiming;
7
8
  /**
8
9
  * How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
9
10
  * assuming an execution time equal to `minExecutionTime`, subtracted from the slot duration. This means that, if the proposer
@@ -37,6 +38,11 @@ export class SequencerTimetable {
37
38
  /** Whether assertTimeLeft will throw if not enough time. */ enforce;
38
39
  /** Duration per block when building multiple blocks per slot (undefined = single block per slot) */ blockDuration;
39
40
  /** Maximum number of blocks that can be built in this slot configuration */ maxNumberOfBlocks;
41
+ /** Whether pipelining is enabled (checkpoint finalization deferred to next slot). */ pipelining;
42
+ /**
43
+ * How far into the target slot attestation collection can extend when pipelining.
44
+ * Covers validator re-execution (one block duration) plus one-way attestation return.
45
+ */ pipeliningAttestationGracePeriod;
40
46
  constructor(opts, metrics, log){
41
47
  this.metrics = metrics;
42
48
  this.log = log;
@@ -46,40 +52,28 @@ export class SequencerTimetable {
46
52
  this.ethereumSlotDuration = opts.ethereumSlotDuration;
47
53
  this.aztecSlotDuration = opts.aztecSlotDuration;
48
54
  this.l1PublishingTime = opts.l1PublishingTime;
49
- this.p2pPropagationTime = opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME;
50
55
  this.blockDuration = opts.blockDurationMs ? opts.blockDurationMs / 1000 : undefined;
51
56
  this.enforce = opts.enforce;
52
- // Assume zero-cost propagation time and faster runs in test environments where L1 slot duration is shortened
53
- if (this.ethereumSlotDuration < 8) {
54
- this.p2pPropagationTime = 0;
55
- this.checkpointAssembleTime = 0.5;
56
- this.checkpointInitializationTime = 0.5;
57
- this.minExecutionTime = 1;
58
- }
59
- // Min execution time cannot be less than the block duration if set
60
- if (this.blockDuration !== undefined && this.minExecutionTime > this.blockDuration) {
61
- this.minExecutionTime = this.blockDuration;
62
- }
57
+ this.pipelining = opts.pipelining ?? false;
58
+ this.checkpointTiming = createCheckpointTimingModel({
59
+ aztecSlotDuration: this.aztecSlotDuration,
60
+ ethereumSlotDuration: this.ethereumSlotDuration,
61
+ blockDuration: this.blockDuration,
62
+ l1PublishingTime: this.l1PublishingTime,
63
+ p2pPropagationTime: opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME,
64
+ pipelining: this.pipelining
65
+ });
66
+ this.p2pPropagationTime = this.checkpointTiming.p2pPropagationTime;
67
+ this.checkpointAssembleTime = this.checkpointTiming.checkpointAssembleTime;
68
+ this.checkpointInitializationTime = this.checkpointTiming.checkpointInitializationTime;
69
+ this.minExecutionTime = this.checkpointTiming.minExecutionTime;
63
70
  // Calculate initialization offset - estimate of time needed for sync + proposer check
64
71
  // This is the baseline for all sub-slot deadlines
65
- this.initializationOffset = this.checkpointInitializationTime;
66
- // Calculate total checkpoint finalization time (assembly + attestations + L1 publishing)
67
- this.checkpointFinalizationTime = this.checkpointAssembleTime + this.p2pPropagationTime * 2 + // Round-trip propagation
68
- this.l1PublishingTime; // L1 publishing
69
- // Calculate maximum number of blocks that fit in this slot
70
- if (!this.blockDuration) {
71
- this.maxNumberOfBlocks = 1; // Single block per slot
72
- } else {
73
- const timeReservedAtEnd = this.blockDuration + // Last sub-slot for validator re-execution
74
- this.checkpointFinalizationTime; // Checkpoint finalization
75
- const timeAvailableForBlocks = this.aztecSlotDuration - this.initializationOffset - timeReservedAtEnd;
76
- this.maxNumberOfBlocks = Math.floor(timeAvailableForBlocks / this.blockDuration);
77
- }
78
- // Minimum work to do within a slot for building a block with the minimum time for execution and publishing its checkpoint
79
- const minWorkToDo = this.initializationOffset + this.minExecutionTime * 2 + // Execution and reexecution
80
- this.checkpointFinalizationTime;
81
- const initializeDeadline = this.aztecSlotDuration - minWorkToDo;
82
- this.initializeDeadline = initializeDeadline;
72
+ this.initializationOffset = this.checkpointTiming.checkpointInitializationTime;
73
+ this.checkpointFinalizationTime = this.checkpointTiming.checkpointFinalizationTime;
74
+ this.pipeliningAttestationGracePeriod = this.checkpointTiming.pipeliningAttestationGracePeriod;
75
+ this.maxNumberOfBlocks = this.checkpointTiming.calculateMaxBlocksPerSlot();
76
+ this.initializeDeadline = this.checkpointTiming.initializeDeadline;
83
77
  this.log?.info(`Sequencer timetable initialized with ${this.maxNumberOfBlocks} blocks per slot (${this.enforce ? 'enforced' : 'not enforced'})`, {
84
78
  ethereumSlotDuration: this.ethereumSlotDuration,
85
79
  aztecSlotDuration: this.aztecSlotDuration,
@@ -90,14 +84,28 @@ export class SequencerTimetable {
90
84
  blockAssembleTime: this.checkpointAssembleTime,
91
85
  initializeDeadline: this.initializeDeadline,
92
86
  enforce: this.enforce,
93
- minWorkToDo,
87
+ pipelining: this.pipelining,
88
+ pipeliningAttestationGracePeriod: this.pipeliningAttestationGracePeriod,
89
+ minWorkToDo: this.checkpointTiming.minimumBuildSlotWork,
94
90
  blockDuration: this.blockDuration,
95
91
  maxNumberOfBlocks: this.maxNumberOfBlocks
96
92
  });
97
- if (initializeDeadline <= 0) {
98
- throw new Error(`Block proposal initialize deadline cannot be negative (got ${initializeDeadline} from total time needed ${minWorkToDo} and a slot duration of ${this.aztecSlotDuration}).`);
93
+ if (this.initializeDeadline <= 0) {
94
+ throw new Error(`Block proposal initialize deadline cannot be negative (got ${this.initializeDeadline} from total time needed ${this.checkpointTiming.minimumBuildSlotWork} and a slot duration of ${this.aztecSlotDuration}).`);
99
95
  }
100
96
  }
97
+ getCheckpointAssemblyDeadline() {
98
+ return this.checkpointTiming.checkpointAssemblyDeadline;
99
+ }
100
+ getCheckpointAttestationDeadline() {
101
+ return this.checkpointTiming.checkpointAttestationDeadline;
102
+ }
103
+ getCheckpointAttestationStartDeadline() {
104
+ return this.checkpointTiming.checkpointAttestationStartDeadline;
105
+ }
106
+ getCheckpointPublishingDeadline() {
107
+ return this.checkpointTiming.checkpointPublishingDeadline;
108
+ }
101
109
  getMaxAllowedTime(state) {
102
110
  switch(state){
103
111
  case SequencerState.STOPPED:
@@ -113,10 +121,11 @@ export class SequencerTimetable {
113
121
  case SequencerState.WAITING_UNTIL_NEXT_BLOCK:
114
122
  return this.initializeDeadline + this.checkpointInitializationTime;
115
123
  case SequencerState.ASSEMBLING_CHECKPOINT:
124
+ return this.getCheckpointAssemblyDeadline();
116
125
  case SequencerState.COLLECTING_ATTESTATIONS:
117
- return this.aztecSlotDuration - this.l1PublishingTime - 2 * this.p2pPropagationTime;
126
+ return this.getCheckpointAttestationStartDeadline();
118
127
  case SequencerState.PUBLISHING_CHECKPOINT:
119
- return this.aztecSlotDuration - this.l1PublishingTime;
128
+ return this.getCheckpointPublishingDeadline();
120
129
  default:
121
130
  {
122
131
  const _exhaustiveCheck = state;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/sequencer-client",
3
- "version": "0.0.1-commit.7035c9bd6",
3
+ "version": "0.0.1-commit.71324e566",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -26,37 +26,37 @@
26
26
  "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
27
27
  },
28
28
  "dependencies": {
29
- "@aztec/aztec.js": "0.0.1-commit.7035c9bd6",
30
- "@aztec/bb-prover": "0.0.1-commit.7035c9bd6",
31
- "@aztec/blob-client": "0.0.1-commit.7035c9bd6",
32
- "@aztec/blob-lib": "0.0.1-commit.7035c9bd6",
33
- "@aztec/constants": "0.0.1-commit.7035c9bd6",
34
- "@aztec/epoch-cache": "0.0.1-commit.7035c9bd6",
35
- "@aztec/ethereum": "0.0.1-commit.7035c9bd6",
36
- "@aztec/foundation": "0.0.1-commit.7035c9bd6",
37
- "@aztec/l1-artifacts": "0.0.1-commit.7035c9bd6",
38
- "@aztec/node-keystore": "0.0.1-commit.7035c9bd6",
39
- "@aztec/noir-acvm_js": "0.0.1-commit.7035c9bd6",
40
- "@aztec/noir-contracts.js": "0.0.1-commit.7035c9bd6",
41
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.7035c9bd6",
42
- "@aztec/noir-types": "0.0.1-commit.7035c9bd6",
43
- "@aztec/p2p": "0.0.1-commit.7035c9bd6",
44
- "@aztec/protocol-contracts": "0.0.1-commit.7035c9bd6",
45
- "@aztec/prover-client": "0.0.1-commit.7035c9bd6",
46
- "@aztec/simulator": "0.0.1-commit.7035c9bd6",
47
- "@aztec/slasher": "0.0.1-commit.7035c9bd6",
48
- "@aztec/stdlib": "0.0.1-commit.7035c9bd6",
49
- "@aztec/telemetry-client": "0.0.1-commit.7035c9bd6",
50
- "@aztec/validator-client": "0.0.1-commit.7035c9bd6",
51
- "@aztec/validator-ha-signer": "0.0.1-commit.7035c9bd6",
52
- "@aztec/world-state": "0.0.1-commit.7035c9bd6",
29
+ "@aztec/aztec.js": "0.0.1-commit.71324e566",
30
+ "@aztec/bb-prover": "0.0.1-commit.71324e566",
31
+ "@aztec/blob-client": "0.0.1-commit.71324e566",
32
+ "@aztec/blob-lib": "0.0.1-commit.71324e566",
33
+ "@aztec/constants": "0.0.1-commit.71324e566",
34
+ "@aztec/epoch-cache": "0.0.1-commit.71324e566",
35
+ "@aztec/ethereum": "0.0.1-commit.71324e566",
36
+ "@aztec/foundation": "0.0.1-commit.71324e566",
37
+ "@aztec/l1-artifacts": "0.0.1-commit.71324e566",
38
+ "@aztec/node-keystore": "0.0.1-commit.71324e566",
39
+ "@aztec/noir-acvm_js": "0.0.1-commit.71324e566",
40
+ "@aztec/noir-contracts.js": "0.0.1-commit.71324e566",
41
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.71324e566",
42
+ "@aztec/noir-types": "0.0.1-commit.71324e566",
43
+ "@aztec/p2p": "0.0.1-commit.71324e566",
44
+ "@aztec/protocol-contracts": "0.0.1-commit.71324e566",
45
+ "@aztec/prover-client": "0.0.1-commit.71324e566",
46
+ "@aztec/simulator": "0.0.1-commit.71324e566",
47
+ "@aztec/slasher": "0.0.1-commit.71324e566",
48
+ "@aztec/stdlib": "0.0.1-commit.71324e566",
49
+ "@aztec/telemetry-client": "0.0.1-commit.71324e566",
50
+ "@aztec/validator-client": "0.0.1-commit.71324e566",
51
+ "@aztec/validator-ha-signer": "0.0.1-commit.71324e566",
52
+ "@aztec/world-state": "0.0.1-commit.71324e566",
53
53
  "lodash.chunk": "^4.2.0",
54
54
  "tslib": "^2.4.0",
55
55
  "viem": "npm:@aztec/viem@2.38.2"
56
56
  },
57
57
  "devDependencies": {
58
- "@aztec/archiver": "0.0.1-commit.7035c9bd6",
59
- "@aztec/kv-store": "0.0.1-commit.7035c9bd6",
58
+ "@aztec/archiver": "0.0.1-commit.71324e566",
59
+ "@aztec/kv-store": "0.0.1-commit.71324e566",
60
60
  "@electric-sql/pglite": "^0.3.14",
61
61
  "@jest/globals": "^30.0.0",
62
62
  "@types/jest": "^30.0.0",
@@ -14,13 +14,12 @@ import type { P2P } from '@aztec/p2p';
14
14
  import type { SlasherClientInterface } from '@aztec/slasher';
15
15
  import type { L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
16
16
  import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
17
- import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
18
17
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
19
18
  import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
20
19
  import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
21
20
 
22
21
  import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
23
- import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
22
+ import type { GlobalVariableBuilder } from '../global_variable_builder/index.js';
24
23
  import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
25
24
  import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
26
25
 
@@ -65,7 +64,9 @@ export class SequencerClient {
65
64
  dateProvider: DateProvider;
66
65
  epochCache?: EpochCache;
67
66
  l1TxUtils: L1TxUtils[];
67
+ funderL1TxUtils?: L1TxUtils;
68
68
  nodeKeyStore: KeystoreManager;
69
+ globalVariableBuilder: GlobalVariableBuilder;
69
70
  },
70
71
  ) {
71
72
  const {
@@ -87,16 +88,14 @@ export class SequencerClient {
87
88
  publicClient,
88
89
  l1TxUtils.map(x => x.getSenderAddress()),
89
90
  );
90
- const publisherManager = new PublisherManager(
91
- l1TxUtils,
92
- getPublisherConfigFromSequencerConfig(config),
93
- log.getBindings(),
94
- );
91
+ const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config), {
92
+ bindings: log.getBindings(),
93
+ funder: deps.funderL1TxUtils,
94
+ });
95
95
  const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
96
- const [l1GenesisTime, slotDuration, rollupVersion, rollupManaLimit] = await Promise.all([
96
+ const [l1GenesisTime, slotDuration, rollupManaLimit] = await Promise.all([
97
97
  rollupContract.getL1GenesisTime(),
98
98
  rollupContract.getSlotDuration(),
99
- rollupContract.getVersion(),
100
99
  rollupContract.getManaLimit().then(Number),
101
100
  ] as const);
102
101
 
@@ -118,11 +117,6 @@ export class SequencerClient {
118
117
  { dateProvider: deps.dateProvider },
119
118
  ));
120
119
 
121
- const slashFactoryContract = new SlashFactoryContract(
122
- publicClient,
123
- config.l1Contracts.slashFactoryAddress?.toString() ?? EthAddress.ZERO.toString(),
124
- );
125
-
126
120
  const publisherFactory =
127
121
  deps.publisherFactory ??
128
122
  new SequencerPublisherFactory(config, {
@@ -130,7 +124,6 @@ export class SequencerClient {
130
124
  blobClient: deps.blobClient,
131
125
  epochCache,
132
126
  governanceProposerContract,
133
- slashFactoryContract,
134
127
  rollupContract,
135
128
  dateProvider: deps.dateProvider,
136
129
  publisherManager,
@@ -140,13 +133,7 @@ export class SequencerClient {
140
133
 
141
134
  const ethereumSlotDuration = config.ethereumSlotDuration;
142
135
 
143
- const globalsBuilder = new GlobalVariableBuilder({
144
- ...config,
145
- l1GenesisTime,
146
- slotDuration: Number(slotDuration),
147
- ethereumSlotDuration,
148
- rollupVersion,
149
- });
136
+ const globalsBuilder = deps.globalVariableBuilder;
150
137
 
151
138
  // When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
152
139
  // Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
@@ -202,7 +189,7 @@ export class SequencerClient {
202
189
  await this.validatorClient?.start();
203
190
  this.sequencer.start();
204
191
  this.l1Metrics?.start();
205
- await this.publisherManager.loadState();
192
+ await this.publisherManager.start();
206
193
  }
207
194
 
208
195
  /**
@@ -211,10 +198,15 @@ export class SequencerClient {
211
198
  public async stop() {
212
199
  await this.sequencer.stop();
213
200
  await this.validatorClient?.stop();
214
- this.publisherManager.interrupt();
201
+ await this.publisherManager.stop();
215
202
  this.l1Metrics?.stop();
216
203
  }
217
204
 
205
+ /** Triggers an immediate run of the sequencer, bypassing the polling interval. */
206
+ public trigger() {
207
+ return this.sequencer.trigger();
208
+ }
209
+
218
210
  public getSequencer(): Sequencer {
219
211
  return this.sequencer;
220
212
  }