Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
18cfdcc
aggregate all block siignatures
g11tech Sep 25, 2025
adecd99
updated spec
g11tech Oct 11, 2025
8739640
update info
g11tech Oct 11, 2025
4ffbfb1
typo
g11tech Oct 11, 2025
af89e1c
improvs
g11tech Oct 11, 2025
505e7ce
further updates to forkchoice
g11tech Oct 11, 2025
e94357e
improvs
g11tech Oct 11, 2025
84a7f7a
apply spec call feedback
g11tech Oct 13, 2025
0636cde
fix the proposer vote construction and consumption
g11tech Oct 13, 2025
603cf87
enroll validators in state
g11tech Oct 13, 2025
92967fc
fix some issues
g11tech Oct 13, 2025
715653c
fix the issue in code as well
g11tech Oct 13, 2025
3d2de22
feat: init aggregate all block signatures as naive list
GrapeBaBa Oct 14, 2025
855a00b
fix: fix state attestations processing
GrapeBaBa Oct 15, 2025
8579814
fix: fix store process_block arg
GrapeBaBa Oct 15, 2025
8fdefec
fix: fix store produce block
GrapeBaBa Oct 15, 2025
e712087
fix: fix test_state
GrapeBaBa Oct 15, 2025
4cd664f
feat: update to `SignedBlockAndVote` structure
GrapeBaBa Oct 15, 2025
e702e4e
clean up proposer attestation data as not needed anymore
g11tech Oct 15, 2025
ae40ef3
Merge remote-tracking branch 'origin/main' into agg-block-sigs
g11tech Oct 15, 2025
5a3051e
add clarification
g11tech Oct 15, 2025
40d005d
removing redundancy in name to shorten it
g11tech Oct 15, 2025
4209e52
add more clarification
g11tech Oct 15, 2025
fc73c2f
fix: fix review comment
GrapeBaBa Oct 16, 2025
968dd55
fix: fix format
GrapeBaBa Oct 16, 2025
a97b671
fix: revert unexpected lint change
GrapeBaBa Oct 16, 2025
6388aad
fix: fix lint issue
GrapeBaBa Oct 17, 2025
ae7e2d2
fix: revert test lint change
GrapeBaBa Oct 17, 2025
6307180
fix: revert lint change
GrapeBaBa Oct 17, 2025
97c9e96
fix: revert lint change
GrapeBaBa Oct 17, 2025
e75d0cc
Apply suggestion from @unnawut
GrapeBaBa Oct 17, 2025
f0c47f8
Apply suggestion from @unnawut
GrapeBaBa Oct 17, 2025
53ca3fa
fix: revert linter
GrapeBaBa Oct 17, 2025
102e03b
Update src/lean_spec/subspecs/containers/vote/vote.py
GrapeBaBa Oct 21, 2025
fc371c5
fix: fix vote target
GrapeBaBa Oct 21, 2025
32f6bf8
update the produce block
g11tech Oct 22, 2025
76d6220
ammed block proposal
g11tech Oct 22, 2025
b29a454
Update src/lean_spec/subspecs/forkchoice/store.py
GrapeBaBa Oct 23, 2025
2f50980
Update src/lean_spec/subspecs/forkchoice/store.py
GrapeBaBa Oct 23, 2025
3d7f527
fix: fix review comment
GrapeBaBa Oct 23, 2025
84cd64f
Update src/lean_spec/subspecs/forkchoice/store.py
GrapeBaBa Oct 23, 2025
8dd4319
fix; fix review comments
GrapeBaBa Oct 23, 2025
dde60f7
fix: fix review comment
GrapeBaBa Oct 23, 2025
c8cba25
Merge branch 'main' into agg-block-sigs
GrapeBaBa Oct 23, 2025
50ef62c
fix: fix merge issue
GrapeBaBa Oct 23, 2025
07a4776
fix: fix review comment
GrapeBaBa Oct 24, 2025
e1f882a
fix: fix review comments
GrapeBaBa Oct 24, 2025
341b2f8
Update src/lean_spec/subspecs/containers/block/block.py
GrapeBaBa Oct 24, 2025
190a1ff
Update src/lean_spec/subspecs/containers/attestation/attestation.py
GrapeBaBa Oct 24, 2025
79513a9
Update src/lean_spec/subspecs/containers/attestation/attestation.py
GrapeBaBa Oct 24, 2025
febaaa6
fix: fix review comments
GrapeBaBa Oct 24, 2025
ebdf203
Merge branch 'main' into agg-block-sigs
GrapeBaBa Oct 24, 2025
022e02e
fix: merge issue
GrapeBaBa Oct 24, 2025
c30e1af
fix: revert
GrapeBaBa Oct 24, 2025
cab98d9
fix: lint
GrapeBaBa Oct 24, 2025
06aab37
Update tests/lean_spec/subspecs/containers/test_state.py
GrapeBaBa Oct 25, 2025
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
32 changes: 27 additions & 5 deletions src/lean_spec/subspecs/containers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,41 @@
"""The container types for the Lean consensus specification."""

from .block import Block, BlockBody, BlockHeader, SignedBlock
from .attestation import (
AggregatedAttestations,
AggregatedSignatures,
AggregationBits,
Attestation,
AttestationData,
SignedAggregatedAttestations,
SignedAttestation,
)
from .block import (
Block,
BlockBody,
BlockHeader,
BlockWithAttestation,
SignedBlockWithAttestation,
)
from .checkpoint import Checkpoint
from .config import Config
from .state import State
from .vote import SignedVote, Vote
from .validator import Validator

__all__ = [
"AggregatedAttestations",
"AggregatedSignatures",
"AggregationBits",
"AttestationData",
"Attestation",
"SignedAttestation",
"SignedAggregatedAttestations",
"Block",
"BlockWithAttestation",
"BlockBody",
"BlockHeader",
"Checkpoint",
"Config",
"SignedBlock",
"SignedVote",
"SignedBlockWithAttestation",
"Validator",
"State",
"Vote",
]
20 changes: 20 additions & 0 deletions src/lean_spec/subspecs/containers/attestation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Attestation containers and related types for the Lean spec."""

from .attestation import (
AggregatedAttestations,
Attestation,
AttestationData,
SignedAggregatedAttestations,
SignedAttestation,
)
from .types import AggregatedSignatures, AggregationBits

__all__ = [
"AttestationData",
"Attestation",
"SignedAttestation",
"SignedAggregatedAttestations",
"AggregatedAttestations",
"AggregatedSignatures",
"AggregationBits",
]
73 changes: 73 additions & 0 deletions src/lean_spec/subspecs/containers/attestation/attestation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Attestation-related container definitions."""

from lean_spec.subspecs.containers.slot import Slot
from lean_spec.types import Bytes4000, Container, Uint64

from ..checkpoint import Checkpoint
from .types import AggregatedSignatures, AggregationBits


class AttestationData(Container):
"""Attestation content describing the validator's observed chain view."""

slot: Slot
"""The slot for which the attestation is made."""

head: Checkpoint
"""The checkpoint representing the head block as observed by the validator."""

target: Checkpoint
"""The checkpoint representing the target block as observed by the validator."""

source: Checkpoint
"""The checkpoint representing the source block as observed by the validator."""


class Attestation(Container):
"""Validator specific attestation wrapping shared attestation data."""

validator_id: Uint64
"""The index of the validator making the attestation."""

data: AttestationData
"""The attestation data voted on by the validator."""


class SignedAttestation(Container):
"""Validator attestation bundled with its signature."""

message: Attestation
"""The attestation message signed by the validator."""

signature: Bytes4000
"""Signature aggregation produced by the leanVM (SNARKs in the future)."""


class AggregatedAttestations(Container):
"""Aggregated attestation consisting of participation bits and message."""

aggregation_bits: AggregationBits
"""Bitfield indicating which validators participated in the aggregation."""

data: AttestationData
"""Combined vote data similar to the beacon chain format.

Multiple validator votes are aggregated here without the complexity of
committee assignments.
"""


class SignedAggregatedAttestations(Container):
"""Aggregated attestation bundled with aggregated signatures."""

message: AggregatedAttestations
"""Aggregated vote data."""

signature: AggregatedSignatures
"""Aggregated vote plus its combined signature.

Stores a naive list of validator signatures that mirrors the attestation
order.

TODO: this will be replaced by a SNARK in future devnets.
"""
19 changes: 19 additions & 0 deletions src/lean_spec/subspecs/containers/attestation/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Attestation-related SSZ types for the Lean consensus specification."""

from lean_spec.types import Bytes4000, SSZList
from lean_spec.types.bitfields import BaseBitlist

from ...chain.config import VALIDATOR_REGISTRY_LIMIT


class AggregationBits(BaseBitlist):
"""Bitlist representing validator participation in an attestation."""

LIMIT = int(VALIDATOR_REGISTRY_LIMIT)


class AggregatedSignatures(SSZList):
"""Naive list of validator signatures used for aggregation placeholders."""

ELEMENT_TYPE = Bytes4000
LIMIT = int(VALIDATOR_REGISTRY_LIMIT)
14 changes: 11 additions & 3 deletions src/lean_spec/subspecs/containers/block/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
"""Block containers and related types for the Lean Ethereum consensus specification."""

from .block import Block, BlockBody, BlockHeader, SignedBlock
from .types import Attestations
from .block import (
Block,
BlockBody,
BlockHeader,
BlockWithAttestation,
SignedBlockWithAttestation,
)
from .types import Attestations, BlockSignatures

__all__ = [
"Block",
"BlockBody",
"BlockHeader",
"SignedBlock",
"BlockWithAttestation",
"SignedBlockWithAttestation",
"Attestations",
"BlockSignatures",
]
41 changes: 29 additions & 12 deletions src/lean_spec/subspecs/containers/block/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
from lean_spec.types import Bytes32, Uint64
from lean_spec.types.container import Container

from .types import Attestations
from ..attestation import Attestation
from .types import Attestations, BlockSignatures


class BlockBody(Container):
"""The body of a block, containing payload data."""

attestations: Attestations
"""
A list of votes included in the block.
"""Plain validator attestations carried in the block body.

Note: This will eventually be replaced by aggregated attestations.
Individual signatures live in the aggregated block signature list, so
these entries contain only vote data without per-attestation signatures.
"""


Expand Down Expand Up @@ -56,14 +57,30 @@ class Block(Container):
"""The block's payload."""


class SignedBlock(Container):
"""A container for a block and the proposer's signature."""
class BlockWithAttestation(Container):
"""Bundle containing a block and the proposer's attestation."""

message: Block
"""The block being signed."""
block: Block
"""The proposed block message."""

signature: Bytes32
"""
The proposer's signature of the block message.
Note: Bytes32 is a placeholder; the actual signature is much larger.
proposer_attestation: Attestation
"""The proposer's vote corresponding to this block."""


class SignedBlockWithAttestation(Container):
"""Envelope carrying a block, proposer vote, and aggregated signatures."""

message: BlockWithAttestation
"""The block plus proposer vote being signed."""

signature: BlockSignatures
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockSignatures sounds like a list of block signatures but it's not. Introducing Signature and Signatures seems better represent what it is and is align with other data structures such as Attestation and Attestations.

Signatures would be removed after we have LeanVM.

"""Aggregated signature payload for the block.

Signatures remain in attestation order followed by the proposer signature
over entire message. For devnet 1, however the proposer signature is just
over message.proposer_attestation since leanVM is not yet performant enough
to aggregate signatures with sufficient throughput.

Eventually this field will be replaced by a SNARK (which represents the
aggregation of all signatures).
"""
15 changes: 11 additions & 4 deletions src/lean_spec/subspecs/containers/block/types.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
"""Block-specific SSZ types for the Lean Ethereum consensus specification."""

from lean_spec.types import SSZList
from lean_spec.types import Bytes4000, SSZList

from ...chain.config import VALIDATOR_REGISTRY_LIMIT
from ..vote import SignedVote
from ..attestation import Attestation


class Attestations(SSZList):
"""List of signed votes (attestations) included in a block."""
"""List of validator attestations included in a block."""

ELEMENT_TYPE = SignedVote
ELEMENT_TYPE = Attestation
LIMIT = int(VALIDATOR_REGISTRY_LIMIT)


class BlockSignatures(SSZList):
"""Aggregated signature list included alongside the block."""

ELEMENT_TYPE = Bytes4000
LIMIT = int(VALIDATOR_REGISTRY_LIMIT)
7 changes: 7 additions & 0 deletions src/lean_spec/subspecs/containers/checkpoint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Checkpoint Container."""

from typing import Self

from lean_spec.subspecs.containers.slot import Slot
from lean_spec.types import Bytes32
from lean_spec.types.container import Container
Expand All @@ -13,3 +15,8 @@ class Checkpoint(Container):

slot: Slot
"""The slot number of the checkpoint's block."""

@classmethod
def default(cls) -> Self:
"""Return a default checkpoint."""
return cls(root=Bytes32.zero(), slot=Slot(0))
2 changes: 2 additions & 0 deletions src/lean_spec/subspecs/containers/state/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
JustificationRoots,
JustificationValidators,
JustifiedSlots,
Validators,
)

__all__ = [
Expand All @@ -14,4 +15,5 @@
"JustificationRoots",
"JustificationValidators",
"JustifiedSlots",
"Validators",
]
26 changes: 14 additions & 12 deletions src/lean_spec/subspecs/containers/state/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@
is_proposer,
)

from ..block import Block, BlockBody, BlockHeader, SignedBlock
from ..block import Block, BlockBody, BlockHeader
from ..block.types import Attestations
from ..checkpoint import Checkpoint
from ..config import Config
from ..slot import Slot
from ..vote import Vote
from .types import (
HistoricalBlockHashes,
JustificationRoots,
JustificationValidators,
JustifiedSlots,
Validators,
)


Expand Down Expand Up @@ -55,6 +55,9 @@ class State(Container):
justified_slots: JustifiedSlots
"""A bitfield indicating which historical slots were justified."""

validators: Validators
"""Registry of validators tracked by the state."""

# Justification tracking (flattened for SSZ compatibility)
justifications_roots: JustificationRoots
"""Roots of justified blocks."""
Expand Down Expand Up @@ -99,10 +102,11 @@ def generate_genesis(cls, genesis_time: Uint64, num_validators: Uint64) -> "Stat
config=genesis_config,
slot=Slot(0),
latest_block_header=genesis_header,
latest_justified=Checkpoint(root=Bytes32.zero(), slot=Slot(0)),
latest_finalized=Checkpoint(root=Bytes32.zero(), slot=Slot(0)),
latest_justified=Checkpoint.default(),
latest_finalized=Checkpoint.default(),
historical_block_hashes=HistoricalBlockHashes(data=[]),
justified_slots=JustifiedSlots(data=[]),
validators=Validators(data=[]),
justifications_roots=JustificationRoots(data=[]),
justifications_validators=JustificationValidators(data=[]),
)
Expand Down Expand Up @@ -429,8 +433,8 @@ def process_attestations(
latest_finalized = self.latest_finalized

# Process each attestation in the block.
for signed_vote in attestations:
vote: Vote = signed_vote.data
for attestation in attestations:
vote = attestation.data
source = vote.source
target = vote.target

Expand Down Expand Up @@ -484,9 +488,9 @@ def process_attestations(
}
)

def state_transition(self, signed_block: SignedBlock, valid_signatures: bool = True) -> "State":
def state_transition(self, block: Block, valid_signatures: bool = True) -> "State":
"""
Apply the complete state transition function for a signed block.
Apply the complete state transition function for a block.

This method represents the full state transition function:
1. Validate signatures if required
Expand All @@ -496,8 +500,8 @@ def state_transition(self, signed_block: SignedBlock, valid_signatures: bool = T

Parameters
----------
signed_block : SignedBlock
The signed block to apply to the state.
block : Block
The block to apply to the state.
valid_signatures : bool, optional
Whether to validate block signatures. Defaults to True.

Expand All @@ -515,8 +519,6 @@ def state_transition(self, signed_block: SignedBlock, valid_signatures: bool = T
if not valid_signatures:
raise AssertionError("Block signatures must be valid")

block = signed_block.message

# First, process any intermediate slots.
state = self.process_slots(block.slot)

Expand Down
Loading
Loading