@aztec/sequencer-client 2.0.3 → 2.1.0-rc.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.
Files changed (44) hide show
  1. package/dest/client/sequencer-client.d.ts.map +1 -1
  2. package/dest/client/sequencer-client.js +7 -4
  3. package/dest/config.d.ts +2 -1
  4. package/dest/config.d.ts.map +1 -1
  5. package/dest/config.js +2 -0
  6. package/dest/publisher/config.d.ts +2 -4
  7. package/dest/publisher/config.d.ts.map +1 -1
  8. package/dest/publisher/config.js +7 -10
  9. package/dest/publisher/index.d.ts +1 -1
  10. package/dest/publisher/index.d.ts.map +1 -1
  11. package/dest/publisher/index.js +1 -1
  12. package/dest/publisher/sequencer-publisher-factory.d.ts +5 -1
  13. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  14. package/dest/publisher/sequencer-publisher-factory.js +8 -1
  15. package/dest/publisher/sequencer-publisher.d.ts +14 -20
  16. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  17. package/dest/publisher/sequencer-publisher.js +53 -58
  18. package/dest/sequencer/errors.d.ts +11 -0
  19. package/dest/sequencer/errors.d.ts.map +1 -0
  20. package/dest/sequencer/errors.js +15 -0
  21. package/dest/sequencer/metrics.d.ts +5 -17
  22. package/dest/sequencer/metrics.d.ts.map +1 -1
  23. package/dest/sequencer/metrics.js +22 -88
  24. package/dest/sequencer/sequencer.d.ts +4 -3
  25. package/dest/sequencer/sequencer.d.ts.map +1 -1
  26. package/dest/sequencer/sequencer.js +27 -21
  27. package/dest/sequencer/timetable.d.ts +0 -6
  28. package/dest/sequencer/timetable.d.ts.map +1 -1
  29. package/dest/sequencer/timetable.js +2 -9
  30. package/dest/sequencer/utils.d.ts +10 -24
  31. package/dest/sequencer/utils.d.ts.map +1 -1
  32. package/dest/sequencer/utils.js +9 -24
  33. package/package.json +28 -28
  34. package/src/client/sequencer-client.ts +6 -2
  35. package/src/config.ts +3 -0
  36. package/src/publisher/config.ts +13 -11
  37. package/src/publisher/index.ts +1 -1
  38. package/src/publisher/sequencer-publisher-factory.ts +12 -2
  39. package/src/publisher/sequencer-publisher.ts +77 -77
  40. package/src/sequencer/errors.ts +21 -0
  41. package/src/sequencer/metrics.ts +24 -100
  42. package/src/sequencer/sequencer.ts +51 -46
  43. package/src/sequencer/timetable.ts +2 -13
  44. package/src/sequencer/utils.ts +10 -24
@@ -1,9 +1,10 @@
1
1
  import type { L2Block } from '@aztec/aztec.js';
2
- import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
+ import { BLOBS_PER_BLOCK, FIELDS_PER_BLOB, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
3
3
  import type { EpochCache } from '@aztec/epoch-cache';
4
4
  import { FormattedViemError, NoCommitteeError, type RollupContract } from '@aztec/ethereum';
5
5
  import { omit, pick } from '@aztec/foundation/collection';
6
6
  import { EthAddress } from '@aztec/foundation/eth-address';
7
+ import { Signature } from '@aztec/foundation/eth-signature';
7
8
  import { Fr } from '@aztec/foundation/fields';
8
9
  import { createLogger } from '@aztec/foundation/log';
9
10
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -11,8 +12,13 @@ import { type DateProvider, Timer } from '@aztec/foundation/timer';
11
12
  import type { TypedEventEmitter } from '@aztec/foundation/types';
12
13
  import type { P2P } from '@aztec/p2p';
13
14
  import type { SlasherClientInterface } from '@aztec/slasher';
14
- import type { CommitteeAttestation, L2BlockSource, ValidateBlockResult } from '@aztec/stdlib/block';
15
- import { type L1RollupConstants, getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
15
+ import {
16
+ type CommitteeAttestation,
17
+ CommitteeAttestationsAndSigners,
18
+ type L2BlockSource,
19
+ type ValidateBlockResult,
20
+ } from '@aztec/stdlib/block';
21
+ import { type L1RollupConstants, getSlotAtTimestamp, getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
16
22
  import { Gas } from '@aztec/stdlib/gas';
17
23
  import {
18
24
  type IFullNodeBlockBuilder,
@@ -21,19 +27,11 @@ import {
21
27
  type WorldStateSynchronizer,
22
28
  } from '@aztec/stdlib/interfaces/server';
23
29
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
24
- import type { BlockProposalOptions } from '@aztec/stdlib/p2p';
25
- import { orderAttestations } from '@aztec/stdlib/p2p';
30
+ import { type BlockProposalOptions, orderAttestations } from '@aztec/stdlib/p2p';
26
31
  import { pickFromSchema } from '@aztec/stdlib/schemas';
27
32
  import type { L2BlockBuiltStats } from '@aztec/stdlib/stats';
28
33
  import { MerkleTreeId } from '@aztec/stdlib/trees';
29
- import {
30
- ContentCommitment,
31
- type FailedTx,
32
- GlobalVariables,
33
- ProposedBlockHeader,
34
- Tx,
35
- type TxHash,
36
- } from '@aztec/stdlib/tx';
34
+ import { ContentCommitment, type FailedTx, GlobalVariables, ProposedBlockHeader, Tx } from '@aztec/stdlib/tx';
37
35
  import { AttestationTimeoutError } from '@aztec/stdlib/validators';
38
36
  import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
39
37
  import type { ValidatorClient } from '@aztec/validator-client';
@@ -45,8 +43,9 @@ import type { GlobalVariableBuilder } from '../global_variable_builder/global_bu
45
43
  import type { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
46
44
  import type { Action, InvalidateBlockRequest, SequencerPublisher } from '../publisher/sequencer-publisher.js';
47
45
  import type { SequencerConfig } from './config.js';
46
+ import { SequencerInterruptedError, SequencerTooSlowError } from './errors.js';
48
47
  import { SequencerMetrics } from './metrics.js';
49
- import { SequencerTimetable, SequencerTooSlowError } from './timetable.js';
48
+ import { SequencerTimetable } from './timetable.js';
50
49
  import { SequencerState, type SequencerStateWithSlot } from './utils.js';
51
50
 
52
51
  export { SequencerState };
@@ -127,15 +126,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
127
126
  ) {
128
127
  super();
129
128
 
130
- // Set an initial coinbase for metrics purposes, but this will potentially change with each block.
131
- const validatorAddresses = this.validatorClient?.getValidatorAddresses() ?? [];
132
- const coinbase =
133
- validatorAddresses.length === 0
134
- ? EthAddress.ZERO
135
- : (this.validatorClient?.getCoinbaseForAttestor(validatorAddresses[0]) ?? EthAddress.ZERO);
136
-
137
- this.metrics = new SequencerMetrics(telemetry, () => this.state, coinbase, this.rollupContract, 'Sequencer');
138
-
129
+ this.metrics = new SequencerMetrics(telemetry, this.rollupContract, 'Sequencer');
139
130
  // Initialize config
140
131
  this.updateConfig(this.config);
141
132
  }
@@ -220,7 +211,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
220
211
  * Starts the sequencer and moves to IDLE state.
221
212
  */
222
213
  public start() {
223
- this.metrics.start();
224
214
  this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollingIntervalMs);
225
215
  this.setState(SequencerState.IDLE, undefined, { force: true });
226
216
  this.runningPromise.start();
@@ -232,9 +222,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
232
222
  */
233
223
  public async stop(): Promise<void> {
234
224
  this.log.info(`Stopping sequencer`);
235
- this.metrics.stop();
225
+ this.setState(SequencerState.STOPPING, undefined, { force: true });
236
226
  this.publisher?.interrupt();
237
- await this.validatorClient?.stop();
238
227
  await this.runningPromise?.stop();
239
228
  this.setState(SequencerState.STOPPED, undefined, { force: true });
240
229
  this.log.info('Stopped sequencer');
@@ -361,8 +350,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
361
350
  const coinbase = this.validatorClient!.getCoinbaseForAttestor(attestorAddress);
362
351
  const feeRecipient = this.validatorClient!.getFeeRecipientForAttestor(attestorAddress);
363
352
 
364
- this.metrics.setCoinbase(coinbase);
365
-
366
353
  // Prepare invalidation request if the pending chain is invalid (returns undefined if no need)
367
354
  const invalidateBlock = await publisher.simulateInvalidateBlock(syncedTo.pendingChainValidationStatus);
368
355
  const canProposeCheck = await publisher.canProposeAtNextEthBlock(
@@ -435,6 +422,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
435
422
  }
436
423
 
437
424
  this.setState(SequencerState.INITIALIZING_PROPOSAL, slot);
425
+
426
+ this.metrics.incOpenSlot(slot, proposerAddressInNextSlot.toString());
438
427
  this.log.verbose(`Preparing proposal for block ${newBlockNumber} at slot ${slot}`, {
439
428
  proposer: proposerInNextSlot?.toString(),
440
429
  coinbase,
@@ -494,7 +483,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
494
483
  if (proposedBlock) {
495
484
  this.lastBlockPublished = block;
496
485
  this.emit('block-published', { blockNumber: newBlockNumber, slot: Number(slot) });
497
- this.metrics.incFilledSlot(publisher.getSenderAddress().toString());
486
+ await this.metrics.incFilledSlot(publisher.getSenderAddress().toString(), coinbase);
498
487
  } else if (block) {
499
488
  this.emit('block-publish-failed', l1Response ?? {});
500
489
  }
@@ -535,6 +524,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
535
524
  opts?: { force?: boolean },
536
525
  ): void;
537
526
  setState(proposedState: SequencerState, slotNumber: bigint | undefined, opts: { force?: boolean } = {}): void {
527
+ if (this.state === SequencerState.STOPPING && proposedState !== SequencerState.STOPPED && !opts.force) {
528
+ this.log.warn(`Cannot set sequencer to ${proposedState} as it is stopping.`);
529
+ throw new SequencerInterruptedError();
530
+ }
538
531
  if (this.state === SequencerState.STOPPED && !opts.force) {
539
532
  this.log.warn(`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped.`);
540
533
  return;
@@ -584,6 +577,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
584
577
  maxTransactions: this.maxTxsPerBlock,
585
578
  maxBlockSize: this.maxBlockSizeInBytes,
586
579
  maxBlockGas: this.maxBlockGas,
580
+ maxBlobFields: BLOBS_PER_BLOCK * FIELDS_PER_BLOB,
587
581
  deadline,
588
582
  };
589
583
  }
@@ -616,7 +610,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
616
610
  const slot = proposalHeader.slotNumber.toBigInt();
617
611
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
618
612
 
619
- // this.metrics.recordNewBlock(blockNumber, validTxs.length);
620
613
  const workTimer = new Timer();
621
614
  this.setState(SequencerState.CREATING_BLOCK, slot);
622
615
 
@@ -675,7 +668,18 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
675
668
  this.log.verbose(`Collected ${attestations.length} attestations`, { blockHash, blockNumber });
676
669
  }
677
670
 
678
- await this.enqueuePublishL2Block(block, attestations, txHashes, invalidateBlock, publisher);
671
+ const attestationsAndSigners = new CommitteeAttestationsAndSigners(attestations ?? []);
672
+ const attestationsAndSignersSignature = this.validatorClient
673
+ ? await this.validatorClient.signAttestationsAndSigners(attestationsAndSigners, proposerAddress)
674
+ : Signature.empty();
675
+
676
+ await this.enqueuePublishL2Block(
677
+ block,
678
+ attestationsAndSigners,
679
+ attestationsAndSignersSignature,
680
+ invalidateBlock,
681
+ publisher,
682
+ );
679
683
  this.metrics.recordBuiltBlock(blockBuildDuration, publicGas.l2Gas);
680
684
  return block;
681
685
  } catch (err) {
@@ -751,7 +755,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
751
755
  this.metrics.recordRequiredAttestations(numberOfRequiredAttestations, attestationTimeAllowed);
752
756
 
753
757
  const timer = new Timer();
754
- let collectedAttestionsCount: number = 0;
758
+ let collectedAttestationsCount: number = 0;
755
759
  try {
756
760
  const attestationDeadline = new Date(this.dateProvider.now() + attestationTimeAllowed * 1000);
757
761
  const attestations = await this.validatorClient.collectAttestations(
@@ -760,17 +764,17 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
760
764
  attestationDeadline,
761
765
  );
762
766
 
763
- collectedAttestionsCount = attestations.length;
767
+ collectedAttestationsCount = attestations.length;
764
768
 
765
769
  // note: the smart contract requires that the signatures are provided in the order of the committee
766
770
  return orderAttestations(attestations, committee);
767
771
  } catch (err) {
768
772
  if (err && err instanceof AttestationTimeoutError) {
769
- collectedAttestionsCount = err.collectedCount;
773
+ collectedAttestationsCount = err.collectedCount;
770
774
  }
771
775
  throw err;
772
776
  } finally {
773
- this.metrics.recordCollectedAttestations(collectedAttestionsCount, timer.ms());
777
+ this.metrics.recordCollectedAttestations(collectedAttestationsCount, timer.ms());
774
778
  }
775
779
  }
776
780
 
@@ -783,8 +787,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
783
787
  }))
784
788
  protected async enqueuePublishL2Block(
785
789
  block: L2Block,
786
- attestations: CommitteeAttestation[] | undefined,
787
- txHashes: TxHash[],
790
+ attestationsAndSigners: CommitteeAttestationsAndSigners,
791
+ attestationsAndSignersSignature: Signature,
788
792
  invalidateBlock: InvalidateBlockRequest | undefined,
789
793
  publisher: SequencerPublisher,
790
794
  ): Promise<void> {
@@ -795,10 +799,15 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
795
799
  const slot = block.header.globalVariables.slotNumber.toNumber();
796
800
  const txTimeoutAt = new Date((this.getSlotStartBuildTimestamp(slot) + this.aztecSlotDuration) * 1000);
797
801
 
798
- const enqueued = await publisher.enqueueProposeL2Block(block, attestations, txHashes, {
799
- txTimeoutAt,
800
- forcePendingBlockNumber: invalidateBlock?.forcePendingBlockNumber,
801
- });
802
+ const enqueued = await publisher.enqueueProposeL2Block(
803
+ block,
804
+ attestationsAndSigners,
805
+ attestationsAndSignersSignature,
806
+ {
807
+ txTimeoutAt,
808
+ forcePendingBlockNumber: invalidateBlock?.forcePendingBlockNumber,
809
+ },
810
+ );
802
811
 
803
812
  if (!enqueued) {
804
813
  throw new Error(`Failed to enqueue publish of block ${block.number}`);
@@ -946,11 +955,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
946
955
  }
947
956
 
948
957
  private getSlotStartBuildTimestamp(slotNumber: number | bigint): number {
949
- return (
950
- Number(this.l1Constants.l1GenesisTime) +
951
- Number(slotNumber) * this.l1Constants.slotDuration -
952
- this.l1Constants.ethereumSlotDuration
953
- );
958
+ return getSlotStartBuildTimestamp(slotNumber, this.l1Constants);
954
959
  }
955
960
 
956
961
  private getSecondsIntoSlot(slotNumber: number | bigint): number {
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from '@aztec/aztec.js';
2
2
 
3
3
  import { DEFAULT_ATTESTATION_PROPAGATION_TIME } from '../config.js';
4
+ import { SequencerTooSlowError } from './errors.js';
4
5
  import type { SequencerMetrics } from './metrics.js';
5
6
  import { SequencerState } from './utils.js';
6
7
 
@@ -139,6 +140,7 @@ export class SequencerTimetable {
139
140
  public getMaxAllowedTime(state: SequencerState): number | undefined {
140
141
  switch (state) {
141
142
  case SequencerState.STOPPED:
143
+ case SequencerState.STOPPING:
142
144
  case SequencerState.IDLE:
143
145
  case SequencerState.SYNCHRONIZING:
144
146
  return; // We don't really care about times for this states
@@ -177,16 +179,3 @@ export class SequencerTimetable {
177
179
  this.log.trace(`Enough time to transition to ${newState}`, { maxAllowedTime, secondsIntoSlot });
178
180
  }
179
181
  }
180
-
181
- export class SequencerTooSlowError extends Error {
182
- constructor(
183
- public readonly proposedState: SequencerState,
184
- public readonly maxAllowedTime: number,
185
- public readonly currentTime: number,
186
- ) {
187
- super(
188
- `Too far into slot for ${proposedState} (time into slot ${currentTime}s greater than ${maxAllowedTime}s allowance)`,
189
- );
190
- this.name = 'SequencerTooSlowError';
191
- }
192
- }
@@ -1,35 +1,21 @@
1
1
  export enum SequencerState {
2
- /**
3
- * Sequencer is stopped and not processing any txs from the pool.
4
- */
2
+ /** Sequencer is stopped and not processing any txs from the pool. */
5
3
  STOPPED = 'STOPPED',
6
- /**
7
- * Sequencer is awaiting the next call to work().
8
- */
4
+ /** Sequencer is being stopped. Will move to STOPPED shortly. */
5
+ STOPPING = 'STOPPING',
6
+ /** Sequencer is awaiting the next call to work(). */
9
7
  IDLE = 'IDLE',
10
- /**
11
- * Synchronizing with the L2 chain.
12
- */
8
+ /** Synchronizing with the L2 chain. */
13
9
  SYNCHRONIZING = 'SYNCHRONIZING',
14
- /**
15
- * Checking if we are the proposer for the current slot.
16
- */
10
+ /** Checking if we are the proposer for the current slot. */
17
11
  PROPOSER_CHECK = 'PROPOSER_CHECK',
18
- /**
19
- * Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise.
20
- */
12
+ /** Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise. */
21
13
  INITIALIZING_PROPOSAL = 'INITIALIZING_PROPOSAL',
22
- /**
23
- * Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
24
- */
14
+ /** Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA. */
25
15
  CREATING_BLOCK = 'CREATING_BLOCK',
26
- /**
27
- * Collecting attestations from its peers. Will move to PUBLISHING_BLOCK.
28
- */
16
+ /** Collecting attestations from its peers. Will move to PUBLISHING_BLOCK. */
29
17
  COLLECTING_ATTESTATIONS = 'COLLECTING_ATTESTATIONS',
30
- /**
31
- * Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING.
32
- */
18
+ /** Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING. */
33
19
  PUBLISHING_BLOCK = 'PUBLISHING_BLOCK',
34
20
  }
35
21