Skip to content

Add EVM storage read-ahead for sequential SLOAD#36

Merged
dominicletz merged 4 commits into
masterfrom
evm-storage-read-ahead
Jul 2, 2026
Merged

Add EVM storage read-ahead for sequential SLOAD#36
dominicletz merged 4 commits into
masterfrom
evm-storage-read-ahead

Conversation

@dominicletz

Copy link
Copy Markdown
Member

Summary

  • Add CMerkleTree.get_range/3 NIF that fetches sequential storage slots in one call (get_item/2 delegates to n=1)
  • Extend the gs port response to return the requested key plus read-ahead followers (default 10, configurable via EVM_STORAGE_READ_AHEAD)
  • Update the C++ EVMC host to populate its storage cache from the multi-value gs response

Test plan

  • mix test test/cmerkletree_test.exs test/evm_storage_readahead_test.exs
  • Replay slow eth_call (Members()) and confirm reduced RPC latency
  • Tune with EVM_STORAGE_READ_AHEAD=0 (single-slot) vs 16 if needed

Made with Cursor

Batch sequential SLOAD lookups via CMerkleTree.get_range/3 and return multiple key/value pairs per gs response so array scans like Members() avoid one IPC per slot.

Co-authored-by: Cursor <cursoragent@cursor.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a storage read-ahead mechanism for the EVM by implementing a new get_range function in the Merkle tree NIF and Elixir wrapper. This allows fetching multiple sequential storage keys in a single roundtrip, which are then cached on the C++ host side. Feedback on these changes highlights several critical improvements: a potential protocol desynchronization bug where a read-ahead count of 256 overflows an 8-bit integer to 0 (suggesting a cap of 254 instead of 255); unnecessary overhead in merkletree_get_item from using the new range lookup instead of direct lookup; a missing guard clause in Elixir's get_range/3 to enforce the maximum count of 256; and an optimization opportunity in get_range_entries to avoid an expensive vector copy by using std::move.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread lib/evm.ex Outdated
Comment thread c_src/nif.cpp Outdated
Comment thread lib/cmerkletree.ex Outdated
Comment thread c_src/nif.cpp
dominicletz and others added 3 commits July 2, 2026 22:04
Cap read-ahead at 254 so the uint8 pair count cannot wrap, restore direct get_item for single lookups, move keys in get_range_entries, and guard get_range/3 count <= 256.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use get_item for single lookups, iolist gs responses, zero-init host ret,
simplify NIF range entries, and add boundary tests for read-ahead 0 and 254.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dominicletz dominicletz merged commit 2eaeb1c into master Jul 2, 2026
2 checks passed
@dominicletz dominicletz deleted the evm-storage-read-ahead branch July 2, 2026 20:36
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