Skip to content

Derive pre-block system-contract and EIP gates from the resolved spec (revm-style ordinal inclusion) #353

Description

@RealiCZ

Summary

The EVM layer derives every behavior gate from one resolved spec via ordinal inclusion (MegaSpecId::is_enabled, same design as revm's SpecId::is_enabled_in), so spec additivity is structural there.
The block layer deviates: pre-block system-contract deploys and EIP gates consult per-fork hardfork registration (is_X_active_at_timestamp) instead of the resolved spec.

With a partial-ladder hardfork config (e.g. a genesis scheduling rex6Time without rex5Time), spec_id(timestamp) resolves REX6 but the Rex5-gated pre-block setup is silently skipped: the EIP-2935/EIP-4788 fail-closed checks, the SequencerRegistry deployment/updates, and the Rex5 oracle bytecode selection.
Every canonical schedule (mainnet/testnet/all-activated constants, real genesis files) carries the complete ladder, where both gating styles are bit-for-bit equivalent — so this is unreachable on well-formed configs and purely a robustness gap.

Raised by Codex review on #348: #348 (comment)

Affected gate sites

  • block/executor.rs:179,244 — is_rex_5_active_at_timestamp (EIP-2935/4788 fail-closed + SequencerRegistry deploy/update)
  • block/eips.rs:62,131 — is_rex_5_active_at_timestamp (result handling variants)
  • system/oracle.rs:61,69,72,119 — MiniRex deploy gate + Rex5/Rex2 bytecode selection
  • system/keyless_deploy.rs:62 — Rex2
  • system/control.rs:64, system/limit_control.rs:43 — Rex4
  • system/sequencer_registry.rs:144 — Rex5

Proposed fix

Resolve spec_id(block_timestamp) once at the pre-block entry point and gate the sites above on spec.is_enabled(MegaSpecId::X).

  • On complete-ladder configs the change is observationally identical (each is_X_active_at_timestamp(ts) ⇔ spec_id(ts).is_enabled(X) when the ladder is complete with monotone times), so stable-spec behavior and replay are unaffected.
  • On partial-ladder configs, additivity becomes structural again: a Rex6-only config deploys all lower-spec system contracts at the Rex6 activation block and enforces the fail-closed checks.

Add a partial-ladder regression test: a config registering only Rex6 must deploy the registry/oracle and enforce the EIP-2935/4788 fail-closed checks at activation.

Related (separate repo)

mega-reth's MegaethChainSpec::from_genesis performs no ladder-completeness validation either (absent forks silently become ForkCondition::Never); a load-time predecessor check there is the matching defense-in-depth.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api:unchangedNo change to the public interface or APIcomp:coreChanges to the `mega-evm` core craterustPull requests that update rust codespec:stableTouches stable spec code — must not change behavior

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions