SLOAD Improvements#12043
Conversation
|
Claude finished @svlachakis's task in 4m 34s —— View job Review
SummaryBoth optimizations are logically correct — no consensus bugs, no data hazards. One misleading comment and a few low-severity observations follow. FindingsMedium
The comment states Consequently the guard fires at most once per transaction (only before the very first storage access), not broadly across "read-mostly" executions as the PR description implies. The guard itself is semantically correct (empty cache ⇒ LowMemo invalidation order in _storages.ResetAndClear(); // PerContractState.Return() is called here → object is pooled
_lastStorageAddress = null; // memo nulled after pool return
_lastStorage = null;
No regression tests The PR opts out of testing for changes on the consensus-critical SLOAD hot path. At minimum, a test exercising
VerdictThe per-contract memo ( |
|
@claude I fixed the MEDIUM COMMENT problem..lol review again |
|
Claude finished @svlachakis's task in 1m 27s —— View job Review
SummaryThe medium finding from the previous review is fixed. Both optimizations are correct and clean. FindingsMedium — ✅ Resolved
The comment was updated to: // If the cache is completely empty (no writes or reads yet this transaction),
// skip hashing the 52-byte cell — TryGetValue would miss anyway.This is accurate. The old comment falsely claimed the cache "only holds journaled WRITES"; the new one correctly says "no writes or reads yet this transaction", which matches the actual semantics (both Low — unchanged from prior review
VerdictAll medium findings are resolved. The per-contract storage memo is correctly invalidated in both |
|
Claude finished @svlachakis's task in 2m 30s —— View job Review
SummaryBoth optimizations are correct. The previous Medium finding (incorrect comment) was resolved. No new issues found. Detailed walkthrough below. Per-contract memo (
|
| Path | _storages cleared |
Memo cleared |
|---|---|---|
Reset(resetBlockChanges: true) |
ResetAndClear() |
✅ |
ClearStorageMap() |
Clear() |
✅ |
After CommitCore (intra-block transaction boundary), _storages is intentionally preserved (block-scoped state) and the memo correctly keeps pointing to the last-used PerContractState, which is still live in the dict. ✅
Null safety of _lastStorage! ✅
When _lastStorageAddress == address is true and address is non-null, _lastStorageAddress was set in a prior GetOrCreateStorage call that also set _lastStorage to the non-null dict value. The ! forgiving operator is justified.
Memo update order in Reset — safe
_storages.ResetAndClear(); // Return() called → object pooled
_lastStorageAddress = null; // nulled after pool return
_lastStorage = null;There is a three-instruction window where _lastStorage references a pooled object. PersistentStorageProvider is single-threaded (one instance per execution context), so this window cannot be observed. No hazard.
Count != 0 guard (PartialStorageProviderBase.cs)
Correctness ✅
Dictionary<K,V>.Count is an O(1) field read. Skipping TryGetValue when Count == 0 is semantically equivalent to running it — it would return false. No data hazard.
Actual scope of the optimization
The comment is now accurate. Because PushToRegistryOnly adds a JustCache entry on every LoadFromTree call, Count becomes 1 after the first storage access. The guard skips the 52-byte hash once per transaction (before the first access), which is meaningful given the per-transaction Reset in CommitCore → base.CommitCore → Reset().
Low findings
No regression tests — the Count == 0 early-exit and the memo hit/miss paths are untested. Given the simplicity and the determinism of the Count == 0 path (fires at the start of every transaction after the base Reset), a simple parametric test would close this gap. Not blocking, but worth a follow-up.
WarmUp brace change — adds curly braces around a single-statement if. Style-conforming but cosmetic noise in the diff.
Verdict
No Critical, High, or Medium findings. The memo is correctly invalidated in all _storages-clearing paths, the equality check is value-based, and the Count != 0 guard comment is accurate. Ready to merge.
Changes
Per-contract storage memo
(
PersistentStorageProvider).** Consecutive SLOADs overwhelmingly hit the same contract; a one-entry memo (_lastStorageAddress→_lastStorage) removes the_storagesdictionary lookup from the per-SLOAD path. Invalidated wherever_storagesis cleared, so the pooled per-contract state is never reachable after return.Skip cell hashing on read-mostly executions
** The intra-block cache only holds journaled writes. On read-mostly executions (e.g.
eth_call) it is empty, so a_intraBlockCache.Count != 0guard skips hashing the 52-byte storage cell on every SLOAD before the lookup that would miss anyway.Types of changes
What types of changes does your code introduce?
Testing
Requires testing