Try   HackMD

Abstract

This document describes an RPC method that provides node-relevant configuration data for the current and next fork.

Motivation

Throughout Ethereum's history, there have been multiple instances where a client was not correctly configured for an upcoming hard fork, causing it to fall out of consensus when the fork boundary was crossed. Most incidents have been minor, such as a single client forking the chain in proof-of-work or having its blocks orphaned in proof-of-stake.

The most significant occurrence was during the Pectra activation on the Holesky testnet. Four out of six clients on the network had an incorrect configuration for the deposits contract. Instead of being orphaned, the incorrect chain was justified, and the side effects persist on Holesky even after reaching finality.

By providing an RPC method that allows clients to report key configuration variables before the next hard fork, operations teams can gain greater confidence that clients are correctly configured and prepared for upcoming forks.

Target Audience and Use Cases

This method is intended for node operators, validator teams, and network monitoring tools to verify client readiness for upcoming forks. Use cases include:

  • Automated pre-fork validation scripts comparing eth_config outputs across nodes.
  • Manual checks by validator operators to ensure alignment with fork specifications.
  • Debugging by client developers to identify configuration mismatches.
  • Automated checks by Consensus Layer counterparties

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Clients MUST expose a new RPC method to report the current functional configuration and the expected next configuration via the standard JSON-RPC port.

Clients MAY also expose this method through the Engine API.

Clients MAY use these configuration objects to manage their per-fork configurations, though they SHOULD NOT simply return unprocessed configuration data.

When reporting the current and next configurations, clients MUST include every configuration parameter specified in this EIP.

Clients MUST return up-to-date configuration values, reflecting the most recent block header they provide. If clients cache the configuration, they MUST ensure such caches are purged when fork boundaries are crossed.

Configuration RPC

A new JSON-RPC API, eth_config, is introduced. It takes no parameters and returns the result object specified in the next section.

Result Object Structure

The RPC response contains four members of two types:

The "current" and "next" members contain the configuration object currently in effect and the next configuration, respectively, or null if the client is not configured to support a future fork.

The "currentHash" and "nextHash" members contain the hash of the current configuration and the next configuration, respectively, or null if the next configuration is also null.

Converting a Fork Configuration to a Hash

To generate a fork hash, the JSON object representing the fork configuration is converted into canonical form as per RFC-8785 (in short no whitespace, sorted keys, and numeric values in their simplest form). The result is then hashed using CRC-32.

The configuration object MUST contain exactly the parameters specified in the fork’s meta-EIP and their configured values—no more, no less. Explanatory comments or client-specific extensions MUST NOT be included in the resulting object.

Fields in the Configuration Object

Each configuration object MUST contain the following fields, presented in canonical order. This RPC assumes the network is post-merge, and no accommodations are specified for proof-of-work-related issues.

Future forks may add, adjust, remove, or update fields. The respective changes MUST be defined in their respective meta-EIPs.

activationTime

The fork activation timestamp, represented as a JSON number in Unix epoch seconds (UTC). For the "current" configuration, this reflects the actual activation time; for "next," it is the scheduled time if known, or null if unscheduled.

blobsSchedule

The blob configuration parameters for the specific fork, as defined in the genesis file. This is a JSON object with three members — basefeeUpdateFraction, max, and target — all represented as JSON numbers.

chainId

The chain ID of the current network, presented as a string with an unsigned 0x-prefixed hexadecimal number, with all leading zeros removed. This specification does not support chains without a chain ID or with a chain ID of zero.

precompiles

A representation of the active precompile contracts for the fork. If a precompile is replaced by an on-chain contract, it is not included.

This is a JSON object where the members are the 20-byte 0x-prefixed hexadecimal addresses of the precompiles (with zeros preserved), and the values are agreed-upon names for each contract, typically specified in the EIP defining that contract.

For Cancun, the contract names are (in order): ECREC, SHA256, RIPEMD160, ID, MODEXP, BN256_ADD, BN256_MUL, BN256_PAIRING, BLAKE2F, KZG_POINT_EVALUATION.

For Prague, the added contracts are (in order): BLS12_G1ADD, BLS12_G1MULTIEXP, BLS12_G2ADD, BLS12_G2MULTIEXP, BLS12_PAIRING, BLS12_MAP_FIELD_TO_CURVE, BLS12_MAP_FIELD_TO_CURVE.

systemContracts

A JSON object representing system-level contracts relevant to the fork, as introduced in their defining EIPs. Keys are the contract names (e.g., BEACON_ROOTS_ADDRESS) from the first EIP where they appeared, sorted alphabetically. Values are 20-byte addresses in 0x-prefixed hexadecimal form, with leading zeros preserved. Omitted for forks before Cancun.

For Cancun the only system contract is BEACON_ROOTS_ADDRESS.

For Prague he system contracts are (in order) BEACON_ROOTS_ADDRESS, CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, DEPOSIT_CONTRACT_ADDRESS, HISTORY_STORAGE_ADDRESS, and WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS.

Future forks MUST define the list of system contracts in their meta-EIPs.

Rationale

Why Enumerate Precompiles? (And in General, Why Track a Particular Config Item?)

The purpose of this specification is to enable nodes to advertise, prior to a fork, that they have the correct configurations loaded and ready. Past testnet and mainnet forks have revealed clients with incorrect precompile sets, chain IDs, deposit contract addresses, and other configuration errors.

For precompiles in particular there has been discussion about removing or replaceing precomiles in future forks, so a full enumeration of precompiles will reflect removal.

Generally, if a configurable variable or constant causes a client to diverge at a fork—whether on mainnet, a testnet, a devnet, or a public rollup—that variable or constant is a candidate for inclusion in the reportable configuration.

Full Configs Instead of Deltas

An initial design considered using a partial configuration for the "next" fork instead of a complete one. However, analysis of past events showed that some parameters causing divergence (e.g., the deposit contract) were introduced in earlier forks, with consensus failures occurring in later forks due to unrelated EIPs relying on those configurations. A partial "next" configuration hash would not have detected such errors.

An alternative—embedding the prior fork’s hash in the next fork—would require defining rules for extracting differences and merging configurations, as well as specifying all prior fork configuration hashes. This would also complicate retroactively adding parameters (e.g., gas schedule constants and variables).

Nested vs. Flat Variables

Nested structures are easier to read, while flat structures are easier to merge. Since this specification uses full configurations for the current and next forks, merging is unnecessary, making readability the priority.

Serving Data Not Specified in genesis.json

Some reported values are specification-level constants, which many clients do not include in their configuration files. However, certain EIP constants (e.g., the deposit contract) have become variables in testnets, necessitating their inclusion.

JSON as Config Format

JSON was chosen for its ubiquity, machine and human readability, and the existence of a standardized canonical form via RFC-8785. YAML lacks a standard canonical form. No Ethereum software uses XML for configuration, and adopting it would increase every client’s library size. An invented format is possible but would require definition and standardization within this specification.

CRC-32 as Hash Format

The reasons for using CRC-32 instead of a cryptographic hash are the same as those in EIP-2124, incorporated by reference. In brief, nodes can lie, the 4-byte reduction is for convenience rather than security, and CRC-32 is widely implemented.

Backwards Compatibility

This EIP does not alter previous behavior. Configurations prior to Cancun are non-standard, and clients sharing pre-Cancun configurations will produce non-standard results.

Clients supporting pre-Cancun forks MAY return partial or non-standard configurations but SHOULD strive to follow the spirit of the fields specified for Cancun configurations. Full compliance is REQUIRED only for Cancun and later forks.

Test Cases

Sample Configs

Holesky Prague Config

{
  "activationTime": 1740434112,
  "blobSchedule": {
    "baseFeeUpdateFraction": 5007716,
    "max": 9,
    "target": 6
  },
  "chainId": "0x4268",
  "precompiles": {
    "0x0000000000000000000000000000000000000001": "ECREC",
    "0x0000000000000000000000000000000000000002": "SHA256",
    "0x0000000000000000000000000000000000000003": "RIPEMD160",
    "0x0000000000000000000000000000000000000004": "ID",
    "0x0000000000000000000000000000000000000005": "MODEXP",
    "0x0000000000000000000000000000000000000006": "BN256_ADD",
    "0x0000000000000000000000000000000000000007": "BN256_MUL",
    "0x0000000000000000000000000000000000000008": "BN256_PAIRING",
    "0x0000000000000000000000000000000000000009": "BLAKE2F",
    "0x000000000000000000000000000000000000000a": "KZG_POINT_EVALUATION",
    "0x000000000000000000000000000000000000000b": "BLS12_G1ADD",
    "0x000000000000000000000000000000000000000c": "BLS12_G1MULTIEXP",
    "0x000000000000000000000000000000000000000d": "BLS12_G2ADD",
    "0x000000000000000000000000000000000000000e": "BLS12_G2MULTIEXP",
    "0x000000000000000000000000000000000000000f": "BLS12_PAIRING",
    "0x0000000000000000000000000000000000000010": "BLS12_MAP_FIELD_TO_CURVE",
    "0x0000000000000000000000000000000000000011": "BLS12_MAP_FIELD_TO_CURVE"
  },
  "systemContracts": {
    "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
    "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS": "0x0000bbddc7ce488642fb579f8b00f3a590007251",
    "DEPOSIT_CONTRACT_ADDRESS": "0x4242424242424242424242424242424242424242",
    "HISTORY_STORAGE_ADDRESS": "0x0000f90827f1c53a10cb7a02335b175320002935",
    "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS": "0x00000961ef480eb55e80d19ad83579a64c007002"
  }
}

Holesky Cancun Config

{
  "activationTime": 1707305664,
  "blobSchedule": {
    "baseFeeUpdateFraction": 3338477,
    "max": 6,
    "target": 3
  },
  "chainId": "0x4268",
  "precompiles": {
    "0x0000000000000000000000000000000000000001": "ECREC",
    "0x0000000000000000000000000000000000000002": "SHA256",
    "0x0000000000000000000000000000000000000003": "RIPEMD160",
    "0x0000000000000000000000000000000000000004": "ID",
    "0x0000000000000000000000000000000000000005": "MODEXP",
    "0x0000000000000000000000000000000000000006": "BN256_ADD",
    "0x0000000000000000000000000000000000000007": "BN256_MUL",
    "0x0000000000000000000000000000000000000008": "BN256_PAIRING",
    "0x0000000000000000000000000000000000000009": "BLAKE2F",
    "0x000000000000000000000000000000000000000a": "KZG_POINT_EVALUATION"
  },
  "systemContracts": {
    "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02"
  }
}

Sample JSON-RPC

The following RPC command, issued on Holesky when Prague was scheduled but not activated:

curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_config","id":1}' http://localhost:8545

would return (after formatting):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "current": {
      "activationTime": 1707305664,
      "blobSchedule": {
        "baseFeeUpdateFraction": 3338477,
        "max": 6,
        "target": 3
      },
      "chainId": "0x4268",
      "precompiles": {
        "0x0000000000000000000000000000000000000001": "ECREC",
        "0x0000000000000000000000000000000000000002": "SHA256",
        "0x0000000000000000000000000000000000000003": "RIPEMD160",
        "0x0000000000000000000000000000000000000004": "ID",
        "0x0000000000000000000000000000000000000005": "MODEXP",
        "0x0000000000000000000000000000000000000006": "BN256_ADD",
        "0x0000000000000000000000000000000000000007": "BN256_MUL",
        "0x0000000000000000000000000000000000000008": "BN256_PAIRING",
        "0x0000000000000000000000000000000000000009": "BLAKE2F",
        "0x000000000000000000000000000000000000000a": "KZG_POINT_EVALUATION"
      },
      "systemContracts": {
        "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02"
      }
    },
    "currentHash": "9c186ad4",
    "next": {
      "activationTime": 1740434112,
      "blobSchedule": {
        "baseFeeUpdateFraction": 5007716,
        "max": 9,
        "target": 6
      },
      "chainId": "0x4268",
      "precompiles": {
        "0x0000000000000000000000000000000000000001": "ECREC",
        "0x0000000000000000000000000000000000000002": "SHA256",
        "0x0000000000000000000000000000000000000003": "RIPEMD160",
        "0x0000000000000000000000000000000000000004": "ID",
        "0x0000000000000000000000000000000000000005": "MODEXP",
        "0x0000000000000000000000000000000000000006": "BN256_ADD",
        "0x0000000000000000000000000000000000000007": "BN256_MUL",
        "0x0000000000000000000000000000000000000008": "BN256_PAIRING",
        "0x0000000000000000000000000000000000000009": "BLAKE2F",
        "0x000000000000000000000000000000000000000a": "KZG_POINT_EVALUATION",
        "0x000000000000000000000000000000000000000b": "BLS12_G1ADD",
        "0x000000000000000000000000000000000000000c": "BLS12_G1MULTIEXP",
        "0x000000000000000000000000000000000000000d": "BLS12_G2ADD",
        "0x000000000000000000000000000000000000000e": "BLS12_G2MULTIEXP",
        "0x000000000000000000000000000000000000000f": "BLS12_PAIRING",
        "0x0000000000000000000000000000000000000010": "BLS12_MAP_FIELD_TO_CURVE",
        "0x0000000000000000000000000000000000000011": "BLS12_MAP_FIELD_TO_CURVE"
      },
      "systemContracts": {
        "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
        "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS": "0x0000bbddc7ce488642fb579f8b00f3a590007251",
        "DEPOSIT_CONTRACT_ADDRESS": "0x4242424242424242424242424242424242424242",
        "HISTORY_STORAGE_ADDRESS": "0x0000f90827f1c53a10cb7a02335b175320002935",
        "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS": "0x00000961ef480eb55e80d19ad83579a64c007002"
      }
    },
    "nextHash": "1c6a3b9f"
  }
}

Reference Implementation

Sample Implementation in Besu

Security Considerations

  • Exposure Risks: Incorrect configurations could leak operational details. Operators SHOULD restrict eth_config to trusted interfaces (e.g., local access or authenticated endpoints).
  • Dishonest Nodes: Clients may report false configurations. Peers or monitoring tools MAY cross-check eth_config outputs against known fork specifications or other nodes’ responses to detect anomalies.
  • DDoS Mitigation: Clients SHOULD cache configuration objects internally and rate-limit eth_config requests to prevent resource exhaustion. Implementations MAY impose a minimum response interval (e.g., 1 second).

Copyright and related rights waived via CC0.