Skip to content

feat(evm): single-dimension gas repricing primitives (1/3)#213

Draft
davidtaikocha wants to merge 7 commits into
mainfrom
zkgas-reprice-design
Draft

feat(evm): single-dimension gas repricing primitives (1/3)#213
davidtaikocha wants to merge 7 commits into
mainfrom
zkgas-reprice-design

Conversation

@davidtaikocha

Copy link
Copy Markdown
Collaborator

What

Foundational, pure additive primitives for a future Taiko fork that folds proving cost into a single repriced gas dimension — the eventual replacement for the current Unzen raw_gas × multiplier zk-gas meter. This is the first of three PRs:

  1. This PR — primitives (no wiring, no behavior change)
  2. Fork wiring + gating — introduce the new TaikoSpecId, wire these into the factory/handler, and gate the difficulty/zk-gas path to end at the new fork (proving cost then commits via the standard gasUsed)
  3. Teardown of the Unzen zk-gas subsystem once Unzen retires

Scope / safety

  • Not wired into execution. Nothing calls this code yet; every existing fork (including Unzen) behaves identically. The only change outside the new module is one pub mod gas_reprice; line.
  • Numbers are non-consensus placeholders. Real opcode/precompile/intrinsic values are a separate calibration effort and must be mirrored in taiko-geth + the prover.
  • All 45 evm-crate tests pass (8 new + 37 existing, including every zk_gas test — confirming zero behavior change).

The primitives (crates/evm/src/gas_reprice/)

  • schedule.rsRepriceSchedule { opcode_surcharge: [u64; 256], tx_intrinsic_surcharge }.
  • opcodes.rsrepriced_instruction_table: an additive static_gas surcharge over revm's spec base table (the same mechanism revm itself uses for EIP-150/2929), charged before the opcode body so OOG, the GAS opcode, and 63/64 call-forwarding stay self-consistent. No revm fork required.
  • precompiles.rsapply_precompile_surcharge: an input-scaled gas surcharge via PrecompilesMap::map_precompile (mutates only gas_used, forwards everything else).
  • intrinsic.rsadd_tx_intrinsic_surcharge: a per-transaction intrinsic addition (covers ecrecover proving) with the same over-limit check revm raises.

Notes for the wiring PR

  • The opcode→fn pairings in opcodes.rs duplicate revm's internal table (because Instruction::static_gas is private) — re-audit them on every reth/revm pin bump (documented in-code).
  • Only a small example opcode set is wired; a surcharge on an unwired opcode is silently ignored by design (documented on the field + pinned by a test).
  • floor_gas (EIP-7623 calldata floor) is intentionally untouched by the intrinsic surcharge.
  • Precompile OOG is carried via PrecompileOutput.status, not always as Err — the wiring layer owns gas-limit re-validation.

🤖 Generated with Claude Code

davidtaikocha and others added 7 commits June 17, 2026 18:05
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Final-review hardening: opcode_surcharge is a [u64;256] but the builder
reprices only the opcodes whose instruction fn it names, so a surcharge on
any other index is dropped. Document this on the field and add a test
pinning it (SSTORE 0x55) so extending coverage stays a conscious change.
`reprice` is a private build-time setup function called 5 times during
instruction-table construction (fork init), not a hot runtime path.
The `#[inline]` annotation implies performance-critical inner-loop
semantics that don't apply here; the compiler's own inlining heuristics
are appropriate for a tiny generic helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant