erigontech / erigontech/erigon

execution/cache: evaluate removing the derived addr→codeHash mapping layer

Open
#22,558 1 comment 0 reactions 2 assignees Claimed by @AskAlexSharov View on GitHub
ErigonDB
Dominant language
Go
Stars
3.6k
Forks
1.5k
Avg merge
1d 16h
Merged PRs (30d)
455

Description

## Summary

`CodeCache.addrToCodeHash` caches addr → account codeHash (zero-hash sentinel for "no code") above `SharedDomains`, so `codeHashForAddr` can answer the EXTCODESIZE / EXTCODEHASH / `GetCode` fast paths without resolving the account record. After #22444 its benefit shrank while it remains the most invalidation-heavy derived state in the shared cache. Question: does it still earn its correctness surface, or should the layer be removed?

## Why its value shrank

#22444 admits shared-cache fills only for data read from the tx snapshot whose frontier the freshness gate checks. A mapping derived from the accounts cache can lag a just-committed flush (the cache-apply loop runs after `tx.Commit`), so `codeHashForAddr` now seeds the mapping only when the accounts cache misses and the snapshot read succeeds. Consequences:

- On an accounts-cache hit, `codeHashForAddr` decodes the codeHash inline from the cached record — an LRU get plus `DeserialiseV3CodeHash`, about the same cost as a mapping hit. The mapping adds nothing there and is not even seeded.
- The mapping's remaining win is confined to addresses whose account record was evicted from the accounts cache (default 1 GB) while the mapping survives in the addr layer (16 MB, ~64 B per entry): a mapping hit then saves one cold accounts read.

## The surface it costs

- It is derived data — a projection of the account record — so every account-mutation path must invalidate it by convention rather than by construction: `StateCache.Apply` deletes it on account update, account deletion, and code deletion.
- It needs its own admission-gated fill (`PutAddrCodeHashIfFresh`) plus the snapshot-sourced-only seeding rule in `codeHashForAddr`. The stale-derived-mapping fix in #22444 was exactly this layer violating that rule: a mapping derived from a pre-apply cache read could be admitted at the `snapshotEnd == appliedEnd` boundary and then serve a stale codeHash to the `GetCodeSize`/`GetCode` fast paths, which have no authoritative fall-through for a non-zero hash.

## Proposed evaluation

Benchmark EXTCODESIZE / EXTCODEHASH / CALL-heavy workloads (benchmarkoor, eest benchmark suites) with the layer removed versus current:

- If the delta is noise: remove `addrToCodeHash`, the `GetAddrCodeHash` / `PutAddrCodeHashIfFresh` / `DeleteAddrCodeHash` API (both `StateCache` and `CodeCache` levels), the mapping-invalidation rules in `Apply`, and the source tracking in `codeHashForAddr`'s resolve — the fast paths then resolve the codeHash via mem → accounts cache → snapshot read on each call.
- If the win is real: keep the layer and close this issue with the numbers, so the invalidation rules carry a documented justification.

Refs: #22444, #22356.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.