Skip to content

core: better block production and usage in fixture - #218

Merged
tcoratger merged 13 commits into
leanEthereum:mainfrom
tcoratger:build-block
Dec 4, 2025
Merged

core: better block production and usage in fixture#218
tcoratger merged 13 commits into
leanEthereum:mainfrom
tcoratger:build-block

Conversation

@tcoratger

@tcoratger tcoratger commented Dec 3, 2025

Copy link
Copy Markdown
Collaborator

🗒️ Description

Now we can use the same block building function in the test fixture that we are using in the spec, making the logic more consistent and more concise.

🔗 Related Issues or PRs

Should close #167

✅ Checklist

  • Ran tox checks to avoid unnecessary CI fails:
    uvx tox
  • Considered adding appropriate tests for the changes.
  • Considered updating the online docs in the ./docs/ directory.

@tcoratger
tcoratger requested review from KolbyML and unnawut December 3, 2025 22:05
@tcoratger

Copy link
Copy Markdown
Collaborator Author

@varun-doshi What do you think about this?

We can rework this again in follow up PRs to cleanup the forkchoice store a bit but I think it solves the problems you had in #213 no?

Comment thread src/lean_spec/subspecs/containers/state/state.py Outdated

@varun-doshi varun-doshi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what if we reverse the duties of the 2 functions to something like this:

def build_block(
    self,
    slot: Slot,
    proposer_index: ValidatorIndex,
    parent_root: Bytes32,
    attestations: list[Attestation] | None = None,
) -> tuple[Block, "State", list[Attestation], list[Signature]]:

    attestations = list(attestations or [])
    signatures: list[Signature] = []

    head_state = self

    while True:
        temp_block = Block(
            slot=slot,
            proposer_index=proposer_index,
            parent_root=parent_root,
            state_root=Bytes32.zero(),
            body=BlockBody(attestations=Attestations(data=attestations)),
        )

        post_state = head_state.process_slots(slot).process_block(temp_block)

        new_attestations = []
        new_signatures = []

        for target in self.available_attestations:
            data = target.data

            if data.head.root not in self.blocks:
                continue

            if data.source != post_state.latest_justified:
                continue

            if data in (a.data for a in attestations):
                continue

            new_attestations.append(target)
            new_signatures.append(target.signature)

        if not new_attestations:
            break

        attestations.extend(new_attestations)
        signatures.extend(new_signatures)

    final_state_root = hash_tree_root(post_state)

    final_block = Block(
        slot=slot,
        proposer_index=proposer_index,
        parent_root=parent_root,
        state_root=final_state_root,
        body=BlockBody(attestations=Attestations(data=attestations)),
    )

    return final_block, post_state, attestations, signatures

and

def produce_block_with_signatures(
    self,
    slot: Slot,
    validator_index: ValidatorIndex,
) -> tuple["Store", Block, list[Signature]]:

    store = self
    head_root = store.head
    head_state = store.states[head_root]

    final_block, final_post_state, _, signatures = head_state.build_block(
        slot=slot,
        proposer_index=validator_index,
        parent_root=head_root,
    )

    block_hash = hash_tree_root(final_block)

    store = store.model_copy(
        update={
            "blocks": {**store.blocks, block_hash: final_block},
            "states": {**store.states, block_hash: final_post_state},
        }
    )

    return store, final_block, signatures

this way we are separating block production/storage and also build_block would be usable separately in test fixtures. We are also not doing the extra state computation. The naming of functions can be changed if needed

@tcoratger

Copy link
Copy Markdown
Collaborator Author

@varun-doshi should be solved, let me know what you think

@varun-doshi varun-doshi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks very neat now
lgtm

@fselmo

fselmo commented Dec 4, 2025

Copy link
Copy Markdown
Contributor

Ah yeah this is much nicer 👌🏼

@tcoratger
tcoratger merged commit edc2dbe into leanEthereum:main Dec 4, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

testing framework: use spec instead of _build_block_from_spec for forkchoice

4 participants