Skip to content

perf(l2): compute base blob fee once per block#6001

Closed
xqft wants to merge 6 commits into
zerocopy_triefrom
opt/p2-fake-exp
Closed

perf(l2): compute base blob fee once per block#6001
xqft wants to merge 6 commits into
zerocopy_triefrom
opt/p2-fake-exp

Conversation

@xqft
Copy link
Copy Markdown
Contributor

@xqft xqft commented Jan 22, 2026

Summary

Optimizes EIP-4844 blob gas calculation by computing base_blob_fee_per_gas once per block instead of twice per transaction, eliminating redundant fake_exponential calls per block.

Motivation

The base blob fee per gas is constant for all transactions in a block (determined by parent_excess_blob_gas and base_fee_update_fraction), yet it was being recomputed:

  • ~768 times in setup_env() (once per transaction)
  • ~768 times in calculate_blob_gas_cost() during transaction execution (via deduct_caller)

This optimization computes the value once at the block level and reuses it, while also simplifying the codebase by removing conditional compilation that was added in a previous approach.

Changes

Removed:

  • fake_exponential_i128() function and all zkVM-specific conditional compilation (#[cfg(any(feature = "zisk", feature = "sp1", feature = "risc0"))])
  • 89 lines of code across block.rs and utils.rs

Modified:

  • calculate_blob_gas_cost() now accepts pre-computed base_blob_fee_per_gas from Environment
  • execute_block() and execute_block_pipeline() compute the value once before the transaction loop
  • setup_env() accepts base_blob_fee_per_gas as a parameter instead of computing it
  • Updated all call sites: execute_tx, execute_tx_in_block, trace_tx_calls, warm_block, rerun_block

Performance Results

ZisK Profile - Block 24291039 (mainnet, 382 transactions)

Metric Baseline Optimized Change
Total Steps 641,671,652 591,264,620 -50.4M (-7.86%)
Total Cost 72.8B 68.1B -4.7B (-6.42%)

Function-Level Impact

Function Baseline Optimized Improvement
LEVM::execute_tx (382 calls) 38.9B 34.3B -11.96%
LEVM::execute_block 41.2B 36.6B -11.33%
VM::execute (386 calls) 35.1B 32.8B -6.70%

Memory Operations

  • memcpy calls: 921,521 → 832,937 (-88,584, -9.6%)
  • memcpy cost: 13.5B → 12.6B (-900M, -6.7%)

Benefits

  1. Performance: Major reduction in zkVM steps/cost
  2. Simplicity: Net -62 lines, removes all conditional compilation
  3. Maintainability: Single code path for all execution contexts
  4. Architecture: Block-level constants computed at block level (correct design)

Test Plan

  • cargo test -p ethrex-common - All tests pass
  • cargo test -p ethrex-vm - All tests pass
  • cargo test -p ethrex-levm - All tests pass
  • ✅ ZisK profile: -7.86% steps on mainnet block

Related

  • Part of zkVM optimization workflow
  • Tracked in scripts/zkvm-bench/logbook.md (Entry docs: add milestones #1)
  • Points to: zerocopy_trie base branch

xqft added 3 commits January 22, 2026 12:12
Replace U256 arithmetic with i128 for EIP-4844 blob gas calculation when
running in zkVM (zisk/sp1/risc0). This is safe because:
- factor = MIN_BASE_FEE_PER_BLOB_GAS (1)
- numerator = parent_excess_blob_gas (u64, typically < 100M)
- denominator = update_fraction (u64, ~8.8M for mainnet)

Expected savings: 25-30M steps (3.8-4.5%) from reduced checked arithmetic
overhead and smaller integer operations.

Includes test to verify i128 matches U256 for typical values.
…r zkVM

Apply same i128 optimization to levm's get_base_fee_per_blob_gas function
which is called during transaction execution. This is the main call site
with ~769 calls per block.
@github-actions github-actions Bot added the L2 Rollup client label Jan 22, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

Lines of code report

Total lines added: 32
Total lines removed: 2
Total lines changed: 34

Detailed view
+-------------------------------------------------+-------+------+
| File                                            | Lines | Diff |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/levm/mod.rs           | 711   | +17  |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/levm/tracing.rs       | 71    | +10  |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/mod.rs                | 176   | +5   |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/hooks/default_hook.rs | 351   | -1   |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/utils.rs              | 431   | -1   |
+-------------------------------------------------+-------+------+

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

Benchmark Results Comparison

No significant difference was registered for any benchmark run.

Detailed Results

Benchmark Results: BubbleSort

Command Mean [s] Min [s] Max [s] Relative
main_revm_BubbleSort 2.995 ± 0.021 2.963 3.028 1.00
main_levm_BubbleSort 3.036 ± 0.039 3.005 3.130 1.01 ± 0.01
pr_revm_BubbleSort 3.007 ± 0.031 2.965 3.059 1.00 ± 0.01
pr_levm_BubbleSort 3.044 ± 0.009 3.032 3.060 1.02 ± 0.01

Benchmark Results: ERC20Approval

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Approval 977.8 ± 5.4 970.7 989.3 1.00
main_levm_ERC20Approval 1064.9 ± 19.3 1051.0 1116.1 1.09 ± 0.02
pr_revm_ERC20Approval 988.6 ± 9.2 977.3 1003.2 1.01 ± 0.01
pr_levm_ERC20Approval 1094.8 ± 9.7 1082.5 1112.8 1.12 ± 0.01

Benchmark Results: ERC20Mint

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Mint 135.2 ± 1.6 134.2 139.3 1.01 ± 0.01
main_levm_ERC20Mint 159.4 ± 1.5 158.0 162.9 1.20 ± 0.01
pr_revm_ERC20Mint 133.3 ± 0.7 132.3 134.9 1.00
pr_levm_ERC20Mint 160.2 ± 0.8 159.1 161.4 1.20 ± 0.01

Benchmark Results: ERC20Transfer

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Transfer 232.4 ± 1.9 230.3 236.3 1.00 ± 0.01
main_levm_ERC20Transfer 268.0 ± 2.5 265.5 273.5 1.15 ± 0.01
pr_revm_ERC20Transfer 232.2 ± 1.6 230.1 235.1 1.00
pr_levm_ERC20Transfer 273.7 ± 4.7 269.6 286.5 1.18 ± 0.02

Benchmark Results: Factorial

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Factorial 222.9 ± 1.5 221.4 225.6 1.01 ± 0.01
main_levm_Factorial 255.2 ± 1.5 253.6 257.9 1.15 ± 0.01
pr_revm_Factorial 221.5 ± 2.3 219.3 226.5 1.00
pr_levm_Factorial 261.5 ± 16.1 253.0 306.6 1.18 ± 0.07

Benchmark Results: FactorialRecursive

Command Mean [s] Min [s] Max [s] Relative
main_revm_FactorialRecursive 1.641 ± 0.051 1.512 1.688 1.00
main_levm_FactorialRecursive 8.298 ± 0.054 8.169 8.353 5.06 ± 0.16
pr_revm_FactorialRecursive 1.689 ± 0.071 1.612 1.860 1.03 ± 0.05
pr_levm_FactorialRecursive 8.279 ± 0.044 8.192 8.350 5.04 ± 0.16

Benchmark Results: Fibonacci

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Fibonacci 200.6 ± 1.3 198.4 203.5 1.03 ± 0.01
main_levm_Fibonacci 249.8 ± 4.8 241.4 257.5 1.28 ± 0.03
pr_revm_Fibonacci 195.7 ± 0.9 194.6 197.7 1.00
pr_levm_Fibonacci 248.8 ± 6.3 235.7 260.3 1.27 ± 0.03

Benchmark Results: FibonacciRecursive

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_FibonacciRecursive 873.1 ± 8.6 862.9 888.1 1.24 ± 0.02
main_levm_FibonacciRecursive 706.5 ± 5.8 698.0 714.3 1.00
pr_revm_FibonacciRecursive 870.5 ± 10.6 854.0 892.9 1.23 ± 0.02
pr_levm_FibonacciRecursive 715.2 ± 13.0 699.4 742.6 1.01 ± 0.02

Benchmark Results: ManyHashes

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ManyHashes 8.4 ± 0.1 8.3 8.5 1.00
main_levm_ManyHashes 9.0 ± 0.1 8.9 9.3 1.08 ± 0.02
pr_revm_ManyHashes 8.5 ± 0.1 8.4 8.9 1.02 ± 0.02
pr_levm_ManyHashes 9.1 ± 0.1 8.9 9.3 1.08 ± 0.02

Benchmark Results: MstoreBench

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_MstoreBench 262.9 ± 6.4 258.4 274.8 1.19 ± 0.03
main_levm_MstoreBench 224.9 ± 9.9 220.5 252.9 1.02 ± 0.05
pr_revm_MstoreBench 256.6 ± 0.9 255.4 258.2 1.16 ± 0.01
pr_levm_MstoreBench 220.6 ± 1.8 219.0 223.6 1.00

Benchmark Results: Push

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Push 290.3 ± 13.4 284.6 328.3 1.03 ± 0.05
main_levm_Push 283.5 ± 1.4 282.2 286.8 1.01 ± 0.03
pr_revm_Push 284.8 ± 0.6 283.4 285.7 1.01 ± 0.03
pr_levm_Push 281.7 ± 7.1 272.2 298.1 1.00

Benchmark Results: SstoreBench_no_opt

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_SstoreBench_no_opt 168.9 ± 4.4 162.5 174.6 1.87 ± 0.09
main_levm_SstoreBench_no_opt 91.3 ± 5.6 86.4 104.8 1.01 ± 0.07
pr_revm_SstoreBench_no_opt 172.4 ± 8.0 162.1 185.8 1.91 ± 0.11
pr_levm_SstoreBench_no_opt 90.2 ± 3.4 86.5 96.0 1.00

Replace the i128 conditional compilation approach with block-level caching
to reduce redundant fake_exponential calls from ~1536 per block to 1.

Changes:
- Remove fake_exponential_i128() and all cfg(zkvm) conditional compilation
- Update calculate_blob_gas_cost() to use pre-computed base_blob_fee_per_gas
  from Environment instead of recomputing (eliminates ~768 calls/block)
- Compute base_blob_fee_per_gas once in execute_block/execute_block_pipeline
  and pass to all transactions (eliminates ~768 calls/block)
- Thread the pre-computed value through setup_env, execute_tx, and
  execute_tx_in_block functions
- Update all call sites in tracing, warm_block, and Evm wrapper

Benefits:
- Simpler codebase: removes 89 lines of conditional compilation
- Same or better performance: 1 U256 fake_exponential vs 1536 i128 operations
- More maintainable: single code path for all execution contexts
- Architecturally correct: block-level constants computed at block level

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@xqft xqft changed the title chore(l2): optimize EIP-4844 blob gas calculation with i128 for zkVM chore(l2): optimize EIP-4844 blob gas by computing once per block Jan 22, 2026
@xqft xqft changed the title chore(l2): optimize EIP-4844 blob gas by computing once per block perf(l2): optimize EIP-4844 blob gas by computing once per block (-7.86%) Jan 22, 2026
Document the block-level base blob fee caching optimization that achieved
-7.86% step reduction (-50.4M steps) on mainnet block 24291039.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the performance Block execution throughput and performance in general label Jan 22, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

Benchmark Block Execution Results Comparison Against Main

Command Mean [s] Min [s] Max [s] Relative
base 65.534 ± 0.473 64.925 66.423 1.00
head 65.717 ± 0.260 65.353 66.052 1.00 ± 0.01

@xqft xqft changed the title perf(l2): optimize EIP-4844 blob gas by computing once per block (-7.86%) perf(l2): optimize EIP-4844 blob gas by computing once per block Jan 22, 2026
@xqft xqft changed the title perf(l2): optimize EIP-4844 blob gas by computing once per block perf(l2): compute blob gas fee once per block Jan 22, 2026
@xqft xqft changed the title perf(l2): compute blob gas fee once per block perf(l2): compute base blob fee once per block Jan 22, 2026
@xqft
Copy link
Copy Markdown
Contributor Author

xqft commented Jan 22, 2026

superseded by #6006

@xqft xqft closed this Jan 22, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in ethrex_performance Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L2 Rollup client performance Block execution throughput and performance in general

Projects

Status: Done
Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant