Skip to content

refactor(forks/lstar): type SignedBlock.proof and rename multi-signature types#799

Merged
tcoratger merged 3 commits into
leanEthereum:mainfrom
tcoratger:refactor/signedblock-proof-typed
May 29, 2026
Merged

refactor(forks/lstar): type SignedBlock.proof and rename multi-signature types#799
tcoratger merged 3 commits into
leanEthereum:mainfrom
tcoratger:refactor/signedblock-proof-typed

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

@tcoratger tcoratger commented May 29, 2026

Summary

Three related commits that clean up the block-level proof field:

  1. fdd0f947 — Type SignedBlock.proof as the typed envelope (later renamed to MultiMessageAggregate — see below). The field was typed as raw ByteList512KiB and producers manually called encode_bytes before storing the result; verify and post-block split paths then decode_bytes-ed it back. Promoting the field to its real type lets SSZ handle (de)serialization at the container boundary.
  2. 76ac8481 — Inline single-use type_two alias. Both verify_signatures and the sync post-block handler bound type_two = signed_block.proof and used the alias exactly once. Drop it.
  3. 7facb6d2 — Rename the multi-signature types to express what they are, not their Rust-prover convention.
    • Classes: TypeOneMultiSignatureSingleMessageAggregate, TypeTwoMultiSignatureMultiMessageAggregate.
    • Variables, test function names, and prose mentions follow.
    • External Rust binding names from leanMultisig-py (aggregate_type_1, verify_type_1, merge_many_type_1, split_type_2_by_msg, verify_type_2_with_messages) are unchanged. Snappy's unrelated "Copy Type 1/2" in node/snappy/encoding.py is also untouched.

Notes

  • The on-wire SSZ encoding of SignedBlock is unchanged — Container { proof: ByteList512KiB } and a bare ByteList512KiB produce the same [4-byte offset = 4][bytes] layout under a parent container's offset region.
  • hash_tree_root(SignedBlock) will change because Container merkleization differs from List[byte] merkleization. Any consensus fixtures or downstream code that hardcode block roots will need regeneration.

Diff size

Commit Files Lines
Type the field 11 +33 / −53
Inline alias 2 +2 / −5
Rename 26 +265 / −236

Test plan

  • just check — lint, format, ty, codespell, mdformat all clean
  • Targeted pytest on the most-affected files (validator service, xmss aggregation, attestation target fork choice, reqresp client range) — 99 passed
  • Full unit-test suite on CI
  • Regenerate consensus fixtures (uv run fill --fork=lstar --clean -n auto) and confirm any block-root-dependent vectors update cleanly

🤖 Generated with Claude Code

tcoratger and others added 3 commits May 29, 2026 17:42
The field was typed as raw ByteList512KiB and producers manually called
encode_bytes before storing the result; verify_signatures and the
post-block split path then decode_bytes-ed it back. Promote the field
to its real type so SSZ handles the (de)serialization once at the
container boundary.

- Removes the encode-then-wrap dance in the validator service and test
  builders.
- Removes the try/decode_bytes/except blocks in verify_signatures and
  the sync service post-block handler.
- Updates SSZ round-trip tests, fork choice tests, and reqresp client
  helpers to construct the typed envelope directly.
- Deletes four tautological decode-smoke assertions in test_service.py
  now that the Pydantic-validated field guarantees the shape.

The on-wire SSZ encoding of SignedBlock is unchanged; hash_tree_root
will change because Container merkleization differs from List[byte]
merkleization, so consensus fixtures that hardcode block roots need
regeneration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both call sites used the local alias exactly once. Drop it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ggregate / MultiMessageAggregate

TypeOneMultiSignature and TypeTwoMultiSignature were named after the
underlying Rust prover convention, not what they semantically are.
Rename them to express the actual data: an aggregate over a single
message versus an aggregate over many distinct messages.

- Classes: TypeOneMultiSignature -> SingleMessageAggregate,
  TypeTwoMultiSignature -> MultiMessageAggregate
- Variables and locals follow the snake_case form:
  type_1 -> single_message_aggregate, type_2 -> multi_message_aggregate
  (plus the compound forms type1_wire, type2_wire, block_t1,
  proposer_type_1, etc.)
- Test function names match: test_type_one_* -> test_single_message_*,
  test_type_two_* -> test_multi_message_*
- Prose mentions of "Type-1" / "Type-2" in docstrings and comments
  become "single-message aggregate" / "multi-message aggregate"

External Rust binding names (aggregate_type_1, verify_type_1,
merge_many_type_1, split_type_2_by_msg, verify_type_2_with_messages)
come from the leanMultisig-py package and are left untouched.

The "Type 1" / "Type 2" mentions in node/snappy/encoding.py refer to
Snappy's Copy Type 1 / Copy Type 2 wire encodings and are unrelated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tcoratger tcoratger changed the title refactor(forks/lstar): type SignedBlock.proof as TypeTwoMultiSignature refactor(forks/lstar): type SignedBlock.proof and rename multi-signature types May 29, 2026
@tcoratger tcoratger merged commit 356a516 into leanEthereum:main May 29, 2026
13 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.

1 participant