Skip to content

fix(genesis): install canonical EIP-2935 block hash history - #74

Merged
shu-unifra merged 5 commits into
dogeos-v0.3.0-developfrom
fix/73-eip2935-history-genesis
Oct 9, 2026
Merged

shu-unifra merged 5 commits into
dogeos-v0.3.0-developfrom
fix/73-eip2935-history-genesis

Conversation

@shu-unifra

@shu-unifra shu-unifra commented Oct 8, 2026 •

Copy link
Copy Markdown

The fresh-chain genesis template enables Feynman at timestamp zero, but the generated alloc omitted its EIP-2935 history account. Both inspected DogeOS execution client families already issue the pre-transaction system call after Feynman, so a missing account leaves L2 hash history empty and makes post-Feynman BLOCKHASH return zero. From block 1 the system call records the parent hash (block 1 stores the genesis hash), and BLOCKHASH reads the same history ring.

Install the canonical 83-byte runtime at 0x0000F90827F1C53a10cb7A02335B175320002935, with nonce 1 and empty history. Pin its code hash in tests and install it directly without a proxy. The existing fork schedule is unchanged.

This changes the mainnet genesis state root and genesis hash. Before the October 13, 2026 mainnet rehearsal, regenerate the Reth mainnet genesis JSON, DOGEOS_MAINNET_GENESIS_HASH and its test, the rollup-node chain spec, and the release images and tag together, alongside the other pending mainnet genesis fixes. All must refer to the same regenerated genesis.

Add runtime and genesis serialization tests, a reproducible generated-genesis/geth StateProcessor integration test, and a read-only RPC smoke checker that can compare history, block hashes, and state roots across endpoints. State reads use EIP-1898 canonical block-hash snapshots, the expected parent is anchored to the selected header, and a final header check rejects reorgs during verification. Unsupported snapshot requests fail without a height-based fallback. The Foundry CI job runs both the RPC regression tests and the actual gen-configs.sh image entrypoint with output-account assertions on the final YAML artifact (including frontend and address exports); the latter does not require a client checkout and links artifacts/ and cache/ into staging to reuse the preceding CI build. Document the audited client revisions, system-call requirements, and separate installation paths for fresh and existing networks.

The existing docker/scripts/verify.sh workflow also checks the canonical history account using cast. It compares exact runtime and nonce 1 at a single block hash, independently of deployment-address configuration. Missing code (0x) emits a warning and skips the history runtime/nonce check so older devnets can still verify. Noncanonical runtime, an installed account with a nonce other than 1, or an RPC failure still causes a nonzero exit. A missing history account does not hide other source-verification failures. This is explicitly reported as runtime/account validation; the Solidity constants library is not submitted as the history runtime's explorer source.

Validation:

  • Original image validation, before the missing-account warning compatibility update: built Dockerfile.base and all three runtime Dockerfiles locally on linux/amd64 using the pinned Foundry v1.3.0-rc2. Ran the default gen-configs ENTRYPOINT and validated its actual YAML artifacts; ran the deploy ENTRYPOINT with real simulation/broadcast against a disposable Anvil initialized from that genesis; verified deployed contracts and preservation of the history account. Ran the verify image ENTRYPOINT with real cast and mocked explorer submissions: canonical account succeeds; missing runtime and wrong nonce fail. No image was published and no live network was used.
  • python3 -m unittest discover -s scripts/integration -p 'test_block_hash_history.py' -v: 5 passed; the original smoke checker fails the new regression tests.
  • python3 scripts/integration/test-eip2935.py --genesis-only: passed. Removing setBlockHashHistory() from the production genesis entry point in an isolated copy makes this check fail with a missing-account error. Both checks are wired into Foundry CI.
  • forge test --evm-version cancun: 556 passed, 0 failed.
  • python3 scripts/integration/test-eip2935.py --geth-repo /path/to/go-ethereum, using revision 33c46866196da34484bf1bfbaab20aa4929b3fcc: passed. Runs the generator image entrypoint in a temporary directory, unwraps its genesis YAML for geth; signed user transactions in blocks 1 and 2 read the correct parent through the history contract and BLOCKHASH. Block gas equals receipt gas.
  • Runtime tests cover malformed input, current/future/expired queries, the inclusive 8191-block boundary, full rollover, ordinary callers being unable to write, and partially filled history after modeled later activation.
  • node --test docker/scripts/verify.test.js: 16 passed after the compatibility update. Covers protocol address, fixed-block reads, missing-account warnings, malformed/noncanonical bytecode, wrong nonce, RPC failures, and preservation of source-verification failures when history is missing.
  • ESLint, Prettier and git diff --check: passed.

Scope and remaining release gates:

  • The geth execution test adapts only two legacy L1 metadata JSON fields; it preserves the generated alloc and uses a fake sealing engine. It does not qualify legacy geth for Tsuki consensus.
  • Reth execution and cross-client replay/state-root equivalence remain unverified. The available local Reth release image could not start its isolated --test path without the test-utils build support; no successful Reth integration run is claimed.
  • Existing deployed account state, a coordinated installation boundary/client release, activation/reorg tests, cold-access accounting, and BLOCKHASH compatibility across that boundary still require client/network qualification. This PR does not change an existing network's genesis or activate a fork there.

Refs #73. Keep the issue open for the remaining client/network acceptance criteria.

@dghelm dghelm left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shu-unifra Codex and Claude both reviewed this, and the fix is correct and matches dogeos-reth. From block 1 the system call records the parent hash (block 1 stores the genesis hash), and post-Feynman BLOCKHASH reads the same ring. Without this account, BLOCKHASH returns 0 on a chain that starts with Feynman active, so this is an opcode fix as well as a history fix. Testnet's manually deployed account already matches the canonical runtime (same code hash) with nonce 1, so the new verify check passes there.

Mainnet genesis gets regenerated before the Oct 13 rehearsal, so we'd like to merge this soon. Three small changes first:

  1. Say explicitly, in the PR and in docs/eip-2935.md, that adding the account changes the mainnet genesis hash. The reth mainnet genesis JSON, DOGEOS_MAINNET_GENESIS_HASH and its test, the rollup-node chain spec, and the release images and tag must be regenerated together, alongside the other pending mainnet genesis fixes.
  2. verify-contracts.js: warn instead of failing when the history account is missing, so older devnets that predate it still verify. Keep failing on a wrong runtime or nonce.
  3. Fix the broken Markdown table in docs/eip-2935.md (around line 15).

Follow-up, not blocking: the essential change is about 40 lines: the runtime constant, the genesis install and its tests, and the generator-entrypoint check (keep that one, since the Forge harness installs the account directly and wouldn't catch a missing call in the generator). These could move to a separate tooling and docs PR:

  • the geth Go integration test (no go.mod here, and it doesn't run in CI);
  • the RPC checker and its tests;
  • most of the 183-line doc, which covers activation on existing networks.

Separately, the CI genesis-only check cold-compiles everything. Linking artifacts/ and cache/ into its staging dir should save a few minutes.

@shu-unifra
shu-unifra merged commit 6804882 into dogeos-v0.3.0-develop Oct 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants