@aztec/sequencer-client 0.0.1-commit.2ed92850 → 0.0.1-commit.2f68f620

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 (129) hide show
  1. package/README.md +281 -21
  2. package/dest/client/sequencer-client.d.ts +19 -9
  3. package/dest/client/sequencer-client.d.ts.map +1 -1
  4. package/dest/client/sequencer-client.js +65 -32
  5. package/dest/config.d.ts +28 -6
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +76 -37
  8. package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
  9. package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
  10. package/dest/global_variable_builder/fee_predictor.js +128 -0
  11. package/dest/global_variable_builder/fee_provider.d.ts +21 -0
  12. package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
  13. package/dest/global_variable_builder/fee_provider.js +58 -0
  14. package/dest/global_variable_builder/global_builder.d.ts +14 -16
  15. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  16. package/dest/global_variable_builder/global_builder.js +16 -50
  17. package/dest/global_variable_builder/index.d.ts +4 -2
  18. package/dest/global_variable_builder/index.d.ts.map +1 -1
  19. package/dest/global_variable_builder/index.js +2 -0
  20. package/dest/index.d.ts +2 -2
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +1 -1
  23. package/dest/publisher/config.d.ts +47 -17
  24. package/dest/publisher/config.d.ts.map +1 -1
  25. package/dest/publisher/config.js +121 -42
  26. package/dest/publisher/index.d.ts +2 -1
  27. package/dest/publisher/index.d.ts.map +1 -1
  28. package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
  29. package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
  30. package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
  31. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +58 -0
  32. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
  33. package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
  34. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
  35. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
  36. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
  37. package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
  38. package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
  39. package/dest/publisher/l1_tx_failed_store/index.js +2 -0
  40. package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
  41. package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
  42. package/dest/publisher/sequencer-bundle-simulator.js +198 -0
  43. package/dest/publisher/sequencer-publisher-factory.d.ts +11 -5
  44. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  45. package/dest/publisher/sequencer-publisher-factory.js +27 -3
  46. package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
  47. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  48. package/dest/publisher/sequencer-publisher-metrics.js +12 -4
  49. package/dest/publisher/sequencer-publisher.d.ts +94 -68
  50. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  51. package/dest/publisher/sequencer-publisher.js +448 -363
  52. package/dest/sequencer/automine/automine_factory.d.ts +54 -0
  53. package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
  54. package/dest/sequencer/automine/automine_factory.js +84 -0
  55. package/dest/sequencer/automine/automine_sequencer.d.ts +151 -0
  56. package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
  57. package/dest/sequencer/automine/automine_sequencer.js +509 -0
  58. package/dest/sequencer/chain_state_overrides.d.ts +61 -0
  59. package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
  60. package/dest/sequencer/chain_state_overrides.js +98 -0
  61. package/dest/sequencer/checkpoint_proposal_job.d.ts +85 -14
  62. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  63. package/dest/sequencer/checkpoint_proposal_job.js +882 -254
  64. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
  65. package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
  66. package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
  67. package/dest/sequencer/checkpoint_voter.d.ts +1 -2
  68. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
  69. package/dest/sequencer/checkpoint_voter.js +2 -5
  70. package/dest/sequencer/events.d.ts +48 -2
  71. package/dest/sequencer/events.d.ts.map +1 -1
  72. package/dest/sequencer/index.d.ts +3 -1
  73. package/dest/sequencer/index.d.ts.map +1 -1
  74. package/dest/sequencer/index.js +2 -0
  75. package/dest/sequencer/metrics.d.ts +23 -8
  76. package/dest/sequencer/metrics.d.ts.map +1 -1
  77. package/dest/sequencer/metrics.js +142 -36
  78. package/dest/sequencer/sequencer.d.ts +85 -22
  79. package/dest/sequencer/sequencer.d.ts.map +1 -1
  80. package/dest/sequencer/sequencer.js +380 -137
  81. package/dest/sequencer/timetable.d.ts +14 -6
  82. package/dest/sequencer/timetable.d.ts.map +1 -1
  83. package/dest/sequencer/timetable.js +47 -46
  84. package/dest/sequencer/types.d.ts +2 -2
  85. package/dest/sequencer/types.d.ts.map +1 -1
  86. package/dest/test/index.d.ts +3 -5
  87. package/dest/test/index.d.ts.map +1 -1
  88. package/dest/test/mock_checkpoint_builder.d.ts +12 -12
  89. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
  90. package/dest/test/mock_checkpoint_builder.js +45 -36
  91. package/dest/test/utils.d.ts +3 -3
  92. package/dest/test/utils.d.ts.map +1 -1
  93. package/dest/test/utils.js +10 -8
  94. package/package.json +27 -28
  95. package/src/client/sequencer-client.ts +91 -35
  96. package/src/config.ts +98 -46
  97. package/src/global_variable_builder/README.md +44 -0
  98. package/src/global_variable_builder/fee_predictor.ts +172 -0
  99. package/src/global_variable_builder/fee_provider.ts +75 -0
  100. package/src/global_variable_builder/global_builder.ts +26 -63
  101. package/src/global_variable_builder/index.ts +3 -1
  102. package/src/index.ts +10 -1
  103. package/src/publisher/config.ts +157 -45
  104. package/src/publisher/index.ts +3 -0
  105. package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
  106. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +57 -0
  107. package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
  108. package/src/publisher/l1_tx_failed_store/index.ts +3 -0
  109. package/src/publisher/sequencer-bundle-simulator.ts +254 -0
  110. package/src/publisher/sequencer-publisher-factory.ts +38 -9
  111. package/src/publisher/sequencer-publisher-metrics.ts +7 -3
  112. package/src/publisher/sequencer-publisher.ts +542 -460
  113. package/src/sequencer/README.md +162 -450
  114. package/src/sequencer/automine/README.md +46 -0
  115. package/src/sequencer/automine/automine_factory.ts +145 -0
  116. package/src/sequencer/automine/automine_sequencer.ts +595 -0
  117. package/src/sequencer/chain_state_overrides.ts +162 -0
  118. package/src/sequencer/checkpoint_proposal_job.ts +1078 -290
  119. package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
  120. package/src/sequencer/checkpoint_voter.ts +1 -12
  121. package/src/sequencer/events.ts +51 -2
  122. package/src/sequencer/index.ts +2 -0
  123. package/src/sequencer/metrics.ts +164 -39
  124. package/src/sequencer/sequencer.ts +471 -157
  125. package/src/sequencer/timetable.ts +62 -56
  126. package/src/sequencer/types.ts +1 -1
  127. package/src/test/index.ts +2 -4
  128. package/src/test/mock_checkpoint_builder.ts +65 -53
  129. package/src/test/utils.ts +31 -10
@@ -1,531 +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), a finalization time (how much time we need for closing a checkpoint and publishing it to L1), and the configured block duration.
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**
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**, then collects a single round of attestations for the entire **checkpoint** from validators, and finally publishes the resulting checkpoint to L1 Ethereum.
35
-
36
- ## Key Concepts
37
-
38
- ### Slot vs Block vs Checkpoint vs Sub-Slot
9
+ Block production runs on three nested clocks:
39
10
 
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
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.
44
14
 
45
- In a typical configuration, 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)
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:
50
16
 
51
- ### The Fixed Sub-Slot Model
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` |
52
25
 
53
- Building multiple blocks per slot uses **fixed sub-slots** with predictable deadlines:
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.
54
27
 
55
- 1. **Equal-duration sub-slots**: All sub-slots have the same duration (`BLOCK_DURATION`)
56
- 2. **Fixed deadlines**: Block N deadline = `initializationOffset + N * BLOCK_DURATION`
57
- 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)
58
- 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
28
+ ## Sub-slots
59
29
 
60
- ## Timing Components
61
-
62
- Understanding slot timing requires knowing these time constants:
63
-
64
- | Component | Example Value | Purpose |
65
- |-----------|---------------|---------|
66
- | **Slot Duration** | 72s | Total time available for the entire checkpoint |
67
- | **Block Duration** | 8s | Duration of each sub-slot (time budget for building one block) |
68
- | **Initialization Offset** | 2s | Fixed estimate for sync + proposer check |
69
- | **Propagation Time** | 2s | Time for messages to travel across the P2P network (one-way) |
70
- | **Finalization Time** | 1s | Time to finalize checkpoint and prepare proposal message |
71
- | **L1 Publishing Time** | 12s | Time reserved for L1 transaction to land in an Ethereum block |
72
- | **Min Execution Time** | 3s | Minimum time needed to meaningfully build a block |
73
-
74
- These values are configurable but must satisfy certain constraints (explained below). Example values may differ from the ones in the source code.
75
-
76
- ## Calculating Sub-Slots and Blocks
77
-
78
- Given a slot configuration, we calculate how many blocks fit using this formula:
30
+ Each sub-slot has a fixed start time and a fixed deadline, both relative to the slot start:
79
31
 
80
32
  ```
81
- timeReservedAtEnd = blockDuration (last sub-slot for reexecution)
82
- + propagationTime (validators receive proposal)
83
- + propagationTime (attestations come back)
84
- + finalizationTime (checkpoint finalization)
85
- + l1PublishingTime (L1 transaction)
86
-
87
- timeAvailableForBlocks = slotDuration - initializationOffset - timeReservedAtEnd
88
-
89
- numberOfBlocks = floor(timeAvailableForBlocks / blockDuration)
90
- ```
91
-
92
- **Example with typical values:**
33
+ subSlotStart[k] = initializationOffset + (k - 1) * blockDuration
34
+ subSlotDeadline[k] = initializationOffset + k * blockDuration
93
35
  ```
94
- timeReservedAtEnd = 8s + 2s + 2s + 1s + 12s = 25s
95
- timeAvailableForBlocks = 72s - 2s - 25s = 45s
96
- numberOfBlocks = floor(45s / 8s) = 5 blocks
97
- ```
98
-
99
- This means:
100
- - Sub-slots 1-5: Build blocks 1-5
101
- - Sub-slot 6: Reserved for validator re-execution of block 5
102
- - After sub-slot 6: Attestation collection, finalization, and L1 publishing
103
-
104
- ## The Sequencer's Work
105
36
 
106
- When elected as proposer for a slot, the sequencer performs these tasks:
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.
107
38
 
108
- ### 1. Initialization Phase
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.
109
40
 
110
- Before building any blocks, the sequencer must:
111
- - Verify it's the designated proposer
112
- - Check all subsystems are synced
113
- - Initialize checkpoint state
114
- - Prepare global variables
41
+ ### Number of sub-slots
115
42
 
116
- 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.
43
+ The maximum number of buildable blocks per slot is:
117
44
 
118
- ### 2. Block Building Loop
119
-
120
- The sequencer builds blocks in **fixed sub-slots** based on the configured block duration.
121
-
122
- #### Sub-slot deadline calculation
123
-
124
- Each sub-slot has a fixed start time and deadline:
125
-
126
- ```
127
- subSlotStart[N] = initializationOffset + (N - 1) * blockDuration
128
- subSlotDeadline[N] = initializationOffset + N * blockDuration
129
45
  ```
46
+ timeReservedAtEnd = checkpointAssembleTime
47
+ + 2 * p2pPropagationTime // proposal out + attestations back
48
+ + blockDuration // last-block re-execution
130
49
 
131
- Where N is the sub-slot number (1-indexed).
50
+ timeAvailableForBlocks = aztecSlotDuration
51
+ - checkpointInitializationTime
52
+ - timeReservedAtEnd
132
53
 
133
- **Example with 2s offset and 8s block duration:**
134
- ```
135
- Sub-slot 1: starts at 2s, deadline at 10s
136
- Sub-slot 2: starts at 10s, deadline at 18s
137
- Sub-slot 3: starts at 18s, deadline at 26s
138
- Sub-slot 4: starts at 26s, deadline at 34s
139
- Sub-slot 5: starts at 34s, deadline at 42s
54
+ maxNumberOfBlocks = floor(timeAvailableForBlocks / blockDuration)
140
55
  ```
141
56
 
142
- #### Building a block
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.
143
58
 
144
- For each sub-slot, the sequencer:
59
+ ### Cooldown after the last sub-slot
145
60
 
146
- 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
147
- 2. **Waits for transactions** (if needed): Wait up to the deadline for minimum number of transactions
148
- 3. **Builds block**: Execute transactions until the deadline of the sub-slot
149
- 4. **Signs and broadcasts**: Finalize block and broadcast proposal to validators
61
+ All `maxNumberOfBlocks` sub-slots build a block. The cooldown lives in the `timeReservedAtEnd` window that follows the last sub-slot:
150
62
 
151
- **Key point:** The deadline is **fixed** based on the sub-slot number, not based on when the previous block finished.
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.
152
67
 
153
- 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.
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`.
154
69
 
155
- #### Waiting for minimum transactions
70
+ ## Timing constants
156
71
 
157
- Before building a block, the sequencer must ensure there are enough transactions in the mempool. This waiting phase has its own timing constraints:
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.
158
73
 
159
- **Configuration:**
160
- - `minTxsPerBlock`: Minimum number of transactions required (configurable, e.g., 1-4)
161
- - Polling interval: 500ms (checks mempool every half-second)
162
- - Deadline: `blockDeadline - 1000ms` (must start building at least 1 second before the block deadline)
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. |
163
85
 
164
- **Behavior:**
165
- 1. Check current pending transaction count
166
- 2. If count >= `minTxsPerBlock`, proceed to build immediately
167
- 3. If count < `minTxsPerBlock`, poll every 500ms until either:
168
- - Enough transactions arrive (proceed to build)
169
- - Deadline is reached (skip building this block)
86
+ ## Deadlines
170
87
 
171
- **Special cases:**
172
- - **Last block with empty checkpoint allowed**: If `buildCheckpointIfEmpty` is true and this is the last block, skip waiting and force build with 0+ transactions
173
- - **Non-enforced timetable**: If enforcement is disabled, exit immediately if not enough transactions (don't wait)
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`.
174
89
 
175
- **Example:**
176
- ```
177
- Sub-slot 3 deadline: 26s
178
- Transaction wait deadline: 25s (26s - 1s)
179
- Current time: 20s
180
-
181
- 20.0s: Check mempool 2 txs (need 4)
182
- 20.5s: Check mempool 2 txs (need 4)
183
- 21.0s: Check mempool 4 txs (need 4) ✓ Start building!
184
- 21-26s: Build block with those 4+ transactions
185
- ```
186
-
187
- If the deadline (25s) is reached with only 2 transactions, the block is skipped and the sequencer moves to the next sub-slot.
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) |
188
100
 
189
- ### 3. Last Block and Validator Re-execution
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.
190
108
 
191
- The **last block** is built during the **penultimate sub-slot**. The final sub-slot is reserved for validators to re-execute the last block.
109
+ ## Example: 72 s slot, 8 s sub-slots
192
110
 
193
- **Why the last sub-slot is reserved:**
111
+ With typical pipelining values:
194
112
 
195
- 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.
196
-
197
- **Timeline for the last block:**
198
-
199
- ```
200
- T: Last block finishes building, checkpoint proposal broadcast
201
- Last sub-slot begins (duration: blockDuration)
202
- T+2s: Validators receive proposal (propagation delay)
203
- T+2s to T+2s+blockDuration: Validators re-execute last block
204
- T+2s+blockDuration: Validators finish re-execution, send attestations
205
- T+4s+blockDuration: Proposer receives attestations (propagation delay)
206
113
  ```
114
+ checkpointInitializationTime = 1s
115
+ blockDuration = 8s
116
+ checkpointAssembleTime = 1s
117
+ p2pPropagationTime = 2s
118
+ l1PublishingTime = 12s
207
119
 
208
- **Example with 8s block duration:**
120
+ timeReservedAtEnd = 1 + 2*2 + 8 = 13s
121
+ timeAvailableForBlocks = 72 - 1 - 13 = 58s
122
+ maxNumberOfBlocks = floor(58 / 8) = 7
209
123
  ```
210
- 42s: Block 5 finishes, checkpoint broadcast, sub-slot 6 starts
211
- 44s: Validators receive checkpoint (42s + 2s)
212
- 44-52s: Validators re-execute Block 5 (8s)
213
- 52s: Validators send attestations
214
- 54s: Proposer receives attestations (52s + 2s)
215
- ```
216
-
217
- 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.
218
-
219
- ### 4. Attestation Collection and L1 Publishing
220
-
221
- After the last block is built and validators have re-executed it:
222
-
223
- 1. **Collect attestations**: Wait for validators to send their signatures (arrive at T+4s+blockDuration)
224
- 2. **Finalize checkpoint**: Sign over attestations, assemble final checkpoint (1s)
225
- 3. **Publish to L1**: Submit transaction to Ethereum (needs 12s to land)
226
-
227
- **Time reserved:** `2*propagationTime + finalizationTime + l1PublishingTime = 2s + 2s + 1s + 12s = 17s`
228
124
 
229
- This 17s comes after the last sub-slot, ensuring we have enough time to complete the checkpoint. If the sequencer receives the necessary attestations before the reserved time, the L1 tx is submitted earlier.
125
+ Seven sub-slots, all of which build a block:
230
126
 
231
- ## Handling Timing Variations
232
-
233
- How does the sequencer timetable handle deviations from the expected times.
234
-
235
- ### Fast Initialization
236
-
237
- **Scenario:** Initialization completes at 1s instead of 2s
238
-
239
- ```
240
- 0-1s: SYNCHRONIZING, PROPOSER_CHECK (1s actual, vs 2s estimate)
241
- 1s: Ready to build Block 1
242
- 1-10s: Build Block 1 (9s available vs 8s budgeted)
243
- 10s: Block 1 deadline
244
- 10-18s: Build Block 2
245
- ...
246
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)
247
135
 
248
- **Result:** Block 1 gets a bonus 1s of execution time. The extra time allows for more transactions or more complex execution.
249
-
250
- ### Slow Initialization
251
-
252
- **Scenario:** Initialization completes at 3s instead of 2s
253
-
254
- 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)
255
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)
256
146
  ```
257
- 0-3s: SYNCHRONIZING, PROPOSER_CHECK (3s actual, vs 2s estimate)
258
- 3s: Ready to build Block 1
259
- 3-10s: Build Block 1 (7s available vs 8s budgeted)
260
- 10s: Block 1 deadline
261
- 10-18s: Build Block 2
262
- ...
263
- ```
264
-
265
- **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.
266
147
 
267
- ### Very Slow Initialization
148
+ ## Parallel execution: proposer vs committee
268
149
 
269
- **Scenario:** Initialization completes at 9s instead of 2s
270
-
271
- 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.
272
151
 
273
152
  ```
274
- 0-9s: SYNCHRONIZING, PROPOSER_CHECK (9s actual, vs 2s estimate)
275
- 9s: Ready to build Block 1
276
- Check: Can we start Block 1 in sub-slot 1?
277
- - Sub-slot 1 deadline: 10s
278
- - Current time: 9s
279
- - Time available: 1s
280
- - MIN_EXECUTION_TIME: 3s
281
- - 1s < 3s, so CANNOT use sub-slot 1
282
-
283
- Use sub-slot 2 instead:
284
- 9s: Start building Block 1 using sub-slot 2
285
- 9-18s: Build Block 1 (9s available vs 8s budgeted)
286
- 18s: Block 1 deadline (sub-slot 2)
287
- 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
288
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 |
289
181
  ```
290
182
 
291
- **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**:
292
184
 
293
- ### 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.
294
188
 
295
- **Scenario:** Block 2 takes 9s instead of 8s
189
+ ## Handling timing variations
296
190
 
297
- This scenario should not happen since the sequencer forcefully stops the block builder at the given deadline, but we still consider it.
191
+ ### Fast initialization (0.5 s instead of 1 s)
298
192
 
299
- ```
300
- 10s: Start building Block 2
301
- 19s: Block 2 finishes (1s late, deadline was 18s)
302
- 19s: Broadcast Block 2
303
- Check: Can we start Block 3?
304
- - Block 3 deadline: 26s
305
- - Current time: 19s
306
- - Time available: 7s
307
- - MIN_EXECUTION_TIME: 3s
308
- - 7s >= 3s, so CAN start Block 3
309
-
310
- 19-26s: Build Block 3 (7s available vs 8s budgeted)
311
- 26s: Block 3 deadline
312
- ```
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.
313
194
 
314
- **Result:** Block 3 has less time (7s instead of 8s), but we still build it. The delay propagates but doesn't cascade uncontrollably.
195
+ ### Slow initialization (2 s instead of 1 s)
315
196
 
316
- **Extreme case:** If Block 2 finishes at 24s (6s late):
317
- ```
318
- 24s: Block 2 finishes (6s late)
319
- Check: Can we start Block 3 in sub-slot 3?
320
- - Sub-slot 3 deadline: 26s
321
- - Current time: 24s
322
- - Time available: 2s
323
- - MIN_EXECUTION_TIME: 3s
324
- - 2s < 3s, so CANNOT use sub-slot 3
325
-
326
- Use sub-slot 4 instead:
327
- 24-34s: Build Block 3 using sub-slot 4 (10s available vs 8s budgeted)
328
- ```
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.
329
198
 
330
- **Result:** Sub-slot 3 is skipped, we build Block 3 using sub-slot 4 instead with bonus time.
199
+ ### Very slow initialization (8 s)
331
200
 
332
- ### Block Finishes Early
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.
333
202
 
334
- **Scenario:** Block 2 finishes at 15s instead of 18s
203
+ ### Block takes longer than its budget
335
204
 
336
- 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:
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.
337
206
 
338
- ```
339
- 10-15s: Build Block 2 (5s used vs 8s budgeted)
340
- 15s: Block 2 finished
341
- 15s: Broadcast Block 2
342
- Check: Should we start Block 3 now or wait?
343
- - Next sub-slot starts at 18s
344
- - Wait until 18s to maintain regular intervals
345
-
346
- 15-18s: WAITING_UNTIL_NEXT_BLOCK
347
- 18s: Start building Block 3
348
- 18-26s: Build Block 3
349
- ```
207
+ ### Block finishes early
350
208
 
351
- **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.
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.
352
210
 
353
- ## Parallel execution between Proposers and Validators
211
+ ### Block proposal returns insufficient txs
354
212
 
355
- A key aspect of this design is **parallel execution** between proposer and validators.
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.
356
214
 
357
- ### Timeline Example (8-second sub-slots)
215
+ ### Build slot ends before attestations arrive
358
216
 
359
- ```
360
- Time | Proposer | Validators
361
- -----|----------------------------|---------------------------
362
- 2s | Start building Block 1 | (idle)
363
- 10s | Finish Block 1, broadcast | (idle)
364
- 10s | Start building Block 2 |
365
- 12s | | Receive Block 1 (10s + 2s)
366
- | | Start re-executing Block 1
367
- 18s | Finish Block 2, broadcast |
368
- 20s | | Finish re-executing Block 1 (12s + 8s)
369
- | | Receive Block 2 (18s + 2s)
370
- | | Start re-executing Block 2
371
- 18s | Start building Block 3 |
372
- 26s | Finish Block 3, broadcast |
373
- 28s | | Finish re-executing Block 2 (20s + 8s)
374
- | | Receive Block 3 (26s + 2s)
375
- | | Start re-executing Block 3
376
- ...
377
- 42s | Finish Block 5, broadcast |
378
- | checkpoint proposal |
379
- 44s | | Finish re-executing Block 4 (36s + 8s)
380
- | | Receive Block 5 + checkpoint (42s + 2s)
381
- | | Start re-executing Block 5
382
- 42-54s| COLLECTING_ATTESTATIONS |
383
- 52s | | Finish re-executing Block 5 (44s + 8s)
384
- | | Send attestations
385
- 54s | Receive attestations | (done)
386
- 54-55s| ASSEMBLING_CHECKPOINT |
387
- 55s | PUBLISHING_CHECKPOINT |
388
- ```
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.
389
220
 
390
- **Key observations:**
391
- - Validators lag by ~2s (propagation delay)
392
- - While proposer builds Block N+1, validators re-execute Block N (parallel work)
393
- - For the last block, proposer waits while validators re-execute
394
- - The last sub-slot provides the time budget for this waiting period
221
+ ### Pipelined parent fails on L1
395
222
 
396
- ## Configuration Guidelines
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.
397
224
 
398
- When configuring timing parameters, ensure these constraints are satisfied:
225
+ ## Configuration constraints
399
226
 
400
- ### Minimum Slot Duration
227
+ `initializeDeadline` must be positive, so `aztecSlotDuration > checkpointInitializationTime + 2 * minExecutionTime`. With defaults that lower bound is 5 s, far below any realistic slot length.
401
228
 
402
- For a valid configuration:
403
- ```
404
- slotDuration >= initializationOffset
405
- + blockDuration * 2 (at least 2 blocks)
406
- + blockDuration (last sub-slot)
407
- + 2 * propagationTime (round-trip)
408
- + finalizationTime (checkpoint finalization)
409
- + l1PublishingTime (L1 publishing)
410
- ```
229
+ For multi-block production to make sense, `maxNumberOfBlocks ≥ 2`:
411
230
 
412
- Simplified:
413
231
  ```
414
- slotDuration >= initializationOffset + 3*blockDuration + 2*propagationTime + finalizationTime + l1PublishingTime
232
+ aztecSlotDuration checkpointInitializationTime
233
+ + 2 * blockDuration // two blocks
234
+ + checkpointAssembleTime
235
+ + 2 * p2pPropagationTime
236
+ + blockDuration // last-block re-execution window
415
237
  ```
416
238
 
417
- **Example:**
418
- ```
419
- slotDuration >= 2s + 3*8s + 2*2s + 1s + 12s = 2s + 24s + 4s + 1s + 12s = 43s
420
- ```
421
-
422
- For a 72s slot, this leaves `72s - 43s = 29s` of slack, allowing for about 3-4 additional blocks (29s / 8s ≈ 3.6).
423
-
424
- ### Block Duration Constraints
425
-
426
- Block duration should be greater than the min execution time, and ideally a divisor of the time available for building.
427
-
428
- ```
429
- blockDuration >= MIN_EXECUTION_TIME (3s practical minimum for meaningful execution)
430
- ```
431
-
432
- ### Initialization Offset
433
-
434
- The initialization offset should be set based on empirical measurements of how long initialization typically takes, with typical values being 1-3 seconds.
435
-
436
- **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.
437
-
438
- ### Propagation Time
439
-
440
- Should be measured empirically on the actual P2P network, accounting for:
441
- - Network latency between geographically distributed validators
442
- - Gossip network propagation (not direct communication)
443
- - Block/checkpoint size (larger messages take longer)
444
-
445
- Typical values: 1-3 seconds
446
-
447
- ### L1 Publishing Time
448
-
449
- Must account for Ethereum slot duration (12s) and blob propagation time:
450
- - Bare minimum: 8s (Ethereum allows txs up to 4s into the slot)
451
- - Recommended minimum: 12s (full Ethereum slot)
452
- - With high blob congestion: 24s (two slots)
453
-
454
- ## State Machine
455
-
456
- The sequencer transitions through these states during a slot:
457
-
458
- | State | Time Budget | Purpose |
459
- |-------|-------------|---------|
460
- | **SYNCHRONIZING** | No limit | Wait for all subsystems to sync |
461
- | **PROPOSER_CHECK** | Part of init offset | Verify we're the proposer |
462
- | **INITIALIZING_CHECKPOINT** | Part of init offset | Set up checkpoint state |
463
- | **WAITING_FOR_TXS** | Until block deadline | Wait for enough transactions |
464
- | **CREATING_BLOCK** | Until block deadline | Execute transactions and build block |
465
- | **WAITING_UNTIL_NEXT_BLOCK** | Until next sub-slot start | Sleep between blocks to maintain intervals |
466
- | **ASSEMBLING_CHECKPOINT** | assembleTime (1s) | Assemble final checkpoint |
467
- | **COLLECTING_ATTESTATIONS** | Until L1 publish deadline | Wait for validator signatures |
468
- | **PUBLISHING_CHECKPOINT** | Until slot end | Submit to L1 |
469
-
470
- ## Complete Example: 72-Second Slot with 8-Second Sub-Slots
471
-
472
- Let's walk through a complete slot with the happy path:
473
-
474
- ```
475
- T=0s Slot begins for slot N
476
-
477
- T=0-2s SYNCHRONIZING, PROPOSER_CHECK, INITIALIZING_CHECKPOINT
478
- Actual time: 1.8s (slightly faster than 2s estimate)
479
-
480
- T=2s Sub-slot 1 deadline calculation: 2s + 1*8s = 10s
481
- T=1.8s Ready to build, start Block 1 immediately
482
- Available time: 10s - 1.8s = 8.2s (bonus 0.2s!)
483
- T=1.8-9.5s CREATING_BLOCK 1
484
- T=9.5s Block 1 complete, broadcast
485
- T=9.5-10s Wait for next sub-slot
486
-
487
- T=10s Sub-slot 2 starts, deadline: 2s + 2*8s = 18s
488
- T=10-17.5s CREATING_BLOCK 2
489
- T=17.5s Block 2 complete, broadcast
490
- T=17.5-18s Wait for next sub-slot
491
-
492
- T=18s Sub-slot 3 starts, deadline: 2s + 3*8s = 26s
493
- T=18-25s CREATING_BLOCK 3
494
- T=25s Block 3 complete, broadcast
495
- T=25-26s Wait for next sub-slot
496
-
497
- T=26s Sub-slot 4 starts, deadline: 2s + 4*8s = 34s
498
- T=26-33.5s CREATING_BLOCK 4
499
- T=33.5s Block 4 complete, broadcast
500
- T=33.5-34s Wait for next sub-slot
501
-
502
- T=34s Sub-slot 5 starts, deadline: 2s + 5*8s = 42s
503
- T=34-41s CREATING_BLOCK 5 (last block)
504
- T=41s Block 5 complete
505
-
506
- T=41s ASSEMBLING_CHECKPOINT (1s)
507
- T=42s Checkpoint proposal broadcast
508
- Sub-slot 6 starts (last sub-slot, reserved for validator reexec)
509
-
510
- T=44s Validators receive checkpoint (42s + 2s propagation)
511
- Validators start re-executing Block 5
512
-
513
- T=52s Validators finish re-executing Block 5 (44s + 8s)
514
- Validators send attestations
515
-
516
- T=54s COLLECTING_ATTESTATIONS
517
- Proposer receives attestations (52s + 2s propagation)
518
-
519
- T=55s PUBLISHING_CHECKPOINT
520
- Sign over attestations, submit L1 transaction
521
-
522
- T=67s L1 transaction lands in Ethereum block (12s)
523
-
524
- T=72s Slot ends (5s buffer remaining)
525
- ```
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.
526
240
 
527
- **Summary:**
528
- - Built 5 blocks (sub-slots 1-5)
529
- - Last sub-slot (6) reserved for validator re-execution
530
- - Total time: 72s
531
- - 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.