@aztec/sequencer-client 0.0.1-commit.9372f48 → 0.0.1-commit.949a33fd8
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.
- package/dest/client/sequencer-client.d.ts +17 -7
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +63 -30
- package/dest/config.d.ts +26 -7
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +57 -37
- package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
- package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_predictor.js +128 -0
- package/dest/global_variable_builder/fee_provider.d.ts +21 -0
- package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_provider.js +58 -0
- package/dest/global_variable_builder/global_builder.d.ts +15 -16
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +16 -50
- package/dest/global_variable_builder/index.d.ts +4 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/global_variable_builder/index.js +2 -0
- package/dest/publisher/config.d.ts +47 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +121 -42
- package/dest/publisher/index.d.ts +2 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
- package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +58 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/index.js +2 -0
- package/dest/publisher/sequencer-publisher-factory.d.ts +11 -5
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +27 -3
- package/dest/publisher/sequencer-publisher.d.ts +75 -48
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +434 -141
- package/dest/sequencer/chain_state_overrides.d.ts +25 -0
- package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
- package/dest/sequencer/chain_state_overrides.js +39 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +52 -10
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +718 -245
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/events.d.ts +7 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +23 -8
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +117 -21
- package/dest/sequencer/sequencer.d.ts +54 -19
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +190 -99
- package/dest/sequencer/timetable.d.ts +17 -6
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +51 -46
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/index.d.ts +3 -5
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +11 -11
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +45 -34
- package/dest/test/utils.d.ts +3 -3
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +10 -8
- package/package.json +27 -28
- package/src/client/sequencer-client.ts +81 -30
- package/src/config.ts +75 -46
- package/src/global_variable_builder/README.md +44 -0
- package/src/global_variable_builder/fee_predictor.ts +172 -0
- package/src/global_variable_builder/fee_provider.ts +75 -0
- package/src/global_variable_builder/global_builder.ts +27 -63
- package/src/global_variable_builder/index.ts +3 -1
- package/src/publisher/config.ts +157 -45
- package/src/publisher/index.ts +3 -0
- package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +57 -0
- package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
- package/src/publisher/l1_tx_failed_store/index.ts +3 -0
- package/src/publisher/sequencer-publisher-factory.ts +38 -9
- package/src/publisher/sequencer-publisher.ts +501 -202
- package/src/sequencer/README.md +82 -13
- package/src/sequencer/chain_state_overrides.ts +87 -0
- package/src/sequencer/checkpoint_proposal_job.ts +889 -265
- package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +6 -1
- package/src/sequencer/metrics.ts +132 -25
- package/src/sequencer/sequencer.ts +266 -113
- package/src/sequencer/timetable.ts +70 -57
- package/src/sequencer/types.ts +1 -1
- package/src/test/index.ts +2 -4
- package/src/test/mock_checkpoint_builder.ts +63 -49
- package/src/test/utils.ts +31 -10
package/src/sequencer/README.md
CHANGED
|
@@ -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),
|
|
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
|
|
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 L1 publishing is deferred to the target slot and removed from the current slot budget. Attestation collection is completed inside the build slot itself, so the proposer can send the L1 transaction immediately at the target-slot boundary.
|
|
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,20 @@ 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
|
|
80
|
+
Given a slot configuration, we calculate how many blocks fit using these formulas:
|
|
79
81
|
|
|
80
82
|
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
+ 2 * propagationTime (proposal out + attestations back)
|
|
93
|
+
+ blockDuration (last-block re-execution)
|
|
86
94
|
|
|
87
95
|
timeAvailableForBlocks = slotDuration - initializationOffset - timeReservedAtEnd
|
|
88
96
|
|
|
@@ -101,6 +109,60 @@ This means:
|
|
|
101
109
|
- Sub-slot 6: Reserved for validator re-execution of block 5
|
|
102
110
|
- After sub-slot 6: Attestation collection, finalization, and L1 publishing
|
|
103
111
|
|
|
112
|
+
**The same slot with proposer pipelining enabled:**
|
|
113
|
+
```
|
|
114
|
+
timeReservedAtEnd = 1s + 2*2s + 8s = 13s
|
|
115
|
+
timeAvailableForBlocks = 72s - 2s - 13s = 57s
|
|
116
|
+
numberOfBlocks = floor(57s / 8s) = 7 blocks
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The extra two block opportunities come from not charging the current slot for L1 publishing. The proposal broadcast, attestation round-trip, and last-block re-execution are now all reserved inside the build slot so that attestations are in hand at the slot boundary.
|
|
120
|
+
|
|
121
|
+
### Pipelining Mode
|
|
122
|
+
|
|
123
|
+
When proposer pipelining is enabled, the sequencer uses the current wall-clock slot to build the checkpoint for the **next target slot**, and finishes collecting attestations before the slot boundary so that L1 publishing can happen immediately at the target-slot boundary.
|
|
124
|
+
|
|
125
|
+
It helps to think in terms of two different slots:
|
|
126
|
+
|
|
127
|
+
- **Wall-clock slot N-1**: The sequencer initializes checkpoint `N`, builds its blocks, validators re-execute the last block, and attestations are gathered
|
|
128
|
+
- **Target slot N**: The checkpoint is submitted to L1
|
|
129
|
+
|
|
130
|
+
So the work is split like this:
|
|
131
|
+
|
|
132
|
+
- **During slot N-1**: Initialization, block building, last-block re-execution, proposal broadcast, and attestation collection
|
|
133
|
+
- **At the start of slot N**: The L1 transaction is submitted — attestations are already in hand
|
|
134
|
+
|
|
135
|
+
In other words, pipelining moves **block production, block re-execution, proposal broadcast, and attestation collection** into the build slot, while **L1 submission** happens aligned with slot `N`. With default values (72s slot, 6s block, 2s p2p, 1s assemble), the last build-slot block finishes at `T = slotDuration - timeReservedAtEnd = 61s`, the proposer broadcasts the checkpoint at `T=62s` after `assembleTime=1s`, and attestations are in hand by `T=72s` (the slot boundary).
|
|
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
|
+
- Broadcast checkpoint 12 proposal
|
|
142
|
+
- Validators re-execute the last block of checkpoint 12
|
|
143
|
+
- Collect checkpoint 12 attestations (all complete before slot 11 ends)
|
|
144
|
+
|
|
145
|
+
Slot 12 (target/submission slot):
|
|
146
|
+
- Submit checkpoint 12 to L1 at the slot boundary
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
For timetable purposes:
|
|
150
|
+
|
|
151
|
+
- `maxNumberOfBlocks` is computed by reserving assembly + round-trip p2p + last-block re-execution at the end of the slot
|
|
152
|
+
- `initializeDeadline` no longer subtracts checkpoint finalization time; it only requires enough time for initialization and two execution windows
|
|
153
|
+
|
|
154
|
+
In code, that means:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
initializeDeadline (normal mode) =
|
|
158
|
+
slotDuration - initializationOffset - 2 * minExecutionTime - checkpointFinalizationTime
|
|
159
|
+
|
|
160
|
+
initializeDeadline (pipelining) =
|
|
161
|
+
slotDuration - initializationOffset - 2 * minExecutionTime
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The fixed sub-slot deadlines themselves do not change. Pipelining only changes how much of the slot is considered available for block building, and when the broadcast and attestation windows close.
|
|
165
|
+
|
|
104
166
|
## The Sequencer's Work
|
|
105
167
|
|
|
106
168
|
When elected as proposer for a slot, the sequencer performs these tasks:
|
|
@@ -226,7 +288,9 @@ After the last block is built and validators have re-executed it:
|
|
|
226
288
|
|
|
227
289
|
**Time reserved:** `2*propagationTime + finalizationTime + l1PublishingTime = 2s + 2s + 1s + 12s = 17s`
|
|
228
290
|
|
|
229
|
-
|
|
291
|
+
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.
|
|
292
|
+
|
|
293
|
+
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
294
|
|
|
231
295
|
## Handling Timing Variations
|
|
232
296
|
|
|
@@ -399,7 +463,7 @@ When configuring timing parameters, ensure these constraints are satisfied:
|
|
|
399
463
|
|
|
400
464
|
### Minimum Slot Duration
|
|
401
465
|
|
|
402
|
-
For a valid configuration:
|
|
466
|
+
For a valid multi-block configuration without pipelining:
|
|
403
467
|
```
|
|
404
468
|
slotDuration >= initializationOffset
|
|
405
469
|
+ blockDuration * 2 (at least 2 blocks)
|
|
@@ -414,6 +478,11 @@ Simplified:
|
|
|
414
478
|
slotDuration >= initializationOffset + 3*blockDuration + 2*propagationTime + finalizationTime + l1PublishingTime
|
|
415
479
|
```
|
|
416
480
|
|
|
481
|
+
With proposer pipelining enabled, the same "at least 2 buildable blocks plus the final validator re-execution sub-slot" requirement becomes:
|
|
482
|
+
```
|
|
483
|
+
slotDuration >= initializationOffset + 3*blockDuration
|
|
484
|
+
```
|
|
485
|
+
|
|
417
486
|
**Example:**
|
|
418
487
|
```
|
|
419
488
|
slotDuration >= 2s + 3*8s + 2*2s + 1s + 12s = 2s + 24s + 4s + 1s + 12s = 43s
|
|
@@ -465,7 +534,7 @@ The sequencer transitions through these states during a slot:
|
|
|
465
534
|
| **WAITING_UNTIL_NEXT_BLOCK** | Until next sub-slot start | Sleep between blocks to maintain intervals |
|
|
466
535
|
| **ASSEMBLING_CHECKPOINT** | assembleTime (1s) | Assemble final checkpoint |
|
|
467
536
|
| **COLLECTING_ATTESTATIONS** | Until L1 publish deadline | Wait for validator signatures |
|
|
468
|
-
| **PUBLISHING_CHECKPOINT** | Until
|
|
537
|
+
| **PUBLISHING_CHECKPOINT** | Until L1 publish deadline | Submit to L1 |
|
|
469
538
|
|
|
470
539
|
## Complete Example: 72-Second Slot with 8-Second Sub-Slots
|
|
471
540
|
|
|
@@ -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
|
+
}
|