erigontech / erigontech/erigon
execution/cache: evaluate removing the derived addr→codeHash mapping layer
- 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
Assessment
This issue has not been assessed yet.