erigontech / erigontech/erigon
Rationalize normalizeWriteSet: collapse its 7 write-set passes (behavior-preserving)
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 1.5k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 455
Description
### Summary
`normalizeWriteSet` (`execution/stagedsync/exec3_parallel.go`) makes **seven** separate passes over the write-set collections, including two full `writes.AllHeaders()` walks. It should be rationalized to fewer passes.
### The passes today
1. `writes.SelfDestructs()` — build the self-destruct set
2. `writes.AllHeaders()` — main filter loop
3. `writes.AllHeaders()` — **again**, only to collect `allAddresses`
4. `filtered.AllHeaders()` — build `addrFields` (which fields are already present)
5. `allAddresses` — account-field backfill (version map → state reader)
6. `filtered.Codes()` — `codeInOutput`
7. `filtered.CodeHashes()` — `codeHashInOutput` (CodePath-travels-with-CodeHash recovery)
The two `writes.AllHeaders()` passes (2 and 3) are plainly redundant — `allAddresses` can be gathered during pass 2. Passes 4/6/7 over `filtered` can largely fold into the backfill.
### Why it's non-trivial (and gated on tests)
The main loop is ordering- and state-dependent: the self-destruct storage-delete cascade, per-slot no-op filtering (version-map floor vs SD-zero baseline vs state-reader pre-block vs SD history scan), account-field resolution, EIP-161 empty-account removal, and the 7702 CodePath recovery all interact. It's a consensus-critical path (a mistake is a wrong trie root), so it needs a full characterization-test net before refactoring.
### Test net (in place)
Existing unit coverage in `exec3_finalize_test.go` / `calc_state_test.go` plus the branches added in PR #21536 (`1c6c29e7e0`):
- metamorphic same-tx SELFDESTRUCT-then-CREATE2 keeps recreate writes
- stale (non-validated) incarnation SelfDestructPath ignored
- post-self-destruct zero storage write dropped via the SD history scan
- CREATE2-after-SD zeroes missing fields (not stale pre-SD values); value-transfer resurrect inherits them
- storage write-back of the pre-block value dropped via the state reader
These plus the end-to-end `execmodule` reorg/SD tests (`TestDeleteRecreateSlots*`, `TestSelfDestructReceive`, `TestCVE2020_26265`, `TestRecreateAndRewind`) should stay green across the refactor.
### Scope
Pure refactor — no behavior change. Fold the redundant passes, keep every listed test green. Split out from PR #21536 (typed-vio) so that PR stays scoped to correctness + the safe hot-path wins.
Contributor guide
Research direction
Start with normalizeWriteSet in execution/stagedsync/exec3_parallel.go and trace the existing write-set passes and their state-dependent ordering. Run the coverage in exec3_finalize_test.go and calc_state_test.go, including the branches from PR #21536, then the execmodule reorg and self-destruct tests. Done means fewer passes with behavior unchanged and every listed test remaining green.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, performance
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100