Skip to content

fix(ssz): read generalized index paths as the SSZ specification does - #2516

Merged
tcoratger merged 1 commit into
ethereum:masterfrom
tcoratger:ssz-path-names
Nov 14, 2026
Merged

tcoratger merged 1 commit into
ethereum:masterfrom
tcoratger:ssz-path-names

Conversation

@tcoratger

Copy link
Copy Markdown
Collaborator

ssz.get_generalized_index now reads a path as the consensus specification does.
A field of a container is named, never given by its position, and the words __active_fields__ and __selector__ select the mixed-in nodes of a progressive container and of a union.

Part of #2480

The problem

The consensus specification computes generalized indices with get_generalized_index(type, *path).
In the release that tests/sources.toml pins, a part of the path that steps into a container must be a field name.
An integer there is an error: for a container C, the path (2,) raises "C has no field named 2".

The export added in #2508 took an integer as the position of the field.
So a caller that relied on the error, such as a negative test, got an index instead.

The same reader also names the field layout of a progressive container __active_fields__, and the selector of a union __selector__.
Both are the right child of their node.
The export knew only __len__, so it refused both words, although the SSZ library has a step for each.

The idea

The step reader of the export now refuses an integer when the type it has reached is a container or a progressive container.
Every other shape keeps its integer steps: elements of lists and vectors, bits of bitfields, and the selector of a union.
EthLib's own paths in Lean still select fields by position; only the Python path changes.
The two words map to the existing steps for the field layout and the selector, and behave like __len__ past the tree.

Example

For NESTED, a container whose second field pair is itself a container:

  • get_generalized_index(NESTED, "pair") is 5, as before.
  • get_generalized_index(NESTED, 1) was 5, and is now refused with path: no field 1.
  • get_generalized_index(NESTED, "pair", 0) is refused with path: no field 0.
  • For SQUARE, a progressive container, get_generalized_index(SQUARE, "__active_fields__") is 3, the right child of the root, as in the reference.

For reviewers

  • The error is the one an unknown field name gets, so a caller sees one kind of fault for a field that a path does not name.
  • A path that has already left the tree keeps its old error: the step reader sees no type there.
  • The same release gives no branch for the root, generalized index 1: its build_proof raises "the root has no proof branch of its own".
    EthLib's export refuses index 1 too, so that point of feat(ssz): export generalized indices, Merkle proofs and chunk roots #2508 needs no change.

Checks

  • lake build --wfail Exports, lake exe gen-bindings (contract regenerated for the changed doc): passed.
  • scripts/check_lean_layout.py --base upstream/master, scripts/check_layers.py: passed.
  • ruff check, ruff format --check, ty check, scripts/check_python_comments.py --all: passed.
  • pytest bindings/python/tests/ssz: 4266 passed, 3 skipped.
  • 57 type-and-path cases compared with the SSZ package of the pinned consensus-specs release: the same outcome and index on each.
    The two words were the one divergence that comparison found; they now give 3, as the reference does.
  • Statement audit (FULL) and spec-fidelity review: no CRITICAL or MAJOR finding left.

🤖 Generated with Claude Code

A field of a container is named, never given by its position: the export
took a position there, and now refuses it with the error for an unknown
field. A path also takes `__active_fields__` and `__selector__`, the
mixed-in nodes of a progressive container and of a union, which the
export refused.

Part of ethereum#2480

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tcoratger
tcoratger merged commit fcf08cb into ethereum:master Nov 14, 2026
12 of 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