Skip to content

refactor(types/uint): polish base uint type#769

Open
tcoratger wants to merge 6 commits into
leanEthereum:mainfrom
tcoratger:refactor-uint-polish
Open

refactor(types/uint): polish base uint type#769
tcoratger wants to merge 6 commits into
leanEthereum:mainfrom
tcoratger:refactor-uint-polish

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

Summary

  • Enforce strict same-type equality in BaseUint: Uint8(5) == Uint16(5) previously returned True while hash(Uint8(5)) != hash(Uint16(5)), silently corrupting set and dict membership. __eq__ and __ne__ now require type(other) is type(self).
  • Add parametrized tests covering every ordered pair of distinct widths, plus a sanity test that hashes still diverge across widths (consistent with the strict-eq rule).

This is the first commit in a series — more uint polish will follow on this branch.

Test plan

  • uv run pytest tests/lean_spec/types/test_uint.py — 309 passed
  • just check — ruff, format, ty, codespell, mdformat all clean

tcoratger and others added 6 commits May 24, 2026 17:17
The hash mixes in the concrete subclass, so allowing cross-width equality
broke the hash/eq contract: Uint8(5) == Uint16(5) returned True while
hash(Uint8(5)) != hash(Uint16(5)), silently corrupting set and dict
membership. Tighten __eq__ and __ne__ to require type(other) is type(self)
and add parametrized tests covering every ordered pair of distinct widths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every BaseUint binary operator now uses type(other) is type(self) instead
of isinstance(other, BaseUint). Previously, Uint8(5) + Uint16(10) silently
produced Uint8(15) because the result type defaulted to the LHS. Now any
cross-width or cross-newtype mixing raises TypeError, matching how a
strongly typed language rejects u8 + u16 or Slot + Uint64.

Also in this commit:
- __rpow__ gains the missing mod parameter for 3-arg pow.
- __pow__ uses overloads to express the parent's two-overload return shape.
- Dead _validate_int_operand helper removed (no callers remain).
- Class docstring documents the universal strict-type rule.

Consumers throughout the chain/clock, fork-choice, validator service, and
xmss code that were silently relying on cross-type interop are updated to
convert explicitly via int() or the appropriate newtype constructor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Strip backticks, drop restated-code prose, collapse multi-line docstrings to
single-sentence summaries where the signature already documents the rest, and
fix two factually wrong Raises sections that cited non-existent error types.

Add brief Why comments to the Pydantic schema body where the plumbing is
non-obvious.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every pytest.raises now anchors on the exact exception message via
re.escape, replacing partial or wildcard matches that could silently
accept the wrong error.

Add tests for the previously-untested three-argument reverse pow paths
(both the success path and the modulo type-rejection branch), lifting
uint.py coverage to 100%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Store.time is an Interval; the StoreChecks comparison field was still
typed as Uint64, which under the strict-typing rule causes Interval !=
Uint64 to raise TypeError during fixture validation. Update the field
to Interval and the two test call sites that constructed Uint64 values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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