Skip to content

Add MIP-8 page commit tests.#27

Open
mijovic wants to merge 1 commit into
forks/monad_ninefrom
mip8-page-commit-tests
Open

Add MIP-8 page commit tests.#27
mijovic wants to merge 1 commit into
forks/monad_ninefrom
mip8-page-commit-tests

Conversation

@mijovic

@mijovic mijovic commented Jun 22, 2026

Copy link
Copy Markdown

🗒️ Description

🔗 Related Issues or PRs

N/A.

✅ Checklist

  • All: Ran fast static checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    just static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.
  • Tests: For PRs implementing a missed test case, update the post-mortem document to add an entry the list.
  • Ported Tests: All converted JSON/YML tests from ethereum/tests or tests/static have been assigned @ported_from marker.

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

Greptile Summary

This PR adds a new test module for MIP-8 paged storage commitment, covering both page_commit and storage_root_paged from ethereum.paged_storage_trie.

  • Known-answer vectors: Six pinned page_commit digests are included with a clear warning that they were generated from the spec itself and must be cross-checked against the Monad reference client before being treated as canonical.
  • Property tests: Structural guarantees (length, determinism, sensitivity to value/offset, zero-page rejection, order-independence, and cross-page distinction) are validated without relying on precomputed constants.
  • Manual reconstruction test: test_single_page_root_matches_manual_reconstruction rebuilds the keccak-MPT root by hand and compares it to storage_root_paged, independently verifying slot grouping, trie key derivation, and rlp.encode(commitment) leaf framing.

Confidence Score: 5/5

Test-only addition; no production logic is changed and the new tests are consistent with the existing paged_storage_trie implementation.

The test helpers, known-answer vectors, and property assertions all match the production code exactly. Two pre-existing comment threads cover the two noted test gaps; no new correctness issues were found.

No files require special attention.

Important Files Changed

Filename Overview
packages/testing/src/execution_testing/forks/tests/test_paged_storage_trie.py New test file adding known-answer vectors and property tests for MIP-8 page commitment. Logic is consistent with the paged_storage_trie implementation; two existing comment threads cover the duplicate empty-storage test and the dead branch in the manual reconstruction.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Helpers
        H1["_page(slot_values)"]
        H2["_storage(slot_values)"]
    end
    subgraph page_commit Tests
        PC1["known_vectors"]
        PC2["length_is_32"]
        PC3["rejects_all_zero_page"]
        PC4["deterministic"]
        PC5["sensitive_to_value"]
        PC6["sensitive_to_offset"]
    end
    subgraph storage_root_paged Tests
        SR1["empty_storage_is_empty_trie_root"]
        SR2["storage_root_length_is_32"]
        SR3["order_independent"]
        SR4["distinguishes_pages"]
        SR5["clears_to_empty"]
        SR6["single_page_manual_reconstruction"]
    end
    H1 --> PC1 & PC2 & PC3 & PC4 & PC5 & PC6 & SR6
    H2 --> SR2 & SR3 & SR4 & SR5 & SR6
    PC1 & SR6 --> page_commit["page_commit() BLAKE3 ISMC"]
    SR1 & SR2 & SR3 & SR4 & SR5 & SR6 --> storage_root_paged["storage_root_paged() keccak-MPT"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph Helpers
        H1["_page(slot_values)"]
        H2["_storage(slot_values)"]
    end
    subgraph page_commit Tests
        PC1["known_vectors"]
        PC2["length_is_32"]
        PC3["rejects_all_zero_page"]
        PC4["deterministic"]
        PC5["sensitive_to_value"]
        PC6["sensitive_to_offset"]
    end
    subgraph storage_root_paged Tests
        SR1["empty_storage_is_empty_trie_root"]
        SR2["storage_root_length_is_32"]
        SR3["order_independent"]
        SR4["distinguishes_pages"]
        SR5["clears_to_empty"]
        SR6["single_page_manual_reconstruction"]
    end
    H1 --> PC1 & PC2 & PC3 & PC4 & PC5 & PC6 & SR6
    H2 --> SR2 & SR3 & SR4 & SR5 & SR6
    PC1 & SR6 --> page_commit["page_commit() BLAKE3 ISMC"]
    SR1 & SR2 & SR3 & SR4 & SR5 & SR6 --> storage_root_paged["storage_root_paged() keccak-MPT"]
Loading

Reviews (2): Last reviewed commit: "Add MIP-8 page commit tests." | Re-trigger Greptile

@mijovic mijovic requested review from QEDK and pdobacz as code owners June 22, 2026 13:21
@mijovic mijovic changed the base branch from execute-with-eestnet-mip8 to forks/monad_nine June 22, 2026 13:22
Comment on lines +187 to +203
) -> None:
"""``storage_root_paged`` matches a keccak-MPT built by hand.

Cross-checks the trie-assembly layer for a single page (page 0): slot
grouping, the ``keccak256(page_index)`` trie key, and the
``rlp.encode(commitment)`` leaf framing — independently of the BLAKE3
internals of ``page_commit``.
"""
commitment = page_commit(_page(slot_values))
key = keccak256(U256(0).to_be_bytes32())
obj = {bytes_to_nibble_list(key): rlp.encode(commitment)}

root_node = encode_internal_node(patricialize(obj, Uint(0)))
encoded = rlp.encode(root_node)
expected = keccak256(encoded) if len(encoded) < 32 else Hash32(root_node)

assert storage_root_paged(_storage(slot_values)) == expected

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 if len(encoded) < 32 branch is dead for all parametrized cases

For a single-page leaf the MPT root_node encodes to a [hex-prefix-path, rlp(commitment)] structure where the path alone is 33 bytes (0x20 || 32-byte keccak key) and the value is 33 bytes. rlp.encode(root_node) is therefore always well above 32 bytes, so the keccak256(encoded) path on line 200 is never exercised by this test. The assertion on line 203 ends up testing only the else / Hash32(root_node) branch. This is consistent with what the production code does for these inputs, but if the threshold condition was accidentally inverted in either place the test would not catch it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/testing/src/execution_testing/forks/tests/test_paged_storage_trie.py
Line: 187-203

Comment:
**`if len(encoded) < 32` branch is dead for all parametrized cases**

For a single-page leaf the MPT `root_node` encodes to a `[hex-prefix-path, rlp(commitment)]` structure where the path alone is 33 bytes (`0x20` || 32-byte keccak key) and the value is 33 bytes. `rlp.encode(root_node)` is therefore always well above 32 bytes, so the `keccak256(encoded)` path on line 200 is never exercised by this test. The assertion on line 203 ends up testing only the `else` / `Hash32(root_node)` branch. This is consistent with what the production code does for these inputs, but if the threshold condition was accidentally inverted in either place the test would not catch it.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

@mijovic mijovic changed the base branch from forks/monad_nine to forks/monad_ten June 22, 2026 13:26
@mijovic mijovic changed the base branch from forks/monad_ten to execute-with-eestnet-mip8 June 22, 2026 13:27
@mijovic mijovic force-pushed the mip8-page-commit-tests branch from 083df74 to a7da928 Compare June 22, 2026 13:29
@mijovic mijovic changed the base branch from execute-with-eestnet-mip8 to forks/monad_nine June 22, 2026 13:29

@pdobacz pdobacz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, this is a great addition to the tests of the mEELS implementation of MIP-8, but note it is not a new spec test (the remaining 3 points from your list you've sent me seem to be new spec tests)

@pdobacz

pdobacz commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

the CI failure, seems like it needs a formatter run:

uv run ruff format src packages tests && uv run ruff check src packages tests --exclude tests/fixtures --fix --unsafe-fixes

is my go-to line for this

just static

to check afterwards

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.

2 participants