erigontech / erigontech/erigon
execution/state: GetCodeHash over-refresh + read-path/object-reuse follow-up (after #21536)
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 1.5k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 455
Description
Consolidated scope for the follow-up PR that comes **directly after #21536** (the typed-vio refactor). This is the exec-path / read-path work that was deliberately kept out of #21536 to keep it a mechanical type refactor (see #21536's "Explicitly deferred to the next PR" section) and is item 2 of the ordered follow-up list in #22154.
Chained to:
- #22154 — follow-up list, item 2 ("Remove the GetCodeHash over-refresh"), and its perf table (the warm-extcodehash outlier + the 5/6-rank contract cells this targets).
- #21536 — the typed surface + versionMap-as-read-source groundwork this builds on, and the review threads that deferred each item below.
## Scope
### 1. GetCodeHash over-refresh (headline)
`GetCodeHash` reads `CodeHashPath` 2–3× through the `GetCodeHash → versionedReadCore → getStateObject` nesting, plus a full-account `refreshVersionedAccount` and a per-read `SelfDestructPath` probe. Cut this to a **watermark-gated, per-field refresh**. This is the lever for the **warm-extcodehash** outlier and the contract first-touch / warm-call cells (the 5/6-rank cells in #22154's bench table).
### 2. Read-set-hit double map probe
`versionedReadCore` calls `getHeader` for the version-gating decision, then the typed wrapper re-fetches the same cell for its value (`read_paths.go`). Collapse to a single typed fetch — requires `getHeader` to carry the typed value (signature change). Same read-path surface as item 1, so done together.
### 3. cellPool utilization — VersionMap.Release() teardown walk
The `cellPool*` pools landed in #21536 as groundwork but are not reused yet (`Put` runs only on revert/conflict paths; the per-block `VersionMap` is discarded unwalked). Add the executor-teardown release walk so cross-block cell reuse actually happens — the "state cache as an object pool for the VM" step #21536 sets up.
### 4. WriteSet ownership by type
`normalizeWriteSet`'s output shares cells with `blockIO`, and the "don't mutate a shared cell" rule is enforced only by comment. Make ownership a type-level property (owned/mutable vs shared/read-only view) so a caller can't mutate a shared cell.
## Related (separately tracked — may ride along)
- #22216 — collapse `normalizeWriteSet`'s 7 write-set passes (behavior-preserving).
- #22204 — empty-code → `DomainDel` single choke point (triplicated today).
## Sequencing
Blocked on the two preceding PRs landing; the task list here is only coherent once both are in:
- **#21536** (typed-vio refactor) — provides the typed read surface + versionMap-as-read-source that items 1–2 build on, and the cellPool groundwork (item 3) and shared-cell WriteSet (item 4).
- **#22154** (cache stack consolidation) — the read/cache foundation this refreshes against; the perf targets (warm-extcodehash outlier, 5/6-rank contract cells) are measured on that stack.
Once both have landed this becomes a clean, self-contained PR. Re-run the #22154 bench afterwards to confirm the warm-extcodehash / contract-cell wins.
Contributor guide
Assessment
This issue has not been assessed yet.