Skip to content

Conversation

@fmoletta
Copy link
Contributor

@fmoletta fmoletta commented Nov 27, 2025

Motivation
Addressing #5344 by using the existing block_hash_cache to preload the previous 256 block hashes so we can skip block hash lookup during execution
Alternative to #5434 as proposed by review comment #5434 (comment)

Description

  • Preload previous 256 block hashes to the block hash cache upon VM database creation
  • Rely on block hash cache when executing BLOCKHASH opcode instead of performing lookups

Benchmark Results: worse results than #5434 for BlockHash EEST gas benchmark:
1080.92 Mgas/s PR #5434
802.74 Mgas/s This PR
32.18 Gas/s Main (7b4a0ba)

@github-actions github-actions bot added the L1 Ethereum client label Nov 27, 2025
@github-actions
Copy link

github-actions bot commented Nov 27, 2025

Lines of code report

Total lines added: 49
Total lines removed: 4
Total lines changed: 53

Detailed view
+-------------------------------------------------------+-------+------+
| File                                                  | Lines | Diff |
+-------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/blockchain.rs                | 1517  | +1   |
+-------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/vm.rs                        | 123   | -1   |
+-------------------------------------------------------+-------+------+
| ethrex/crates/storage/api.rs                          | 252   | +5   |
+-------------------------------------------------------+-------+------+
| ethrex/crates/storage/store.rs                        | 1504  | +7   |
+-------------------------------------------------------+-------+------+
| ethrex/crates/storage/store_db/in_memory.rs           | 637   | +15  |
+-------------------------------------------------------+-------+------+
| ethrex/crates/storage/store_db/rocksdb.rs             | 1746  | +21  |
+-------------------------------------------------------+-------+------+
| ethrex/tooling/ef_tests/state/utils.rs                | 59    | -1   |
+-------------------------------------------------------+-------+------+
| ethrex/tooling/ef_tests/state_v2/src/modules/utils.rs | 45    | -2   |
+-------------------------------------------------------+-------+------+

@github-actions
Copy link

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 3.015 ± 0.037 2.974 3.081 1.00
main_levm_BubbleSort 3.088 ± 0.030 3.066 3.156 1.02 ± 0.02
pr_revm_BubbleSort 3.016 ± 0.010 3.000 3.028 1.00 ± 0.01
pr_levm_BubbleSort 3.102 ± 0.065 3.051 3.228 1.03 ± 0.03

Benchmark Results: ERC20Approval

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Approval 996.5 ± 11.8 984.1 1025.6 1.00
main_levm_ERC20Approval 1098.0 ± 20.2 1080.5 1145.2 1.10 ± 0.02
pr_revm_ERC20Approval 1003.0 ± 12.1 994.1 1030.7 1.01 ± 0.02
pr_levm_ERC20Approval 1090.7 ± 17.6 1079.4 1139.3 1.09 ± 0.02

Benchmark Results: ERC20Mint

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Mint 135.9 ± 0.9 134.9 137.5 1.01 ± 0.01
main_levm_ERC20Mint 163.3 ± 2.3 160.3 166.5 1.21 ± 0.02
pr_revm_ERC20Mint 134.9 ± 1.7 133.8 139.5 1.00
pr_levm_ERC20Mint 162.2 ± 1.6 160.5 165.4 1.20 ± 0.02

Benchmark Results: ERC20Transfer

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Transfer 235.5 ± 1.6 233.1 237.3 1.00 ± 0.01
main_levm_ERC20Transfer 271.0 ± 3.4 267.3 279.8 1.16 ± 0.02
pr_revm_ERC20Transfer 234.5 ± 2.0 232.4 239.5 1.00
pr_levm_ERC20Transfer 271.8 ± 3.7 268.1 279.2 1.16 ± 0.02

Benchmark Results: Factorial

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Factorial 222.1 ± 1.4 220.9 225.6 1.00
main_levm_Factorial 281.7 ± 29.3 266.4 358.0 1.27 ± 0.13
pr_revm_Factorial 222.7 ± 1.1 222.0 225.7 1.00 ± 0.01
pr_levm_Factorial 274.4 ± 11.3 267.5 302.8 1.24 ± 0.05

Benchmark Results: FactorialRecursive

Command Mean [s] Min [s] Max [s] Relative
main_revm_FactorialRecursive 1.653 ± 0.040 1.594 1.719 1.00 ± 0.03
main_levm_FactorialRecursive 8.279 ± 0.058 8.211 8.398 5.02 ± 0.12
pr_revm_FactorialRecursive 1.649 ± 0.037 1.574 1.691 1.00
pr_levm_FactorialRecursive 8.346 ± 0.079 8.225 8.484 5.06 ± 0.12

Benchmark Results: Fibonacci

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Fibonacci 199.4 ± 2.5 197.9 206.3 1.00
main_levm_Fibonacci 269.3 ± 15.4 261.8 311.3 1.35 ± 0.08
pr_revm_Fibonacci 199.5 ± 3.1 197.9 208.2 1.00 ± 0.02
pr_levm_Fibonacci 270.9 ± 13.7 261.5 306.2 1.36 ± 0.07

Benchmark Results: FibonacciRecursive

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_FibonacciRecursive 866.8 ± 6.8 855.5 875.6 1.14 ± 0.01
main_levm_FibonacciRecursive 773.8 ± 33.5 742.0 826.1 1.02 ± 0.05
pr_revm_FibonacciRecursive 863.7 ± 8.3 852.3 882.3 1.14 ± 0.01
pr_levm_FibonacciRecursive 757.5 ± 6.4 742.4 767.7 1.00

Benchmark Results: ManyHashes

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ManyHashes 8.4 ± 0.0 8.4 8.5 1.00 ± 0.01
main_levm_ManyHashes 9.0 ± 0.2 8.8 9.3 1.06 ± 0.03
pr_revm_ManyHashes 8.4 ± 0.1 8.3 8.5 1.00
pr_levm_ManyHashes 8.9 ± 0.1 8.8 9.3 1.06 ± 0.02

Benchmark Results: MstoreBench

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_MstoreBench 253.9 ± 2.4 250.2 257.6 1.05 ± 0.01
main_levm_MstoreBench 251.0 ± 11.7 238.0 264.4 1.04 ± 0.05
pr_revm_MstoreBench 256.9 ± 3.8 253.3 266.9 1.07 ± 0.02
pr_levm_MstoreBench 240.9 ± 1.8 239.2 244.8 1.00

Benchmark Results: Push

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Push 288.1 ± 1.0 286.5 289.8 1.00
main_levm_Push 325.0 ± 20.0 310.6 356.3 1.13 ± 0.07
pr_revm_Push 288.6 ± 2.2 285.9 292.2 1.00 ± 0.01
pr_levm_Push 322.5 ± 16.6 313.2 354.3 1.12 ± 0.06

Benchmark Results: SstoreBench_no_opt

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_SstoreBench_no_opt 167.0 ± 2.6 162.9 169.3 1.87 ± 0.05
main_levm_SstoreBench_no_opt 89.1 ± 2.1 86.4 92.5 1.00
pr_revm_SstoreBench_no_opt 167.7 ± 6.7 162.5 185.3 1.88 ± 0.09
pr_levm_SstoreBench_no_opt 89.5 ± 2.2 87.0 93.9 1.00 ± 0.03

newest: BlockNumber,
oldest: BlockNumber,
) -> Result<Vec<BlockHash>, StoreError> {
self.engine.get_canonical_block_hashes(newest, oldest)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be reading from memory most of the time. Only on startup it should need to go to the DB to populate its in-memory cache.

Comment on lines +1546 to +1552
let mut results = Vec::with_capacity(newest.saturating_sub(oldest) as usize);
for number in (oldest..newest).rev() {
match db.get_cf(&cf, number.to_le_bytes())? {
Some(res) => results.push(BlockHashRLP::from_bytes(res).to()?),
None => break,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should fetch the whole range in batch:

Suggested change
let mut results = Vec::with_capacity(newest.saturating_sub(oldest) as usize);
for number in (oldest..newest).rev() {
match db.get_cf(&cf, number.to_le_bytes())? {
Some(res) => results.push(BlockHashRLP::from_bytes(res).to()?),
None => break,
}
}
let keys = (oldest..newest).map(BlockNumber::to_le_bytes());
let hashes = db.batched_multiget_cf(&cf, keys, true);
hashes.into_iter().map(|h| h.ok().flatten().or_else(|| StoreError::Custom("missing value"))).collect()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants