Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Unzen Fork

Upcoming protocol fork introducing block-level zk gas metering.

Unzen is an upcoming fork that introduces zk gas as a protocol-level budget for proving work. Instead of limiting blocks only by ordinary EVM gas, Unzen adds a separate weighted gas metric that reflects how expensive different opcodes and precompiles are to prove.

The objective is to cap proving time per block with a protocol constant, BLOCK_ZK_GAS_LIMIT, so a block cannot be valid if it would require more proving work than the protocol budget allows.

For the source protocol details, see the upstream ZK Gas specification.

EVM Version: Osaka

Unzen targets the Osaka EVM version. This will make the Cancun, Prague, and Osaka execution-layer features available to contracts.

The main contract-facing additions are:

  • Cancun opcodes: TSTORE, TLOAD, MCOPY, BLOBHASH, and BLOBBASEFEE
  • Prague precompiles: BLS12-381 operations at addresses 0x0b through 0x11
  • Osaka opcode: CLZ (0x1e), exposed by Solidity inline assembly as clz
  • Osaka precompile: P256VERIFY for secp256r1 signature verification at address 0x100

Block-Level ZK Gas Limit

Unzen defines BLOCK_ZK_GAS_LIMIT as the maximum cumulative zk gas allowed in a block.

The initial specification sets:

ConstantValue
BLOCK_ZK_GAS_LIMIT100,000,000

All transactions in a block are metered, including system and anchor transactions.

If cumulative zk gas exceeds the block limit during execution:

  • the transaction that crossed the limit is aborted
  • all state changes from that transaction are discarded
  • transactions that completed before it are kept
  • all remaining transactions in the block are skipped

This makes the zk gas limit a block validity constraint rather than a mempool policy or local prover preference.

Weighted Opcode Metering

zk gas is calculated by multiplying normal EVM gas spent by a proving-cost multiplier.

For ordinary opcodes, Unzen meters each opcode execution as:

zk_gas += step_gas * opcode_multiplier[opcode]

step_gas is the gas charged by the EVM for a single opcode, including static cost and dynamic costs such as memory expansion or storage access charges.

The multiplier table is derived from per-opcode proving-time benchmarks. Expensive operations receive higher multipliers. For example, mulmod, div, mod, keccak256, and call receive larger weights than simple stack or memory operations.

Unlisted opcodes default to max(uint16) as a fail-safe, making missing multiplier entries immediately exceed practical limits.

Precompile Metering

Precompiles require explicit metering because they do not execute through the normal opcode loop.

When a CALL-family opcode invokes an active precompile:

  • the CALL-family opcode is metered for opcode-side spawn overhead
  • the precompile itself is metered separately
  • the precompile multiplier is indexed by the low byte of the precompile address

The precompile charge is:

precompile_zk_gas = precompile_gas_used * precompile_multiplier[address]

precompile_gas_used is the gas charged by the precompile's own gas schedule, excluding the CALL-family opcode's separate costs.

This keeps heavyweight precompiles such as modexp, point evaluation, BLAKE2F, and pairing operations represented in the block's proving budget.

Spawn Opcode Estimation

Spawn opcodes need special handling because they can create child execution frames and pre-charge parent gas with a child execution budget.

If Unzen used the observed parent opcode gas delta directly, the same child execution path could be counted twice:

  • once through the parent's forwarded gas budget
  • once through the child frame's actual opcode and precompile execution

Unzen avoids this by using fixed raw-gas estimates for spawn opcodes whenever a child frame is created or a precompile is invoked.

OpcodeEstimated raw gas
CALL12,500
CALLCODE12,500
DELEGATECALL3,500
STATICCALL3,500
CREATE37,000
CREATE244,500

Child-frame execution is still metered normally. The fixed parent-side estimate only replaces the parent opcode's observed gas delta so the forwarded child budget is not double counted.