ZEVM Internal Support: Light Mode Semantics
ZEVM Internal Support: Light Mode Semantics
Section titled “ZEVM Internal Support: Light Mode Semantics”This page supports the normative light-mode contract in:
docs/specs/prd.mddocs/specs/json-rpc-contract.md
1. Runtime Role
Section titled “1. Runtime Role”Light mode is a read-only runtime that serves proof-backed execution-state reads.
Supported RPC surface:
zevm_lightSyncStatuseth_chainIdeth_blockNumbereth_getBalanceeth_getCodeeth_getStorageAteth_getTransactionCount
Unsupported in light mode (-32010) includes:
eth_call(proof-backed target deferred in phase 1)eth_estimateGaseth_feeHistoryeth_sendTransaction,eth_sendRawTransactioneth_getBlockByNumber,eth_getBlockByHasheth_getBlockTransactionCountByHash,eth_getBlockTransactionCountByNumbereth_getTransactionByHash,eth_getTransactionByBlockHashAndIndex,eth_getTransactionByBlockNumberAndIndex,eth_getTransactionReceipteth_getBlockReceipts,eth_getLogs- all trusted-only dev-node controls (
zevm_*mutation/mining/snapshot/impersonation controls)
2. Networks And Chain IDs
Section titled “2. Networks And Chain IDs”Light mode supports exactly:
mainnet->0x1sepolia->0xaa36a7(11155111)holesky->0x4268(17000)
eth_chainId must return the fixed mapping for the selected network.
Network-set governance:
- phase-1 light-network set is closed and exact:
mainnet,sepolia,holesky - adding, removing, or renaming a supported light network is a normative contract change and requires synchronized updates to
docs/specs/prd.mdanddocs/specs/json-rpc-contract.md
Startup input rule:
consensusRpcUrlmust serve the same network selected bynetwork- checkpoint startup inputs from CLI/config (
--checkpoint,mode.light.checkpoint) must be0x-prefixed 32-byte hashes (Hash32) --strict-checkpoint-ageis a presence flag: present meanstrue, omitted meansfalse, and explicit assignment forms (for example--strict-checkpoint-age=false) are invalid- selected startup checkpoint hash must resolve on the configured
networkviaconsensusRpcUrl; network mismatch is startup failure before opening the HTTP listener - phase-1 operator-facing light-mode startup inputs are
network,consensusRpcUrl,executionRpcUrl,checkpoint,checkpointDir,maxCheckpointAgeSeconds, andstrictCheckpointAge executionRpcUrlis the execution JSON-RPC source used for proof-backed execution reads
Startup consensus-network handshake (before listener):
- resolve
network,consensusRpcUrl, and selected startup checkpoint from startup precedence - call
GET <consensusRpcUrl>/eth/v1/beacon/genesis - require HTTP
200and parsedata.genesis_validators_rootasHash32 - require root match for selected
network:mainnet->0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95sepolia->0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078holesky->0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1
- if handshake fails (request failure, non-
200, malformed payload, missing/invalid root, or root mismatch), startup fails before opening the HTTP listener
3. Checkpoint Selection And Age
Section titled “3. Checkpoint Selection And Age”Checkpoint precedence:
- user-supplied CLI checkpoint (
--checkpoint), when provided - config checkpoint (
mode.light.checkpoint), when set - persisted
${resolvedCheckpointDir}/checkpoint - baked network default
Precedence fallthrough is absence-driven only: ZEVM advances to a lower-precedence checkpoint source only when the higher-precedence source is absent.
Once a checkpoint source is selected by precedence, that selected source is final for that startup attempt; any validation/derivation failure for the selected source must fail startup before opening the HTTP listener, and ZEVM must not fall back to lower-precedence checkpoint sources.
Precedence scope clarification:
- this precedence applies only to startup checkpoint selection
checkpointDir,maxCheckpointAgeSeconds, andstrictCheckpointAgeresolve independently per field as: user-supplied CLI value > config value > mode default- persisted
${resolvedCheckpointDir}/checkpointdoes not set or overridecheckpointDir,maxCheckpointAgeSeconds, orstrictCheckpointAge
Path resolution for persisted checkpoint input:
checkpointDirdefault template is.zevm/checkpoints/<network>;<network>expands from resolved startupnetworkafter CLI/config merge- after CLI/config merge and
<network>expansion, any relativecheckpointDirvalue (including the default.zevm/checkpoints/<network>) is resolved against the process current working directory at startup - persisted checkpoint startup input path is
${resolvedCheckpointDir}/checkpoint, whereresolvedCheckpointDiris the absolute path after that resolution step
If CLI checkpoint, config checkpoint, and persisted ${resolvedCheckpointDir}/checkpoint are all absent, ZEVM selects the baked network default checkpoint and checkpointSource = "default".
Baked default checkpoints are precedence inputs, not frozen public compatibility hashes.
Baked default checkpoint values are ZEVM bundled release/build inputs. For a given ZEVM release/build artifact and network, the selected baked default is deterministic.
Baked defaults are implementation-defined and may rotate across releases/builds.
Canonical release metadata artifact for baked defaults:
releaseIdentifiermust exactly equal the GitHub release tag name that carries metadata assets; tag-based identifiers match^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$, and commit-based identifiers match^commit-[0-9a-f]{40}$- each ZEVM
releaseIdentifierpublishes exactly one machine-readablelight-default-checkpoints.jsonasset athttps://github.com/evmts/zevm/releases/download/<releaseIdentifier>/light-default-checkpoints.json light-default-checkpoints.jsontop-level fields are exactlyschemaVersion,releaseIdentifier, anddefaultsschemaVersioniszevm-light-default-checkpoints.v1releaseIdentifiermatches the publishingreleaseIdentifierdefaultscontains exactlymainnet,sepolia, andholesky; each value is a0x-prefixed 32-byte hash (Hash32) equal to that release/build’s bundled baked default for the network- values are immutable per published release identifier; corrections publish a new release identifier with its own
light-default-checkpoints.json - correction releases include one release-notes supersession note under heading
## ZEVM Supersession Notewith required lines:schemaVersion,supersedesReleaseIdentifier,correctedArtifacts, andreason - publication-time validation gate is mandatory for canonical publication claims: before a release is treated or announced as canonical under this contract, CI/release automation validates both required artifacts (
release-tuple.json,light-default-checkpoints.json) from published release assets against PRD section 3.4 requirements - publication-time gate failure on either required artifact (missing, duplicate, unreadable, malformed, schema-mismatched, or value-mismatched) blocks canonical publication claims for that
releaseIdentifier; correction requires a newreleaseIdentifier(no in-place repair) - operators deterministically discover per-network baked defaults from that artifact; runtime probing via
zevm_lightSyncStatusis optional verification - deterministic baked-default discovery from release metadata is defined only for published release identifiers
- for unreleased commit builds without published
light-default-checkpoints.json, baked defaults remain implementation-defined and are not contract-discoverable from metadata - operators that require deterministic checkpoint selection for unreleased commit builds must provide an explicit checkpoint via CLI/config instead of relying on baked defaults
Persisted checkpoint file contract:
- file path:
${resolvedCheckpointDir}/checkpoint, whereresolvedCheckpointDiris derived from mergedcheckpointDirby applying<network>expansion and then resolving relative paths against startup current working directory - if
${resolvedCheckpointDir}/checkpointis missing, persisted checkpoint input is treated as absent and precedence falls through - content: exactly 64 hex chars (32-byte hash, no
0xprefix) - trimmed whitespace is ignored on read
- this format split is intentional: CLI/config checkpoint inputs use
0x-prefixed 32-byte hashes, while persisted${resolvedCheckpointDir}/checkpointuses 64 hex chars without0x - if the file exists but is unreadable, startup fails before opening the HTTP listener
- if the file is readable but trimmed content is malformed, startup fails before opening the HTTP listener
- in phase 1, ZEVM treats
${resolvedCheckpointDir}/checkpointas startup input only and does not create, update, or delete this file during runtime lastCheckpointruntime progression is not persisted to${resolvedCheckpointDir}/checkpointin phase 1- operators may update
${resolvedCheckpointDir}/checkpointbetween restarts; startup precedence is re-evaluated on each process start
Age policy:
ageis ZEVM’s startup-time freshness value for the selected startup checkpointageis evaluated once during startup, after checkpoint selection and before stale-policy decisionageis measured in whole seconds:age = max(0, startupTimeSeconds - checkpointTimeSeconds)startupTimeSecondsis sampled at age-check timecheckpointTimeSecondsis derived deterministically from Beacon API data for the selected startup checkpoint hash on the selected network, usingconsensusRpcUrland not filesystem metadata/local file times- derivation steps are exact:
- call
GET <consensusRpcUrl>/eth/v1/beacon/genesis, require HTTP200, parsedata.genesis_timeas decimal unsigned integergenesisTimeSeconds - call
GET <consensusRpcUrl>/eth/v1/beacon/headers/{selectedCheckpointHash}, require HTTP200, parsedata.rootasHash32and require equality withselectedCheckpointHash, then parsedata.header.message.slotas decimal unsigned integercheckpointSlot - use
SECONDS_PER_SLOT = 12for phase-1 supported light networks and computecheckpointTimeSeconds = genesisTimeSeconds + (checkpointSlot * SECONDS_PER_SLOT)with integer arithmetic - use computed
checkpointTimeSecondsas integer Unix seconds in age evaluation
- call
- any request failure, non-
200, missing/malformed required field, checkpoint-root mismatch, or arithmetic overflow in this derivation is inability to resolvecheckpointTimeSecondsand is startup failure before listening age == maxCheckpointAgeSecondsis valid- only
age > maxCheckpointAgeSecondsis stale - stale +
strictCheckpointAge = false: emit one operator-facing startup warning before listening, then continue startup - non-strict stale warnings must be surfaced on startup logs via process
stderrand must not rely on JSON-RPC visibility - phase 1 defines no dedicated CLI/config controls for startup log level, log file paths, or alternative startup log sinks
- the non-strict stale warning must include: selected checkpoint hash,
checkpointSource,checkpointTimeSeconds,startupTimeSeconds, computedage,maxCheckpointAgeSeconds, andstrictCheckpointAge = false - stale +
strictCheckpointAge = true: startup failure before listening - inability to resolve
checkpointTimeSecondsfor the selected startup checkpoint is startup failure before listening
4. Sync Status Semantics
Section titled “4. Sync Status Semantics”zevm_lightSyncStatus fields include:
ready: read-availability gatestatus:syncing,synced, orerrornetwork: selected light network (mainnet,sepolia, orholesky)checkpointSource:explicit,persisted, ordefaultlastCheckpoint: most recently accepted checkpoint rootoptimisticSlot,safeSlot,finalizedSlot
Invariants:
ready = trueonly whenstatus = "synced"status = "syncing"orstatus = "error"impliesready = falsenetworkis always present and equals the selected startup light network for the process lifetimereadymay transition fromfalsetotrueonly whenstatustransitions tosyncedafter ZEVM has accepted verified optimistic, safe, and finalized heads for the selected network- while
ready = true, slot coherence must hold:finalizedSlot <= safeSlot <= optimisticSlot - selector semantics are unchanged:
latestresolves to the optimistic execution head,saferesolves to the consensus-backed safe execution head, andfinalizedresolves to the consensus-finalized execution head - if
statusleavessyncedor slot coherence cannot be maintained, ZEVM must setready = falsein the same state transition before serving subsequent gated RPC calls checkpointSourcereflects the selected startup checkpoint source and remains stable for the process lifetime:explicit: selected from user-provided checkpoint input (CLI--checkpointor configmode.light.checkpoint)persisted: selected from${resolvedCheckpointDir}/checkpointdefault: selected from ZEVM bundled release/build default checkpoint for the selected network (deterministic for that release/build artifact; may rotate across releases/builds and is published in that release’s requiredlight-default-checkpoints.json)
lastCheckpointis always present asHash32after listener startupoptimisticSlot,safeSlot, andfinalizedSlotare always present asQuantityHexvalues (notnull)finalizedSlot <= safeSlot <= optimisticSlot- while
status = "syncing", slot values may remain0x0until headers are available - when
status = "error", slot fields keep the last known values and are not nullified
lastCheckpoint semantics:
- initialized from selected startup checkpoint after validation
- updated whenever a newer checkpoint is accepted
- reflects current accepted checkpoint state, not a pinned startup value
checkpointSourcedoes not change whenlastCheckpointadvanceslastCheckpointupdates do not imply on-disk checkpoint persistence in phase 1
Lifecycle transitions:
- listener-start entry state:
status = "syncing"andready = false syncing -> synced: initial light sync has accepted verified optimistic, safe, and finalized heads; this transition also setsready = truesyncing -> error: light sync fails after listener startupsynced -> error: previously synced runtime later fails to advance/verify or loses slot coherence; this transition also setsready = falsebefore serving subsequent gated RPC calls- phase-1 recovery from
errorrequires operator action: fix upstream/configuration cause and restart ZEVM
Operational implications by state:
status = "syncing": proof-backed reads andeth_blockNumberremain gated (-32011);eth_chainIdandzevm_lightSyncStatusstay callablestatus = "synced": proof-backed reads are enabled (ready = true); proof failures still surface as-32014or-32015status = "error": proof-backed reads andeth_blockNumberremain gated (-32011) until successful process restart
5. Readiness And Selector Boundaries
Section titled “5. Readiness And Selector Boundaries”Readiness:
- readiness gating applies to proof-backed reads and
eth_blockNumberonly eth_chainIdandzevm_lightSyncStatusare always callable in light mode regardless ofready- while
ready=false, proof-backed reads (including numeric selectors, even if out of retained window) andeth_blockNumberfail with-32011 - numeric-window validation (
-32602) applies only whenready=true - while
ready=true, reads are served only when proof verification succeeds
Selector rules:
- supported tags:
latest,safe,finalized,earliest, numeric pendingunsupported (-32010)- numeric selectors allowed only for block
0plus retained-history window of latest8191verified blocks - numeric outside retained history when otherwise ready ->
-32602 - proof verification failure ->
-32014 - malformed data from upstream proof source ->
-32015
Light mode does not provide arbitrary archive reads outside retained verified history.