@aztec/sequencer-client 0.0.1-commit.b2a5d0dd1 → 0.0.1-commit.b3d3157a
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/README.md +281 -21
- package/dest/client/sequencer-client.d.ts +3 -3
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +6 -6
- package/dest/config.d.ts +6 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +33 -10
- package/dest/global_variable_builder/fee_provider.js +1 -1
- package/dest/global_variable_builder/global_builder.d.ts +2 -3
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +1 -1
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +3 -3
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
- package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
- package/dest/publisher/sequencer-bundle-simulator.js +198 -0
- package/dest/publisher/sequencer-publisher.d.ts +36 -36
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +271 -500
- package/dest/sequencer/automine/automine_factory.d.ts +54 -0
- package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
- package/dest/sequencer/automine/automine_factory.js +84 -0
- package/dest/sequencer/automine/automine_sequencer.d.ts +151 -0
- package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
- package/dest/sequencer/automine/automine_sequencer.js +509 -0
- package/dest/sequencer/chain_state_overrides.d.ts +52 -16
- package/dest/sequencer/chain_state_overrides.d.ts.map +1 -1
- package/dest/sequencer/chain_state_overrides.js +86 -27
- package/dest/sequencer/checkpoint_proposal_job.d.ts +24 -6
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +373 -83
- package/dest/sequencer/events.d.ts +42 -2
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/index.d.ts +3 -1
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +2 -0
- package/dest/sequencer/metrics.d.ts +3 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +7 -0
- package/dest/sequencer/sequencer.d.ts +44 -9
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +256 -79
- package/dest/sequencer/timetable.d.ts +3 -6
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +3 -7
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/utils.d.ts +1 -1
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +7 -6
- package/package.json +27 -27
- package/src/client/sequencer-client.ts +12 -7
- package/src/config.ts +38 -10
- package/src/global_variable_builder/fee_provider.ts +1 -1
- package/src/global_variable_builder/global_builder.ts +2 -3
- package/src/index.ts +10 -1
- package/src/publisher/config.ts +2 -2
- package/src/publisher/sequencer-bundle-simulator.ts +254 -0
- package/src/publisher/sequencer-publisher.ts +286 -521
- package/src/sequencer/README.md +162 -520
- package/src/sequencer/automine/README.md +46 -0
- package/src/sequencer/automine/automine_factory.ts +145 -0
- package/src/sequencer/automine/automine_sequencer.ts +595 -0
- package/src/sequencer/chain_state_overrides.ts +133 -58
- package/src/sequencer/checkpoint_proposal_job.ts +420 -100
- package/src/sequencer/events.ts +46 -2
- package/src/sequencer/index.ts +2 -0
- package/src/sequencer/metrics.ts +9 -0
- package/src/sequencer/sequencer.ts +284 -95
- package/src/sequencer/timetable.ts +2 -9
- package/src/sequencer/types.ts +1 -1
- package/src/test/utils.ts +28 -10
package/src/sequencer/README.md
CHANGED
|
@@ -1,601 +1,243 @@
|
|
|
1
1
|
# Sequencer Timing Model
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This document covers how the sequencer schedules its work within a slot. See the [package README](../../README.md) for the high-level architecture; this one focuses on the timing math and the state-machine deadlines.
|
|
4
4
|
|
|
5
|
-
**
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
0s: Slot starts
|
|
9
|
-
0-2s: Sync + proposer check (fixed 2s offset)
|
|
10
|
-
|
|
11
|
-
Sub-slot 1: 2s-10s → Build Block 1, deadline at 10s
|
|
12
|
-
Sub-slot 2: 10s-18s → Build Block 2, deadline at 18s
|
|
13
|
-
Sub-slot 3: 18s-26s → Build Block 3, deadline at 26s
|
|
14
|
-
Sub-slot 4: 26s-34s → Build Block 4, deadline at 34s
|
|
15
|
-
Sub-slot 5: 34s-42s → Build Block 5 (last block), deadline at 42s
|
|
16
|
-
Sub-slot 6: 42s-50s → Reserved for validators to re-execute Block 5
|
|
17
|
-
|
|
18
|
-
42s: Broadcast checkpoint with Block 5
|
|
19
|
-
44s: Validators receive proposal (2s propagation)
|
|
20
|
-
44-52s: Validators re-execute Block 5 (8s)
|
|
21
|
-
52s: Validators send attestations
|
|
22
|
-
54s: Proposer receives attestations (2s propagation)
|
|
23
|
-
54-55s: Finalize checkpoint (1s)
|
|
24
|
-
55-67s: Publish to L1 (12s)
|
|
25
|
-
72s: Slot ends
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Deadlines are fixed relative to slot start, not relative to when work actually completes. If you finish initialization at 1s instead of 2s, you get bonus time for Block 1. If you finish at 3s, you have less time. If you finish at 9s, you skip the first sub-slot altogether and start building for the second one.
|
|
29
|
-
|
|
30
|
-
---
|
|
5
|
+
The model described here is for **proposer pipelining**, the only mode the production sequencer runs in (the proposer always builds for `slot + 1`). The deterministic single-sequencer `AutomineSequencer` used in some e2e tests publishes synchronously in-slot and does not use this timing model.
|
|
31
6
|
|
|
32
7
|
## Overview
|
|
33
8
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## Key Concepts
|
|
37
|
-
|
|
38
|
-
### Slot vs Block vs Checkpoint vs Sub-Slot
|
|
39
|
-
|
|
40
|
-
- **Slot**: A fixed time window (e.g., 72 seconds) during which a proposer can build blocks
|
|
41
|
-
- **Block**: A single batch of transactions, executed and validated
|
|
42
|
-
- **Checkpoint**: The collection of all blocks built in a slot, attested by validators and published to L1
|
|
43
|
-
- **Sub-slot**: A fixed-duration time window within a slot (e.g., 8 seconds) during which a block should be built
|
|
44
|
-
|
|
45
|
-
In a typical configuration without pipelining, a 72-second slot contains:
|
|
46
|
-
- 1 initialization period (2 seconds)
|
|
47
|
-
- 5 block-building sub-slots (8 seconds each = 40 seconds)
|
|
48
|
-
- 1 last validator re-execution sub-slot (8 seconds)
|
|
49
|
-
- 1 attestation and publishing period (17 seconds)
|
|
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
|
-
|
|
53
|
-
### The Fixed Sub-Slot Model
|
|
54
|
-
|
|
55
|
-
Building multiple blocks per slot uses **fixed sub-slots** with predictable deadlines:
|
|
56
|
-
|
|
57
|
-
1. **Equal-duration sub-slots**: All sub-slots have the same duration (`BLOCK_DURATION`)
|
|
58
|
-
2. **Fixed deadlines**: Block N deadline = `initializationOffset + N * BLOCK_DURATION`
|
|
59
|
-
3. **Last sub-slot reserved**: The final sub-slot is reserved for validators to re-execute the last block (no block is built during this sub-slot)
|
|
60
|
-
4. **Skip if too late**: If we can't start a block with at least `MIN_EXECUTION_TIME` remaining before its deadline, we immediately start building in the next sub-slot
|
|
61
|
-
|
|
62
|
-
## Timing Components
|
|
63
|
-
|
|
64
|
-
Understanding slot timing requires knowing these time constants:
|
|
65
|
-
|
|
66
|
-
| Component | Example Value | Purpose |
|
|
67
|
-
|-----------|---------------|---------|
|
|
68
|
-
| **Slot Duration** | 72s | Total time available for the entire checkpoint |
|
|
69
|
-
| **Block Duration** | 8s | Duration of each sub-slot (time budget for building one block) |
|
|
70
|
-
| **Initialization Offset** | 2s | Fixed estimate for sync + proposer check |
|
|
71
|
-
| **Propagation Time** | 2s | Time for messages to travel across the P2P network (one-way) |
|
|
72
|
-
| **Finalization Time** | 1s | Time to finalize checkpoint and prepare proposal message |
|
|
73
|
-
| **L1 Publishing Time** | 12s | Time reserved for L1 transaction to land in an Ethereum block |
|
|
74
|
-
| **Min Execution Time** | 3s | Minimum time needed to meaningfully build a block |
|
|
75
|
-
|
|
76
|
-
These values are configurable but must satisfy certain constraints (explained below). Example values may differ from the ones in the source code.
|
|
77
|
-
|
|
78
|
-
## Calculating Sub-Slots and Blocks
|
|
79
|
-
|
|
80
|
-
Given a slot configuration, we calculate how many blocks fit using these formulas:
|
|
81
|
-
|
|
82
|
-
```
|
|
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)
|
|
93
|
-
|
|
94
|
-
timeAvailableForBlocks = slotDuration - initializationOffset - timeReservedAtEnd
|
|
95
|
-
|
|
96
|
-
numberOfBlocks = floor(timeAvailableForBlocks / blockDuration)
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**Example with typical values:**
|
|
100
|
-
```
|
|
101
|
-
timeReservedAtEnd = 8s + 2s + 2s + 1s + 12s = 25s
|
|
102
|
-
timeAvailableForBlocks = 72s - 2s - 25s = 45s
|
|
103
|
-
numberOfBlocks = floor(45s / 8s) = 5 blocks
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
This means:
|
|
107
|
-
- Sub-slots 1-5: Build blocks 1-5
|
|
108
|
-
- Sub-slot 6: Reserved for validator re-execution of block 5
|
|
109
|
-
- After sub-slot 6: Attestation collection, finalization, and L1 publishing
|
|
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**.
|
|
9
|
+
Block production runs on three nested clocks:
|
|
123
10
|
|
|
124
|
-
|
|
11
|
+
- A **slot** is a fixed window (e.g. 72 s) during which one elected proposer is allowed to build.
|
|
12
|
+
- A slot contains several equal-length **sub-slots** (e.g. 8 s). Each sub-slot owns the budget for one L2 block and has a deadline fixed relative to the slot start.
|
|
13
|
+
- All blocks built within one slot make up one **checkpoint**, which is what eventually goes on L1.
|
|
125
14
|
|
|
126
|
-
|
|
127
|
-
- **Target slot N**: Checkpoint `N` is proposed, attestations are gathered, and the L1 transaction is submitted
|
|
15
|
+
Under pipelining, the proposer for slot `N` does its building inside slot `N - 1` ("build slot"). Slot `N` ("target slot") is only used to mine the L1 transaction. This shifts work like this:
|
|
128
16
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
```
|
|
17
|
+
| Phase | When |
|
|
18
|
+
| ------------------------------ | -------------- |
|
|
19
|
+
| Initialization | slot `N - 1` |
|
|
20
|
+
| Block building | slot `N - 1` |
|
|
21
|
+
| Checkpoint proposal broadcast | slot `N - 1` |
|
|
22
|
+
| Last-block re-execution | slot `N - 1` |
|
|
23
|
+
| Attestation collection | slot `N - 1` |
|
|
24
|
+
| L1 submission | slot `N` |
|
|
149
25
|
|
|
150
|
-
|
|
26
|
+
The wall-clock slot the sequencer is reasoning about ("build slot") and the slot the checkpoint commits to ("target slot") are always `N - 1` and `N` respectively.
|
|
151
27
|
|
|
152
|
-
|
|
153
|
-
- `initializeDeadline` no longer subtracts checkpoint finalization time; it only requires enough time for initialization, execution, and validator re-execution
|
|
28
|
+
## Sub-slots
|
|
154
29
|
|
|
155
|
-
|
|
30
|
+
Each sub-slot has a fixed start time and a fixed deadline, both relative to the slot start:
|
|
156
31
|
|
|
157
32
|
```
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
initializeDeadline (pipelining) =
|
|
162
|
-
slotDuration - initializationOffset - 2 * minExecutionTime
|
|
33
|
+
subSlotStart[k] = initializationOffset + (k - 1) * blockDuration
|
|
34
|
+
subSlotDeadline[k] = initializationOffset + k * blockDuration
|
|
163
35
|
```
|
|
164
36
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
## The Sequencer's Work
|
|
168
|
-
|
|
169
|
-
When elected as proposer for a slot, the sequencer performs these tasks:
|
|
170
|
-
|
|
171
|
-
### 1. Initialization Phase
|
|
172
|
-
|
|
173
|
-
Before building any blocks, the sequencer must:
|
|
174
|
-
- Verify it's the designated proposer
|
|
175
|
-
- Check all subsystems are synced
|
|
176
|
-
- Initialize checkpoint state
|
|
177
|
-
- Prepare global variables
|
|
178
|
-
|
|
179
|
-
Note that the initialization phase has a **fixed time budget** (`initializationOffset`, typically 2s). This is an *estimate*, not a deadline. The sequencer will take as long as it needs for initialization, but the sub-slot deadlines remain fixed regardless.
|
|
180
|
-
|
|
181
|
-
### 2. Block Building Loop
|
|
37
|
+
with `k = 1, 2, ..., maxNumberOfBlocks`. Deadlines do **not** shift based on when the previous block finished. If a block finishes early, the sequencer waits for the next sub-slot to begin (so validators see a regular cadence). If it finishes late, the next block has correspondingly less time.
|
|
182
38
|
|
|
183
|
-
|
|
39
|
+
`canStartNextBlock(secondsIntoSlot)` walks the sub-slot list and returns the first one with at least `minExecutionTime` left before its deadline. Sub-slots that no longer have enough headroom are skipped entirely.
|
|
184
40
|
|
|
185
|
-
|
|
41
|
+
### Number of sub-slots
|
|
186
42
|
|
|
187
|
-
|
|
43
|
+
The maximum number of buildable blocks per slot is:
|
|
188
44
|
|
|
189
45
|
```
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
46
|
+
timeReservedAtEnd = checkpointAssembleTime
|
|
47
|
+
+ 2 * p2pPropagationTime // proposal out + attestations back
|
|
48
|
+
+ blockDuration // last-block re-execution
|
|
193
49
|
|
|
194
|
-
|
|
50
|
+
timeAvailableForBlocks = aztecSlotDuration
|
|
51
|
+
- checkpointInitializationTime
|
|
52
|
+
- timeReservedAtEnd
|
|
195
53
|
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
Sub-slot 1: starts at 2s, deadline at 10s
|
|
199
|
-
Sub-slot 2: starts at 10s, deadline at 18s
|
|
200
|
-
Sub-slot 3: starts at 18s, deadline at 26s
|
|
201
|
-
Sub-slot 4: starts at 26s, deadline at 34s
|
|
202
|
-
Sub-slot 5: starts at 34s, deadline at 42s
|
|
54
|
+
maxNumberOfBlocks = floor(timeAvailableForBlocks / blockDuration)
|
|
203
55
|
```
|
|
204
56
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
For each sub-slot, the sequencer:
|
|
208
|
-
|
|
209
|
-
1. **Checks if we can start**: If current time is past `deadline - MIN_EXECUTION_TIME`, skip this sub-slot, and start building the block as if it were on the next sub-slot
|
|
210
|
-
2. **Waits for transactions** (if needed): Wait up to the deadline for minimum number of transactions
|
|
211
|
-
3. **Builds block**: Execute transactions until the deadline of the sub-slot
|
|
212
|
-
4. **Signs and broadcasts**: Finalize block and broadcast proposal to validators
|
|
57
|
+
The reservation at the end of the slot is sized so that, on the happy path, attestations are in hand by the time the target slot starts. The enforced `COLLECTING_ATTESTATIONS` and `PUBLISHING_CHECKPOINT` deadlines are softer (see the deadline table below) and let a late attestation spill into the target slot. L1 publishing is **not** included in `timeReservedAtEnd` — that is paid for by the target slot.
|
|
213
58
|
|
|
214
|
-
|
|
59
|
+
### Cooldown after the last sub-slot
|
|
215
60
|
|
|
216
|
-
|
|
61
|
+
All `maxNumberOfBlocks` sub-slots build a block. The cooldown lives in the `timeReservedAtEnd` window that follows the last sub-slot:
|
|
217
62
|
|
|
218
|
-
|
|
63
|
+
- 1 × `checkpointAssembleTime` to assemble and sign the checkpoint,
|
|
64
|
+
- 1 × `p2pPropagationTime` for the `CheckpointProposal` to reach the committee,
|
|
65
|
+
- 1 × `blockDuration` for the committee to re-execute the last block,
|
|
66
|
+
- 1 × `p2pPropagationTime` for attestations to come back.
|
|
219
67
|
|
|
220
|
-
|
|
68
|
+
These four windows total `checkpointAssembleTime + blockDuration + 2 * p2pPropagationTime`, exactly the `timeReservedAtEnd` formula above. The block built in the last sub-slot is *not* broadcast as a regular `BlockProposal`; the proposer holds it as `blockPendingBroadcast` so it travels bundled inside the `CheckpointProposal`.
|
|
221
69
|
|
|
222
|
-
|
|
223
|
-
- `minTxsPerBlock`: Minimum number of transactions required (configurable, e.g., 1-4)
|
|
224
|
-
- Polling interval: 500ms (checks mempool every half-second)
|
|
225
|
-
- Deadline: `blockDeadline - 1000ms` (must start building at least 1 second before the block deadline)
|
|
70
|
+
## Timing constants
|
|
226
71
|
|
|
227
|
-
|
|
228
|
-
1. Check current pending transaction count
|
|
229
|
-
2. If count >= `minTxsPerBlock`, proceed to build immediately
|
|
230
|
-
3. If count < `minTxsPerBlock`, poll every 500ms until either:
|
|
231
|
-
- Enough transactions arrive (proceed to build)
|
|
232
|
-
- Deadline is reached (skip building this block)
|
|
72
|
+
These constants come from `@aztec/stdlib/timetable` (see `stdlib/src/timetable/index.ts`). Some are fixed across the network, some are inputs from configuration.
|
|
233
73
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
74
|
+
| Constant | Source | Typical value | Purpose |
|
|
75
|
+
| --------------------------------- | --------------------------------------- | ------------- | ---------------------------------------------------- |
|
|
76
|
+
| `aztecSlotDuration` | L1 rollup contract | 72 s | Length of one Aztec slot. |
|
|
77
|
+
| `ethereumSlotDuration` | L1 rollup contract | 12 s | Length of one Ethereum slot. |
|
|
78
|
+
| `blockDuration` | `blockDurationMs` config | 6–8 s | Sub-slot length. |
|
|
79
|
+
| `checkpointInitializationTime` | constant (`CHECKPOINT_INITIALIZATION_TIME`) | 1 s | Estimated sync + proposer check time. |
|
|
80
|
+
| `checkpointAssembleTime` | constant (`CHECKPOINT_ASSEMBLE_TIME`) | 1 s | Time to assemble and sign the checkpoint after the last block. |
|
|
81
|
+
| `p2pPropagationTime` | `attestationPropagationTime` config | 2 s | One-way p2p estimate (proposals, attestations). |
|
|
82
|
+
| `l1PublishingTime` | `l1PublishingTime` config | 12 s | Time reserved for the L1 tx to land. Used by the target slot, not the build slot. |
|
|
83
|
+
| `minExecutionTime` | constant (`MIN_EXECUTION_TIME`) | 2 s | Minimum headroom to start a block. |
|
|
84
|
+
| `initializationOffset` | `=checkpointInitializationTime` | 1 s | Where sub-slot 1 starts. |
|
|
237
85
|
|
|
238
|
-
|
|
239
|
-
```
|
|
240
|
-
Sub-slot 3 deadline: 26s
|
|
241
|
-
Transaction wait deadline: 25s (26s - 1s)
|
|
242
|
-
Current time: 20s
|
|
243
|
-
|
|
244
|
-
20.0s: Check mempool → 2 txs (need 4)
|
|
245
|
-
20.5s: Check mempool → 2 txs (need 4)
|
|
246
|
-
21.0s: Check mempool → 4 txs (need 4) ✓ Start building!
|
|
247
|
-
21-26s: Build block with those 4+ transactions
|
|
248
|
-
```
|
|
86
|
+
## Deadlines
|
|
249
87
|
|
|
250
|
-
|
|
88
|
+
`SequencerTimetable.getMaxAllowedTime(state)` returns the latest second-into-slot a given state is allowed to be entered. `assertTimeLeft()` throws `SequencerTooSlowError` if the slot has already advanced past that deadline. Sub-slot scheduling is measured against the build slot (`slotNow`); state assertions, however, are measured against whichever slot `setState` was called with — for the publishing path that is the target slot, which is why the publishing deadline is allowed to exceed `aztecSlotDuration`.
|
|
251
89
|
|
|
252
|
-
|
|
90
|
+
| State | Max allowed time (seconds into build slot) |
|
|
91
|
+
| --------------------------- | --------------------------------------------------------------------------- |
|
|
92
|
+
| `PROPOSER_CHECK` | `initializeDeadline = aztecSlotDuration - (checkpointInitializationTime + 2*minExecutionTime)` |
|
|
93
|
+
| `INITIALIZING_CHECKPOINT` | same as `PROPOSER_CHECK` |
|
|
94
|
+
| `WAITING_FOR_TXS` | `initializeDeadline + checkpointInitializationTime` |
|
|
95
|
+
| `CREATING_BLOCK` | same as `WAITING_FOR_TXS` |
|
|
96
|
+
| `WAITING_UNTIL_NEXT_BLOCK` | same as `WAITING_FOR_TXS` |
|
|
97
|
+
| `ASSEMBLING_CHECKPOINT` | `aztecSlotDuration + pipeliningAttestationGracePeriod` |
|
|
98
|
+
| `COLLECTING_ATTESTATIONS` | same as `ASSEMBLING_CHECKPOINT` |
|
|
99
|
+
| `PUBLISHING_CHECKPOINT` | `2 * aztecSlotDuration - ethereumSlotDuration` (extends into the target slot) |
|
|
253
100
|
|
|
254
|
-
|
|
101
|
+
In production-like timing, `pipeliningAttestationGracePeriod` is zero, so `ASSEMBLING_CHECKPOINT` and
|
|
102
|
+
`COLLECTING_ATTESTATIONS` must be *entered* before the build-slot boundary. Local networks with
|
|
103
|
+
`l1PublishingTime < ethereumSlotDuration` can use the target-slot attestation window as grace while preserving the
|
|
104
|
+
L1-geometry publishing cutoff. Once entered, attestation collection itself has its own
|
|
105
|
+
`checkpointAttestationDeadline = 2 * aztecSlotDuration - ethereumSlotDuration`, so a late attestation arriving after
|
|
106
|
+
the boundary is still accepted. The publishing deadline extends into the target slot because that is when the L1 tx is
|
|
107
|
+
actually submitted.
|
|
255
108
|
|
|
256
|
-
|
|
109
|
+
## Example: 72 s slot, 8 s sub-slots
|
|
257
110
|
|
|
258
|
-
|
|
111
|
+
With typical pipelining values:
|
|
259
112
|
|
|
260
|
-
**Timeline for the last block:**
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
T: Last block finishes building, checkpoint proposal broadcast
|
|
264
|
-
Last sub-slot begins (duration: blockDuration)
|
|
265
|
-
T+2s: Validators receive proposal (propagation delay)
|
|
266
|
-
T+2s to T+2s+blockDuration: Validators re-execute last block
|
|
267
|
-
T+2s+blockDuration: Validators finish re-execution, send attestations
|
|
268
|
-
T+4s+blockDuration: Proposer receives attestations (propagation delay)
|
|
269
113
|
```
|
|
114
|
+
checkpointInitializationTime = 1s
|
|
115
|
+
blockDuration = 8s
|
|
116
|
+
checkpointAssembleTime = 1s
|
|
117
|
+
p2pPropagationTime = 2s
|
|
118
|
+
l1PublishingTime = 12s
|
|
270
119
|
|
|
271
|
-
|
|
120
|
+
timeReservedAtEnd = 1 + 2*2 + 8 = 13s
|
|
121
|
+
timeAvailableForBlocks = 72 - 1 - 13 = 58s
|
|
122
|
+
maxNumberOfBlocks = floor(58 / 8) = 7
|
|
272
123
|
```
|
|
273
|
-
42s: Block 5 finishes, checkpoint broadcast, sub-slot 6 starts
|
|
274
|
-
44s: Validators receive checkpoint (42s + 2s)
|
|
275
|
-
44-52s: Validators re-execute Block 5 (8s)
|
|
276
|
-
52s: Validators send attestations
|
|
277
|
-
54s: Proposer receives attestations (52s + 2s)
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
Note that validators finish at `52s`, which is `2s` after the last sub-slot ends at `50s`. This is expected and accounted for in the `timeReservedAtEnd` calculation.
|
|
281
|
-
|
|
282
|
-
### 4. Attestation Collection and L1 Publishing
|
|
283
|
-
|
|
284
|
-
After the last block is built and validators have re-executed it:
|
|
285
|
-
|
|
286
|
-
1. **Collect attestations**: Wait for validators to send their signatures (arrive at T+4s+blockDuration)
|
|
287
|
-
2. **Finalize checkpoint**: Sign over attestations, assemble final checkpoint (1s)
|
|
288
|
-
3. **Publish to L1**: Submit transaction to Ethereum (needs 12s to land)
|
|
289
|
-
|
|
290
|
-
**Time reserved:** `2*propagationTime + finalizationTime + l1PublishingTime = 2s + 2s + 1s + 12s = 17s`
|
|
291
|
-
|
|
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`.
|
|
295
124
|
|
|
296
|
-
|
|
125
|
+
Seven sub-slots, all of which build a block:
|
|
297
126
|
|
|
298
|
-
How does the sequencer timetable handle deviations from the expected times.
|
|
299
|
-
|
|
300
|
-
### Fast Initialization
|
|
301
|
-
|
|
302
|
-
**Scenario:** Initialization completes at 1s instead of 2s
|
|
303
|
-
|
|
304
|
-
```
|
|
305
|
-
0-1s: SYNCHRONIZING, PROPOSER_CHECK (1s actual, vs 2s estimate)
|
|
306
|
-
1s: Ready to build Block 1
|
|
307
|
-
1-10s: Build Block 1 (9s available vs 8s budgeted)
|
|
308
|
-
10s: Block 1 deadline
|
|
309
|
-
10-18s: Build Block 2
|
|
310
|
-
...
|
|
311
127
|
```
|
|
128
|
+
Sub-slot 1: starts 1s, deadline 9s (Block 1)
|
|
129
|
+
Sub-slot 2: starts 9s, deadline 17s (Block 2)
|
|
130
|
+
Sub-slot 3: starts 17s, deadline 25s (Block 3)
|
|
131
|
+
Sub-slot 4: starts 25s, deadline 33s (Block 4)
|
|
132
|
+
Sub-slot 5: starts 33s, deadline 41s (Block 5)
|
|
133
|
+
Sub-slot 6: starts 41s, deadline 49s (Block 6)
|
|
134
|
+
Sub-slot 7: starts 49s, deadline 57s (Block 7 — held for the checkpoint proposal)
|
|
312
135
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
This may happen if the sequencer has a slow L1 RPC endpoint and syncing the previous checkpoint from L1 takes longer than expected.
|
|
136
|
+
57s: Block 7 done, ASSEMBLING_CHECKPOINT (1s)
|
|
137
|
+
58s: CheckpointProposal broadcast
|
|
138
|
+
60s: Committee receives proposal (+2s p2p)
|
|
139
|
+
60-68s: Committee re-executes Block 7
|
|
140
|
+
68s: Committee sends attestations
|
|
141
|
+
70s: Proposer has the quorum (+2s p2p)
|
|
320
142
|
|
|
143
|
+
70-72s: Slack
|
|
144
|
+
72s: Build slot ends → L1 submission starts (target slot begins)
|
|
145
|
+
84s: L1 tx mined inside the target slot (+12s)
|
|
321
146
|
```
|
|
322
|
-
0-3s: SYNCHRONIZING, PROPOSER_CHECK (3s actual, vs 2s estimate)
|
|
323
|
-
3s: Ready to build Block 1
|
|
324
|
-
3-10s: Build Block 1 (7s available vs 8s budgeted)
|
|
325
|
-
10s: Block 1 deadline
|
|
326
|
-
10-18s: Build Block 2
|
|
327
|
-
...
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**Result:** Block 1 has 1s less time (7s instead of 8s). Still enough time to build a block, just with fewer transactions or simpler execution.
|
|
331
|
-
|
|
332
|
-
### Very Slow Initialization
|
|
333
147
|
|
|
334
|
-
|
|
148
|
+
## Parallel execution: proposer vs committee
|
|
335
149
|
|
|
336
|
-
While
|
|
150
|
+
While the proposer builds block `k+1`, the committee is re-executing block `k`. The pipeline keeps both sides busy except for the cooldown sub-slot.
|
|
337
151
|
|
|
338
152
|
```
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
18s: Block 1 deadline (sub-slot 2)
|
|
352
|
-
18-26s: Build Block 2 using sub-slot 3
|
|
153
|
+
Time | Proposer | Committee
|
|
154
|
+
-----|------------------------------|--------------------------------------
|
|
155
|
+
1s | Start Block 1 | (idle)
|
|
156
|
+
9s | Finish Block 1, broadcast |
|
|
157
|
+
9s | Start Block 2 |
|
|
158
|
+
11s | | Receive Block 1 (9s + 2s)
|
|
159
|
+
| | Re-execute Block 1
|
|
160
|
+
17s | Finish Block 2, broadcast |
|
|
161
|
+
17s | Start Block 3 |
|
|
162
|
+
19s | | Finish Block 1 (11s + 8s)
|
|
163
|
+
| | Receive Block 2 (17s + 2s)
|
|
164
|
+
| | Re-execute Block 2
|
|
353
165
|
...
|
|
166
|
+
49s | Finish Block 6, broadcast |
|
|
167
|
+
49s | Start Block 7 (last) |
|
|
168
|
+
51s | | Receive Block 6 (49s + 2s)
|
|
169
|
+
| | Re-execute Block 6
|
|
170
|
+
57s | Finish Block 7 (held) |
|
|
171
|
+
| ASSEMBLING_CHECKPOINT (1s) |
|
|
172
|
+
58s | Broadcast CheckpointProposal |
|
|
173
|
+
59s | | Finish Block 6 (51s + 8s)
|
|
174
|
+
60s | | Receive Block 7 + Checkpoint (58s + 2s)
|
|
175
|
+
| | Re-execute Block 7
|
|
176
|
+
68s | | Send attestations (60s + 8s)
|
|
177
|
+
70s | Receive attestations |
|
|
178
|
+
70-72s| Slack |
|
|
179
|
+
72s | L1 tx submitted |
|
|
180
|
+
84s | L1 tx mined |
|
|
354
181
|
```
|
|
355
182
|
|
|
356
|
-
**
|
|
183
|
+
**Observations**:
|
|
357
184
|
|
|
358
|
-
|
|
185
|
+
- Validators always lag the proposer by ~2 s (one p2p hop).
|
|
186
|
+
- For the last block there is no `k+1` to build alongside; once the proposer broadcasts the `CheckpointProposal`, it just waits while the committee re-executes.
|
|
187
|
+
- L1 publishing happens entirely inside the next slot and does not steal time from block building.
|
|
359
188
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
This scenario should not happen since the sequencer forcefully stops the block builder at the given deadline, but we still consider it.
|
|
363
|
-
|
|
364
|
-
```
|
|
365
|
-
10s: Start building Block 2
|
|
366
|
-
19s: Block 2 finishes (1s late, deadline was 18s)
|
|
367
|
-
19s: Broadcast Block 2
|
|
368
|
-
Check: Can we start Block 3?
|
|
369
|
-
- Block 3 deadline: 26s
|
|
370
|
-
- Current time: 19s
|
|
371
|
-
- Time available: 7s
|
|
372
|
-
- MIN_EXECUTION_TIME: 3s
|
|
373
|
-
- 7s >= 3s, so CAN start Block 3
|
|
374
|
-
|
|
375
|
-
19-26s: Build Block 3 (7s available vs 8s budgeted)
|
|
376
|
-
26s: Block 3 deadline
|
|
377
|
-
```
|
|
189
|
+
## Handling timing variations
|
|
378
190
|
|
|
379
|
-
|
|
191
|
+
### Fast initialization (0.5 s instead of 1 s)
|
|
380
192
|
|
|
381
|
-
|
|
382
|
-
```
|
|
383
|
-
24s: Block 2 finishes (6s late)
|
|
384
|
-
Check: Can we start Block 3 in sub-slot 3?
|
|
385
|
-
- Sub-slot 3 deadline: 26s
|
|
386
|
-
- Current time: 24s
|
|
387
|
-
- Time available: 2s
|
|
388
|
-
- MIN_EXECUTION_TIME: 3s
|
|
389
|
-
- 2s < 3s, so CANNOT use sub-slot 3
|
|
390
|
-
|
|
391
|
-
Use sub-slot 4 instead:
|
|
392
|
-
24-34s: Build Block 3 using sub-slot 4 (10s available vs 8s budgeted)
|
|
393
|
-
```
|
|
193
|
+
Sub-slot 1's deadline is still 9 s, so Block 1 gets a 0.5 s bonus before hitting its deadline. No structural change.
|
|
394
194
|
|
|
395
|
-
|
|
195
|
+
### Slow initialization (2 s instead of 1 s)
|
|
396
196
|
|
|
397
|
-
|
|
197
|
+
Block 1 has 7 s of build time instead of 8 s. Still well above `minExecutionTime`, so the block still gets built. No sub-slots are skipped.
|
|
398
198
|
|
|
399
|
-
|
|
199
|
+
### Very slow initialization (8 s)
|
|
400
200
|
|
|
401
|
-
|
|
201
|
+
Sub-slot 1's deadline (9 s) is closer than `minExecutionTime` (2 s), so it is skipped entirely. The first attempted block runs in sub-slot 2 with the usual budget. The checkpoint will have one fewer block.
|
|
402
202
|
|
|
403
|
-
|
|
404
|
-
10-15s: Build Block 2 (5s used vs 8s budgeted)
|
|
405
|
-
15s: Block 2 finished
|
|
406
|
-
15s: Broadcast Block 2
|
|
407
|
-
Check: Should we start Block 3 now or wait?
|
|
408
|
-
- Next sub-slot starts at 18s
|
|
409
|
-
- Wait until 18s to maintain regular intervals
|
|
410
|
-
|
|
411
|
-
15-18s: WAITING_UNTIL_NEXT_BLOCK
|
|
412
|
-
18s: Start building Block 3
|
|
413
|
-
18-26s: Build Block 3
|
|
414
|
-
```
|
|
203
|
+
### Block takes longer than its budget
|
|
415
204
|
|
|
416
|
-
|
|
205
|
+
`CheckpointBuilder` enforces the deadline by stopping public-tx execution; in practice a block can only overrun by the time it takes to finalize the block (typically < 1 s). The next sub-slot starts as scheduled but with proportionally less headroom. If that headroom drops below `minExecutionTime`, the next sub-slot is skipped.
|
|
417
206
|
|
|
418
|
-
|
|
207
|
+
### Block finishes early
|
|
419
208
|
|
|
420
|
-
|
|
209
|
+
The sequencer transitions to `WAITING_UNTIL_NEXT_BLOCK` and sleeps until the next sub-slot start. This keeps the cadence regular and gives validators predictable arrival times for re-execution.
|
|
421
210
|
|
|
422
|
-
###
|
|
211
|
+
### Block proposal returns insufficient txs
|
|
423
212
|
|
|
424
|
-
|
|
425
|
-
Time | Proposer | Validators
|
|
426
|
-
-----|----------------------------|---------------------------
|
|
427
|
-
2s | Start building Block 1 | (idle)
|
|
428
|
-
10s | Finish Block 1, broadcast | (idle)
|
|
429
|
-
10s | Start building Block 2 |
|
|
430
|
-
12s | | Receive Block 1 (10s + 2s)
|
|
431
|
-
| | Start re-executing Block 1
|
|
432
|
-
18s | Finish Block 2, broadcast |
|
|
433
|
-
20s | | Finish re-executing Block 1 (12s + 8s)
|
|
434
|
-
| | Receive Block 2 (18s + 2s)
|
|
435
|
-
| | Start re-executing Block 2
|
|
436
|
-
18s | Start building Block 3 |
|
|
437
|
-
26s | Finish Block 3, broadcast |
|
|
438
|
-
28s | | Finish re-executing Block 2 (20s + 8s)
|
|
439
|
-
| | Receive Block 3 (26s + 2s)
|
|
440
|
-
| | Start re-executing Block 3
|
|
441
|
-
...
|
|
442
|
-
42s | Finish Block 5, broadcast |
|
|
443
|
-
| checkpoint proposal |
|
|
444
|
-
44s | | Finish re-executing Block 4 (36s + 8s)
|
|
445
|
-
| | Receive Block 5 + checkpoint (42s + 2s)
|
|
446
|
-
| | Start re-executing Block 5
|
|
447
|
-
42-54s| COLLECTING_ATTESTATIONS |
|
|
448
|
-
52s | | Finish re-executing Block 5 (44s + 8s)
|
|
449
|
-
| | Send attestations
|
|
450
|
-
54s | Receive attestations | (done)
|
|
451
|
-
54-55s| ASSEMBLING_CHECKPOINT |
|
|
452
|
-
55s | PUBLISHING_CHECKPOINT |
|
|
453
|
-
```
|
|
213
|
+
The current sub-slot is dropped without committing anything. The loop retries on the next sub-slot. If `buildCheckpointIfEmpty` is true, the last sub-slot is forced through with whatever is available, including zero txs.
|
|
454
214
|
|
|
455
|
-
|
|
456
|
-
- Validators lag by ~2s (propagation delay)
|
|
457
|
-
- While proposer builds Block N+1, validators re-execute Block N (parallel work)
|
|
458
|
-
- For the last block, proposer waits while validators re-execute
|
|
459
|
-
- The last sub-slot provides the time budget for this waiting period
|
|
215
|
+
### Build slot ends before attestations arrive
|
|
460
216
|
|
|
461
|
-
|
|
217
|
+
`assertTimeLeft` will reject `PUBLISHING_CHECKPOINT` if the attestation deadline has passed; the slot is abandoned, and
|
|
218
|
+
`checkpoint-publish-failed` is emitted. The `PUBLISHING_CHECKPOINT` deadline allows spillover into the target slot
|
|
219
|
+
(`2 * aztecSlotDuration - ethereumSlotDuration`) precisely to absorb a small overrun.
|
|
462
220
|
|
|
463
|
-
|
|
221
|
+
### Pipelined parent fails on L1
|
|
464
222
|
|
|
465
|
-
|
|
223
|
+
Before submitting, the job calls `waitForValidParentCheckpointOnL1`. If the parent we built on top of did not land cleanly (wrong archive, missing attestations, etc.) the job discards its checkpoint, emits `pipelined-checkpoint-discarded`, and enqueues an invalidation for the parent so the next proposer doesn't get stuck on the same bad ancestor.
|
|
466
224
|
|
|
467
|
-
|
|
468
|
-
```
|
|
469
|
-
slotDuration >= initializationOffset
|
|
470
|
-
+ blockDuration * 2 (at least 2 blocks)
|
|
471
|
-
+ blockDuration (last sub-slot)
|
|
472
|
-
+ 2 * propagationTime (round-trip)
|
|
473
|
-
+ finalizationTime (checkpoint finalization)
|
|
474
|
-
+ l1PublishingTime (L1 publishing)
|
|
475
|
-
```
|
|
225
|
+
## Configuration constraints
|
|
476
226
|
|
|
477
|
-
|
|
478
|
-
```
|
|
479
|
-
slotDuration >= initializationOffset + 3*blockDuration + 2*propagationTime + finalizationTime + l1PublishingTime
|
|
480
|
-
```
|
|
227
|
+
`initializeDeadline` must be positive, so `aztecSlotDuration > checkpointInitializationTime + 2 * minExecutionTime`. With defaults that lower bound is 5 s, far below any realistic slot length.
|
|
481
228
|
|
|
482
|
-
|
|
483
|
-
```
|
|
484
|
-
slotDuration >= initializationOffset + 3*blockDuration
|
|
485
|
-
```
|
|
229
|
+
For multi-block production to make sense, `maxNumberOfBlocks ≥ 2`:
|
|
486
230
|
|
|
487
|
-
**Example:**
|
|
488
231
|
```
|
|
489
|
-
|
|
232
|
+
aztecSlotDuration ≥ checkpointInitializationTime
|
|
233
|
+
+ 2 * blockDuration // two blocks
|
|
234
|
+
+ checkpointAssembleTime
|
|
235
|
+
+ 2 * p2pPropagationTime
|
|
236
|
+
+ blockDuration // last-block re-execution window
|
|
490
237
|
```
|
|
491
238
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
### Block Duration Constraints
|
|
495
|
-
|
|
496
|
-
Block duration should be greater than the min execution time, and ideally a divisor of the time available for building.
|
|
497
|
-
|
|
498
|
-
```
|
|
499
|
-
blockDuration >= MIN_EXECUTION_TIME (3s practical minimum for meaningful execution)
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
### Initialization Offset
|
|
503
|
-
|
|
504
|
-
The initialization offset should be set based on empirical measurements of how long initialization typically takes, with typical values being 1-3 seconds.
|
|
505
|
-
|
|
506
|
-
**Key point:** This is an *estimate*, not a hard deadline. The sequencer will take as long as needed for initialization. If it takes longer than the offset, the first block just has less time. If it takes less, the first block has bonus time.
|
|
507
|
-
|
|
508
|
-
### Propagation Time
|
|
509
|
-
|
|
510
|
-
Should be measured empirically on the actual P2P network, accounting for:
|
|
511
|
-
- Network latency between geographically distributed validators
|
|
512
|
-
- Gossip network propagation (not direct communication)
|
|
513
|
-
- Block/checkpoint size (larger messages take longer)
|
|
514
|
-
|
|
515
|
-
Typical values: 1-3 seconds
|
|
516
|
-
|
|
517
|
-
### L1 Publishing Time
|
|
518
|
-
|
|
519
|
-
Must account for Ethereum slot duration (12s) and blob propagation time:
|
|
520
|
-
- Bare minimum: 8s (Ethereum allows txs up to 4s into the slot)
|
|
521
|
-
- Recommended minimum: 12s (full Ethereum slot)
|
|
522
|
-
- With high blob congestion: 24s (two slots)
|
|
523
|
-
|
|
524
|
-
## State Machine
|
|
525
|
-
|
|
526
|
-
The sequencer transitions through these states during a slot:
|
|
527
|
-
|
|
528
|
-
| State | Time Budget | Purpose |
|
|
529
|
-
|-------|-------------|---------|
|
|
530
|
-
| **SYNCHRONIZING** | No limit | Wait for all subsystems to sync |
|
|
531
|
-
| **PROPOSER_CHECK** | Part of init offset | Verify we're the proposer |
|
|
532
|
-
| **INITIALIZING_CHECKPOINT** | Part of init offset | Set up checkpoint state |
|
|
533
|
-
| **WAITING_FOR_TXS** | Until block deadline | Wait for enough transactions |
|
|
534
|
-
| **CREATING_BLOCK** | Until block deadline | Execute transactions and build block |
|
|
535
|
-
| **WAITING_UNTIL_NEXT_BLOCK** | Until next sub-slot start | Sleep between blocks to maintain intervals |
|
|
536
|
-
| **ASSEMBLING_CHECKPOINT** | assembleTime (1s) | Assemble final checkpoint |
|
|
537
|
-
| **COLLECTING_ATTESTATIONS** | Until L1 publish deadline | Wait for validator signatures |
|
|
538
|
-
| **PUBLISHING_CHECKPOINT** | Until L1 publish deadline | Submit to L1 |
|
|
539
|
-
|
|
540
|
-
## Complete Example: 72-Second Slot with 8-Second Sub-Slots
|
|
541
|
-
|
|
542
|
-
Let's walk through a complete slot with the happy path:
|
|
543
|
-
|
|
544
|
-
```
|
|
545
|
-
T=0s Slot begins for slot N
|
|
546
|
-
|
|
547
|
-
T=0-2s SYNCHRONIZING, PROPOSER_CHECK, INITIALIZING_CHECKPOINT
|
|
548
|
-
Actual time: 1.8s (slightly faster than 2s estimate)
|
|
549
|
-
|
|
550
|
-
T=2s Sub-slot 1 deadline calculation: 2s + 1*8s = 10s
|
|
551
|
-
T=1.8s Ready to build, start Block 1 immediately
|
|
552
|
-
Available time: 10s - 1.8s = 8.2s (bonus 0.2s!)
|
|
553
|
-
T=1.8-9.5s CREATING_BLOCK 1
|
|
554
|
-
T=9.5s Block 1 complete, broadcast
|
|
555
|
-
T=9.5-10s Wait for next sub-slot
|
|
556
|
-
|
|
557
|
-
T=10s Sub-slot 2 starts, deadline: 2s + 2*8s = 18s
|
|
558
|
-
T=10-17.5s CREATING_BLOCK 2
|
|
559
|
-
T=17.5s Block 2 complete, broadcast
|
|
560
|
-
T=17.5-18s Wait for next sub-slot
|
|
561
|
-
|
|
562
|
-
T=18s Sub-slot 3 starts, deadline: 2s + 3*8s = 26s
|
|
563
|
-
T=18-25s CREATING_BLOCK 3
|
|
564
|
-
T=25s Block 3 complete, broadcast
|
|
565
|
-
T=25-26s Wait for next sub-slot
|
|
566
|
-
|
|
567
|
-
T=26s Sub-slot 4 starts, deadline: 2s + 4*8s = 34s
|
|
568
|
-
T=26-33.5s CREATING_BLOCK 4
|
|
569
|
-
T=33.5s Block 4 complete, broadcast
|
|
570
|
-
T=33.5-34s Wait for next sub-slot
|
|
571
|
-
|
|
572
|
-
T=34s Sub-slot 5 starts, deadline: 2s + 5*8s = 42s
|
|
573
|
-
T=34-41s CREATING_BLOCK 5 (last block)
|
|
574
|
-
T=41s Block 5 complete
|
|
575
|
-
|
|
576
|
-
T=41s ASSEMBLING_CHECKPOINT (1s)
|
|
577
|
-
T=42s Checkpoint proposal broadcast
|
|
578
|
-
Sub-slot 6 starts (last sub-slot, reserved for validator reexec)
|
|
579
|
-
|
|
580
|
-
T=44s Validators receive checkpoint (42s + 2s propagation)
|
|
581
|
-
Validators start re-executing Block 5
|
|
582
|
-
|
|
583
|
-
T=52s Validators finish re-executing Block 5 (44s + 8s)
|
|
584
|
-
Validators send attestations
|
|
585
|
-
|
|
586
|
-
T=54s COLLECTING_ATTESTATIONS
|
|
587
|
-
Proposer receives attestations (52s + 2s propagation)
|
|
588
|
-
|
|
589
|
-
T=55s PUBLISHING_CHECKPOINT
|
|
590
|
-
Sign over attestations, submit L1 transaction
|
|
591
|
-
|
|
592
|
-
T=67s L1 transaction lands in Ethereum block (12s)
|
|
593
|
-
|
|
594
|
-
T=72s Slot ends (5s buffer remaining)
|
|
595
|
-
```
|
|
239
|
+
Block duration should be ≥ `minExecutionTime` (otherwise no sub-slot ever has enough headroom). `p2pPropagationTime` should be measured against the deployment's actual p2p latency: it directly determines how much of each slot is spent on the cooldown.
|
|
596
240
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
- Total time: 72s
|
|
601
|
-
- Buffer: 5s (72s - 67s)
|
|
241
|
+
`l1PublishingTime` should fit inside the Ethereum slot the target slot maps to. The default of 12 s lines up with one
|
|
242
|
+
Ethereum slot; fast local networks may reduce it to use the target-slot attestation window as assembly and attestation
|
|
243
|
+
grace.
|