Skip to content

Commit ef203fe

Browse files
committed
Address review feedback on style and the placeholder entry
Apply the review suggestions that need no design discussion: move `SLOT_DURATION_SCHEDULE` under the existing scheduling section and drop the extra config comments, remove the no-op `FAR_FUTURE_EPOCH` entry and the guard that existed only to serve it, annotate the new `slot` parameter inside the deadline helper signatures, drop the `field(default_factory=...)` defaults from `Store`, break the inactivity penalty denominator into named variables, delete the note about the unchanged blob sidecar retention window, and qualify "era" as "slot duration era".
1 parent 5c7dd04 commit ef203fe

6 files changed

Lines changed: 68 additions & 104 deletions

File tree

configs/mainnet.yaml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ HEZE_FORK_EPOCH: 18446744073709551615
6464
# EIP8321
6565
EIP8321_FORK_VERSION: 0xe8321000
6666
EIP8321_FORK_EPOCH: 18446744073709551615
67-
# EIP8198 (experimental)
67+
# EIP8198
6868
EIP8198_FORK_VERSION: 0xe8198000
6969
EIP8198_FORK_EPOCH: 18446744073709551615
7070

@@ -113,7 +113,6 @@ PAYLOAD_ATTESTATION_DUE_BPS: 7500
113113
# 6667 basis points, ~67% of SLOT_DURATION_MS
114114
INCLUSION_LIST_DUE_BPS: 6667
115115

116-
117116
# Validator cycle
118117
# ---------------------------------------------------------------
119118
# 2**2 (= 4)
@@ -240,20 +239,7 @@ BLOB_SCHEDULE:
240239

241240
GAS_LIMIT_SCHEDULE: []
242241

243-
# Slot duration schedule (EIP8198)
244-
# ---------------------------------------------------------------
245-
246-
SLOT_DURATION_SCHEDULE:
247-
- EPOCH: 18446744073709551615 # TBD
248-
SLOT_DURATION_MS: 10000
249-
PROPOSER_REORG_CUTOFF_MS: 1667
250-
ATTESTATION_DUE_MS: 2500
251-
AGGREGATE_DUE_MS: 5000
252-
SYNC_MESSAGE_DUE_MS: 2500
253-
CONTRIBUTION_DUE_MS: 5000
254-
PAYLOAD_DUE_MS: 5000
255-
PAYLOAD_ATTESTATION_DUE_MS: 7500
256-
INCLUSION_LIST_DUE_MS: 6667
242+
SLOT_DURATION_SCHEDULE: []
257243

258244
# Fast Confirmation Rule
259245
# ---------------------------------------------------------------

configs/minimal.yaml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ HEZE_FORK_EPOCH: 18446744073709551615
6060
# [customized] EIP8321
6161
EIP8321_FORK_VERSION: 0xe8321001
6262
EIP8321_FORK_EPOCH: 18446744073709551615
63-
# EIP8198 (experimental)
63+
# EIP8198
6464
EIP8198_FORK_VERSION: 0xe8198001
6565
EIP8198_FORK_EPOCH: 18446744073709551615
6666

@@ -109,7 +109,6 @@ PAYLOAD_ATTESTATION_DUE_BPS: 7500
109109
# 6667 basis points, ~67% of SLOT_DURATION_MS
110110
INCLUSION_LIST_DUE_BPS: 6667
111111

112-
113112
# Validator cycle
114113
# ---------------------------------------------------------------
115114
# 2**2 (= 4)
@@ -233,20 +232,7 @@ BLOB_SCHEDULE: []
233232

234233
GAS_LIMIT_SCHEDULE: []
235234

236-
# Slot duration schedule (EIP8198)
237-
# ---------------------------------------------------------------
238-
239-
SLOT_DURATION_SCHEDULE:
240-
- EPOCH: 18446744073709551615 # TBD
241-
SLOT_DURATION_MS: 5000 # [customized]
242-
PROPOSER_REORG_CUTOFF_MS: 833
243-
ATTESTATION_DUE_MS: 1250
244-
AGGREGATE_DUE_MS: 2500
245-
SYNC_MESSAGE_DUE_MS: 1250
246-
CONTRIBUTION_DUE_MS: 2500
247-
PAYLOAD_DUE_MS: 2500
248-
PAYLOAD_ATTESTATION_DUE_MS: 3750
249-
INCLUSION_LIST_DUE_MS: 3333
235+
SLOT_DURATION_SCHEDULE: []
250236

251237
# Fast Confirmation Rule
252238
# ---------------------------------------------------------------

specs/_features/eip8198/beacon-chain.md

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
EIP-8198 ("Quick Slots") makes the slot duration schedulable, with a first
3131
reduction from 12 to 10 seconds intended at the fork epoch. The slot structure
3232
is unchanged, and each schedule entry carries the intra-slot deadlines of its
33-
era as explicit millisecond values, so they can be adjusted whenever the slot
34-
duration changes. The remaining duration-dependent parameters are rescaled by
35-
the ratio `r = get_slot_duration_ms(epoch) / SLOT_DURATION_MS` to keep their
36-
wall-clock behavior constant: issuance and churn are per-epoch rates and scale
37-
by `r`, while the inactivity penalty scales by `r**2` so that the cumulative
38-
leak over a fixed wall-clock duration is unchanged. Each formula applies the
39-
ratio inline rather than pre-computing rounded constants. Epoch- and
33+
slot duration era as explicit millisecond values, so they can be adjusted
34+
whenever the slot duration changes. The remaining duration-dependent parameters
35+
are rescaled by the ratio `r = get_slot_duration_ms(epoch) / SLOT_DURATION_MS`
36+
to keep their wall-clock behavior constant: issuance and churn are per-epoch
37+
rates and scale by `r`, while the inactivity penalty scales by `r**2` so that
38+
the cumulative leak over a fixed wall-clock duration is unchanged. Each formula
39+
applies the ratio inline rather than pre-computing rounded constants. Epoch- and
4040
slot-denominated quantities — withdrawability and slashing windows, sync
4141
committee periods, per-payload and per-epoch processing limits — keep their
4242
counts, so their wall-clock spans scale with the slot duration.
@@ -53,8 +53,7 @@ deadlines for a given epoch. Epochs before the first entry use
5353

5454
There MUST NOT exist multiple slot duration schedule entries with the same epoch
5555
value. The epoch value in each entry MUST be greater than or equal to
56-
`EIP8198_FORK_EPOCH`; an entry with an epoch of `FAR_FUTURE_EPOCH` is not
57-
scheduled and has no effect. The slot duration in each entry MUST be a positive
56+
`EIP8198_FORK_EPOCH`. The slot duration in each entry MUST be a positive
5857
multiple of `1000`, so that every slot boundary has an exact integer-second
5958
timestamp. Every deadline in an entry MUST be positive and less than the entry's
6059
slot duration, and the deadlines MUST preserve the inherited ordering: the
@@ -67,14 +66,14 @@ MUST be accompanied by a `BLOB_SCHEDULE` entry at the same epoch that scales the
6766
maximum blobs per block by the slot-duration ratio (rounding down), keeping blob
6867
throughput per unit time constant.
6968

70-
The epoch of the mainnet entry below is **TBD** and is intended to be the fork
69+
The schedule is empty until the epoch of the first slot duration change is
70+
decided; the intended mainnet entry is a 10-second slot duration at the fork
7171
epoch.
7272

7373
<!-- list-of-records:slot_duration_schedule -->
7474

75-
| Epoch | Slot Duration Ms | Proposer Reorg Cutoff Ms | Attestation Due Ms | Aggregate Due Ms | Sync Message Due Ms | Contribution Due Ms | Payload Due Ms | Payload Attestation Due Ms | Inclusion List Due Ms | Description |
76-
| -------------------: | ---------------: | -----------------------: | -----------------: | ---------------: | ------------------: | ------------------: | -------------: | -------------------------: | --------------------: | ----------- |
77-
| 18446744073709551615 | 10000 | 1667 | 2500 | 5000 | 2500 | 5000 | 5000 | 7500 | 6667 | 10 seconds |
75+
| Epoch | Slot Duration Ms | Proposer Reorg Cutoff Ms | Attestation Due Ms | Aggregate Due Ms | Sync Message Due Ms | Contribution Due Ms | Payload Due Ms | Payload Attestation Due Ms | Inclusion List Due Ms | Description |
76+
| ----: | ---------------: | -----------------------: | -----------------: | ---------------: | ------------------: | ------------------: | -------------: | -------------------------: | --------------------: | ----------- |
7877

7978
## Helpers
8079

@@ -104,7 +103,7 @@ def get_slot_timing_parameters(epoch: Epoch) -> SlotTimingParameters:
104103
Return the slot timing parameters in effect at ``epoch``.
105104
"""
106105
for entry in sorted(SLOT_DURATION_SCHEDULE, key=lambda entry: entry["EPOCH"], reverse=True):
107-
if entry["EPOCH"] != FAR_FUTURE_EPOCH and epoch >= entry["EPOCH"]:
106+
if epoch >= entry["EPOCH"]:
108107
return SlotTimingParameters(
109108
slot_duration_ms=entry["SLOT_DURATION_MS"],
110109
proposer_reorg_cutoff_ms=entry["PROPOSER_REORG_CUTOFF_MS"],
@@ -150,8 +149,6 @@ def compute_slot_start_time_ms(genesis_time: Uint64, slot: Slot) -> Uint64:
150149
era_start_slot = GENESIS_SLOT
151150
era_duration_ms = SLOT_DURATION_MS
152151
for entry in sorted(SLOT_DURATION_SCHEDULE, key=lambda entry: entry["EPOCH"]):
153-
if entry["EPOCH"] == FAR_FUTURE_EPOCH:
154-
break
155152
entry_slot = compute_start_slot_at_epoch(entry["EPOCH"])
156153
if slot < entry_slot:
157154
break
@@ -173,8 +170,6 @@ def compute_slot_at_time_ms(genesis_time: Uint64, time_ms: Uint64) -> Slot:
173170
era_start_slot = GENESIS_SLOT
174171
era_duration_ms = SLOT_DURATION_MS
175172
for entry in sorted(SLOT_DURATION_SCHEDULE, key=lambda entry: entry["EPOCH"]):
176-
if entry["EPOCH"] == FAR_FUTURE_EPOCH:
177-
break
178173
entry_slot = compute_start_slot_at_epoch(entry["EPOCH"])
179174
era_length_ms = (entry_slot - era_start_slot) * era_duration_ms
180175
if remaining_ms < era_length_ms:
@@ -253,13 +248,10 @@ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], S
253248
)
254249
# [Modified in EIP8198]
255250
slot_duration_ms = get_slot_duration_ms(get_current_epoch(state))
256-
penalty_denominator = (
257-
INACTIVITY_SCORE_BIAS
258-
* INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
259-
* SLOT_DURATION_MS
260-
* SLOT_DURATION_MS
261-
// (slot_duration_ms * slot_duration_ms)
262-
)
251+
duration_squared = slot_duration_ms * slot_duration_ms
252+
base_duration_squared = SLOT_DURATION_MS * SLOT_DURATION_MS
253+
penalty_quotient = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
254+
penalty_denominator = penalty_quotient * base_duration_squared // duration_squared
263255
penalties[index] += Gwei(penalty_numerator // penalty_denominator)
264256
return rewards, penalties
265257
```

specs/_features/eip8198/fork-choice.md

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ EIP-8198 makes the slot duration change per `SLOT_DURATION_SCHEDULE`. Intra-slot
3939
deadlines are read from the schedule entry in effect at a duty's slot, so the
4040
deadline helpers gain a `slot` parameter; the inherited basis-point deadlines
4141
apply before the first schedule entry. The mapping between wall-clock time and
42-
slot number becomes piecewise over the schedule's eras, and every timeliness
42+
slot number becomes piecewise over the slot duration eras, and every timeliness
4343
check is rebased on the new `get_time_into_slot_ms` helper. The store clock
4444
gains millisecond precision: implementations MUST drive the store with
4545
`on_tick_ms`; the whole-second `on_tick` remains only as a compatibility
@@ -67,18 +67,16 @@ class Store:
6767
unrealized_finalized_checkpoint: Checkpoint
6868
proposer_boost_root: Root
6969
equivocating_indices: Set[ValidatorIndex]
70-
blocks: Dict[Root, BeaconBlock] = field(default_factory=dict)
71-
block_states: Dict[Root, BeaconState] = field(default_factory=dict)
72-
block_timeliness: Dict[Root, list[bool]] = field(default_factory=dict)
73-
checkpoint_states: Dict[Checkpoint, BeaconState] = field(default_factory=dict)
74-
latest_messages: Dict[ValidatorIndex, LatestMessage] = field(default_factory=dict)
75-
unrealized_justifications: Dict[Root, Checkpoint] = field(default_factory=dict)
76-
payloads: Dict[Root, ExecutionPayloadEnvelope] = field(default_factory=dict)
77-
payload_timeliness_vote: Dict[Root, list[Optional[Boolean]]] = field(default_factory=dict)
78-
payload_data_availability_vote: Dict[Root, list[Optional[Boolean]]] = field(
79-
default_factory=dict
80-
)
81-
payload_inclusion_list_satisfaction: Dict[Root, bool] = field(default_factory=dict)
70+
blocks: Dict[Root, BeaconBlock]
71+
block_states: Dict[Root, BeaconState]
72+
block_timeliness: Dict[Root, list[bool]]
73+
checkpoint_states: Dict[Checkpoint, BeaconState]
74+
latest_messages: Dict[ValidatorIndex, LatestMessage]
75+
unrealized_justifications: Dict[Root, Checkpoint]
76+
payloads: Dict[Root, ExecutionPayloadEnvelope]
77+
payload_timeliness_vote: Dict[Root, list[Optional[Boolean]]]
78+
payload_data_availability_vote: Dict[Root, list[Optional[Boolean]]]
79+
payload_inclusion_list_satisfaction: Dict[Root, bool]
8280
```
8381

8482
### Modified `get_forkchoice_store`
@@ -111,6 +109,7 @@ def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -
111109
block_states={anchor_root: copy(anchor_state)},
112110
block_timeliness={anchor_root: [True, True]},
113111
checkpoint_states={justified_checkpoint: copy(anchor_state)},
112+
latest_messages={},
114113
unrealized_justifications={anchor_root: justified_checkpoint},
115114
payloads={},
116115
payload_timeliness_vote={anchor_root: [None] * PTC_SIZE},
@@ -166,72 +165,80 @@ since the deadline of a duty is read from the schedule entry in effect at its
166165
slot.
167166

168167
```python
169-
def get_attestation_due_ms(slot: Slot) -> Uint64:
170-
# [Modified in EIP8198]
171-
# Added `slot`
168+
def get_attestation_due_ms(
169+
# [New in EIP8198]
170+
slot: Slot,
171+
) -> Uint64:
172172
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).attestation_due_ms
173173
```
174174

175175
### Modified `get_proposer_reorg_cutoff_ms`
176176

177177
```python
178-
def get_proposer_reorg_cutoff_ms(slot: Slot) -> Uint64:
179-
# [Modified in EIP8198]
180-
# Added `slot`
178+
def get_proposer_reorg_cutoff_ms(
179+
# [New in EIP8198]
180+
slot: Slot,
181+
) -> Uint64:
181182
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).proposer_reorg_cutoff_ms
182183
```
183184

184185
### Modified `get_aggregate_due_ms`
185186

186187
```python
187-
def get_aggregate_due_ms(slot: Slot) -> Uint64:
188-
# [Modified in EIP8198]
189-
# Added `slot`
188+
def get_aggregate_due_ms(
189+
# [New in EIP8198]
190+
slot: Slot,
191+
) -> Uint64:
190192
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).aggregate_due_ms
191193
```
192194

193195
### Modified `get_sync_message_due_ms`
194196

195197
```python
196-
def get_sync_message_due_ms(slot: Slot) -> Uint64:
197-
# [Modified in EIP8198]
198-
# Added `slot`
198+
def get_sync_message_due_ms(
199+
# [New in EIP8198]
200+
slot: Slot,
201+
) -> Uint64:
199202
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).sync_message_due_ms
200203
```
201204

202205
### Modified `get_contribution_due_ms`
203206

204207
```python
205-
def get_contribution_due_ms(slot: Slot) -> Uint64:
206-
# [Modified in EIP8198]
207-
# Added `slot`
208+
def get_contribution_due_ms(
209+
# [New in EIP8198]
210+
slot: Slot,
211+
) -> Uint64:
208212
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).contribution_due_ms
209213
```
210214

211215
### Modified `get_payload_due_ms`
212216

213217
```python
214-
def get_payload_due_ms(slot: Slot) -> Uint64:
215-
# [Modified in EIP8198]
216-
# Added `slot`
218+
def get_payload_due_ms(
219+
# [New in EIP8198]
220+
slot: Slot,
221+
) -> Uint64:
217222
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).payload_due_ms
218223
```
219224

220225
### Modified `get_payload_attestation_due_ms`
221226

222227
```python
223-
def get_payload_attestation_due_ms(slot: Slot) -> Uint64:
224-
# [Modified in EIP8198]
225-
# Added `slot`
228+
def get_payload_attestation_due_ms(
229+
# [New in EIP8198]
230+
slot: Slot,
231+
) -> Uint64:
226232
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).payload_attestation_due_ms
227233
```
228234

229235
### Modified `get_inclusion_list_due_ms`
230236

231237
```python
232-
def get_inclusion_list_due_ms(slot: Slot) -> Uint64:
233-
# [Modified in EIP8198]
234-
# Added `slot`
238+
def get_inclusion_list_due_ms(
239+
# [New in EIP8198]
240+
slot: Slot,
241+
) -> Uint64:
235242
return get_slot_timing_parameters(compute_epoch_at_slot(slot)).inclusion_list_due_ms
236243
```
237244

specs/_features/eip8198/p2p-interface.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,7 @@ Request and response message types are unchanged from Heze. In the inherited
167167
data-column sidecar request validations and pruning guidance,
168168
`get_data_column_sidecars_retention_start(current_epoch)` replaces the rolling
169169
`current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` term; the
170-
inherited `FULU_FORK_EPOCH` floor is unchanged. The blob sidecar Req/Resp
171-
messages are already deprecated as of
172-
`FULU_FORK_EPOCH + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS`, so their retention
173-
window needs no treatment.
170+
inherited `FULU_FORK_EPOCH` floor is unchanged.
174171

175172
Epoch-denominated retention windows without a wall-clock target — in particular
176173
the block retention window `compute_min_epochs_for_block_requests()` — keep

tests/core/pyspec/eth_consensus_specs/test/eip8198/unittests/test_slot_duration.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,8 @@ def test_retention_window_preserves_wall_clock_length(spec, state):
507507
@with_phases([EIP8198])
508508
@spec_test
509509
@single_phase
510-
def test_unscheduled_entry_has_no_effect(spec):
511-
# The default schedule only contains the placeholder entry at
512-
# FAR_FUTURE_EPOCH, which must behave as if the schedule were empty.
513-
for entry in spec.config.SLOT_DURATION_SCHEDULE:
514-
assert entry["EPOCH"] == spec.FAR_FUTURE_EPOCH
515-
assert spec.get_slot_duration_ms(spec.FAR_FUTURE_EPOCH) == spec.config.SLOT_DURATION_MS
510+
def test_empty_schedule_keeps_base_duration(spec):
511+
assert spec.config.SLOT_DURATION_SCHEDULE == ()
516512
for epoch in (spec.GENESIS_EPOCH, spec.Epoch(8192), spec.Epoch(100_000)):
517513
assert spec.get_slot_duration_ms(epoch) == spec.config.SLOT_DURATION_MS
518514
slot = spec.compute_start_slot_at_epoch(epoch)

0 commit comments

Comments
 (0)