diff --git a/Cargo.toml b/Cargo.toml index 3d8c5c55..b327a689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,19 +45,19 @@ alloy-eips = { version = "1.0.34", default-features = false } alloy-consensus = { version = "1.0.27", default-features = false } alloy-primitives = { version = "1.0.0", default-features = false } alloy-sol-types = { version = "1.0.0", default-features = false } -alloy-hardforks = { version = "0.4.2" } +alloy-hardforks = { version = "0.4.7" } alloy-rpc-types-eth = { version = "1.0.27", default-features = false } alloy-rpc-types-engine = { version = "1.0.27", default-features = false } # op-alloy -alloy-op-hardforks = { version = "0.4.2" } +alloy-op-hardforks = { version = "0.4.7" } op-alloy = { version = "0.23", default-features = false, features = [ "consensus", ] } # revm -revm = { version = "33.0.0", default-features = false } -op-revm = { version = "14.0.0", default-features = false } +revm = { version = "34.0.0", default-features = false } +op-revm = { version = "15.0.0", default-features = false } # misc auto_impl = "1" @@ -66,10 +66,3 @@ serde = { version = "1", default-features = false, features = ["derive"] } thiserror = { version = "2.0.0", default-features = false } serde_json = "1" test-case = "3" - -[patch.crates-io] -# revm = { git = "https://github.com/bluealloy/revm", rev = "11b16259" } -# op-revm = { git = "https://github.com/bluealloy/revm", rev = "11b16259" } - -#alloy-hardforks = { git = "https://github.com/alloy-rs/hardforks", rev = "0fd230f5aa24c4f6a8c593918b7449df0c20f60a" } -#alloy-op-hardforks = { git = "https://github.com/alloy-rs/hardforks", rev = "0fd230f5aa24c4f6a8c593918b7449df0c20f60a" } diff --git a/crates/evm/src/block/state.rs b/crates/evm/src/block/state.rs index 1f3ab1f0..47d0bf56 100644 --- a/crates/evm/src/block/state.rs +++ b/crates/evm/src/block/state.rs @@ -1,6 +1,5 @@ //! State database abstraction. -use alloy_primitives::Address; use revm::database::State; /// A type which has the state of the blockchain. @@ -9,19 +8,6 @@ use revm::database::State; pub trait StateDB: revm::Database { /// State clear EIP-161 is enabled in Spurious Dragon hardfork. fn set_state_clear_flag(&mut self, has_state_clear: bool); - - /// Iterates over received balances and increment all account balances. - /// - /// **Note**: If account is not found inside cache state it will be loaded from database. - /// - /// Update will create transitions for all accounts that are updated. - /// - /// If using this to implement withdrawals, zero balances must be filtered out before calling - /// this function. - fn increment_balances( - &mut self, - balances: impl IntoIterator, - ) -> Result<(), Self::Error>; } /// auto_impl unable to reconcile return associated type from supertrait @@ -29,24 +15,10 @@ impl StateDB for &mut T { fn set_state_clear_flag(&mut self, has_state_clear: bool) { StateDB::set_state_clear_flag(*self, has_state_clear); } - - fn increment_balances( - &mut self, - balances: impl IntoIterator, - ) -> Result<(), Self::Error> { - StateDB::increment_balances(*self, balances) - } } impl StateDB for State { fn set_state_clear_flag(&mut self, has_state_clear: bool) { self.cache.set_state_clear_flag(has_state_clear); } - - fn increment_balances( - &mut self, - balances: impl IntoIterator, - ) -> Result<(), Self::Error> { - Self::increment_balances(self, balances) - } } diff --git a/crates/evm/src/block/state_changes.rs b/crates/evm/src/block/state_changes.rs index 741481e4..5587317d 100644 --- a/crates/evm/src/block/state_changes.rs +++ b/crates/evm/src/block/state_changes.rs @@ -1,6 +1,7 @@ //! State changes that are not related to transactions. use super::{calc, BlockExecutionError}; +use alloc::boxed::Box; use alloy_consensus::BlockHeader; use alloy_eips::eip4895::{Withdrawal, Withdrawals}; use alloy_hardforks::EthereumHardforks; @@ -127,9 +128,9 @@ where *address, Account { info: account.clone(), - storage: Default::default(), + original_info: Box::new(account.clone()), status: AccountStatus::Touched, - transaction_id: 0, + ..Default::default() }, )) }; diff --git a/crates/evm/src/env.rs b/crates/evm/src/env.rs index c8bb0a2c..70b573ce 100644 --- a/crates/evm/src/env.rs +++ b/crates/evm/src/env.rs @@ -9,7 +9,7 @@ use revm::{ }; /// Container type that holds both the configuration and block environment for EVM execution. -#[derive(Debug, Clone, Default, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct EvmEnv { /// The configuration environment with handler settings pub cfg_env: CfgEnv, @@ -17,6 +17,12 @@ pub struct EvmEnv { pub block_env: BlockEnv, } +impl + Clone, B: Default> Default for EvmEnv { + fn default() -> Self { + Self { cfg_env: CfgEnv::new_with_spec(Spec::default()), block_env: B::default() } + } +} + impl EvmEnv { /// Create a new `EvmEnv` from its components. /// diff --git a/crates/evm/src/eth/block.rs b/crates/evm/src/eth/block.rs index 24cf34a6..7b435cbc 100644 --- a/crates/evm/src/eth/block.rs +++ b/crates/evm/src/eth/block.rs @@ -21,8 +21,10 @@ use alloy_eips::{eip4895::Withdrawals, eip7685::Requests, Encodable2718}; use alloy_hardforks::EthereumHardfork; use alloy_primitives::{Bytes, Log, B256}; use revm::{ - context::Block, context_interface::result::ResultAndState, database::State, DatabaseCommit, - Inspector, + context::Block, + context_interface::result::ResultAndState, + database::{DatabaseCommitExt, State}, + DatabaseCommit, Inspector, }; /// Context for Ethereum block execution. diff --git a/crates/evm/src/eth/mod.rs b/crates/evm/src/eth/mod.rs index 343169bd..8361d997 100644 --- a/crates/evm/src/eth/mod.rs +++ b/crates/evm/src/eth/mod.rs @@ -49,7 +49,7 @@ pub struct EthEvmBuilder { impl EthEvmBuilder { /// Creates a builder from the provided `EvmEnv` and database. - pub const fn new(db: DB, env: EvmEnv) -> Self { + pub fn new(db: DB, env: EvmEnv) -> Self { Self { db, block_env: env.block_env, diff --git a/crates/evm/src/op/env.rs b/crates/evm/src/op/env.rs index b073c63e..e729248f 100644 --- a/crates/evm/src/op/env.rs +++ b/crates/evm/src/op/env.rs @@ -54,7 +54,7 @@ impl EvmEnv { fn for_op(input: EvmEnvInput, chain_spec: impl OpHardforks, chain_id: ChainId) -> Self { let spec = crate::op::spec_by_timestamp_after_bedrock(&chain_spec, input.timestamp); - let cfg_env = CfgEnv::new().with_chain_id(chain_id).with_spec(spec); + let cfg_env = CfgEnv::new().with_chain_id(chain_id).with_spec_and_mainnet_gas_params(spec); let blob_excess_gas_and_price = spec .into_eth_spec() diff --git a/crates/evm/src/overrides.rs b/crates/evm/src/overrides.rs index ce71c90b..a3f4ee9d 100644 --- a/crates/evm/src/overrides.rs +++ b/crates/evm/src/overrides.rs @@ -3,7 +3,7 @@ //! This module provides helper functions for RPC implementations, including: //! - Block and state overrides -use alloc::collections::BTreeMap; +use alloc::{boxed::Box, collections::BTreeMap}; use alloy_primitives::{keccak256, map::HashMap, Address, B256, U256}; use alloy_rpc_types_eth::{ state::{AccountOverride, StateOverride}, @@ -144,7 +144,8 @@ where // Create a new account marked as touched let mut acc = revm::state::Account { - info, + info: info.clone(), + original_info: Box::new(info), status: AccountStatus::Touched, storage: Default::default(), transaction_id: 0, diff --git a/crates/evm/src/traits.rs b/crates/evm/src/traits.rs index 6ea028d4..d3781673 100644 --- a/crates/evm/src/traits.rs +++ b/crates/evm/src/traits.rs @@ -6,8 +6,8 @@ use alloy_primitives::{Address, Log, B256, U256}; use core::{error::Error, fmt, fmt::Debug}; use revm::{ context::{ - journaled_state::TransferError, Block, Cfg, ContextTr, DBErrorMarker, JournalTr, - Transaction, + journaled_state::{account::JournaledAccountTr, TransferError}, + Block, Cfg, ContextTr, DBErrorMarker, JournalTr, Transaction, }, interpreter::{SStoreResult, StateLoad}, primitives::{StorageKey, StorageValue}, @@ -50,20 +50,44 @@ impl EvmInternalsError { trait EvmInternalsTr: Database + Debug { fn load_account(&mut self, address: Address) -> Result, EvmInternalsError>; - fn load_account_code( - &mut self, + fn load_account_mut_skip_cold_load<'a>( + &'a mut self, + address: Address, + skip_cold_load: bool, + ) -> Result>, EvmInternalsError>; + + /// Loads an account mutably. + fn load_account_mut<'a>( + &'a mut self, + address: Address, + ) -> Result>, EvmInternalsError> { + self.load_account_mut_skip_cold_load(address, false) + } + + fn load_account_code<'a>( + &'a mut self, address: Address, - ) -> Result, EvmInternalsError>; + ) -> Result>, EvmInternalsError> { + let mut account = self.load_account_mut(address)?; + account.load_code().map_err(|e| EvmInternalsError::database(e.unwrap_db_error()))?; + Ok(account) + } /// Increments the balance of the account. - fn balance_incr(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError>; + fn balance_incr(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> { + self.load_account_mut(address)?.incr_balance(balance); + Ok(()) + } /// Sets the balance of the the account /// /// Touches the account in all cases. /// /// If the given `balance` is the same as the account's, no journal entry is created. - fn set_balance(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError>; + fn set_balance(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> { + self.load_account_mut(address)?.set_balance(balance); + Ok(()) + } /// Transfers the balance from one account to another. /// @@ -78,27 +102,60 @@ trait EvmInternalsTr: Database + Debug { /// Increments the nonce of the account. /// /// This creates a new journal entry with this change. - fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError>; + fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError> { + self.load_account_mut(address)?.bump_nonce(); + Ok(()) + } fn sload( &mut self, address: Address, key: StorageKey, - ) -> Result, EvmInternalsError>; + ) -> Result, EvmInternalsError> { + self.load_account_mut(address)? + .sload(key, false) + .map(|i| i.map(|i| i.present_value())) + .map_err(|e| EvmInternalsError::database(e.unwrap_db_error())) + } - fn touch_account(&mut self, address: Address); + fn touch_account(&mut self, address: Address) -> Result<(), EvmInternalsError> { + self.load_account_mut(address)?.touch(); + Ok(()) + } - fn set_code(&mut self, address: Address, code: Bytecode); + /// Sets bytecode to the account. Internally calls [`EvmInternalsTr::set_code_with_hash`]. + /// + /// This will load the account, mark it as touched and set the code and code hash. + /// It will return an error if database error occurs. + fn set_code(&mut self, address: Address, code: Bytecode) -> Result<(), EvmInternalsError> { + let hash = code.hash_slow(); + self.set_code_with_hash(address, code, hash) + } - /// Sets bytecode with hash. Assume that account is warm. - fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256); + /// Sets bytecode with hash to the account. + /// + /// This will load the account, mark it as touched and set the code and code hash. + /// It will return an error if database error occurs. + fn set_code_with_hash( + &mut self, + address: Address, + code: Bytecode, + hash: B256, + ) -> Result<(), EvmInternalsError> { + self.load_account_mut(address)?.set_code(hash, code); + Ok(()) + } fn sstore( &mut self, address: Address, key: StorageKey, value: StorageValue, - ) -> Result, EvmInternalsError>; + ) -> Result, EvmInternalsError> { + self.load_account_mut(address)? + .sstore(key, value, false) + .map_err(|e| EvmInternalsError::database(e.unwrap_db_error())) + } fn log(&mut self, log: Log); @@ -146,21 +203,19 @@ where self.0.load_account(address).map_err(EvmInternalsError::database) } - fn load_account_code( - &mut self, + fn load_account_mut_skip_cold_load<'a>( + &'a mut self, address: Address, - ) -> Result, EvmInternalsError> { - self.0.load_account_with_code(address).map_err(EvmInternalsError::database) - } - - fn balance_incr(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> { - self.0.balance_incr(address, balance).map_err(EvmInternalsError::database) - } - - fn set_balance(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> { - let mut account = self.0.load_account_mut(address).map_err(EvmInternalsError::database)?; - account.set_balance(balance); - Ok(()) + skip_cold_load: bool, + ) -> Result>, EvmInternalsError> { + self.0 + .load_account_mut_skip_cold_load(address, skip_cold_load) + .map(|state_load| { + state_load.map(|journaled_account| { + Box::new(journaled_account) as Box + }) + }) + .map_err(EvmInternalsError::database) } fn transfer( @@ -172,40 +227,6 @@ where self.0.transfer(from, to, balance).map_err(EvmInternalsError::database) } - fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError> { - self.0.load_account_mut(address).map_err(EvmInternalsError::database)?.bump_nonce(); - Ok(()) - } - - fn sload( - &mut self, - address: Address, - key: StorageKey, - ) -> Result, EvmInternalsError> { - self.0.sload(address, key).map_err(EvmInternalsError::database) - } - - fn touch_account(&mut self, address: Address) { - self.0.touch_account(address); - } - - fn set_code(&mut self, address: Address, code: Bytecode) { - self.0.set_code(address, code); - } - - fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) { - self.0.set_code_with_hash(address, code, hash); - } - - fn sstore( - &mut self, - address: Address, - key: StorageKey, - value: StorageValue, - ) -> Result, EvmInternalsError> { - self.0.sstore(address, key, value).map_err(EvmInternalsError::database) - } - fn log(&mut self, log: Log) { self.0.log(log); } @@ -298,11 +319,28 @@ impl<'a> EvmInternals<'a> { self.internals.load_account(address) } + /// Loads an account. + pub fn load_account_mut<'b>( + &'b mut self, + address: Address, + ) -> Result>, EvmInternalsError> { + self.internals.load_account_mut(address) + } + + /// Loads an account mutably, skipping cold load if specified. + pub fn load_account_mut_skip_cold_load<'b>( + &'b mut self, + address: Address, + skip_cold_load: bool, + ) -> Result>, EvmInternalsError> { + self.internals.load_account_mut_skip_cold_load(address, skip_cold_load) + } + /// Loads an account AND it's code. - pub fn load_account_code( - &mut self, + pub fn load_account_code<'b>( + &'b mut self, address: Address, - ) -> Result, EvmInternalsError> { + ) -> Result>, EvmInternalsError> { self.internals.load_account_code(address) } @@ -357,23 +395,36 @@ impl<'a> EvmInternals<'a> { } /// Touches the account. - pub fn touch_account(&mut self, address: Address) { - self.internals.touch_account(address); + /// + /// This will load the account and return an error if database error occurs. + pub fn touch_account(&mut self, address: Address) -> Result<(), EvmInternalsError> { + self.internals.touch_account(address) } /// Sets bytecode to the account. - pub fn set_code(&mut self, address: Address, code: Bytecode) { - self.internals.set_code(address, code); + /// + /// This will load the account, mark it as touched and set the code and code hash. + /// It will return an error if database error occurs. + pub fn set_code(&mut self, address: Address, code: Bytecode) -> Result<(), EvmInternalsError> { + self.internals.set_code(address, code) } /// Sets bytecode with hash to the account. /// - /// Assumes that the account is warm. - pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) { - self.internals.set_code_with_hash(address, code, hash); + /// This will load the account, mark it as touched and set the code and code hash. + /// It will return an error if database error occurs. + pub fn set_code_with_hash( + &mut self, + address: Address, + code: Bytecode, + hash: B256, + ) -> Result<(), EvmInternalsError> { + self.internals.set_code_with_hash(address, code, hash) } /// Stores the storage value in Journal state. + /// + /// This will load the account and storage value and return an error if database error occurs. pub fn sstore( &mut self, address: Address, diff --git a/crates/op-evm/src/block/mod.rs b/crates/op-evm/src/block/mod.rs index 9960cac6..6d9c8a17 100644 --- a/crates/op-evm/src/block/mod.rs +++ b/crates/op-evm/src/block/mod.rs @@ -26,7 +26,7 @@ pub use receipt_builder::OpAlloyReceiptBuilder; use receipt_builder::OpReceiptBuilder; use revm::{ context::{result::ResultAndState, Block}, - database::State, + database::{DatabaseCommitExt, State}, Database as _, DatabaseCommit, Inspector, }; diff --git a/deny.toml b/deny.toml index 607ec730..e32a2135 100644 --- a/deny.toml +++ b/deny.toml @@ -50,5 +50,5 @@ unknown-registry = "deny" unknown-git = "deny" allow-git = [ "https://github.com/bluealloy/revm", - "https://github.com/alloy-rs/hardforks", + #"https://github.com/alloy-rs/hardforks", ]