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
2 changes: 0 additions & 2 deletions src/lean_spec/subspecs/containers/block/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
class AggregatedAttestations(SSZList[AggregatedAttestation]):
"""List of aggregated attestations included in a block."""

ELEMENT_TYPE = AggregatedAttestation
LIMIT = int(VALIDATOR_REGISTRY_LIMIT)


Expand All @@ -35,5 +34,4 @@ class AttestationSignatures(SSZList[AggregatedSignatureProof]):
- proof bytes from leanVM signature aggregation.
"""

ELEMENT_TYPE = AggregatedSignatureProof
LIMIT = int(VALIDATOR_REGISTRY_LIMIT)
3 changes: 0 additions & 3 deletions src/lean_spec/subspecs/containers/state/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@
class HistoricalBlockHashes(SSZList[Bytes32]):
"""List of historical block root hashes up to historical_roots_limit."""

ELEMENT_TYPE = Bytes32
LIMIT = int(DEVNET_CONFIG.historical_roots_limit)


class JustificationRoots(SSZList[Bytes32]):
"""List of justified block roots up to historical_roots_limit."""

ELEMENT_TYPE = Bytes32
LIMIT = int(DEVNET_CONFIG.historical_roots_limit)


Expand All @@ -38,5 +36,4 @@ class JustificationValidators(BaseBitlist):
class Validators(SSZList[Validator]):
"""Validator registry tracked in the state."""

ELEMENT_TYPE = Validator
LIMIT = int(DEVNET_CONFIG.validator_registry_limit)
5 changes: 0 additions & 5 deletions src/lean_spec/subspecs/xmss/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class HashDigestVector(SSZVector[Fp]):
as SSZ can pack these back-to-back without per-element offsets.
"""

ELEMENT_TYPE = Fp
LENGTH = HASH_DIGEST_LENGTH


Expand All @@ -67,7 +66,6 @@ class HashDigestList(SSZList[HashDigestVector]):
This type is used to represent collections of hash digests in the XMSS scheme.
"""

ELEMENT_TYPE = HashDigestVector
LIMIT = NODE_LIST_LIMIT


Expand All @@ -80,7 +78,6 @@ class Parameter(SSZVector[Fp]):
certain cross-key attacks. It is public knowledge.
"""

ELEMENT_TYPE = Fp
LENGTH = TARGET_CONFIG.PARAMETER_LEN


Expand All @@ -95,7 +92,6 @@ class Randomness(SSZVector[Fp]):
SSZ notation: `Vector[Fp, RAND_LEN_FE]`
"""

ELEMENT_TYPE = Fp
LENGTH = TARGET_CONFIG.RAND_LEN_FE


Expand Down Expand Up @@ -152,5 +148,4 @@ class HashTreeLayers(SSZList[HashTreeLayer]):
- Maximum: `LOG_LIFETIME + 1` layers
"""

ELEMENT_TYPE = HashTreeLayer
LIMIT = LAYERS_LIMIT
56 changes: 40 additions & 16 deletions src/lean_spec/types/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

Example:
class Uint64Vector4(SSZVector[Uint64]):
ELEMENT_TYPE = Uint64
LENGTH = 4

vec = Uint64Vector4(data=[...])
Expand All @@ -54,12 +53,12 @@ class SSZVector(SSZModel, Generic[T]):
The length is fixed at the type level and cannot change at runtime.

Subclasses must define:
ELEMENT_TYPE: The SSZ type of each element
LENGTH: The exact number of elements

The ELEMENT_TYPE is automatically inferred from the generic parameter.

Example:
class Uint16Vector2(SSZVector[Uint16]):
ELEMENT_TYPE = Uint16
LENGTH = 2

vec = Uint16Vector2(data=[Uint16(1), Uint16(2)])
Expand All @@ -72,17 +71,29 @@ class Uint16Vector2(SSZVector[Uint16]):
"""

ELEMENT_TYPE: ClassVar[Type[SSZType]]
"""The SSZ type of elements in this vector."""
"""The SSZ type of elements in this vector (auto-inferred from generic parameter)."""

LENGTH: ClassVar[int]
"""The exact number of elements (fixed at the type level)."""

data: Sequence[T] = Field(default_factory=tuple)
"""
The immutable sequence of elements.

Accepts lists or tuples on input; stored as a tuple after validation.
"""
def __init_subclass__(cls, **kwargs: Any) -> None:
"""Automatically set ELEMENT_TYPE from the generic parameter."""
super().__init_subclass__(**kwargs)

# Skip if ELEMENT_TYPE is explicitly defined in this class
if "ELEMENT_TYPE" in cls.__dict__:
return

# Extract type argument from Pydantic's generic metadata
for base in cls.__bases__:
metadata = getattr(base, "__pydantic_generic_metadata__", None)
if metadata and metadata.get("origin") is SSZVector:
args = metadata.get("args", ())
if args:
cls.ELEMENT_TYPE = args[0]
return

@field_serializer("data", when_used="json")
def _serialize_data(self, value: Sequence[T]) -> list[Any]:
Expand Down Expand Up @@ -243,12 +254,12 @@ class SSZList(SSZModel, Generic[T]):
Unlike Vector, the length can vary at runtime.

Subclasses must define:
ELEMENT_TYPE: The SSZ type of each element
LIMIT: The maximum number of elements allowed

The ELEMENT_TYPE is automatically inferred from the generic parameter.

Example:
class Uint64List32(SSZList[Uint64]):
ELEMENT_TYPE = Uint64
LIMIT = 32

my_list = Uint64List32(data=[Uint64(1), Uint64(2)])
Expand All @@ -262,17 +273,30 @@ class Uint64List32(SSZList[Uint64]):
"""

ELEMENT_TYPE: ClassVar[Type[SSZType]]
"""The SSZ type of elements in this list."""
"""The SSZ type of elements in this list (auto-inferred from generic parameter)."""

LIMIT: ClassVar[int]
"""The maximum number of elements allowed."""

data: Sequence[T] = Field(default_factory=tuple)
"""
The immutable sequence of elements.

Accepts lists or tuples on input; stored as a tuple after validation.
"""
"""The immutable sequence of elements."""

def __init_subclass__(cls, **kwargs: Any) -> None:
"""Automatically set ELEMENT_TYPE from the generic parameter."""
super().__init_subclass__(**kwargs)

# Skip if ELEMENT_TYPE is explicitly defined in this class
if "ELEMENT_TYPE" in cls.__dict__:
return

# Extract type argument from Pydantic's generic metadata
for base in cls.__bases__:
metadata = getattr(base, "__pydantic_generic_metadata__", None)
if metadata and metadata.get("origin") is SSZList:
args = metadata.get("args", ())
if args:
cls.ELEMENT_TYPE = args[0]
return

@field_serializer("data", when_used="json")
def _serialize_data(self, value: Sequence[T]) -> list[Any]:
Expand Down
18 changes: 6 additions & 12 deletions tests/lean_spec/subspecs/ssz/test_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,23 @@


# Concrete SSZList classes for tests
class Uint16List32(SSZList):
ELEMENT_TYPE = Uint16
class Uint16List32(SSZList[Uint16]):
LIMIT = 32


class Uint16List128(SSZList):
ELEMENT_TYPE = Uint16
class Uint16List128(SSZList[Uint16]):
LIMIT = 128


class Uint16List1024(SSZList):
ELEMENT_TYPE = Uint16
class Uint16List1024(SSZList[Uint16]):
LIMIT = 1024


class Uint32List128(SSZList):
ELEMENT_TYPE = Uint32
class Uint32List128(SSZList[Uint32]):
LIMIT = 128


class Uint256List32(SSZList):
ELEMENT_TYPE = Uint256
class Uint256List32(SSZList[Uint256]):
LIMIT = 32


Expand Down Expand Up @@ -460,10 +455,9 @@ class Bitlist512(BaseBitlist):


# Define explicit SSZVector types for testing our new approach
class Uint16Vector2(SSZVector):
class Uint16Vector2(SSZVector[Uint16]):
"""A vector of exactly 2 Uint16 values."""

ELEMENT_TYPE = Uint16
LENGTH = 2


Expand Down
Loading
Loading