Skip to content

fix(l1): iterate from the seek key in the in-memory backend - #7137

Open
IIITManjeet wants to merge 1 commit into
lambdaclass:mainfrom
IIITManjeet:fix/in-memory-prefix-iterator-seek-semantics
Open

fix(l1): iterate from the seek key in the in-memory backend#7137
IIITManjeet wants to merge 1 commit into
lambdaclass:mainfrom
IIITManjeet:fix/in-memory-prefix-iterator-seek-semantics

Conversation

@IIITManjeet

Copy link
Copy Markdown

Motivation

Store::get_receipts_for_block_from_index builds a block_hash || start_index seek key and hands it to prefix_iterator, relying on the backend to position there and iterate forward:

let mut seek_key = prefix.clone();               // block_hash, 32 bytes
seek_key.extend_from_slice(&start_index.to_be_bytes());
let iter = txn.prefix_iterator(RECEIPTS_V2, &seek_key)?;

RocksDB's prefix_iterator_cf does exactly that, and the loop stops itself once the 32-byte block hash stops matching. The in-memory backend instead filtered on a literal key.starts_with(seek_key), so only the key equal to block_hash || start_index survived.

On EngineType::InMemory, get_receipts_for_block therefore returned a single receipt per block, no matter how many were stored — so eth_getTransactionReceipt could only ever resolve transaction index 0. EngineType::InMemory is reachable outside tests via cmd/ethrex/initializers.rs:212.

cleanup_old_witnesses is affected the same way: it iterates from the oldest witness block number and breaks past a threshold, intending to prune the whole range, but under the old filter only ever saw one block number's keys.

Description

Changes the in-memory backend's prefix_iterator to seek semantics — retain keys >= prefix, then sort — matching RocksDB. Entries were already sorted afterwards, and every caller either passes an empty prefix (the migrations, unaffected) or bounds its own scan, so no caller relies on the old truncating behaviour.

The regression test goes in the store_tests suite, which runs against every engine, so it pins in-memory/RocksDB parity rather than just in-memory correctness. It covers all three read shapes: the whole block, a non-zero start index, and a bounded count.

Question for reviewers: is EngineType::InMemory intended to be production-reachable, or is it considered test-only? That determines whether this is a user-facing RPC bug or "only" a backend-parity defect that made in-memory tests unable to observe more than one receipt per block. Either way the backends should agree, but it affects how this should be prioritised and whether it warrants a backport.

Testing

  • cargo test -p ethrex-storage — 87 passed, 0 failed
  • cargo test -p ethrex-test --test ethrex_tests storage:: — 24 passed, 0 failed
  • Negative control: with the one-line fix reverted, the new test fails exactly as predicted — 4 receipts written, 1 returned
  • cargo fmt --all -- --check clean; cargo clippy -p ethrex-storage --all-targets clean

Checklist

  • Updated STORE_SCHEMA_VERSION (crates/storage/lib.rs) if the PR includes breaking changes to the Store requiring a re-sync.

Not applicable — this changes read-path iteration only. No stored bytes, key schema, or table layout change, so no re-sync is required.

`get_receipts_for_block_from_index` builds a `block_hash || start_index`
seek key and hands it to `prefix_iterator`, relying on the backend to
position there and iterate forward. RocksDB's `prefix_iterator_cf` does
exactly that, and the caller stops itself once the 32-byte block hash
stops matching.

The in-memory backend instead filtered on `key.starts_with(seek_key)`,
so only the key equal to `block_hash || start_index` survived. On
`EngineType::InMemory`, `get_receipts_for_block` therefore returned a
single receipt per block, and `eth_getTransactionReceipt` could only
ever resolve transaction index 0.

`cleanup_old_witnesses` was affected the same way: it iterates from the
oldest witness block number and breaks past a threshold, intending to
prune the whole range, but only ever saw one block number's keys.

The regression test is added to the `store_tests` suite, which runs
against every engine, so it pins in-memory/RocksDB parity rather than
just in-memory correctness.
@IIITManjeet
IIITManjeet requested a review from a team as a code owner August 12, 2026 21:53

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@github-actions github-actions Bot added the external-contributor PR opened by a contributor outside the team label Aug 12, 2026
@IIITManjeet

Copy link
Copy Markdown
Author

Hey @ilitteri can you please have a look at my PR.
Best
Manjeet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor PR opened by a contributor outside the team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant