diff --git a/CHANGELOG.md b/CHANGELOG.md index e6766c94caa..6430c6715e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 2025-11-13 +- Avoid recalculating blob base fee while preparing transactions [#5328](https://github.com/lambdaclass/ethrex/pull/5328) - Use BlobDB for account_codes column family [#5300](https://github.com/lambdaclass/ethrex/pull/5300) ### 2025-11-12 diff --git a/crates/vm/backends/levm/mod.rs b/crates/vm/backends/levm/mod.rs index 1a260e7e05a..ce89c3d52f0 100644 --- a/crates/vm/backends/levm/mod.rs +++ b/crates/vm/backends/levm/mod.rs @@ -26,6 +26,7 @@ use ethrex_levm::constants::{ use ethrex_levm::db::gen_db::GeneralizedDatabase; use ethrex_levm::errors::{InternalError, TxValidationError}; use ethrex_levm::tracing::LevmCallTracer; +use ethrex_levm::utils::get_base_fee_per_blob_gas; use ethrex_levm::vm::VMType; use ethrex_levm::{ Environment, @@ -206,6 +207,7 @@ impl LEVM { &vm_type, )?; + let block_excess_blob_gas = block_header.excess_blob_gas.map(U256::from); let config = EVMConfig::new_from_chain_config(&chain_config, block_header); let env = Environment { origin: tx_sender, @@ -217,8 +219,9 @@ impl LEVM { prev_randao: Some(block_header.prev_randao), chain_id: chain_config.chain_id.into(), base_fee_per_gas: block_header.base_fee_per_gas.unwrap_or_default().into(), + base_blob_fee_per_gas: get_base_fee_per_blob_gas(block_excess_blob_gas, &config)?, gas_price, - block_excess_blob_gas: block_header.excess_blob_gas.map(U256::from), + block_excess_blob_gas, block_blob_gas_used: block_header.blob_gas_used.map(U256::from), tx_blob_hashes: tx.blob_versioned_hashes(), tx_max_priority_fee_per_gas: tx.max_priority_fee().map(U256::from), @@ -685,6 +688,7 @@ fn env_from_generic( let chain_config = db.store.get_chain_config()?; let gas_price = calculate_gas_price_for_generic(tx, header.base_fee_per_gas.unwrap_or(INITIAL_BASE_FEE)); + let block_excess_blob_gas = header.excess_blob_gas.map(U256::from); let config = EVMConfig::new_from_chain_config(&chain_config, header); Ok(Environment { origin: tx.from.0.into(), @@ -698,8 +702,9 @@ fn env_from_generic( prev_randao: Some(header.prev_randao), chain_id: chain_config.chain_id.into(), base_fee_per_gas: header.base_fee_per_gas.unwrap_or_default().into(), + base_blob_fee_per_gas: get_base_fee_per_blob_gas(block_excess_blob_gas, &config)?, gas_price, - block_excess_blob_gas: header.excess_blob_gas.map(U256::from), + block_excess_blob_gas, block_blob_gas_used: header.blob_gas_used.map(U256::from), tx_blob_hashes: tx.blob_versioned_hashes.clone(), tx_max_priority_fee_per_gas: tx.max_priority_fee_per_gas.map(U256::from), diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index 0a7d1c81cb2..215dc05c0b7 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -28,6 +28,7 @@ pub struct Environment { pub difficulty: U256, pub chain_id: U256, pub base_fee_per_gas: U256, + pub base_blob_fee_per_gas: U256, pub gas_price: U256, // Effective gas price pub block_excess_blob_gas: Option, pub block_blob_gas_used: Option, diff --git a/crates/vm/levm/src/hooks/default_hook.rs b/crates/vm/levm/src/hooks/default_hook.rs index ec3d1214d9d..df84045c41a 100644 --- a/crates/vm/levm/src/hooks/default_hook.rs +++ b/crates/vm/levm/src/hooks/default_hook.rs @@ -276,8 +276,7 @@ pub fn validate_max_fee_per_blob_gas( vm: &mut VM<'_>, tx_max_fee_per_blob_gas: U256, ) -> Result<(), VMError> { - let base_fee_per_blob_gas = - get_base_fee_per_blob_gas(vm.env.block_excess_blob_gas, &vm.env.config)?; + let base_fee_per_blob_gas = vm.env.base_blob_fee_per_gas; if tx_max_fee_per_blob_gas < base_fee_per_blob_gas { return Err(TxValidationError::InsufficientMaxFeePerBlobGas { base_fee_per_blob_gas, diff --git a/crates/vm/levm/src/opcode_handlers/block.rs b/crates/vm/levm/src/opcode_handlers/block.rs index e9a7f20076c..8e66250e193 100644 --- a/crates/vm/levm/src/opcode_handlers/block.rs +++ b/crates/vm/levm/src/opcode_handlers/block.rs @@ -166,17 +166,9 @@ impl<'a> VM<'a> { self.current_call_frame .increase_consumed_gas(gas_cost::BLOBBASEFEE)?; - let blob_base_fee = match self.blob_base_fee.get() { - Some(value) => *value, - None => { - let value = - get_base_fee_per_blob_gas(self.env.block_excess_blob_gas, &self.env.config)?; - _ = self.blob_base_fee.set(value); - value - } - }; - - self.current_call_frame.stack.push(blob_base_fee)?; + self.current_call_frame + .stack + .push(self.env.base_blob_fee_per_gas)?; Ok(OpcodeResult::Continue) } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index dfb38081272..ba1e0985374 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -23,7 +23,7 @@ use ethrex_common::{ types::{AccessListEntry, Code, Fork, Log, Transaction, fee_config::FeeConfig}, }; use std::{ - cell::{OnceCell, RefCell}, + cell::RefCell, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, mem, rc::Rc, @@ -327,8 +327,6 @@ pub struct VM<'a> { /// The opcode table mapping opcodes to opcode handlers for fast lookup. /// Build dynamically according to the given fork config. pub(crate) opcode_table: [OpCodeFn<'a>; 256], - /// Cached `BLOBBASEFEE` value. - pub(crate) blob_base_fee: OnceCell, } impl<'a> VM<'a> { @@ -378,7 +376,6 @@ impl<'a> VM<'a> { ), env, opcode_table: VM::build_opcode_table(fork), - blob_base_fee: OnceCell::new(), }; let call_type = if is_create { diff --git a/tooling/ef_tests/state/runner/levm_runner.rs b/tooling/ef_tests/state/runner/levm_runner.rs index 790b13e0c1f..330502d4853 100644 --- a/tooling/ef_tests/state/runner/levm_runner.rs +++ b/tooling/ef_tests/state/runner/levm_runner.rs @@ -17,6 +17,7 @@ use ethrex_levm::{ db::gen_db::GeneralizedDatabase, errors::{ExecutionReport, TxValidationError, VMError}, tracing::LevmCallTracer, + utils::get_base_fee_per_blob_gas, vm::{VM, VMType}, }; use ethrex_rlp::encode::RLPEncode; @@ -189,6 +190,12 @@ pub fn prepare_vm_for_tx<'a>( ..Default::default() }), }; + let base_blob_fee_per_gas = + get_base_fee_per_blob_gas(test.env.current_excess_blob_gas, &config).map_err(|e| { + EFTestRunnerError::FailedToEnsurePreState(format!( + "Failed to calculate base blob fee: {e}" + )) + })?; VM::new( Environment { @@ -202,6 +209,7 @@ pub fn prepare_vm_for_tx<'a>( difficulty: test.env.current_difficulty, chain_id: U256::from(1), base_fee_per_gas: test.env.current_base_fee.unwrap_or_default(), + base_blob_fee_per_gas, gas_price: effective_gas_price(test, &test_tx)?, block_excess_blob_gas: test.env.current_excess_blob_gas, block_blob_gas_used: None, diff --git a/tooling/ef_tests/state_v2/src/modules/runner.rs b/tooling/ef_tests/state_v2/src/modules/runner.rs index 861ba6332fa..cf3a5dc18f5 100644 --- a/tooling/ef_tests/state_v2/src/modules/runner.rs +++ b/tooling/ef_tests/state_v2/src/modules/runner.rs @@ -9,7 +9,10 @@ use ethrex_common::{ LegacyTransaction, Transaction, TxKind, }, }; -use ethrex_levm::{EVMConfig, Environment, tracing::LevmCallTracer, vm::VM, vm::VMType}; +use ethrex_levm::{ + EVMConfig, Environment, tracing::LevmCallTracer, utils::get_base_fee_per_blob_gas, vm::VM, + vm::VMType, +}; use crate::modules::{ error::RunnerError, @@ -112,6 +115,9 @@ pub fn get_vm_env_for_test( let blob_schedule = EVMConfig::canonical_values(test_case.fork); let config = EVMConfig::new(test_case.fork, blob_schedule); let gas_price = effective_gas_price(&test_env, test_case)?; + let base_blob_fee_per_gas = + get_base_fee_per_blob_gas(test_env.current_excess_blob_gas, &config) + .map_err(|e| RunnerError::Custom(format!("Failed to get blob base fee: {e}")))?; Ok(Environment { origin: test_case.sender, gas_limit: test_case.gas, @@ -123,6 +129,7 @@ pub fn get_vm_env_for_test( difficulty: test_env.current_difficulty, chain_id: U256::from(1), base_fee_per_gas: test_env.current_base_fee.unwrap_or_default(), + base_blob_fee_per_gas, gas_price, block_excess_blob_gas: test_env.current_excess_blob_gas, block_blob_gas_used: None,