Context
The leanSpec fork choice store uses an interval-based tick system to coordinate actions within each slot. Every slot is divided into 5 intervals (0–4), each 800ms apart. Different actions fire at specific intervals:
| Interval |
Action |
Condition |
| 0 |
accept_new_attestations |
Only if local validator is the proposer |
| 1 |
(none — vote propagation window) |
— |
| 2 |
aggregate |
Only if local validator is an aggregator |
| 3 |
update_safe_target |
Always |
| 4 |
accept_new_attestations |
Always |
This is defined in Store.tick_interval in src/lean_spec/subspecs/forkchoice/store.py.
No spec test filler currently exercises this system. Client teams need test vectors to verify their tick handling is correct.
What to test
Write a fork choice filler that builds a short chain, then advances time through all 5 intervals of a single slot using TickStep. After each tick, use StoreChecks to verify the expected store state.
Scenario
- Build a 2-block chain (slots 1 and 2) with 4 validators
- Have validators gossip attestations for slot 2
- Advance time through intervals 0–4 of slot 3 using
TickStep
- After each interval, assert the correct store state via
StoreChecks
Key assertions
- After interval 0: if proposer, new attestations are accepted (head may update)
- After interval 3: safe target is recomputed
- After interval 4: new attestations are accepted unconditionally
Where to add the test
Create a new file: tests/consensus/devnet/fc/test_tick_system.py
Code skeleton
"""Tick interval system tests."""
from consensus_testing import (
BlockSpec,
BlockStep,
ForkChoiceTestFiller,
GossipAttestationSpec,
AttestationStep,
StoreChecks,
TickStep,
)
from lean_spec.subspecs.containers.slot import Slot
from lean_spec.subspecs.containers.validator import ValidatorIndex
def test_tick_interval_progression_through_full_slot(
fork_choice_test: ForkChoiceTestFiller,
) -> None:
"""Advance through all 5 intervals of a slot and verify interval-specific actions fire."""
# genesis_time = 0, so slot N starts at N * 4 seconds = N * 4000 ms
# Each interval = 800ms
# Slot 3 intervals: time 12000, 12800, 13600, 14400, 15200 (in ms)
# TickStep.time is in seconds, so: 12, 12.8, 13.6, 14.4, 15.2
# But time is integer (unix timestamp), so we need to work in whole seconds
# or verify the framework handles ms. Check Store.on_tick for units.
#
# TODO: verify time units in TickStep (seconds vs milliseconds vs intervals)
# and adjust the tick times accordingly.
fork_choice_test(
steps=[
# Build a short chain
BlockStep(block=BlockSpec(slot=Slot(1), label="block_1")),
BlockStep(block=BlockSpec(slot=Slot(2), label="block_2")),
# Gossip attestations from validators
AttestationStep(
attestation=GossipAttestationSpec(
validator_id=ValidatorIndex(1),
slot=Slot(2),
target_slot=Slot(2),
target_root_label="block_2",
),
),
# Advance through slot 3 intervals via TickStep
# ... fill in tick times based on time unit discovery
# After each tick, add StoreChecks to verify expected state
],
)
How to run
uv run fill --fork=devnet --clean -n auto -k test_tick_interval_progression
References
Store.tick_interval: src/lean_spec/subspecs/forkchoice/store.py
Store.on_tick: same file
- Chain timing constants:
src/lean_spec/subspecs/chain/config.py
- Existing fork choice fillers for patterns:
tests/consensus/devnet/fc/
Context
The leanSpec fork choice store uses an interval-based tick system to coordinate actions within each slot. Every slot is divided into 5 intervals (0–4), each 800ms apart. Different actions fire at specific intervals:
accept_new_attestationsaggregateupdate_safe_targetaccept_new_attestationsThis is defined in
Store.tick_intervalinsrc/lean_spec/subspecs/forkchoice/store.py.No spec test filler currently exercises this system. Client teams need test vectors to verify their tick handling is correct.
What to test
Write a fork choice filler that builds a short chain, then advances time through all 5 intervals of a single slot using
TickStep. After each tick, useStoreChecksto verify the expected store state.Scenario
TickStepStoreChecksKey assertions
Where to add the test
Create a new file:
tests/consensus/devnet/fc/test_tick_system.pyCode skeleton
How to run
References
Store.tick_interval:src/lean_spec/subspecs/forkchoice/store.pyStore.on_tick: same filesrc/lean_spec/subspecs/chain/config.pytests/consensus/devnet/fc/