# Ethereum zkVM: `ChainConfig` Shape in `StatelessInput` This document explores a bit the design space for including `ChainConfig` in `StatelessInput` for Ethereum guest programs. ## Context The [`StatelessInput` struct](https://github.com/ethereum/execution-specs/blob/ec23140720d6a9257a907c470ba1874623bd7b50/src/ethereum/forks/amsterdam/stateless.py#L90-L118) defines the information a guest program receives to execute a block statelessly. It currently includes a `chain_config` field of type [`ChainConfig`](https://github.com/ethereum/execution-specs/blob/ec23140720d6a9257a907c470ba1874623bd7b50/src/ethereum/forks/amsterdam/stateless.py#L77-L87). While the purpose of most `StatelessInput` fields is clear, the role of `chain_config` is less obvious. ## Why do we need this field? Start with necessity: one could argue that the guest program can already hardcode the `mainnet` chain configuration. In that model, the guest ELF already contains the configuration needed to decide which forks and parameters are active at a given block number or timestamp, so it does not need to receive that configuration as input. Omitting it also avoids deserializing and parsing the field, although that overhead is likely insignificant in the grand scheme of things. Beyond the mainnet use case, guest programs are also used in other setups: - Devnets or testnets with a `ChainConfig` different from mainnet. - EEST tests, which define [custom forks](https://github.com/jsign/execution-specs/blob/4ef381a0f75c96b52da635653ab580e731d3882a/packages/testing/src/execution_testing/forks/forks/transition.py#L19-L80) that can be quite arbitrary, such as `PragueToOsakaAt15k`. ## What are the main options? Without being exhaustive with all the design space, there are at least three main options, each with different tradeoffs. ### Option 1: `chain_config` is not part of `StatelessInput` Pros: - The guest program does not have to deserialize or parse `ChainConfig`, since it is hardcoded as a constant. This is unlikely to be meaningful overhead, but it is still saved work. - There is no risk of the host misconfiguring this input. - The verifier does not need a separate `chain_config` public input, because the accepted guest image/VK implicitly commits to the configured network. Cons: - Maintaining separate ELFs/VKs for mainnet, public testnets, private devnets, and EEST transition forks can become operationally noisy. - In particular, EEST fixture runs would require compiling guest programs into multiple ELFs depending on how many forks the fixtures target, such as Osaka, `OsakaToAmsterdamAt15k`, and Amsterdam. That is painful for testing infrastructure. - Misconfiguration risk moves from host-provided input to artifact selection: the verifier, CI, or release pipeline may accept the wrong image/VK. - A prover using the wrong ELF should produce a proof that the verifier rejects. The soundness risk appears only if the verifier or artifact-management pipeline accepts the wrong VK/image ID for the target network. - If a devnet changes an activation time or a testnet updates a parameter, the guest image/VK may need to change even when protocol semantics do not. ### Option 2: `StatelessInput` includes a full `ChainConfig` Pros: - New ELFs are still needed for new fork semantics, but not for every chain ID, devnet activation time, or EEST transition schedule. - CI pipelines and CL verification-key management are simpler. - Activation times and parameters can change without recompiling the guest, provided the relevant semantics are already implemented. - With a public `chain_config_root`, the verifier knows exactly which configuration the proof used, improving proof verifiability. Cons: - The guest program has to deserialize and parse this extra field in `StatelessInput`. As noted above, this overhead should not be significant. We could assume `None` means mainnet to optimize for the common case. - We need to standardize the shape of `ChainConfig`. One possible source of inspiration is [EIP-7910](https://eips.ethereum.org/EIPS/eip-7910). - We need to include `ChainConfig` as a public input, and the CL must verify it according to the target network. Note that `chain_config` might not need a full fork description. As EIP-7910 suggests, a current/next/last-style representation may be enough. ### Option 3: `chain_config` only references a `chain_id` (current-ish design) Pros: - `ChainConfig` is configurable through a defined set of `chain_id` values, which can distinguish between mainnet, devnets, and testnets. Cons: - This design is not enough to support EEST fixtures properly, since fixtures assume `chain_id == 1` for different fork configurations, such as `Prague` and `PragueToOsakaAt15k`. If we agree to assign explicit `chain_id` values to EEST custom forks, we could mitigate this drawback. However, this might be a breaking change for standard EL clients if they assume `chain_id` is always `1`, although that should not be too hard to fix.