@aztec/sequencer-client 0.0.1-commit.35158ae7e → 0.0.1-commit.3750d92a7

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 +3 -1
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +3 -4
  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 +3 -8
  14. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  15. package/dest/global_variable_builder/global_builder.js +4 -39
  16. package/dest/global_variable_builder/index.d.ts +3 -1
  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 +1 -1
  20. package/dest/publisher/config.d.ts.map +1 -1
  21. package/dest/publisher/config.js +2 -2
  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 +1 -3
  25. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  26. package/dest/publisher/sequencer-publisher-factory.js +0 -1
  27. package/dest/publisher/sequencer-publisher.d.ts +47 -44
  28. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  29. package/dest/publisher/sequencer-publisher.js +112 -115
  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 +73 -20
  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 +5 -7
  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 +8 -43
  58. package/src/global_variable_builder/index.ts +2 -0
  59. package/src/publisher/config.ts +6 -4
  60. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +3 -1
  61. package/src/publisher/sequencer-publisher-factory.ts +0 -3
  62. package/src/publisher/sequencer-publisher.ts +174 -163
  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 +110 -22
  70. package/src/sequencer/timetable.ts +57 -45
@@ -1,8 +1,8 @@
1
1
  # Sequencer Timing Model
2
2
 
3
- The Aztec sequencer divides each slot into **fixed-duration sub-slots**. Each sub-slot has a pre-defined start and end time based on an initialization offset (how much time we expect syncing the previous slot will take), a finalization time (how much time we need for closing a checkpoint and publishing it to L1), and the configured block duration.
3
+ The Aztec sequencer divides each slot into **fixed-duration sub-slots**. Each sub-slot has a pre-defined start and end time based on an initialization offset (how much time we expect syncing the previous slot will take), the configured block duration, and whether checkpoint finalization is paid for in the current slot or deferred under proposer pipelining.
4
4
 
5
- **Example: 72-second slot with 8-second sub-slots**
5
+ **Example: 72-second slot with 8-second sub-slots (non-pipelined)**
6
6
 
7
7
  ```
8
8
  0s: Slot starts
@@ -31,7 +31,7 @@ Deadlines are fixed relative to slot start, not relative to when work actually c
31
31
 
32
32
  ## Overview
33
33
 
34
- The Aztec sequencer operates in fixed-duration **slots** (typically 72 seconds). During each slot, a designated proposer builds multiple **blocks** containing transactions over multiple **sub-slots**, then collects a single round of attestations for the entire **checkpoint** from validators, and finally publishes the resulting checkpoint to L1 Ethereum.
34
+ The Aztec sequencer operates in fixed-duration **slots** (typically 72 seconds). During each slot, a designated proposer builds multiple **blocks** containing transactions over multiple **sub-slots**. In the default mode, the same slot also reserves time to collect attestations for the resulting **checkpoint**, finalize it, and publish it to L1 Ethereum. When proposer pipelining is enabled, the slot budget for block building is larger because checkpoint finalization is deferred to the next target slot.
35
35
 
36
36
  ## Key Concepts
37
37
 
@@ -42,12 +42,14 @@ The Aztec sequencer operates in fixed-duration **slots** (typically 72 seconds).
42
42
  - **Checkpoint**: The collection of all blocks built in a slot, attested by validators and published to L1
43
43
  - **Sub-slot**: A fixed-duration time window within a slot (e.g., 8 seconds) during which a block should be built
44
44
 
45
- In a typical configuration, a 72-second slot contains:
45
+ In a typical configuration without pipelining, a 72-second slot contains:
46
46
  - 1 initialization period (2 seconds)
47
47
  - 5 block-building sub-slots (8 seconds each = 40 seconds)
48
48
  - 1 last validator re-execution sub-slot (8 seconds)
49
49
  - 1 attestation and publishing period (17 seconds)
50
50
 
51
+ With proposer pipelining enabled, the last validator re-execution sub-slot is still reserved, but the checkpoint finalization and L1 publishing budget is no longer subtracted when deciding how many block-building sub-slots fit in the slot.
52
+
51
53
  ### The Fixed Sub-Slot Model
52
54
 
53
55
  Building multiple blocks per slot uses **fixed sub-slots** with predictable deadlines:
@@ -75,14 +77,19 @@ These values are configurable but must satisfy certain constraints (explained be
75
77
 
76
78
  ## Calculating Sub-Slots and Blocks
77
79
 
78
- Given a slot configuration, we calculate how many blocks fit using this formula:
80
+ Given a slot configuration, we calculate how many blocks fit using these formulas:
79
81
 
80
82
  ```
81
- timeReservedAtEnd = blockDuration (last sub-slot for reexecution)
82
- + propagationTime (validators receive proposal)
83
- + propagationTime (attestations come back)
84
- + finalizationTime (checkpoint finalization)
85
- + l1PublishingTime (L1 transaction)
83
+ checkpointFinalizationTime = propagationTime
84
+ + propagationTime
85
+ + finalizationTime
86
+ + l1PublishingTime
87
+
88
+ timeReservedAtEnd (normal mode) = blockDuration (last sub-slot for reexecution)
89
+ + checkpointFinalizationTime
90
+
91
+ timeReservedAtEnd (pipelining) = assembleTime
92
+ + propagationTime (proposal must reach validators before the slot flips)
86
93
 
87
94
  timeAvailableForBlocks = slotDuration - initializationOffset - timeReservedAtEnd
88
95
 
@@ -101,6 +108,62 @@ This means:
101
108
  - Sub-slot 6: Reserved for validator re-execution of block 5
102
109
  - After sub-slot 6: Attestation collection, finalization, and L1 publishing
103
110
 
111
+ **The same slot with proposer pipelining enabled:**
112
+ ```
113
+ timeReservedAtEnd = 1s + 2s = 3s
114
+ timeAvailableForBlocks = 72s - 2s - 3s = 67s
115
+ numberOfBlocks = floor(67s / 8s) = 8 blocks
116
+ ```
117
+
118
+ The extra two block opportunities come from not charging the current slot for checkpoint finalization and L1 publishing.
119
+
120
+ ### Pipelining Mode
121
+
122
+ When proposer pipelining is enabled, the sequencer uses the current wall-clock slot to build the checkpoint for the **next target slot**.
123
+
124
+ It helps to think in terms of two different slots:
125
+
126
+ - **Wall-clock slot N-1**: The sequencer initializes checkpoint `N`, builds its blocks, and validators re-execute the last block
127
+ - **Target slot N**: Checkpoint `N` is proposed, attestations are gathered, and the L1 transaction is submitted
128
+
129
+ So the work is split like this:
130
+
131
+ - **During slot N-1**: Initialization, block building, and last-block re-execution
132
+ - **Near the end of slot N-1**: The checkpoint proposal is broadcast so validators can start the last re-execution as slot `N` begins.
133
+ - **During slot N**: Validators finish re-executing, send attestations, the proposer collects them, and the checkpoint is submitted to L1 before slot `N` reaches its publish cutoff
134
+
135
+ In other words, pipelining does not mean "do everything for slot N earlier". It specifically moves **block production and block re-execution** earlier, while **checkpoint proposal, attestation gathering, and L1 submission** remain aligned with slot `N`.
136
+
137
+ **Example: building checkpoint 12 while wall-clock time is in slot 11**
138
+ ```
139
+ Slot 11 (wall clock):
140
+ - Build blocks that will make up checkpoint 12
141
+ - Validators re-execute the last block of checkpoint 12
142
+ - Broadcast checkpoint 12 proposal
143
+ - Collect checkpoint 12 attestations
144
+
145
+ Slot 12 (target/submission slot):
146
+ - Collect attestations for checkpoint 12 until slot 12 reaches its L1 publish cutoff
147
+ - Submit checkpoint 12 to L1
148
+ ```
149
+
150
+ For timetable purposes, this changes two things:
151
+
152
+ - `maxNumberOfBlocks` is computed by reserving only the final validator re-execution sub-slot
153
+ - `initializeDeadline` no longer subtracts checkpoint finalization time; it only requires enough time for initialization, execution, and validator re-execution
154
+
155
+ In code, that means:
156
+
157
+ ```
158
+ initializeDeadline (normal mode) =
159
+ slotDuration - initializationOffset - 2 * minExecutionTime - checkpointFinalizationTime
160
+
161
+ initializeDeadline (pipelining) =
162
+ slotDuration - initializationOffset - 2 * minExecutionTime
163
+ ```
164
+
165
+ The fixed sub-slot deadlines themselves do not change. Pipelining only changes how much of the slot is considered available for block building.
166
+
104
167
  ## The Sequencer's Work
105
168
 
106
169
  When elected as proposer for a slot, the sequencer performs these tasks:
@@ -226,7 +289,9 @@ After the last block is built and validators have re-executed it:
226
289
 
227
290
  **Time reserved:** `2*propagationTime + finalizationTime + l1PublishingTime = 2s + 2s + 1s + 12s = 17s`
228
291
 
229
- This 17s comes after the last sub-slot, ensuring we have enough time to complete the checkpoint. If the sequencer receives the necessary attestations before the reserved time, the L1 tx is submitted earlier.
292
+ In the non-pipelined path, this 17s comes after the last sub-slot, ensuring we have enough time to complete the checkpoint. If the sequencer receives the necessary attestations before the reserved time, the L1 tx is submitted earlier.
293
+
294
+ With proposer pipelining enabled, this finalization budget is not charged against the current slot when calculating how many blocks fit. The checkpoint is instead queued for submission at the start of the target slot, so proposal broadcast, attestation gathering, and L1 submission happen in slot `N` while block building and block re-execution already happened in slot `N-1`.
230
295
 
231
296
  ## Handling Timing Variations
232
297
 
@@ -399,7 +464,7 @@ When configuring timing parameters, ensure these constraints are satisfied:
399
464
 
400
465
  ### Minimum Slot Duration
401
466
 
402
- For a valid configuration:
467
+ For a valid multi-block configuration without pipelining:
403
468
  ```
404
469
  slotDuration >= initializationOffset
405
470
  + blockDuration * 2 (at least 2 blocks)
@@ -414,6 +479,11 @@ Simplified:
414
479
  slotDuration >= initializationOffset + 3*blockDuration + 2*propagationTime + finalizationTime + l1PublishingTime
415
480
  ```
416
481
 
482
+ With proposer pipelining enabled, the same "at least 2 buildable blocks plus the final validator re-execution sub-slot" requirement becomes:
483
+ ```
484
+ slotDuration >= initializationOffset + 3*blockDuration
485
+ ```
486
+
417
487
  **Example:**
418
488
  ```
419
489
  slotDuration >= 2s + 3*8s + 2*2s + 1s + 12s = 2s + 24s + 4s + 1s + 12s = 43s
@@ -465,7 +535,7 @@ The sequencer transitions through these states during a slot:
465
535
  | **WAITING_UNTIL_NEXT_BLOCK** | Until next sub-slot start | Sleep between blocks to maintain intervals |
466
536
  | **ASSEMBLING_CHECKPOINT** | assembleTime (1s) | Assemble final checkpoint |
467
537
  | **COLLECTING_ATTESTATIONS** | Until L1 publish deadline | Wait for validator signatures |
468
- | **PUBLISHING_CHECKPOINT** | Until slot end | Submit to L1 |
538
+ | **PUBLISHING_CHECKPOINT** | Until L1 publish deadline | Submit to L1 |
469
539
 
470
540
  ## Complete Example: 72-Second Slot with 8-Second Sub-Slots
471
541
 
@@ -0,0 +1,87 @@
1
+ import { RollupContract, SimulationOverridesBuilder, type SimulationOverridesPlan } from '@aztec/ethereum/contracts';
2
+ import { CheckpointNumber } from '@aztec/foundation/branded-types';
3
+ import type { Fr } from '@aztec/foundation/curves/bn254';
4
+ import type { Logger } from '@aztec/foundation/log';
5
+ import type { ProposedCheckpointData } from '@aztec/stdlib/checkpoint';
6
+
7
+ type PipelinedParentSimulationOverridesPlanInput = {
8
+ checkpointNumber: CheckpointNumber;
9
+ proposedCheckpointData?: ProposedCheckpointData;
10
+ rollup: RollupContract;
11
+ log: Logger;
12
+ };
13
+
14
+ type SubmissionSimulationOverridesPlanInput = {
15
+ pipelinedParentPlan?: SimulationOverridesPlan;
16
+ invalidateToPendingCheckpointNumber?: CheckpointNumber;
17
+ lastArchiveRoot: Fr;
18
+ pipeliningEnabled: boolean;
19
+ };
20
+
21
+ /** Builds the simulated parent checkpoint view used while constructing a pipelined proposal. */
22
+ export async function buildPipelinedParentSimulationOverridesPlan(
23
+ input: PipelinedParentSimulationOverridesPlanInput,
24
+ ): Promise<SimulationOverridesPlan | undefined> {
25
+ const parentCheckpointNumber = CheckpointNumber(input.checkpointNumber - 1);
26
+ const builder = new SimulationOverridesBuilder().forPendingCheckpoint(parentCheckpointNumber);
27
+
28
+ const pendingFeeHeader = await computePipelinedParentFeeHeader(input);
29
+ if (pendingFeeHeader) {
30
+ builder.withPendingFeeHeader(pendingFeeHeader);
31
+ }
32
+
33
+ return builder.build();
34
+ }
35
+
36
+ /** Builds the simulated chain view used when validating and enqueueing checkpoint submission. */
37
+ export function buildSubmissionSimulationOverridesPlan(
38
+ input: SubmissionSimulationOverridesPlanInput,
39
+ ): SimulationOverridesPlan | undefined {
40
+ const pendingCheckpointNumber =
41
+ input.invalidateToPendingCheckpointNumber ?? input.pipelinedParentPlan?.pendingCheckpointNumber;
42
+
43
+ const builder = SimulationOverridesBuilder.from(input.pipelinedParentPlan).forPendingCheckpoint(
44
+ pendingCheckpointNumber,
45
+ );
46
+
47
+ if (input.pipeliningEnabled && pendingCheckpointNumber !== undefined) {
48
+ builder.withPendingArchive(input.lastArchiveRoot);
49
+ }
50
+
51
+ return builder.build();
52
+ }
53
+
54
+ /** Derives the pending parent fee header used during pipelined proposal simulation. */
55
+ export async function computePipelinedParentFeeHeader(input: PipelinedParentSimulationOverridesPlanInput) {
56
+ if (!input.proposedCheckpointData || input.checkpointNumber < 2) {
57
+ return undefined;
58
+ }
59
+
60
+ const grandparentCheckpointNumber = CheckpointNumber(input.checkpointNumber - 2);
61
+
62
+ try {
63
+ const [grandparentCheckpoint, manaTarget] = await Promise.all([
64
+ input.rollup.getCheckpoint(grandparentCheckpointNumber),
65
+ input.rollup.getManaTarget(),
66
+ ]);
67
+
68
+ if (!grandparentCheckpoint?.feeHeader) {
69
+ input.log.error(
70
+ `Grandparent checkpoint or feeHeader missing for checkpoint ${grandparentCheckpointNumber.toString()}`,
71
+ );
72
+ return undefined;
73
+ }
74
+
75
+ return RollupContract.computeChildFeeHeader(
76
+ grandparentCheckpoint.feeHeader,
77
+ input.proposedCheckpointData.totalManaUsed,
78
+ input.proposedCheckpointData.feeAssetPriceModifier,
79
+ manaTarget,
80
+ );
81
+ } catch (err) {
82
+ input.log.error(
83
+ `Failed to derive pipelined parent fee header for checkpoint ${grandparentCheckpointNumber.toString()}: ${err}`,
84
+ );
85
+ return undefined;
86
+ }
87
+ }