@aztec/sequencer-client 0.68.0 → 0.68.2

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.
@@ -1,6 +1,8 @@
1
1
  import { type L1ToL2MessageSource, type L2BlockSource, type WorldStateSynchronizer } from '@aztec/circuit-types';
2
2
  import { type ContractDataSource } from '@aztec/circuits.js';
3
+ import { isAnvilTestChain } from '@aztec/ethereum';
3
4
  import { type EthAddress } from '@aztec/foundation/eth-address';
5
+ import { type DateProvider } from '@aztec/foundation/timer';
4
6
  import { type P2P } from '@aztec/p2p';
5
7
  import { LightweightBlockBuilderFactory } from '@aztec/prover-client/block-builder';
6
8
  import { PublicProcessorFactory } from '@aztec/simulator';
@@ -17,7 +19,7 @@ import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js';
17
19
  * Encapsulates the full sequencer and publisher.
18
20
  */
19
21
  export class SequencerClient {
20
- constructor(private sequencer: Sequencer) {}
22
+ constructor(protected sequencer: Sequencer) {}
21
23
 
22
24
  /**
23
25
  * Initializes and starts a new instance.
@@ -43,6 +45,7 @@ export class SequencerClient {
43
45
  l1ToL2MessageSource: L1ToL2MessageSource;
44
46
  telemetry: TelemetryClient;
45
47
  publisher?: L1Publisher;
48
+ dateProvider: DateProvider;
46
49
  },
47
50
  ) {
48
51
  const {
@@ -57,7 +60,7 @@ export class SequencerClient {
57
60
  const publisher = deps.publisher ?? new L1Publisher(config, telemetryClient);
58
61
  const globalsBuilder = new GlobalVariableBuilder(config);
59
62
 
60
- const publicProcessorFactory = new PublicProcessorFactory(contractDataSource, telemetryClient);
63
+ const publicProcessorFactory = new PublicProcessorFactory(contractDataSource, deps.dateProvider, telemetryClient);
61
64
 
62
65
  const rollup = publisher.getRollupContract();
63
66
  const [l1GenesisTime, slotDuration] = await Promise.all([
@@ -65,6 +68,23 @@ export class SequencerClient {
65
68
  rollup.read.SLOT_DURATION(),
66
69
  ] as const);
67
70
 
71
+ const ethereumSlotDuration = config.ethereumSlotDuration;
72
+
73
+ // When running in anvil, assume we can post a tx up until the very last second of an L1 slot.
74
+ // Otherwise, assume we must have broadcasted the tx before the slot started (we use a default
75
+ // maxL1TxInclusionTimeIntoSlot of zero) to get the tx into that L1 slot.
76
+ // In theory, the L1 slot has an initial 4s phase where the block is propagated, so we could
77
+ // make it with a propagation time into slot equal to 4s. However, we prefer being conservative.
78
+ // See https://www.blocknative.com/blog/anatomy-of-a-slot#7 for more info.
79
+ const maxL1TxInclusionTimeIntoSlot =
80
+ config.maxL1TxInclusionTimeIntoSlot ?? isAnvilTestChain(config.l1ChainId) ? ethereumSlotDuration : 0;
81
+
82
+ const l1Constants = {
83
+ l1GenesisTime,
84
+ slotDuration: Number(slotDuration),
85
+ ethereumSlotDuration,
86
+ };
87
+
68
88
  const sequencer = new Sequencer(
69
89
  publisher,
70
90
  validatorClient,
@@ -76,10 +96,10 @@ export class SequencerClient {
76
96
  l1ToL2MessageSource,
77
97
  publicProcessorFactory,
78
98
  new TxValidatorFactory(worldStateSynchronizer.getCommitted(), contractDataSource, !!config.enforceFees),
79
- Number(l1GenesisTime),
80
- Number(slotDuration),
99
+ l1Constants,
100
+ deps.dateProvider,
81
101
  telemetryClient,
82
- config,
102
+ { ...config, maxL1TxInclusionTimeIntoSlot },
83
103
  );
84
104
  await validatorClient?.start();
85
105
  await sequencer.start();
package/src/config.ts CHANGED
@@ -106,6 +106,11 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
106
106
  parseEnv: (val: string) => EthAddress.fromString(val),
107
107
  defaultValue: EthAddress.ZERO,
108
108
  },
109
+ maxL1TxInclusionTimeIntoSlot: {
110
+ env: 'SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT',
111
+ description: 'How many seconds into an L1 slot we can still send a tx and get it mined.',
112
+ parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
113
+ },
109
114
  };
110
115
 
111
116
  export const chainConfigMappings: ConfigMappingsType<ChainConfig> = {
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './client/index.js';
2
2
  export * from './config.js';
3
3
  export * from './publisher/index.js';
4
+ export { Sequencer, SequencerState } from './sequencer/index.js';
4
5
 
5
6
  // Used by the node to simulate public parts of transactions. Should these be moved to a shared library?
6
7
  // ISSUE(#9832)
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  type EpochProofQuote,
3
+ type L1RollupConstants,
3
4
  type L1ToL2MessageSource,
4
5
  type L2Block,
5
6
  type L2BlockSource,
@@ -27,7 +28,7 @@ import { Fr } from '@aztec/foundation/fields';
27
28
  import { createLogger } from '@aztec/foundation/log';
28
29
  import { RunningPromise } from '@aztec/foundation/running-promise';
29
30
  import { pickFromSchema } from '@aztec/foundation/schemas';
30
- import { Timer, elapsed } from '@aztec/foundation/timer';
31
+ import { type DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
31
32
  import { type P2P } from '@aztec/p2p';
32
33
  import { type BlockBuilderFactory } from '@aztec/prover-client/block-builder';
33
34
  import { type PublicProcessorFactory } from '@aztec/simulator';
@@ -41,7 +42,9 @@ import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js
41
42
  import { getDefaultAllowedSetupFunctions } from './allowed.js';
42
43
  import { type SequencerConfig } from './config.js';
43
44
  import { SequencerMetrics } from './metrics.js';
44
- import { SequencerState, getSecondsIntoSlot, orderAttestations } from './utils.js';
45
+ import { SequencerState, orderAttestations } from './utils.js';
46
+
47
+ export { SequencerState };
45
48
 
46
49
  export type ShouldProposeArgs = {
47
50
  pendingTxsCount?: number;
@@ -63,6 +66,8 @@ export class SequencerTooSlowError extends Error {
63
66
  }
64
67
  }
65
68
 
69
+ type SequencerRollupConstants = Pick<L1RollupConstants, 'ethereumSlotDuration' | 'l1GenesisTime' | 'slotDuration'>;
70
+
66
71
  /**
67
72
  * Sequencer client
68
73
  * - Wins a period of time to become the sequencer (depending on finalized protocol).
@@ -77,12 +82,14 @@ export class Sequencer {
77
82
  private pollingIntervalMs: number = 1000;
78
83
  private maxTxsPerBlock = 32;
79
84
  private minTxsPerBLock = 1;
85
+ private maxL1TxInclusionTimeIntoSlot = 0;
80
86
  // TODO: zero values should not be allowed for the following 2 values in PROD
81
87
  private _coinbase = EthAddress.ZERO;
82
88
  private _feeRecipient = AztecAddress.ZERO;
83
89
  private state = SequencerState.STOPPED;
84
90
  private allowedInSetup: AllowedElement[] = getDefaultAllowedSetupFunctions();
85
91
  private maxBlockSizeInBytes: number = 1024 * 1024;
92
+ private processTxTime: number = 12;
86
93
  private metrics: SequencerMetrics;
87
94
  private isFlushing: boolean = false;
88
95
 
@@ -104,8 +111,8 @@ export class Sequencer {
104
111
  private l1ToL2MessageSource: L1ToL2MessageSource,
105
112
  private publicProcessorFactory: PublicProcessorFactory,
106
113
  private txValidatorFactory: TxValidatorFactory,
107
- protected l1GenesisTime: number,
108
- private aztecSlotDuration: number,
114
+ protected l1Constants: SequencerRollupConstants,
115
+ private dateProvider: DateProvider,
109
116
  telemetry: TelemetryClient,
110
117
  private config: SequencerConfig = {},
111
118
  private log = createLogger('sequencer'),
@@ -152,6 +159,9 @@ export class Sequencer {
152
159
  if (config.governanceProposerPayload) {
153
160
  this.publisher.setPayload(config.governanceProposerPayload);
154
161
  }
162
+ if (config.maxL1TxInclusionTimeIntoSlot !== undefined) {
163
+ this.maxL1TxInclusionTimeIntoSlot = config.maxL1TxInclusionTimeIntoSlot;
164
+ }
155
165
  this.enforceTimeTable = config.enforceTimeTable === true;
156
166
 
157
167
  this.setTimeTable();
@@ -161,20 +171,59 @@ export class Sequencer {
161
171
  }
162
172
 
163
173
  private setTimeTable() {
174
+ // How late into the slot can we be to start working
175
+ const initialTime = 1;
176
+
177
+ // How long it takes to validate the txs collected and get ready to start building
178
+ const blockPrepareTime = 2;
179
+
180
+ // How long it takes to for attestations to travel across the p2p layer.
181
+ const attestationPropagationTime = 2;
182
+
183
+ // How long it takes to get a published block into L1. L1 builders typically accept txs up to 4 seconds into their slot,
184
+ // but we'll timeout sooner to give it more time to propagate (remember we also have blobs!). Still, when working in anvil,
185
+ // we can just post in the very last second of the L1 slot.
186
+ const l1PublishingTime = this.l1Constants.ethereumSlotDuration - this.maxL1TxInclusionTimeIntoSlot;
187
+
188
+ // How much time we spend validating and processing a block after building it
189
+ const blockValidationTime = 1;
190
+
191
+ // How much time we have left in the slot for actually processing txs and building the block.
192
+ const remainingTimeInSlot =
193
+ this.aztecSlotDuration -
194
+ initialTime -
195
+ blockPrepareTime -
196
+ l1PublishingTime -
197
+ 2 * attestationPropagationTime -
198
+ blockValidationTime;
199
+
200
+ // Check that numbers make sense
201
+ if (this.enforceTimeTable && remainingTimeInSlot < 0) {
202
+ throw new Error(`Not enough time for block building in ${this.aztecSlotDuration}s slot`);
203
+ }
204
+
205
+ // How much time we have for actually processing txs. Note that we need both the sequencer and the validators to execute txs.
206
+ const processTxsTime = remainingTimeInSlot / 2;
207
+ this.processTxTime = processTxsTime;
208
+
164
209
  const newTimeTable: Record<SequencerState, number> = {
210
+ // No checks needed for any of these transitions
165
211
  [SequencerState.STOPPED]: this.aztecSlotDuration,
166
212
  [SequencerState.IDLE]: this.aztecSlotDuration,
167
213
  [SequencerState.SYNCHRONIZING]: this.aztecSlotDuration,
168
- [SequencerState.PROPOSER_CHECK]: this.aztecSlotDuration, // We always want to allow the full slot to check if we are the proposer
169
- [SequencerState.WAITING_FOR_TXS]: 5,
170
- [SequencerState.CREATING_BLOCK]: 7,
171
- [SequencerState.PUBLISHING_BLOCK_TO_PEERS]: 7 + this.maxTxsPerBlock * 2, // if we take 5 seconds to create block, then 4 transactions at 2 seconds each
172
- [SequencerState.WAITING_FOR_ATTESTATIONS]: 7 + this.maxTxsPerBlock * 2 + 3, // it shouldn't take 3 seconds to publish to peers
173
- [SequencerState.PUBLISHING_BLOCK]: 7 + this.maxTxsPerBlock * 2 + 3 + 5, // wait 5 seconds for attestations
214
+ // We always want to allow the full slot to check if we are the proposer
215
+ [SequencerState.PROPOSER_CHECK]: this.aztecSlotDuration,
216
+ // First transition towards building a block
217
+ [SequencerState.WAITING_FOR_TXS]: initialTime,
218
+ // We then validate the txs and prepare to start building the block
219
+ [SequencerState.CREATING_BLOCK]: initialTime + blockPrepareTime,
220
+ // We start collecting attestations after building the block
221
+ [SequencerState.COLLECTING_ATTESTATIONS]: initialTime + blockPrepareTime + processTxsTime + blockValidationTime,
222
+ // We publish the block after collecting attestations
223
+ [SequencerState.PUBLISHING_BLOCK]: this.aztecSlotDuration - l1PublishingTime,
174
224
  };
175
- if (this.enforceTimeTable && newTimeTable[SequencerState.PUBLISHING_BLOCK] > this.aztecSlotDuration) {
176
- throw new Error('Sequencer cannot publish block in less than a slot');
177
- }
225
+
226
+ this.log.verbose(`Sequencer time table updated with ${processTxsTime}s for processing txs`, newTimeTable);
178
227
  this.timeTable = newTimeTable;
179
228
  }
180
229
 
@@ -297,7 +346,8 @@ export class Sequencer {
297
346
  Fr.ZERO,
298
347
  );
299
348
 
300
- // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here
349
+ // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here.
350
+ // TODO: We should validate only the number of txs we need to speed up this process.
301
351
  const allValidTxs = await this.takeValidTxs(
302
352
  pendingTxs,
303
353
  this.txValidatorFactory.validatorForNewTxs(newGlobalVariables, this.allowedInSetup),
@@ -372,24 +422,21 @@ export class Sequencer {
372
422
  return true;
373
423
  }
374
424
 
375
- if (this.timeTable[proposedState] === this.aztecSlotDuration) {
425
+ const maxAllowedTime = this.timeTable[proposedState];
426
+ if (maxAllowedTime === this.aztecSlotDuration) {
376
427
  return true;
377
428
  }
378
429
 
379
- const bufferSeconds = this.timeTable[proposedState] - secondsIntoSlot;
430
+ const bufferSeconds = maxAllowedTime - secondsIntoSlot;
380
431
 
381
432
  if (bufferSeconds < 0) {
382
- this.log.warn(
383
- `Too far into slot to transition to ${proposedState}. max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
384
- );
433
+ this.log.warn(`Too far into slot to transition to ${proposedState}`, { maxAllowedTime, secondsIntoSlot });
385
434
  return false;
386
435
  }
387
436
 
388
437
  this.metrics.recordStateTransitionBufferMs(Math.floor(bufferSeconds * 1000), proposedState);
389
438
 
390
- this.log.debug(
391
- `Enough time to transition to ${proposedState}, max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
392
- );
439
+ this.log.trace(`Enough time to transition to ${proposedState}`, { maxAllowedTime, secondsIntoSlot });
393
440
  return true;
394
441
  }
395
442
 
@@ -407,7 +454,7 @@ export class Sequencer {
407
454
  this.log.warn(`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped.`);
408
455
  return;
409
456
  }
410
- const secondsIntoSlot = getSecondsIntoSlot(this.l1GenesisTime, this.aztecSlotDuration, Number(currentSlotNumber));
457
+ const secondsIntoSlot = this.getSecondsIntoSlot(currentSlotNumber);
411
458
  if (!this.doIHaveEnoughTimeLeft(proposedState, secondsIntoSlot)) {
412
459
  throw new SequencerTooSlowError(this.state, proposedState, this.timeTable[proposedState], secondsIntoSlot);
413
460
  }
@@ -466,12 +513,14 @@ export class Sequencer {
466
513
  * @param newGlobalVariables - The global variables for the new block
467
514
  * @param historicalHeader - The historical header of the parent
468
515
  * @param interrupt - The interrupt callback, used to validate the block for submission and check if we should propose the block
516
+ * @param opts - Whether to just validate the block as a validator, as opposed to building it as a proposal
469
517
  */
470
518
  private async buildBlock(
471
519
  validTxs: Tx[],
472
520
  newGlobalVariables: GlobalVariables,
473
521
  historicalHeader?: BlockHeader,
474
522
  interrupt?: (processedTxs: ProcessedTx[]) => Promise<void>,
523
+ opts: { validateOnly?: boolean } = {},
475
524
  ) {
476
525
  const blockNumber = newGlobalVariables.blockNumber.toBigInt();
477
526
  const slot = newGlobalVariables.slotNumber.toBigInt();
@@ -511,15 +560,42 @@ export class Sequencer {
511
560
  const blockBuilder = this.blockBuilderFactory.create(orchestratorFork);
512
561
  await blockBuilder.startNewBlock(newGlobalVariables, l1ToL2Messages);
513
562
 
563
+ // We set the deadline for tx processing to the start of the CREATING_BLOCK phase, plus the expected time for tx processing.
564
+ // Deadline is only set if enforceTimeTable is enabled.
565
+ const processingEndTimeWithinSlot = this.timeTable[SequencerState.CREATING_BLOCK] + this.processTxTime;
566
+ const processingDeadline = this.enforceTimeTable
567
+ ? new Date((this.getSlotStartTimestamp(slot) + processingEndTimeWithinSlot) * 1000)
568
+ : undefined;
569
+ this.log.verbose(`Processing ${validTxs.length} txs`, {
570
+ slot,
571
+ slotStart: new Date(this.getSlotStartTimestamp(slot) * 1000),
572
+ now: new Date(this.dateProvider.now()),
573
+ deadline: processingDeadline,
574
+ });
575
+ const processingTxValidator = this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork);
514
576
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
515
- processor.process(validTxs, blockSize, this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork)),
577
+ processor.process(validTxs, blockSize, processingTxValidator, processingDeadline),
516
578
  );
579
+
517
580
  if (failedTxs.length > 0) {
518
581
  const failedTxData = failedTxs.map(fail => fail.tx);
519
582
  this.log.verbose(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
520
583
  await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
521
584
  }
522
585
 
586
+ if (
587
+ !opts.validateOnly && // We check for minTxCount only if we are proposing a block, not if we are validating it
588
+ !this.isFlushing && // And we skip the check when flushing, since we want all pending txs to go out, no matter if too few
589
+ this.minTxsPerBLock !== undefined &&
590
+ processedTxs.length < this.minTxsPerBLock
591
+ ) {
592
+ this.log.warn(
593
+ `Block ${blockNumber} has too few txs to be proposed (got ${processedTxs.length} but required ${this.minTxsPerBLock})`,
594
+ { slot, blockNumber, processedTxCount: processedTxs.length },
595
+ );
596
+ throw new Error(`Block has too few successful txs to be proposed`);
597
+ }
598
+
523
599
  const start = process.hrtime.bigint();
524
600
  await blockBuilder.addTxs(processedTxs);
525
601
  const end = process.hrtime.bigint();
@@ -528,7 +604,7 @@ export class Sequencer {
528
604
 
529
605
  await interrupt?.(processedTxs);
530
606
 
531
- // All real transactions have been added, set the block as full and complete the proving.
607
+ // All real transactions have been added, set the block as full and pad if needed
532
608
  const block = await blockBuilder.setBlockCompleted();
533
609
 
534
610
  return {
@@ -540,8 +616,16 @@ export class Sequencer {
540
616
  };
541
617
  } finally {
542
618
  // We create a fresh processor each time to reset any cached state (eg storage writes)
543
- await publicProcessorFork.close();
544
- await orchestratorFork.close();
619
+ // We wait a bit to close the forks since the processor may still be working on a dangling tx
620
+ // which was interrupted due to the processingDeadline being hit.
621
+ setTimeout(async () => {
622
+ try {
623
+ await publicProcessorFork.close();
624
+ await orchestratorFork.close();
625
+ } catch (err) {
626
+ this.log.error(`Error closing forks`, err);
627
+ }
628
+ }, 5000);
545
629
  }
546
630
  }
547
631
 
@@ -593,6 +677,9 @@ export class Sequencer {
593
677
  }
594
678
  };
595
679
 
680
+ // Start collecting proof quotes for the previous epoch if needed in the background
681
+ const proofQuotePromise = this.createProofClaimForPreviousEpoch(slot);
682
+
596
683
  try {
597
684
  const buildBlockRes = await this.buildBlock(validTxs, newGlobalVariables, historicalHeader, interrupt);
598
685
  const { block, publicProcessorDuration, numProcessedTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
@@ -630,12 +717,12 @@ export class Sequencer {
630
717
  const stopCollectingAttestationsTimer = this.metrics.startCollectingAttestationsTimer();
631
718
  const attestations = await this.collectAttestations(block, txHashes);
632
719
  if (attestations !== undefined) {
633
- this.log.verbose(`Collected ${attestations.length} attestations`);
720
+ this.log.verbose(`Collected ${attestations.length} attestations`, { blockHash, blockNumber });
634
721
  }
635
722
  stopCollectingAttestationsTimer();
636
723
 
637
- this.log.debug('Collecting proof quotes');
638
- const proofQuote = await this.createProofClaimForPreviousEpoch(newGlobalVariables.slotNumber.toBigInt());
724
+ // Get the proof quote for the previous epoch, if any
725
+ const proofQuote = await proofQuotePromise;
639
726
 
640
727
  await this.publishL2Block(block, attestations, txHashes, proofQuote);
641
728
  this.metrics.recordPublishedBlock(workDuration);
@@ -687,21 +774,19 @@ export class Sequencer {
687
774
  }
688
775
 
689
776
  const numberOfRequiredAttestations = Math.floor((committee.length * 2) / 3) + 1;
777
+ const slotNumber = block.header.globalVariables.slotNumber.toBigInt();
778
+ this.setState(SequencerState.COLLECTING_ATTESTATIONS, slotNumber);
690
779
 
691
- this.log.debug('Creating block proposal');
780
+ this.log.debug('Creating block proposal for validators');
692
781
  const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes);
693
782
  if (!proposal) {
694
783
  this.log.warn(`Failed to create block proposal, skipping collecting attestations`);
695
784
  return undefined;
696
785
  }
697
786
 
698
- const slotNumber = block.header.globalVariables.slotNumber.toBigInt();
699
-
700
- this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS, slotNumber);
701
787
  this.log.debug('Broadcasting block proposal to validators');
702
788
  this.validatorClient.broadcastBlockProposal(proposal);
703
789
 
704
- this.setState(SequencerState.WAITING_FOR_ATTESTATIONS, slotNumber);
705
790
  const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations);
706
791
 
707
792
  // note: the smart contract requires that the signatures are provided in the order of the committee
@@ -718,6 +803,7 @@ export class Sequencer {
718
803
  }
719
804
 
720
805
  // Get quotes for the epoch to be proven
806
+ this.log.debug(`Collecting proof quotes for epoch ${epochToProve}`);
721
807
  const quotes = await this.p2pClient.getEpochProofQuotes(epochToProve);
722
808
  this.log.verbose(`Retrieved ${quotes.length} quotes for slot ${slotNumber} epoch ${epochToProve}`, {
723
809
  epochToProve,
@@ -861,6 +947,19 @@ export class Sequencer {
861
947
  return result;
862
948
  }
863
949
 
950
+ private getSlotStartTimestamp(slotNumber: number | bigint): number {
951
+ return Number(this.l1Constants.l1GenesisTime) + Number(slotNumber) * this.l1Constants.slotDuration;
952
+ }
953
+
954
+ private getSecondsIntoSlot(slotNumber: number | bigint): number {
955
+ const slotStartTimestamp = this.getSlotStartTimestamp(slotNumber);
956
+ return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));
957
+ }
958
+
959
+ get aztecSlotDuration() {
960
+ return this.l1Constants.slotDuration;
961
+ }
962
+
864
963
  get coinbase(): EthAddress {
865
964
  return this._coinbase;
866
965
  }
@@ -869,7 +968,3 @@ export class Sequencer {
869
968
  return this._feeRecipient;
870
969
  }
871
970
  }
872
-
873
- /**
874
- * State of the sequencer.
875
- */
@@ -27,13 +27,9 @@ export enum SequencerState {
27
27
  */
28
28
  CREATING_BLOCK = 'CREATING_BLOCK',
29
29
  /**
30
- * Publishing blocks to validator peers. Will move to WAITING_FOR_ATTESTATIONS.
30
+ * Collecting attestations from its peers. Will move to PUBLISHING_BLOCK.
31
31
  */
32
- PUBLISHING_BLOCK_TO_PEERS = 'PUBLISHING_BLOCK_TO_PEERS',
33
- /**
34
- * The block has been published to peers, and we are waiting for attestations. Will move to PUBLISHING_CONTRACT_DATA.
35
- */
36
- WAITING_FOR_ATTESTATIONS = 'WAITING_FOR_ATTESTATIONS',
32
+ COLLECTING_ATTESTATIONS = 'COLLECTING_ATTESTATIONS',
37
33
  /**
38
34
  * Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING.
39
35
  */
@@ -72,8 +68,3 @@ export function orderAttestations(attestations: BlockAttestation[], orderAddress
72
68
 
73
69
  return orderedAttestations;
74
70
  }
75
-
76
- export function getSecondsIntoSlot(l1GenesisTime: number, aztecSlotDuration: number, slotNumber: number): number {
77
- const slotStartTimestamp = l1GenesisTime + slotNumber * aztecSlotDuration;
78
- return Number((Date.now() / 1000 - slotStartTimestamp).toFixed(3));
79
- }