Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions packages/testing/src/consensus_testing/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from framework.forks import BaseFork

from lean_spec.spec.forks.lstar.spec import LstarSpec


class Lstar(BaseFork):
"""Lstar fork — base fork for the lean Ethereum protocol."""
Expand All @@ -12,8 +10,3 @@ class Lstar(BaseFork):
def name(cls) -> str:
"""Return the fork name."""
return "Lstar"

@classmethod
def spec_class(cls) -> type[LstarSpec]:
"""Return the ForkProtocol implementation for this fork."""
return LstarSpec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from pydantic import Field, model_validator

from consensus_testing.genesis import generate_pre_state
from consensus_testing.keys import XmssKeyManager
from consensus_testing.test_fixtures.base import BaseConsensusFixture
from consensus_testing.test_types import (
Expand Down Expand Up @@ -56,12 +57,12 @@ class ForkChoiceTest(BaseConsensusFixture):
description: ClassVar[str] = "Tests event-driven fork choice through Store operations"
"""Human-readable summary for fixture documentation."""

anchor_state: State | None = None
anchor_state: State = Field(default_factory=generate_pre_state)
"""
Initial trusted consensus state.

Most tests start from genesis.
The pytest fixture provides this automatically.
Defaults to the standard genesis state.
Spell it out only when the test needs a non-default anchor.
"""

anchor_block: Block | None = None
Expand Down Expand Up @@ -120,7 +121,7 @@ def set_anchor_block_default(self) -> Self:
Most tests start from genesis.
Deriving the anchor block from state reduces boilerplate.
"""
if self.anchor_block is None and self.anchor_state is not None:
if self.anchor_block is None:
# Build a minimal genesis block from the state's header fields.
#
# The state already contains the block header.
Expand Down Expand Up @@ -177,7 +178,6 @@ def make_fixture(self) -> Self:
#
# Pydantic validators should have populated these fields.
# These assertions guard against misuse.
assert self.anchor_state is not None, "anchor state must be set before making fixture"
assert self.anchor_block is not None, "anchor block must be set before making fixture"
assert self.max_slot is not None, "max slot must be set before making fixture"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

from typing import Any, ClassVar

from pydantic import ConfigDict, PrivateAttr, field_serializer
from pydantic import ConfigDict, Field, PrivateAttr, field_serializer

from consensus_testing.genesis import generate_pre_state
from consensus_testing.keys import XmssKeyManager
from consensus_testing.test_fixtures.base import BaseConsensusFixture
from consensus_testing.test_types import AggregatedAttestationSpec, BlockSpec, StateExpectation
Expand Down Expand Up @@ -50,8 +51,13 @@ class StateTransitionTest(BaseConsensusFixture):

model_config = ConfigDict(arbitrary_types_allowed=True)

pre: State
"""The initial consensus state before processing."""
pre: State = Field(default_factory=generate_pre_state)
"""
The initial consensus state before processing.

Defaults to the standard genesis state.
Spell it out only when the test needs a non-default pre-state.
"""

blocks: list[BlockSpec]
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from pydantic import Field

from consensus_testing.genesis import generate_pre_state
from consensus_testing.keys import XmssKeyManager
from consensus_testing.test_fixtures.base import BaseConsensusFixture
from consensus_testing.test_types import BlockSpec
Expand Down Expand Up @@ -39,11 +40,11 @@ class VerifySignaturesTest(BaseConsensusFixture):
format_name: ClassVar[str] = "verify_signatures_test"
description: ClassVar[str] = "Tests signature verification for signed blocks."

anchor_state: State | None = None
anchor_state: State = Field(default_factory=generate_pre_state)
"""
The initial consensus state before processing.

If not provided, the framework will use the genesis fixture.
Defaults to the standard genesis state.
"""

block: BlockSpec = Field(exclude=True)
Expand Down Expand Up @@ -101,9 +102,6 @@ def make_fixture(self) -> VerifySignaturesTest:
Raises:
AssertionError: If signature verification fails unexpectedly.
"""
# Ensure anchor_state is set
assert self.anchor_state is not None, "anchor state must be set before making the fixture"

# Use shared key manager
key_manager = XmssKeyManager.shared()

Expand Down Expand Up @@ -264,7 +262,6 @@ def _apply_tamper(self, signed_block: SignedBlock) -> SignedBlock:
attestations = body.attestations.data
if len(attestations) < 2:
raise ValueError("swap_first_two_attestations requires at least two attestations")
assert self.anchor_state is not None

key_manager = XmssKeyManager.shared()
original_attestation_proofs = [
Expand Down
27 changes: 0 additions & 27 deletions packages/testing/src/framework/pytest_plugins/filler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from typing import Any

import pytest
from consensus_testing import generate_pre_state
from consensus_testing.forks import FORKS_BY_NAME
from consensus_testing.test_fixtures import (
ApiEndpointTest,
Expand Down Expand Up @@ -341,22 +340,6 @@ def test_case_description(request: pytest.FixtureRequest) -> str:
return combined_docstring


@pytest.fixture(scope="function")
def pre(request: pytest.FixtureRequest, fork: Any) -> Any:
"""
Default consensus pre-state.

Tests can request this fixture to customize the initial state,
or omit it to use the default (auto-injected by framework).
"""
spec = fork.spec_class()()

if hasattr(request, "param"):
return generate_pre_state(fork=spec, **request.param)

return generate_pre_state(fork=spec)


def base_spec_filler_parametrizer(fixture_class: Any) -> Any:
"""
Generate pytest.fixture for a given fixture class.
Expand All @@ -376,23 +359,13 @@ def base_spec_filler_parametrizer_func(
request: pytest.FixtureRequest,
fork: Any,
test_case_description: str,
pre: Any, # Auto-inject pre fixture
) -> Any:
"""Fixture used to instantiate an auto-fillable fixture object."""

class FixtureWrapper(fixture_class):
"""Wrapper class that auto-fills and collects fixtures on instantiation."""

def __init__(self, **kwargs: Any) -> None:
# Auto-inject pre-state if not provided by test
if "pre" not in kwargs and "anchor_state" not in kwargs:
# Determine which field to inject based on fixture type
if hasattr(fixture_class, "__annotations__"):
if "pre" in fixture_class.__annotations__:
kwargs["pre"] = pre
elif "anchor_state" in fixture_class.__annotations__:
kwargs["anchor_state"] = pre

super().__init__(**kwargs)

filled_fixture = self.make_fixture()
Expand Down
5 changes: 5 additions & 0 deletions src/lean_spec/spec/crypto/xmss/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

from lean_multisig_py import setup_prover

# Why: break the import cycle between the signature and fork containers.
# The signature containers need the fork slot type, while the fork
# aggregation containers import the signature containers back.
# Loading the forks package first lets the cycle resolve from any entry point.
import lean_spec.spec.forks # noqa: F401
from lean_spec.config import LEAN_ENV
from lean_spec.spec.crypto.xmss.containers import PublicKey, SecretKey
from lean_spec.spec.crypto.xmss.interface import TARGET_SIGNATURE_SCHEME, GeneralizedXmssScheme
Expand Down
3 changes: 0 additions & 3 deletions tests/consensus/lstar/fc/test_block_attestation_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
ForkChoiceStep,
ForkChoiceTestFiller,
StoreChecks,
generate_pre_state,
)
from consensus_testing.keys import XmssKeyManager

Expand Down Expand Up @@ -99,7 +98,6 @@ def test_block_with_maximum_attestations(
)

fork_choice_test(
anchor_state=generate_pre_state(),
steps=chain,
)

Expand Down Expand Up @@ -175,6 +173,5 @@ def test_block_exceeding_maximum_attestations_is_rejected(
)

fork_choice_test(
anchor_state=generate_pre_state(),
steps=chain,
)
11 changes: 0 additions & 11 deletions tests/consensus/lstar/state_transition/test_block_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def test_process_first_block_after_genesis(
This is the foundation for all subsequent blocks.
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1)),
],
Expand Down Expand Up @@ -70,7 +69,6 @@ def test_linear_chain_multiple_blocks(
5. Final state at slot 5
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), parent_label="block_1", label="block_2"),
Expand Down Expand Up @@ -114,7 +112,6 @@ def test_blocks_with_gaps(
This validates resilience to gaps.
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(4), parent_label="block_1", label="block_4"),
Expand Down Expand Up @@ -150,7 +147,6 @@ def test_block_at_large_slot_number(
4. State remains consistent
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(100)),
],
Expand Down Expand Up @@ -182,7 +178,6 @@ def test_block_at_very_large_slot_with_many_skipped(
5. No integer overflow or memory issues
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(500)),
],
Expand Down Expand Up @@ -225,7 +220,6 @@ def test_block_with_invalid_proposer(
# - expected proposer is Uint64(1),
# - we'll try to use Uint64(5) instead
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(
slot=Slot(1),
Expand Down Expand Up @@ -263,7 +257,6 @@ def test_block_with_invalid_parent_root(
Without this check, attackers could create invalid chain branches.
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(
slot=Slot(1),
Expand Down Expand Up @@ -299,7 +292,6 @@ def test_block_with_invalid_state_root(
This is a critical validation - without it, proposers could claim any arbitrary state.
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(
slot=Slot(1),
Expand Down Expand Up @@ -377,7 +369,6 @@ def test_block_extends_deep_chain(
)

state_transition_test(
pre=generate_pre_state(),
blocks=blocks,
post=StateExpectation(slot=Slot(20)),
)
Expand Down Expand Up @@ -419,7 +410,6 @@ def test_empty_blocks(
]

state_transition_test(
pre=generate_pre_state(),
blocks=blocks,
post=StateExpectation(
slot=Slot(6), latest_block_header_slot=Slot(6), historical_block_hashes_count=6
Expand Down Expand Up @@ -451,7 +441,6 @@ def test_empty_blocks_with_missed_slots(

"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), body=None, parent_label="block_1", label="block_2"),
Expand Down
11 changes: 0 additions & 11 deletions tests/consensus/lstar/state_transition/test_finalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def test_finalization_on_next_justifiable_step(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -120,7 +119,6 @@ def test_pending_justification_survives_finalization_rebase(
8. justifications_validators contains a single 1-of-4 pending tally
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -307,7 +305,6 @@ def test_mid_block_finalized_slot_visibility(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), parent_label="block_1", label="block_2"),
Expand Down Expand Up @@ -405,7 +402,6 @@ def test_finalization_prunes_stale_pending_votes_and_rebases_window(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -513,7 +509,6 @@ def test_stale_finalized_source_justifies_without_rewinding_finalization(
5. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -640,7 +635,6 @@ def test_source_at_finalized_boundary_justifies_without_refinalizing(
5. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -767,7 +761,6 @@ def test_non_adjacent_justification_finalizes_across_non_justifiable_gap(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), parent_label="block_1", label="block_2"),
Expand Down Expand Up @@ -848,7 +841,6 @@ def test_no_finalization_when_rebased_boundary_exposes_intermediate_justifiable_
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), parent_label="block_1", label="block_2"),
Expand Down Expand Up @@ -973,7 +965,6 @@ def test_mid_block_finalized_slot_rejects_target_that_loses_justifiability(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -1079,7 +1070,6 @@ def test_merged_attestations_for_same_target_justify_and_finalize_cleanly(
7. There are no pending justifications
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(
Expand Down Expand Up @@ -1164,7 +1154,6 @@ def test_rebased_finalization_prunes_stale_votes_and_preserves_future_votes(
8. justifications_validators contains a single 1-of-4 pending tally
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[
BlockSpec(slot=Slot(1), label="block_1"),
BlockSpec(slot=Slot(2), parent_label="block_1", label="block_2"),
Expand Down
1 change: 0 additions & 1 deletion tests/consensus/lstar/state_transition/test_genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def test_genesis_default_configuration(
- 4 validators with zero public_keys
"""
state_transition_test(
pre=generate_pre_state(),
blocks=[],
post=StateExpectation(
slot=Slot(0),
Expand Down
Loading
Loading