erigontech / erigontech/erigon
db/integrity: detect and repair stale CodeDomain entries left by EIP-7702 delegation clears
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 1.5k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 455
Description
## Background
Root cause of #22321: erigon did not delete the `CodeDomain` entry when an EIP-7702 delegation was cleared (authorization to the zero address), leaving `account.codeHash == emptyCodeHash` alongside a stale `0xef0100‖delegate` designator in `CodeDomain`.
**Writer status:** fixed on `main` / 3.6 by #21536 (guard change inside the typed-vio refactor), pinned by the regression test in #22327. **Not fixed on any released line**: the `release/3.4` and `release/3.5` backports (#22328, #22333) were closed without merging, so every 3.x release through v3.5.x — including the current stable — writes a new residue on every delegation clear it executes, until 3.6 rolls out.
The residues **already written** persist in every datadir whose delegation-clear blocks were executed by an affected build, and they are baked into published state snapshot files, so every fresh sync inherits them. A residue heals naturally only when the address receives another code write (re-delegation), which is unbounded.
Consensus and RPC are unaffected — commitment uses the account record's code hash, and EVM/RPC code reads gate on the empty code hash before consulting `CodeDomain`.
## Update after #22701
#22321 was closed by #22701, which scoped the commitment assert to code-bearing accounts (and stopped it from mutating the trie update). Two consequences for this issue:
- The QA-unblock motivation is gone: assert-enabled nodes no longer trip on this residue class, so item 3 of the original ask (heal the QA reference datadirs to green the nightly) is obsolete.
- The inconsistency is now **silent**: no code path detects it anymore. #22701 explicitly defers the data cleanup to this issue, making the integrity check + repair proposed here the only mechanism that will ever surface or remove the residues.
Remaining cost of doing nothing: stale designators permanently baked into `CodeDomain` and every future snapshot lineage (bloat inherited by all fresh syncs), a growing residue population from 3.5.x nodes until 3.6 is the deployed stable, and a standing account↔`CodeDomain` disagreement waiting for any future consumer that assumes they agree.
## Ask
1. An integrity check for the invariant: flag `CodeDomain[addr]` non-empty where the account is missing or has the empty code hash (`db/integrity` addition, runnable via `erigon seg integrity`).
2. A repair mode that deletes such entries at latest state. This is state-root-neutral: the commitment reads the code hash from the account record, not from `CodeDomain` contents.
3. Run the repair on the datadirs that produce published snapshots, so regenerated snapshots stop carrying the residues forward.
Scan cost is one pass over `CodeDomain` latest state plus an `AccountsDomain` lookup per code-bearing key; if that is too slow the residue class from this bug can be pre-filtered to 23-byte `0xef0100…` values, at the cost of missing any residues of other origins.
Contributor guide
Assessment
This issue has not been assessed yet.