Skip to content

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

Open
xqft wants to merge 11 commits into
mainfrom
fake_exp_opt
Open

perf(l2): compute base blob fee once per block#6006
xqft wants to merge 11 commits into
mainfrom
fake_exp_opt

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:

  • in setup_env() (once per transaction)
    -calculate_blob_gas_cost() during transaction execution (via deduct_caller)

This optimization computes the value once at the block level and reuses it.

Changes

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

SP1 - Block 24292781 (mainnet, 341 transactions)

Metric Main Optimized Improvement
Total Execution 602,664,256 cycles 526,071,327 cycles -76.6M (-12.7%)
execute_block 380,618,779 cycles 304,025,850 cycles -76.6M (-20.1%)

All cycle savings are concentrated in the transaction execution phase (execute_block), confirming the optimization eliminates redundant calculations during transaction processing.

ZisK - Block 24292781 (mainnet, 341 transactions)

Metric Main Optimized Improvement
Total Steps 718,743,877 676,897,554 -41.8M (-5.82%)
Total Cost 80.3B 76.5B -3.9B (-4.83%)

Cost Distribution Changes:

Component Main Optimized Change
MAIN 48.9B (60.83%) 46.0B (60.20%) -2.8B (-5.93%)
OPCODES 11.3B (14.13%) 10.6B (13.87%) -748M (-6.59%)
PRECOMPILES 13.9B (17.36%) 13.9B (18.24%) 0 (0%)
MEMORY 5.9B (7.31%) 5.6B (7.31%) -287M (-4.89%)

Test Configuration:

  • Hardware: Apple M1 Pro, 16GB RAM
  • Block: 24292781 (mainnet, 341 transactions, 36M gas)
  • SP1 version: 5.2.4
  • ZisK version: 0.15.0
  • Branches: main (cb6e45a) vs fake_exp_opt (0ed64a1)

xqft added 5 commits January 22, 2026 17:23
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.
@xqft xqft changed the title perf(l2): compute base blob fee once per block chore(l2): compute base blob fee once per block Jan 22, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

Lines of code report

Total lines added: 66
Total lines removed: 4
Total lines changed: 70

Detailed view
+-------------------------------------------------+-------+------+
| File                                            | Lines | Diff |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/levm/mod.rs           | 732   | +38  |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/levm/tracing.rs       | 78    | +17  |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/mod.rs                | 182   | +11  |
+-------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/hooks/default_hook.rs | 349   | -3   |
+-------------------------------------------------+-------+------+
| 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.933 ± 0.037 2.905 3.032 1.00
main_levm_BubbleSort 3.054 ± 0.104 2.996 3.344 1.04 ± 0.04
pr_revm_BubbleSort 2.940 ± 0.013 2.916 2.953 1.00 ± 0.01
pr_levm_BubbleSort 3.063 ± 0.011 3.050 3.081 1.04 ± 0.01

Benchmark Results: ERC20Approval

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Approval 992.5 ± 13.0 977.0 1014.8 1.00
main_levm_ERC20Approval 1075.4 ± 9.4 1057.0 1088.3 1.08 ± 0.02
pr_revm_ERC20Approval 996.5 ± 10.3 984.9 1015.0 1.00 ± 0.02
pr_levm_ERC20Approval 1077.8 ± 11.1 1064.8 1104.9 1.09 ± 0.02

Benchmark Results: ERC20Mint

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Mint 134.7 ± 1.1 133.8 136.5 1.00
main_levm_ERC20Mint 162.2 ± 5.6 157.8 176.0 1.20 ± 0.04
pr_revm_ERC20Mint 135.8 ± 1.8 134.4 140.6 1.01 ± 0.02
pr_levm_ERC20Mint 160.0 ± 1.4 158.2 163.1 1.19 ± 0.01

Benchmark Results: ERC20Transfer

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Transfer 233.4 ± 3.2 230.7 240.0 1.00
main_levm_ERC20Transfer 268.5 ± 1.1 266.3 270.3 1.15 ± 0.02
pr_revm_ERC20Transfer 236.6 ± 4.4 232.8 247.7 1.01 ± 0.02
pr_levm_ERC20Transfer 273.9 ± 3.0 271.0 279.6 1.17 ± 0.02

Benchmark Results: Factorial

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Factorial 220.3 ± 0.9 218.7 222.1 1.00
main_levm_Factorial 255.5 ± 1.3 254.1 257.6 1.16 ± 0.01
pr_revm_Factorial 224.6 ± 2.2 222.3 228.9 1.02 ± 0.01
pr_levm_Factorial 256.2 ± 2.1 253.5 259.4 1.16 ± 0.01

Benchmark Results: FactorialRecursive

Command Mean [s] Min [s] Max [s] Relative
main_revm_FactorialRecursive 1.669 ± 0.047 1.551 1.726 1.00
main_levm_FactorialRecursive 8.476 ± 0.051 8.404 8.523 5.08 ± 0.15
pr_revm_FactorialRecursive 1.696 ± 0.061 1.569 1.777 1.02 ± 0.05
pr_levm_FactorialRecursive 8.274 ± 0.105 8.120 8.447 4.96 ± 0.15

Benchmark Results: Fibonacci

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Fibonacci 194.8 ± 2.2 192.9 200.1 1.00
main_levm_Fibonacci 249.2 ± 3.1 244.9 256.7 1.28 ± 0.02
pr_revm_Fibonacci 198.2 ± 0.9 197.3 199.7 1.02 ± 0.01
pr_levm_Fibonacci 249.7 ± 5.8 242.1 263.6 1.28 ± 0.03

Benchmark Results: FibonacciRecursive

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_FibonacciRecursive 880.5 ± 9.0 865.6 895.2 1.25 ± 0.02
main_levm_FibonacciRecursive 703.5 ± 6.0 696.1 715.8 1.00
pr_revm_FibonacciRecursive 883.7 ± 8.4 871.2 897.2 1.26 ± 0.02
pr_levm_FibonacciRecursive 714.1 ± 32.9 692.8 804.5 1.02 ± 0.05

Benchmark Results: ManyHashes

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ManyHashes 8.6 ± 0.2 8.4 9.1 1.00
main_levm_ManyHashes 9.4 ± 0.1 9.3 9.6 1.09 ± 0.02
pr_revm_ManyHashes 8.8 ± 0.1 8.7 9.1 1.02 ± 0.02
pr_levm_ManyHashes 9.3 ± 0.1 9.2 9.5 1.08 ± 0.02

Benchmark Results: MstoreBench

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_MstoreBench 260.4 ± 3.6 256.7 269.4 1.17 ± 0.02
main_levm_MstoreBench 222.8 ± 1.8 218.9 225.9 1.00
pr_revm_MstoreBench 260.0 ± 1.7 257.9 263.3 1.17 ± 0.01
pr_levm_MstoreBench 224.0 ± 1.1 222.1 225.6 1.01 ± 0.01

Benchmark Results: Push

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Push 286.6 ± 1.8 284.9 291.0 1.02 ± 0.01
main_levm_Push 282.0 ± 3.3 273.0 285.0 1.00
pr_revm_Push 286.4 ± 1.3 284.7 288.8 1.02 ± 0.01
pr_levm_Push 282.9 ± 2.1 278.2 286.6 1.00 ± 0.01

Benchmark Results: SstoreBench_no_opt

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_SstoreBench_no_opt 171.0 ± 6.9 162.1 185.6 1.90 ± 0.09
main_levm_SstoreBench_no_opt 90.1 ± 2.2 87.4 93.6 1.00
pr_revm_SstoreBench_no_opt 170.8 ± 4.0 164.2 180.0 1.90 ± 0.06
pr_levm_SstoreBench_no_opt 90.9 ± 2.0 88.2 93.5 1.01 ± 0.03

@xqft xqft changed the title chore(l2): compute base blob fee once per block perf(l2): compute base blob fee once per block Jan 22, 2026
@github-actions github-actions Bot added L2 Rollup client performance Block execution throughput and performance in general labels Jan 22, 2026
@JereSalo
Copy link
Copy Markdown
Contributor

JereSalo commented Jan 23, 2026

Just wanted to add a quick comment, I tested this with mainnet blocks without zkVMs and the improvement is also noticeable! Maybe I'll upload a picture later of the results.

Edit: It's with a tool that I'm building, I tested random branches and I just saw that yours had a noticeable speedup

@xqft
Copy link
Copy Markdown
Contributor Author

xqft commented Jan 23, 2026

@JereSalo Nice!! yeah would love to include those results in the description too

@xqft xqft changed the title perf(l2): compute base blob fee once per block chore(l2): compute base blob fee once per block Jan 23, 2026
@github-actions github-actions Bot removed the performance Block execution throughput and performance in general label Jan 23, 2026
@xqft xqft changed the title chore(l2): compute base blob fee once per block perf(l2): compute base blob fee once per block Jan 23, 2026
@github-actions github-actions Bot added the performance Block execution throughput and performance in general label Jan 23, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 23, 2026

Benchmark Block Execution Results Comparison Against Main

Command Mean [s] Min [s] Max [s] Relative
base 65.180 ± 0.243 64.794 65.635 1.00
head 65.646 ± 0.371 65.194 66.234 1.01 ± 0.01

@xqft xqft marked this pull request as ready for review January 23, 2026 17:23
@xqft xqft requested a review from a team as a code owner January 23, 2026 17:24
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: No status
Status: Todo

Development

Successfully merging this pull request may close these issues.

5 participants