@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.
Files changed (75) hide show
  1. package/README.md +281 -21
  2. package/dest/client/sequencer-client.d.ts +3 -3
  3. package/dest/client/sequencer-client.d.ts.map +1 -1
  4. package/dest/client/sequencer-client.js +6 -6
  5. package/dest/config.d.ts +6 -3
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +33 -10
  8. package/dest/global_variable_builder/fee_provider.js +1 -1
  9. package/dest/global_variable_builder/global_builder.d.ts +2 -3
  10. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  11. package/dest/global_variable_builder/global_builder.js +1 -1
  12. package/dest/index.d.ts +2 -2
  13. package/dest/index.d.ts.map +1 -1
  14. package/dest/index.js +1 -1
  15. package/dest/publisher/config.d.ts +3 -3
  16. package/dest/publisher/config.d.ts.map +1 -1
  17. package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
  18. package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
  19. package/dest/publisher/sequencer-bundle-simulator.js +198 -0
  20. package/dest/publisher/sequencer-publisher.d.ts +36 -36
  21. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  22. package/dest/publisher/sequencer-publisher.js +271 -500
  23. package/dest/sequencer/automine/automine_factory.d.ts +54 -0
  24. package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
  25. package/dest/sequencer/automine/automine_factory.js +84 -0
  26. package/dest/sequencer/automine/automine_sequencer.d.ts +151 -0
  27. package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
  28. package/dest/sequencer/automine/automine_sequencer.js +509 -0
  29. package/dest/sequencer/chain_state_overrides.d.ts +52 -16
  30. package/dest/sequencer/chain_state_overrides.d.ts.map +1 -1
  31. package/dest/sequencer/chain_state_overrides.js +86 -27
  32. package/dest/sequencer/checkpoint_proposal_job.d.ts +24 -6
  33. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  34. package/dest/sequencer/checkpoint_proposal_job.js +373 -83
  35. package/dest/sequencer/events.d.ts +42 -2
  36. package/dest/sequencer/events.d.ts.map +1 -1
  37. package/dest/sequencer/index.d.ts +3 -1
  38. package/dest/sequencer/index.d.ts.map +1 -1
  39. package/dest/sequencer/index.js +2 -0
  40. package/dest/sequencer/metrics.d.ts +3 -1
  41. package/dest/sequencer/metrics.d.ts.map +1 -1
  42. package/dest/sequencer/metrics.js +7 -0
  43. package/dest/sequencer/sequencer.d.ts +44 -9
  44. package/dest/sequencer/sequencer.d.ts.map +1 -1
  45. package/dest/sequencer/sequencer.js +256 -79
  46. package/dest/sequencer/timetable.d.ts +3 -6
  47. package/dest/sequencer/timetable.d.ts.map +1 -1
  48. package/dest/sequencer/timetable.js +3 -7
  49. package/dest/sequencer/types.d.ts +2 -2
  50. package/dest/sequencer/types.d.ts.map +1 -1
  51. package/dest/test/utils.d.ts +1 -1
  52. package/dest/test/utils.d.ts.map +1 -1
  53. package/dest/test/utils.js +7 -6
  54. package/package.json +27 -27
  55. package/src/client/sequencer-client.ts +12 -7
  56. package/src/config.ts +38 -10
  57. package/src/global_variable_builder/fee_provider.ts +1 -1
  58. package/src/global_variable_builder/global_builder.ts +2 -3
  59. package/src/index.ts +10 -1
  60. package/src/publisher/config.ts +2 -2
  61. package/src/publisher/sequencer-bundle-simulator.ts +254 -0
  62. package/src/publisher/sequencer-publisher.ts +286 -521
  63. package/src/sequencer/README.md +162 -520
  64. package/src/sequencer/automine/README.md +46 -0
  65. package/src/sequencer/automine/automine_factory.ts +145 -0
  66. package/src/sequencer/automine/automine_sequencer.ts +595 -0
  67. package/src/sequencer/chain_state_overrides.ts +133 -58
  68. package/src/sequencer/checkpoint_proposal_job.ts +420 -100
  69. package/src/sequencer/events.ts +46 -2
  70. package/src/sequencer/index.ts +2 -0
  71. package/src/sequencer/metrics.ts +9 -0
  72. package/src/sequencer/sequencer.ts +284 -95
  73. package/src/sequencer/timetable.ts +2 -9
  74. package/src/sequencer/types.ts +1 -1
  75. package/src/test/utils.ts +28 -10
@@ -1,601 +1,243 @@
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), the configured block duration, and whether checkpoint finalization is paid for in the current slot or deferred under proposer pipelining.
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
- **Example: 72-second slot with 8-second sub-slots (non-pipelined)**
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
- 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
-
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
- It helps to think in terms of two different slots:
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
- - **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
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
- 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
- ```
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
- For timetable purposes, this changes two things:
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
- - `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
28
+ ## Sub-slots
154
29
 
155
- In code, that means:
30
+ Each sub-slot has a fixed start time and a fixed deadline, both relative to the slot start:
156
31
 
157
32
  ```
158
- initializeDeadline (normal mode) =
159
- slotDuration - initializationOffset - 2 * minExecutionTime - checkpointFinalizationTime
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
- The fixed sub-slot deadlines themselves do not change. Pipelining only changes how much of the slot is considered available for block building.
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
- The sequencer builds blocks in **fixed sub-slots** based on the configured block duration.
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
- #### Sub-slot deadline calculation
41
+ ### Number of sub-slots
186
42
 
187
- Each sub-slot has a fixed start time and deadline:
43
+ The maximum number of buildable blocks per slot is:
188
44
 
189
45
  ```
190
- subSlotStart[N] = initializationOffset + (N - 1) * blockDuration
191
- subSlotDeadline[N] = initializationOffset + N * blockDuration
192
- ```
46
+ timeReservedAtEnd = checkpointAssembleTime
47
+ + 2 * p2pPropagationTime // proposal out + attestations back
48
+ + blockDuration // last-block re-execution
193
49
 
194
- Where N is the sub-slot number (1-indexed).
50
+ timeAvailableForBlocks = aztecSlotDuration
51
+ - checkpointInitializationTime
52
+ - timeReservedAtEnd
195
53
 
196
- **Example with 2s offset and 8s block duration:**
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
- #### Building a block
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
- **Key point:** The deadline is **fixed** based on the sub-slot number, not based on when the previous block finished.
59
+ ### Cooldown after the last sub-slot
215
60
 
216
- Note that if a block finishes early, then the sequencer waits until the next sub-slot starts to maintain the regular interval. This prevents "rushing ahead" and keeps the timing predictable. Conversely, if the block finishes later than expected, this "eats into" the time budget for the next block.
61
+ All `maxNumberOfBlocks` sub-slots build a block. The cooldown lives in the `timeReservedAtEnd` window that follows the last sub-slot:
217
62
 
218
- #### Waiting for minimum transactions
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
- Before building a block, the sequencer must ensure there are enough transactions in the mempool. This waiting phase has its own timing constraints:
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
- **Configuration:**
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
- **Behavior:**
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
- **Special cases:**
235
- - **Last block with empty checkpoint allowed**: If `buildCheckpointIfEmpty` is true and this is the last block, skip waiting and force build with 0+ transactions
236
- - **Non-enforced timetable**: If enforcement is disabled, exit immediately if not enough transactions (don't wait)
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
- **Example:**
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
- If the deadline (25s) is reached with only 2 transactions, the block is skipped and the sequencer moves to the next sub-slot.
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
- ### 3. Last Block and Validator Re-execution
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
- The **last block** is built during the **penultimate sub-slot**. The final sub-slot is reserved for validators to re-execute the last block.
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
- **Why the last sub-slot is reserved:**
109
+ ## Example: 72 s slot, 8 s sub-slots
257
110
 
258
- Validators execute blocks **sequentially**. While the proposer builds Block N+1, validators are re-executing Block N (with a ~2s delay due to propagation). However, for the **last block**, there's no "Block N+1" to build while validators re-execute. We must wait for them to finish so they can attest.
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
- **Example with 8s block duration:**
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
- ## Handling Timing Variations
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
- **Result:** Block 1 gets a bonus 1s of execution time. The extra time allows for more transactions or more complex execution.
314
-
315
- ### Slow Initialization
316
-
317
- **Scenario:** Initialization completes at 3s instead of 2s
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
- **Scenario:** Initialization completes at 9s instead of 2s
148
+ ## Parallel execution: proposer vs committee
335
149
 
336
- While extremely unlikely, we still account for this scenario. We'd expect it to be related to faults to syncing blob data.
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
- 0-9s: SYNCHRONIZING, PROPOSER_CHECK (9s actual, vs 2s estimate)
340
- 9s: Ready to build Block 1
341
- Check: Can we start Block 1 in sub-slot 1?
342
- - Sub-slot 1 deadline: 10s
343
- - Current time: 9s
344
- - Time available: 1s
345
- - MIN_EXECUTION_TIME: 3s
346
- - 1s < 3s, so CANNOT use sub-slot 1
347
-
348
- Use sub-slot 2 instead:
349
- 9s: Start building Block 1 using sub-slot 2
350
- 9-18s: Build Block 1 (9s available vs 8s budgeted)
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
- **Result:** Sub-slot 1 is skipped entirely. We build 4 blocks instead of 5 (using sub-slots 2-5). Block 1 gets a bonus 1s of time.
183
+ **Observations**:
357
184
 
358
- ### Block Takes Longer Than Expected
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
- **Scenario:** Block 2 takes 9s instead of 8s
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
- **Result:** Block 3 has less time (7s instead of 8s), but we still build it. The delay propagates but doesn't cascade uncontrollably.
191
+ ### Fast initialization (0.5 s instead of 1 s)
380
192
 
381
- **Extreme case:** If Block 2 finishes at 24s (6s late):
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
- **Result:** Sub-slot 3 is skipped, we build Block 3 using sub-slot 4 instead with bonus time.
195
+ ### Slow initialization (2 s instead of 1 s)
396
196
 
397
- ### Block Finishes Early
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
- **Scenario:** Block 2 finishes at 15s instead of 18s
199
+ ### Very slow initialization (8 s)
400
200
 
401
- This can happen if the sequencer hits a block limit (number of txs, gas, size, etc) or runs out of available txs before the sub-slot deadline:
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
- **Result:** We wait until the next sub-slot starts. This prevents "rushing ahead" and maintains consistent block intervals, which is better for validators who are re-executing blocks in parallel.
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
- ## Parallel execution between Proposers and Validators
207
+ ### Block finishes early
419
208
 
420
- A key aspect of this design is **parallel execution** between proposer and validators.
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
- ### Timeline Example (8-second sub-slots)
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
- **Key observations:**
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
- ## Configuration Guidelines
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
- When configuring timing parameters, ensure these constraints are satisfied:
221
+ ### Pipelined parent fails on L1
464
222
 
465
- ### Minimum Slot Duration
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
- For a valid multi-block configuration without pipelining:
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
- Simplified:
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
- 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
- ```
229
+ For multi-block production to make sense, `maxNumberOfBlocks 2`:
486
230
 
487
- **Example:**
488
231
  ```
489
- slotDuration >= 2s + 3*8s + 2*2s + 1s + 12s = 2s + 24s + 4s + 1s + 12s = 43s
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
- For a 72s slot, this leaves `72s - 43s = 29s` of slack, allowing for about 3-4 additional blocks (29s / 8s 3.6).
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
- **Summary:**
598
- - Built 5 blocks (sub-slots 1-5)
599
- - Last sub-slot (6) reserved for validator re-execution
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.