Skip to content

test(fc): tick interval progression through a full slot #555

@tcoratger

Description

@tcoratger

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

  1. Build a 2-block chain (slots 1 and 2) with 4 validators
  2. Have validators gossip attestations for slot 2
  3. Advance time through intervals 0–4 of slot 3 using TickStep
  4. 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/

Metadata

Metadata

Assignees

Labels

good first issueGood for newcomerstestsScope: Changes to the spec tests

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions