Skip to content

test(fc): attestation target walkback respects JUSTIFICATION_LOOKBACK_SLOTS #560

@tcoratger

Description

@tcoratger

Context

When a validator produces an attestation, it needs a target checkpoint — the block it is voting to justify. The target is computed by `Store.get_attestation_target`, which walks backward from the current head toward the safe target.

The walkback is bounded by `JUSTIFICATION_LOOKBACK_SLOTS = 3`. This means:

  • If the head is 10 slots ahead of the safe target, the attestation target is 3 slots back from head, not at the safe target
  • If the head is only 1 slot ahead of the safe target, the target is at the safe target itself

This bound prevents validators from always targeting the same old block, keeping the justification frontier moving.

The existing fillers test basic attestation target advancement but do not specifically verify the lookback bound when head is far ahead of safe target.

What to test

Write a fork choice filler that:

  1. Builds a long chain (10+ blocks) so the head is far ahead
  2. Keeps the safe target near genesis (limited attestation weight)
  3. Calls `get_attestation_target` (implicitly via `StoreChecks`)
  4. Verifies the target is exactly `JUSTIFICATION_LOOKBACK_SLOTS` (3) slots behind head, NOT at the safe target

Key assertions

  • Head is at slot 10
  • Safe target is at slot 0 (genesis)
  • Attestation target slot should be at slot 7 (= 10 - 3), not slot 0
  • `StoreChecks(attestation_target_slot=Slot(7))` validates this

Where to add the test

Add to: `tests/consensus/devnet/fc/test_attestation_target_selection.py` (extends existing file)

Code skeleton

def test_attestation_target_walkback_bounded_by_lookback(
    fork_choice_test: ForkChoiceTestFiller,
) -> None:
    """Attestation target walks back at most JUSTIFICATION_LOOKBACK_SLOTS from head."""
    # Build a long chain without enough attestation weight to advance safe target
    steps = []
    for slot in range(1, 11):
        steps.append(
            BlockStep(
                block=BlockSpec(slot=Slot(slot), label=f"block_{slot}"),
                # After the last block, check the attestation target
                checks=StoreChecks(attestation_target_slot=Slot(7))
                if slot == 10
                else None,
            )
        )
    fork_choice_test(steps=steps)

How to run

uv run fill --fork=devnet --clean -n auto -k test_attestation_target_walkback_bounded

References

  • `Store.get_attestation_target`: `src/lean_spec/subspecs/forkchoice/store.py`
  • `JUSTIFICATION_LOOKBACK_SLOTS = 3`: `src/lean_spec/subspecs/chain/config.py`
  • Existing target tests: `tests/consensus/devnet/fc/test_attestation_target_selection.py`

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