@aztec/sequencer-client 3.0.0-nightly.20251221 → 3.0.0-nightly.20251223

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 (79) hide show
  1. package/dest/client/sequencer-client.d.ts +9 -8
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +28 -24
  4. package/dest/config.d.ts +7 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +63 -26
  7. package/dest/global_variable_builder/global_builder.d.ts +16 -8
  8. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  9. package/dest/global_variable_builder/global_builder.js +35 -26
  10. package/dest/index.d.ts +2 -2
  11. package/dest/index.d.ts.map +1 -1
  12. package/dest/index.js +1 -1
  13. package/dest/publisher/config.d.ts +3 -3
  14. package/dest/publisher/config.d.ts.map +1 -1
  15. package/dest/publisher/config.js +2 -2
  16. package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
  17. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  18. package/dest/publisher/sequencer-publisher-factory.js +1 -1
  19. package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
  20. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  21. package/dest/publisher/sequencer-publisher.d.ts +11 -24
  22. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  23. package/dest/publisher/sequencer-publisher.js +50 -62
  24. package/dest/sequencer/block_builder.d.ts +1 -3
  25. package/dest/sequencer/block_builder.d.ts.map +1 -1
  26. package/dest/sequencer/block_builder.js +4 -2
  27. package/dest/sequencer/checkpoint_builder.d.ts +63 -0
  28. package/dest/sequencer/checkpoint_builder.d.ts.map +1 -0
  29. package/dest/sequencer/checkpoint_builder.js +131 -0
  30. package/dest/sequencer/checkpoint_proposal_job.d.ts +73 -0
  31. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
  32. package/dest/sequencer/checkpoint_proposal_job.js +638 -0
  33. package/dest/sequencer/checkpoint_voter.d.ts +34 -0
  34. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
  35. package/dest/sequencer/checkpoint_voter.js +85 -0
  36. package/dest/sequencer/events.d.ts +46 -0
  37. package/dest/sequencer/events.d.ts.map +1 -0
  38. package/dest/sequencer/events.js +1 -0
  39. package/dest/sequencer/index.d.ts +5 -1
  40. package/dest/sequencer/index.d.ts.map +1 -1
  41. package/dest/sequencer/index.js +4 -0
  42. package/dest/sequencer/metrics.d.ts +3 -1
  43. package/dest/sequencer/metrics.d.ts.map +1 -1
  44. package/dest/sequencer/metrics.js +9 -0
  45. package/dest/sequencer/sequencer.d.ts +87 -127
  46. package/dest/sequencer/sequencer.d.ts.map +1 -1
  47. package/dest/sequencer/sequencer.js +179 -596
  48. package/dest/sequencer/timetable.d.ts +33 -13
  49. package/dest/sequencer/timetable.d.ts.map +1 -1
  50. package/dest/sequencer/timetable.js +73 -39
  51. package/dest/sequencer/types.d.ts +3 -0
  52. package/dest/sequencer/types.d.ts.map +1 -0
  53. package/dest/sequencer/types.js +1 -0
  54. package/dest/sequencer/utils.d.ts +14 -8
  55. package/dest/sequencer/utils.d.ts.map +1 -1
  56. package/dest/sequencer/utils.js +7 -4
  57. package/dest/test/index.d.ts +3 -1
  58. package/dest/test/index.d.ts.map +1 -1
  59. package/package.json +27 -27
  60. package/src/client/sequencer-client.ts +24 -31
  61. package/src/config.ts +68 -25
  62. package/src/global_variable_builder/global_builder.ts +45 -39
  63. package/src/index.ts +2 -0
  64. package/src/publisher/config.ts +3 -3
  65. package/src/publisher/sequencer-publisher-factory.ts +3 -3
  66. package/src/publisher/sequencer-publisher-metrics.ts +2 -2
  67. package/src/publisher/sequencer-publisher.ts +71 -74
  68. package/src/sequencer/block_builder.ts +4 -1
  69. package/src/sequencer/checkpoint_builder.ts +217 -0
  70. package/src/sequencer/checkpoint_proposal_job.ts +701 -0
  71. package/src/sequencer/checkpoint_voter.ts +105 -0
  72. package/src/sequencer/events.ts +27 -0
  73. package/src/sequencer/index.ts +4 -0
  74. package/src/sequencer/metrics.ts +11 -0
  75. package/src/sequencer/sequencer.ts +275 -804
  76. package/src/sequencer/timetable.ts +84 -49
  77. package/src/sequencer/types.ts +6 -0
  78. package/src/sequencer/utils.ts +18 -9
  79. package/src/test/index.ts +2 -0
@@ -1,13 +1,13 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
2
 
3
- import { DEFAULT_ATTESTATION_PROPAGATION_TIME } from '../config.js';
3
+ import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
4
4
  import { SequencerTooSlowError } from './errors.js';
5
5
  import type { SequencerMetrics } from './metrics.js';
6
6
  import { SequencerState } from './utils.js';
7
7
 
8
- const MIN_EXECUTION_TIME = 1;
9
- const BLOCK_PREPARE_TIME = 1;
10
- const BLOCK_VALIDATION_TIME = 1;
8
+ export const MIN_EXECUTION_TIME = 1;
9
+ export const CHECKPOINT_INITIALIZATION_TIME = 1;
10
+ export const CHECKPOINT_FINALIZATION_TIME = 1;
11
11
 
12
12
  export class SequencerTimetable {
13
13
  /**
@@ -22,19 +22,22 @@ export class SequencerTimetable {
22
22
  * but we'll timeout sooner to give it more time to propagate (remember we also have blobs!). Still, when working in anvil,
23
23
  * we can just post in the very last second of the L1 slot and still expect the tx to be accepted.
24
24
  */
25
- public readonly l1PublishingTime;
25
+ public readonly l1PublishingTime: number;
26
26
 
27
- /** What's the minimum time we want to leave available for execution and reexecution (used to derive init deadline) */
27
+ /**
28
+ * What's the minimum time we want to leave available for execution and reexecution (used to derive init deadline)
29
+ * Defaults to half of the block duration if set, otherwise a constant.
30
+ */
28
31
  public readonly minExecutionTime: number = MIN_EXECUTION_TIME;
29
32
 
30
33
  /** How long it takes to get ready to start building */
31
- public readonly blockPrepareTime: number = BLOCK_PREPARE_TIME;
34
+ public readonly checkpointInitializationTime: number = CHECKPOINT_INITIALIZATION_TIME;
32
35
 
33
36
  /** How long it takes to for proposals and attestations to travel across the p2p layer (one-way) */
34
- public readonly attestationPropagationTime: number;
37
+ public readonly p2pPropagationTime: number;
35
38
 
36
- /** How much time we spend validating and processing a block after building it, and assembling the proposal to send to attestors */
37
- public readonly blockValidationTime: number = BLOCK_VALIDATION_TIME;
39
+ /** How much time we spend validating and processing a checkpoint after building it */
40
+ public readonly checkpointFinalizationTime: number = CHECKPOINT_FINALIZATION_TIME;
38
41
 
39
42
  /** Ethereum slot duration in seconds */
40
43
  public readonly ethereumSlotDuration: number;
@@ -42,18 +45,19 @@ export class SequencerTimetable {
42
45
  /** Aztec slot duration in seconds (must be multiple of ethereum slot duration) */
43
46
  public readonly aztecSlotDuration: number;
44
47
 
45
- /** How late into an L1 slot we can send a tx to make sure it gets included in the immediate next block. Complement of l1PublishingTime. */
46
- public readonly maxL1TxInclusionTimeIntoSlot: number;
47
-
48
48
  /** Whether assertTimeLeft will throw if not enough time. */
49
49
  public readonly enforce: boolean;
50
50
 
51
+ /** Duration per block when building multiple blocks per slot (undefined = single block per slot) */
52
+ public readonly blockDuration: number | undefined;
53
+
51
54
  constructor(
52
55
  opts: {
53
56
  ethereumSlotDuration: number;
54
57
  aztecSlotDuration: number;
55
- maxL1TxInclusionTimeIntoSlot: number;
56
- attestationPropagationTime?: number;
58
+ l1PublishingTime: number;
59
+ p2pPropagationTime?: number;
60
+ blockDurationMs?: number;
57
61
  enforce: boolean;
58
62
  },
59
63
  private readonly metrics?: SequencerMetrics,
@@ -61,57 +65,57 @@ export class SequencerTimetable {
61
65
  ) {
62
66
  this.ethereumSlotDuration = opts.ethereumSlotDuration;
63
67
  this.aztecSlotDuration = opts.aztecSlotDuration;
64
- this.maxL1TxInclusionTimeIntoSlot = opts.maxL1TxInclusionTimeIntoSlot;
65
- this.attestationPropagationTime = opts.attestationPropagationTime ?? DEFAULT_ATTESTATION_PROPAGATION_TIME;
66
- this.l1PublishingTime = this.ethereumSlotDuration - this.maxL1TxInclusionTimeIntoSlot;
68
+ this.l1PublishingTime = opts.l1PublishingTime;
69
+ this.p2pPropagationTime = opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME;
70
+ this.blockDuration = opts.blockDurationMs ? opts.blockDurationMs / 1000 : undefined;
71
+ this.minExecutionTime = MIN_EXECUTION_TIME;
67
72
  this.enforce = opts.enforce;
68
73
 
69
74
  // Assume zero-cost propagation time and faster runs in test environments where L1 slot duration is shortened
70
75
  if (this.ethereumSlotDuration < 8) {
71
- this.attestationPropagationTime = 0;
72
- this.blockValidationTime = 0.5;
73
- this.blockPrepareTime = 0.5;
76
+ this.p2pPropagationTime = 0;
77
+ this.checkpointFinalizationTime = 0.5;
78
+ this.checkpointInitializationTime = 0.5;
74
79
  }
75
80
 
76
- const allWorkToDo =
77
- this.blockPrepareTime +
78
- this.minExecutionTime * 2 +
79
- this.attestationPropagationTime * 2 +
80
- this.blockValidationTime +
81
- this.l1PublishingTime;
81
+ // Minimum work to do within a slot for building a block with the minimum time for execution and publishing its checkpoint
82
+ const minWorkToDo =
83
+ this.checkpointInitializationTime +
84
+ this.minExecutionTime * 2 + // Execution and reexecution
85
+ this.checkpointFinalizationTime +
86
+ this.p2pPropagationTime * 2 + // Send proposal and receive attestations
87
+ this.l1PublishingTime; // Submit to L1
82
88
 
83
- const initializeDeadline = this.aztecSlotDuration - allWorkToDo;
89
+ const initializeDeadline = this.aztecSlotDuration - minWorkToDo;
84
90
  this.initializeDeadline = initializeDeadline;
85
91
 
86
92
  this.log.verbose(`Sequencer timetable initialized (${this.enforce ? 'enforced' : 'not enforced'})`, {
87
93
  ethereumSlotDuration: this.ethereumSlotDuration,
88
94
  aztecSlotDuration: this.aztecSlotDuration,
89
- maxL1TxInclusionTimeIntoSlot: this.maxL1TxInclusionTimeIntoSlot,
90
95
  l1PublishingTime: this.l1PublishingTime,
91
96
  minExecutionTime: this.minExecutionTime,
92
- blockPrepareTime: this.blockPrepareTime,
93
- attestationPropagationTime: this.attestationPropagationTime,
94
- blockValidationTime: this.blockValidationTime,
97
+ blockPrepareTime: this.checkpointInitializationTime,
98
+ p2pPropagationTime: this.p2pPropagationTime,
99
+ blockValidationTime: this.checkpointFinalizationTime,
95
100
  initializeDeadline: this.initializeDeadline,
96
101
  enforce: this.enforce,
97
- allWorkToDo,
102
+ allWorkToDo: minWorkToDo,
98
103
  });
99
104
 
100
105
  if (initializeDeadline <= 0) {
101
106
  throw new Error(
102
- `Block proposal initialize deadline cannot be negative (got ${initializeDeadline} from total time needed ${allWorkToDo} and a slot duration of ${this.aztecSlotDuration}).`,
107
+ `Block proposal initialize deadline cannot be negative (got ${initializeDeadline} from total time needed ${minWorkToDo} and a slot duration of ${this.aztecSlotDuration}).`,
103
108
  );
104
109
  }
105
110
  }
106
111
 
107
- private get afterBlockBuildingTimeNeededWithoutReexec() {
108
- return this.blockValidationTime + this.attestationPropagationTime * 2 + this.l1PublishingTime;
109
- }
110
-
111
- public getBlockProposalExecTimeEnd(secondsIntoSlot: number): number {
112
+ /** Deadline for a block proposal execution. Ensures we have enough time left for reexecution and publishing. */
113
+ public getProposerExecTimeEnd(secondsIntoSlot: number): number {
112
114
  // We are N seconds into the slot. We need to account for `afterBlockBuildingTimeNeededWithoutReexec` seconds,
113
115
  // send then split the remaining time between the re-execution and the block building.
114
- const maxAllowed = this.aztecSlotDuration - this.afterBlockBuildingTimeNeededWithoutReexec;
116
+ const afterBlockBuildingTimeNeededWithoutReexec =
117
+ this.checkpointFinalizationTime + this.p2pPropagationTime * 2 + this.l1PublishingTime;
118
+ const maxAllowed = this.aztecSlotDuration - afterBlockBuildingTimeNeededWithoutReexec;
115
119
  const available = maxAllowed - secondsIntoSlot;
116
120
  const executionTimeEnd = secondsIntoSlot + available / 2;
117
121
  this.log.debug(`Block proposal execution time deadline is ${executionTimeEnd}`, {
@@ -123,13 +127,11 @@ export class SequencerTimetable {
123
127
  return executionTimeEnd;
124
128
  }
125
129
 
126
- private get afterBlockReexecTimeNeeded() {
127
- return this.attestationPropagationTime + this.l1PublishingTime;
128
- }
129
-
130
+ /** Deadline for block proposal reexecution. Ensures the proposer has enough time for publishing. */
130
131
  public getValidatorReexecTimeEnd(secondsIntoSlot?: number): number {
131
132
  // We need to leave for `afterBlockReexecTimeNeeded` seconds available.
132
- const validationTimeEnd = this.aztecSlotDuration - this.afterBlockReexecTimeNeeded;
133
+ const afterBlockReexecTimeNeeded = this.p2pPropagationTime + this.l1PublishingTime;
134
+ const validationTimeEnd = this.aztecSlotDuration - afterBlockReexecTimeNeeded;
133
135
  this.log.debug(`Validator re-execution time deadline is ${validationTimeEnd}`, {
134
136
  secondsIntoSlot,
135
137
  validationTimeEnd,
@@ -152,13 +154,16 @@ export class SequencerTimetable {
152
154
  case SequencerState.SYNCHRONIZING:
153
155
  return; // We don't really care about times for this states
154
156
  case SequencerState.PROPOSER_CHECK:
155
- case SequencerState.INITIALIZING_PROPOSAL:
157
+ case SequencerState.INITIALIZING_CHECKPOINT:
156
158
  return this.initializeDeadline;
159
+ case SequencerState.WAITING_FOR_TXS:
157
160
  case SequencerState.CREATING_BLOCK:
158
- return this.initializeDeadline + this.blockPrepareTime;
161
+ case SequencerState.WAITING_UNTIL_NEXT_BLOCK:
162
+ return this.initializeDeadline + this.checkpointInitializationTime;
163
+ case SequencerState.FINALIZING_CHECKPOINT:
159
164
  case SequencerState.COLLECTING_ATTESTATIONS:
160
- return this.aztecSlotDuration - this.l1PublishingTime - 2 * this.attestationPropagationTime;
161
- case SequencerState.PUBLISHING_BLOCK:
165
+ return this.aztecSlotDuration - this.l1PublishingTime - 2 * this.p2pPropagationTime;
166
+ case SequencerState.PUBLISHING_CHECKPOINT:
162
167
  return this.aztecSlotDuration - this.l1PublishingTime;
163
168
  default: {
164
169
  const _exhaustiveCheck: never = state;
@@ -185,4 +190,34 @@ export class SequencerTimetable {
185
190
  this.metrics?.recordStateTransitionBufferMs(Math.floor(bufferSeconds * 1000), newState);
186
191
  this.log.trace(`Enough time to transition to ${newState}`, { maxAllowedTime, secondsIntoSlot });
187
192
  }
193
+
194
+ /**
195
+ * Get timing information for building blocks within a slot.
196
+ * @param secondsIntoSlot - Current seconds into the slot
197
+ * @returns Object containing:
198
+ * - canStart: boolean - Whether there's time to start a block now
199
+ * - deadline: number - Deadline (seconds into slot) for building the block
200
+ * - isLastBlock: boolean - Whether the next block would be the last one in the checkpoint
201
+ */
202
+ public canStartNextBlock(secondsIntoSlot: number): {
203
+ canStart: boolean;
204
+ deadline: number | undefined;
205
+ isLastBlock: boolean;
206
+ } {
207
+ const minExecutionTime = this.minExecutionTime;
208
+ const deadline = this.enforce ? this.getProposerExecTimeEnd(secondsIntoSlot) : undefined;
209
+
210
+ // Always allow to start if we don't enforce the timetable
211
+ const canStart = !this.enforce || deadline === undefined || deadline - secondsIntoSlot >= minExecutionTime;
212
+
213
+ // Single block per slot
214
+ if (this.blockDuration === undefined) {
215
+ this.log.debug(`${canStart ? 'Can' : 'Cannot'} start single-block checkpoint at ${secondsIntoSlot}s into slot`);
216
+ return { deadline, canStart, isLastBlock: true };
217
+ }
218
+
219
+ // Multiple blocks per slot
220
+ // TODO(palla/mbps) Implement me
221
+ return { deadline, canStart, isLastBlock: true };
222
+ }
188
223
  }
@@ -0,0 +1,6 @@
1
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
2
+
3
+ export type SequencerRollupConstants = Pick<
4
+ L1RollupConstants,
5
+ 'ethereumSlotDuration' | 'l1GenesisTime' | 'slotDuration'
6
+ >;
@@ -9,22 +9,31 @@ export enum SequencerState {
9
9
  SYNCHRONIZING = 'SYNCHRONIZING',
10
10
  /** Checking if we are the proposer for the current slot. */
11
11
  PROPOSER_CHECK = 'PROPOSER_CHECK',
12
- /** Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise. */
13
- INITIALIZING_PROPOSAL = 'INITIALIZING_PROPOSAL',
14
- /** Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA. */
12
+ /** Initializing the checkpoint proposal. */
13
+ INITIALIZING_CHECKPOINT = 'INITIALIZING_CHECKPOINT',
14
+ /** Waiting for transactions to arrive in the pool. */
15
+ WAITING_FOR_TXS = 'WAITING_FOR_TXS',
16
+ /** Creating a new L2 block. Includes processing public function calls. */
15
17
  CREATING_BLOCK = 'CREATING_BLOCK',
16
- /** Collecting attestations from its peers. Will move to PUBLISHING_BLOCK. */
18
+ /** Waiting until the next block can be created. */
19
+ WAITING_UNTIL_NEXT_BLOCK = 'WAITING_UNTIL_NEXT_BLOCK',
20
+ /** Finalizing and broadcasting the checkpoint. */
21
+ FINALIZING_CHECKPOINT = 'FINALIZING_CHECKPOINT',
22
+ /** Collecting attestations from its peers. */
17
23
  COLLECTING_ATTESTATIONS = 'COLLECTING_ATTESTATIONS',
18
- /** Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING. */
19
- PUBLISHING_BLOCK = 'PUBLISHING_BLOCK',
24
+ /** Sending the tx to L1 with the L2 checkpoint data and awaiting it to be mined.. */
25
+ PUBLISHING_CHECKPOINT = 'PUBLISHING_CHECKPOINT',
20
26
  }
21
27
 
22
28
  export type SequencerStateWithSlot =
23
- | SequencerState.INITIALIZING_PROPOSAL
29
+ | SequencerState.INITIALIZING_CHECKPOINT
30
+ | SequencerState.WAITING_FOR_TXS
24
31
  | SequencerState.CREATING_BLOCK
32
+ | SequencerState.WAITING_UNTIL_NEXT_BLOCK
25
33
  | SequencerState.COLLECTING_ATTESTATIONS
26
- | SequencerState.PUBLISHING_BLOCK
27
- | SequencerState.PROPOSER_CHECK;
34
+ | SequencerState.PUBLISHING_CHECKPOINT
35
+ | SequencerState.PROPOSER_CHECK
36
+ | SequencerState.FINALIZING_CHECKPOINT;
28
37
 
29
38
  export type SequencerStateCallback = () => SequencerState;
30
39
 
package/src/test/index.ts CHANGED
@@ -6,6 +6,7 @@ import type { ValidatorClient } from '@aztec/validator-client';
6
6
  import { SequencerClient } from '../client/sequencer-client.js';
7
7
  import type { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
8
8
  import type { SequencerPublisher } from '../publisher/sequencer-publisher.js';
9
+ import type { FullNodeCheckpointsBuilder } from '../sequencer/checkpoint_builder.js';
9
10
  import { Sequencer } from '../sequencer/sequencer.js';
10
11
  import type { SequencerTimetable } from '../sequencer/timetable.js';
11
12
 
@@ -15,6 +16,7 @@ class TestSequencer_ extends Sequencer {
15
16
  declare public publisher: SequencerPublisher;
16
17
  declare public publisherFactory: SequencerPublisherFactory;
17
18
  declare public validatorClient: ValidatorClient;
19
+ declare public checkpointsBuilder: FullNodeCheckpointsBuilder;
18
20
  }
19
21
 
20
22
  export type TestSequencer = TestSequencer_;