diff --git a/Cargo.lock b/Cargo.lock index 4365f595f4..5584cdade2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2593,9 +2593,6 @@ dependencies = [ "indicatif", "once_cell", "revm", - "revm-database", - "revm-inspector", - "revm-precompile", "rstest", "serde", ] diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index 17261787bb..7cf016fd20 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true [dependencies] # revm -revm = { workspace = true, features = ["std", "hashbrown", "c-kzg", "blst"] } +revm = { workspace = true, features = ["std", "hashbrown", "c-kzg", "blst", "serde-json"] } primitives.workspace = true database.workspace = true database-interface.workspace = true diff --git a/crates/context/interface/src/context.rs b/crates/context/interface/src/context.rs index e3cfbafbac..a707fe5c92 100644 --- a/crates/context/interface/src/context.rs +++ b/crates/context/interface/src/context.rs @@ -1,5 +1,5 @@ pub use crate::journaled_state::StateLoad; -use crate::{Block, Cfg, Database, Journal, Transaction}; +use crate::{Block, Cfg, Database, JournalTr, Transaction}; use auto_impl::auto_impl; use primitives::U256; @@ -9,7 +9,7 @@ pub trait ContextTr { type Tx: Transaction; type Cfg: Cfg; type Db: Database; - type Journal: Journal; + type Journal: JournalTr; type Chain; fn tx(&self) -> &Self::Tx; diff --git a/crates/context/interface/src/journaled_state.rs b/crates/context/interface/src/journaled_state.rs index 9675a12d49..fc96f352b7 100644 --- a/crates/context/interface/src/journaled_state.rs +++ b/crates/context/interface/src/journaled_state.rs @@ -8,7 +8,7 @@ use state::{ Account, Bytecode, }; -pub trait Journal { +pub trait JournalTr { type Database: Database; type FinalOutput; @@ -177,7 +177,7 @@ pub trait Journal { /// Does cleanup and returns modified state. /// - /// This resets the [Journal] to its initial state. + /// This resets the [JournalTr] to its initial state. fn finalize(&mut self) -> Self::FinalOutput; } diff --git a/crates/context/interface/src/lib.rs b/crates/context/interface/src/lib.rs index 79689a00b4..bd0ef4991c 100644 --- a/crates/context/interface/src/lib.rs +++ b/crates/context/interface/src/lib.rs @@ -16,5 +16,5 @@ pub use block::Block; pub use cfg::{Cfg, CreateScheme, TransactTo}; pub use context::ContextTr; pub use database_interface::{DBErrorMarker, Database}; -pub use journaled_state::Journal; +pub use journaled_state::JournalTr; pub use transaction::{Transaction, TransactionType}; diff --git a/crates/context/src/context.rs b/crates/context/src/context.rs index 4b397c71ac..53394cacde 100644 --- a/crates/context/src/context.rs +++ b/crates/context/src/context.rs @@ -1,5 +1,5 @@ -use crate::{block::BlockEnv, cfg::CfgEnv, journaled_state::JournaledState, tx::TxEnv}; -use context_interface::{Block, Cfg, ContextTr, Journal, Transaction}; +use crate::{block::BlockEnv, cfg::CfgEnv, journaled_state::Journal, tx::TxEnv}; +use context_interface::{Block, Cfg, ContextTr, JournalTr, Transaction}; use database_interface::{Database, EmptyDB}; use derive_where::derive_where; use specification::hardfork::SpecId; @@ -11,7 +11,7 @@ pub struct Context< TX = TxEnv, CFG = CfgEnv, DB: Database = EmptyDB, - JOURNAL: Journal = JournaledState, + JOURNAL: JournalTr = Journal, CHAIN = (), > { /// Block information. @@ -33,7 +33,7 @@ impl< TX: Transaction, DB: Database, CFG: Cfg, - JOURNAL: Journal, + JOURNAL: JournalTr, CHAIN, > ContextTr for Context { @@ -91,7 +91,7 @@ impl< BLOCK: Block + Default, TX: Transaction + Default, DB: Database, - JOURNAL: Journal, + JOURNAL: JournalTr, CHAIN: Default, > Context { @@ -118,9 +118,9 @@ where TX: Transaction, CFG: Cfg, DB: Database, - JOURNAL: Journal, + JOURNAL: JournalTr, { - pub fn with_new_journal>( + pub fn with_new_journal>( self, mut journal: OJOURNAL, ) -> Context { @@ -139,9 +139,9 @@ where pub fn with_db( self, db: ODB, - ) -> Context, CHAIN> { + ) -> Context, CHAIN> { let spec = self.cfg.spec().into(); - let mut journaled_state = JournaledState::new(spec, db); + let mut journaled_state = Journal::new(spec, db); journaled_state.set_spec_id(spec); Context { tx: self.tx, diff --git a/crates/context/src/journal_init.rs b/crates/context/src/journal_init.rs deleted file mode 100644 index 083cf36a09..0000000000 --- a/crates/context/src/journal_init.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::journaled_state::JournaledState; -use database_interface::EmptyDB; - -/// A clonable version of JournaledState that uses EmptyDB. -pub type JournalInit = JournaledState; - -impl JournaledState { - pub fn into_init(self) -> JournalInit { - JournalInit { - database: EmptyDB::default(), - state: self.state, - transient_storage: self.transient_storage, - logs: self.logs, - depth: self.depth, - journal: self.journal, - spec: self.spec, - warm_preloaded_addresses: self.warm_preloaded_addresses, - precompiles: self.precompiles, - } - } - - pub fn to_init(&self) -> JournalInit { - JournalInit { - database: EmptyDB::default(), - state: self.state.clone(), - transient_storage: self.transient_storage.clone(), - logs: self.logs.clone(), - depth: self.depth, - journal: self.journal.clone(), - spec: self.spec, - warm_preloaded_addresses: self.warm_preloaded_addresses.clone(), - precompiles: self.precompiles.clone(), - } - } -} diff --git a/crates/context/src/journaled_state.rs b/crates/context/src/journaled_state.rs index 6b0d00675a..b70be78ed8 100644 --- a/crates/context/src/journaled_state.rs +++ b/crates/context/src/journaled_state.rs @@ -1,55 +1,21 @@ +mod entry; +mod init; + +pub use entry::{JournalEntry, JournalEntryTr}; +pub use init::JournalInit; + use bytecode::Bytecode; use context_interface::{ context::{SStoreResult, SelfDestructResult, StateLoad}, - journaled_state::{AccountLoad, Journal, JournalCheckpoint, TransferError}, + journaled_state::{AccountLoad, JournalCheckpoint, JournalTr, TransferError}, }; +use core::mem; use database_interface::Database; -use primitives::{ - hash_map::Entry, Address, HashMap, HashSet, Log, B256, KECCAK_EMPTY, PRECOMPILE3, U256, -}; +use primitives::{hash_map::Entry, Address, HashMap, HashSet, Log, B256, KECCAK_EMPTY, U256}; use specification::hardfork::{SpecId, SpecId::*}; use state::{Account, EvmState, EvmStorageSlot, TransientStorage}; - -use core::mem; use std::{vec, vec::Vec}; -use crate::JournalInit; - -/// Trait for journal entries. it tracks changes across the state and allows to revert them. -pub trait JournalEntryTr { - fn account_warmed(address: Address) -> Self; - - fn account_destroyed( - address: Address, - target: Address, - was_destroyed: bool, - had_balance: U256, - ) -> Self; - - fn account_touched(address: Address) -> Self; - - fn balance_transfer(from: Address, to: Address, balance: U256) -> Self; - - fn nonce_changed(address: Address) -> Self; - - fn account_created(address: Address) -> Self; - - fn storage_changed(address: Address, key: U256, had_value: U256) -> Self; - - fn storage_warmed(address: Address, key: U256) -> Self; - - fn transient_storage_changed(address: Address, key: U256, had_value: U256) -> Self; - - fn code_changed(address: Address) -> Self; - - fn revert( - self, - state: &mut EvmState, - transient_storage: &mut TransientStorage, - is_spurious_dragon_enabled: bool, - ); -} - /// A journal of state changes internal to the EVM /// /// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added. @@ -57,7 +23,7 @@ pub trait JournalEntryTr { /// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct JournaledState +pub struct Journal where ENTRY: JournalEntryTr, { @@ -96,12 +62,19 @@ where pub precompiles: HashSet
, } -impl Journal for JournaledState { +/// Output of the journal after finalizing. +pub struct JournalOutput { + /// Changes or touched accounts that loads, created or changed in the journal. + pub state: EvmState, + /// Logs that were emitted by contract calls. + pub logs: Vec, +} + +impl JournalTr for Journal { type Database = DB; - // TODO : Make a struck here. - type FinalOutput = (EvmState, Vec); + type FinalOutput = JournalOutput; - fn new(database: DB) -> JournaledState { + fn new(database: DB) -> Journal { Self::new(SpecId::LATEST, database) } @@ -276,11 +249,11 @@ impl Journal for JournaledState let state = mem::take(state); let logs = mem::take(logs); - (state, logs) + JournalOutput { state, logs } } } -impl JournaledState { +impl Journal { /// Creates new JournaledState. /// /// `warm_preloaded_addresses` is used to determine if address is considered warm loaded. @@ -289,7 +262,7 @@ impl JournaledState { /// # Note /// This function will journal state after Spurious Dragon fork. /// And will not take into account if account is not existing or empty. - pub fn new(spec: SpecId, database: DB) -> JournaledState { + pub fn new(spec: SpecId, database: DB) -> Journal { Self { database, state: HashMap::default(), @@ -518,19 +491,6 @@ impl JournaledState { Ok(checkpoint) } - /// Reverts all changes that happened in given journal entries. - #[inline] - fn journal_revert( - state: &mut EvmState, - transient_storage: &mut TransientStorage, - journal_entries: Vec, - is_spurious_dragon_enabled: bool, - ) { - for entry in journal_entries.into_iter().rev() { - entry.revert(state, transient_storage, is_spurious_dragon_enabled); - } - } - /// Makes a checkpoint that in case of Revert can bring back state to this point. #[inline] pub fn checkpoint(&mut self) -> JournalCheckpoint { @@ -563,12 +523,9 @@ impl JournaledState { .rev() .take(len - checkpoint.journal_i) .for_each(|cs| { - Self::journal_revert( - state, - transient_storage, - mem::take(cs), - is_spurious_dragon_enabled, - ) + for entry in mem::take(cs).into_iter().rev() { + entry.revert(state, transient_storage, is_spurious_dragon_enabled); + } }); self.logs.truncate(checkpoint.log_i); @@ -910,236 +867,10 @@ impl JournaledState { } } -/// Journal entries that are used to track changes to the state and are used to revert it. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum JournalEntry { - /// Used to mark account that is warm inside EVM in regard to EIP-2929 AccessList. - /// Action: We will add Account to state. - /// Revert: we will remove account from state. - AccountWarmed { address: Address }, - /// Mark account to be destroyed and journal balance to be reverted - /// Action: Mark account and transfer the balance - /// Revert: Unmark the account and transfer balance back - AccountDestroyed { - address: Address, - target: Address, - was_destroyed: bool, // if account had already been destroyed before this journal entry - had_balance: U256, - }, - /// Loading account does not mean that account will need to be added to MerkleTree (touched). - /// Only when account is called (to execute contract or transfer balance) only then account is made touched. - /// Action: Mark account touched - /// Revert: Unmark account touched - AccountTouched { address: Address }, - /// Transfer balance between two accounts - /// Action: Transfer balance - /// Revert: Transfer balance back - BalanceTransfer { - from: Address, - to: Address, - balance: U256, - }, - /// Increment nonce - /// Action: Increment nonce by one - /// Revert: Decrement nonce by one - NonceChange { - address: Address, //geth has nonce value, - }, - /// Create account: - /// Actions: Mark account as created - /// Revert: Unmark account as created and reset nonce to zero. - AccountCreated { address: Address }, - /// Entry used to track storage changes - /// Action: Storage change - /// Revert: Revert to previous value - StorageChanged { - address: Address, - key: U256, - had_value: U256, - }, - /// Entry used to track storage warming introduced by EIP-2929. - /// Action: Storage warmed - /// Revert: Revert to cold state - StorageWarmed { address: Address, key: U256 }, - /// It is used to track an EIP-1153 transient storage change. - /// Action: Transient storage changed. - /// Revert: Revert to previous value. - TransientStorageChange { - address: Address, - key: U256, - had_value: U256, - }, - /// Code changed - /// Action: Account code changed - /// Revert: Revert to previous bytecode. - CodeChange { address: Address }, -} -impl JournalEntryTr for JournalEntry { - fn account_warmed(address: Address) -> Self { - JournalEntry::AccountWarmed { address } - } - - fn account_destroyed( - address: Address, - target: Address, - was_destroyed: bool, // if account had already been destroyed before this journal entry - had_balance: U256, - ) -> Self { - JournalEntry::AccountDestroyed { - address, - target, - was_destroyed, - had_balance, - } - } - - fn account_touched(address: Address) -> Self { - JournalEntry::AccountTouched { address } - } - - fn balance_transfer(from: Address, to: Address, balance: U256) -> Self { - JournalEntry::BalanceTransfer { from, to, balance } - } - - fn account_created(address: Address) -> Self { - JournalEntry::AccountCreated { address } - } - - fn storage_changed(address: Address, key: U256, had_value: U256) -> Self { - JournalEntry::StorageChanged { - address, - key, - had_value, - } - } - - fn nonce_changed(address: Address) -> Self { - JournalEntry::NonceChange { address } - } - - fn storage_warmed(address: Address, key: U256) -> Self { - JournalEntry::StorageWarmed { address, key } - } - - fn transient_storage_changed(address: Address, key: U256, had_value: U256) -> Self { - JournalEntry::TransientStorageChange { - address, - key, - had_value, - } - } - - fn code_changed(address: Address) -> Self { - JournalEntry::CodeChange { address } - } - - fn revert( - self, - state: &mut EvmState, - transient_storage: &mut TransientStorage, - is_spurious_dragon_enabled: bool, - ) { - match self { - JournalEntry::AccountWarmed { address } => { - state.get_mut(&address).unwrap().mark_cold(); - } - JournalEntry::AccountTouched { address } => { - if is_spurious_dragon_enabled && address == PRECOMPILE3 { - return; - } - // remove touched status - state.get_mut(&address).unwrap().unmark_touch(); - } - JournalEntry::AccountDestroyed { - address, - target, - was_destroyed, - had_balance, - } => { - let account = state.get_mut(&address).unwrap(); - // set previous state of selfdestructed flag, as there could be multiple - // selfdestructs in one transaction. - if was_destroyed { - // flag is still selfdestructed - account.mark_selfdestruct(); - } else { - // flag that is not selfdestructed - account.unmark_selfdestruct(); - } - account.info.balance += had_balance; - - if address != target { - let target = state.get_mut(&target).unwrap(); - target.info.balance -= had_balance; - } - } - JournalEntry::BalanceTransfer { from, to, balance } => { - // we don't need to check overflow and underflow when adding and subtracting the balance. - let from = state.get_mut(&from).unwrap(); - from.info.balance += balance; - let to = state.get_mut(&to).unwrap(); - to.info.balance -= balance; - } - JournalEntry::NonceChange { address } => { - state.get_mut(&address).unwrap().info.nonce -= 1; - } - JournalEntry::AccountCreated { address } => { - let account = &mut state.get_mut(&address).unwrap(); - account.unmark_created(); - account - .storage - .values_mut() - .for_each(|slot| slot.mark_cold()); - account.info.nonce = 0; - } - JournalEntry::StorageWarmed { address, key } => { - state - .get_mut(&address) - .unwrap() - .storage - .get_mut(&key) - .unwrap() - .mark_cold(); - } - JournalEntry::StorageChanged { - address, - key, - had_value, - } => { - state - .get_mut(&address) - .unwrap() - .storage - .get_mut(&key) - .unwrap() - .present_value = had_value; - } - JournalEntry::TransientStorageChange { - address, - key, - had_value, - } => { - let tkey = (address, key); - if had_value.is_zero() { - // if previous value is zero, remove it - transient_storage.remove(&tkey); - } else { - // if not zero, reinsert old value to transient storage. - transient_storage.insert(tkey, had_value); - } - } - JournalEntry::CodeChange { address } => { - let acc = state.get_mut(&address).unwrap(); - acc.info.code_hash = KECCAK_EMPTY; - acc.info.code = None; - } - } - } -} - -impl JournaledState { - /// Initialize a new JournaledState from JournalInit with a database +impl Journal { + /// Creates a new JournaledState by copying state data from a JournalInit and provided database. + /// This allows reusing the state, logs, and other data from a previous execution context while + /// connecting it to a different database backend. pub fn from_init(init: &JournalInit, database: DB) -> Self { Self { database, diff --git a/crates/context/src/journaled_state/entry.rs b/crates/context/src/journaled_state/entry.rs new file mode 100644 index 0000000000..45e066a0c8 --- /dev/null +++ b/crates/context/src/journaled_state/entry.rs @@ -0,0 +1,299 @@ +use primitives::{Address, KECCAK_EMPTY, PRECOMPILE3, U256}; +use state::{EvmState, TransientStorage}; + +/// Trait for tracking and reverting state changes in the EVM. +/// Journal entry contains information about state changes that can be reverted. +pub trait JournalEntryTr { + /// Creates a journal entry for when an account is accessed and marked as "warm" for gas metering + fn account_warmed(address: Address) -> Self; + + /// Creates a journal entry for when an account is destroyed via SELFDESTRUCT + /// Records the target address that received the destroyed account's balance, + /// whether the account was already destroyed, and its balance before destruction + /// on revert, the balance is transferred back to the original account + fn account_destroyed( + address: Address, + target: Address, + was_destroyed: bool, + had_balance: U256, + ) -> Self; + + /// Creates a journal entry for when an account is "touched" - accessed in a way that may require saving it. + /// If account is empty and touch it will be removed from the state (EIP-161 state clear EIP) + fn account_touched(address: Address) -> Self; + + /// Creates a journal entry for a balance transfer between accounts + fn balance_transfer(from: Address, to: Address, balance: U256) -> Self; + + /// Creates a journal entry for when an account's nonce is incremented. + fn nonce_changed(address: Address) -> Self; + + /// Creates a journal entry for when a new account is created + fn account_created(address: Address) -> Self; + + /// Creates a journal entry for when a storage slot is modified + /// Records the previous value for reverting + fn storage_changed(address: Address, key: U256, had_value: U256) -> Self; + + /// Creates a journal entry for when a storage slot is accessed and marked as "warm" for gas metering + /// This is called with SLOAD opcode. + fn storage_warmed(address: Address, key: U256) -> Self; + + /// Creates a journal entry for when a transient storage slot is modified (EIP-1153) + /// Records the previous value for reverting + fn transient_storage_changed(address: Address, key: U256, had_value: U256) -> Self; + + /// Creates a journal entry for when an account's code is modified + fn code_changed(address: Address) -> Self; + + /// Reverts the state change recorded by this journal entry + /// + /// More information on what is reverted can be found in [`JournalEntry`] enum. + /// + /// # Notes + /// + /// The spurious dragon flag is used to skip revertion 0x000..0003 precompile. This + /// Behaviour is special and it caused by bug in Geth and Parity that is explained in [PR#716](https://github.com/ethereum/EIPs/issues/716). + /// + /// From yellow paper: + /// ```text + /// K.1. Deletion of an Account Despite Out-of-gas. At block 2675119, in the transaction 0xcf416c536ec1a19ed1fb89e + /// 4ec7ffb3cf73aa413b3aa9b77d60e4fd81a4296ba, an account at address 0x03 was called and an out-of-gas occurred during + /// the call. Against the equation (209), this added 0x03 in the set of touched addresses, and this transaction turned σ[0x03] + /// into ∅. + /// ``` + fn revert( + self, + state: &mut EvmState, + transient_storage: &mut TransientStorage, + is_spurious_dragon_enabled: bool, + ); +} + +/// Journal entries that are used to track changes to the state and are used to revert it. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum JournalEntry { + /// Used to mark account that is warm inside EVM in regard to EIP-2929 AccessList. + /// Action: We will add Account to state. + /// Revert: we will remove account from state. + AccountWarmed { address: Address }, + /// Mark account to be destroyed and journal balance to be reverted + /// Action: Mark account and transfer the balance + /// Revert: Unmark the account and transfer balance back + AccountDestroyed { + address: Address, + target: Address, + was_destroyed: bool, // if account had already been destroyed before this journal entry + had_balance: U256, + }, + /// Loading account does not mean that account will need to be added to MerkleTree (touched). + /// Only when account is called (to execute contract or transfer balance) only then account is made touched. + /// Action: Mark account touched + /// Revert: Unmark account touched + AccountTouched { address: Address }, + /// Transfer balance between two accounts + /// Action: Transfer balance + /// Revert: Transfer balance back + BalanceTransfer { + from: Address, + to: Address, + balance: U256, + }, + /// Increment nonce + /// Action: Increment nonce by one + /// Revert: Decrement nonce by one + NonceChange { + address: Address, //geth has nonce value, + }, + /// Create account: + /// Actions: Mark account as created + /// Revert: Unmark account as created and reset nonce to zero. + AccountCreated { address: Address }, + /// Entry used to track storage changes + /// Action: Storage change + /// Revert: Revert to previous value + StorageChanged { + address: Address, + key: U256, + had_value: U256, + }, + /// Entry used to track storage warming introduced by EIP-2929. + /// Action: Storage warmed + /// Revert: Revert to cold state + StorageWarmed { address: Address, key: U256 }, + /// It is used to track an EIP-1153 transient storage change. + /// Action: Transient storage changed. + /// Revert: Revert to previous value. + TransientStorageChange { + address: Address, + key: U256, + had_value: U256, + }, + /// Code changed + /// Action: Account code changed + /// Revert: Revert to previous bytecode. + CodeChange { address: Address }, +} +impl JournalEntryTr for JournalEntry { + fn account_warmed(address: Address) -> Self { + JournalEntry::AccountWarmed { address } + } + + fn account_destroyed( + address: Address, + target: Address, + was_destroyed: bool, // if account had already been destroyed before this journal entry + had_balance: U256, + ) -> Self { + JournalEntry::AccountDestroyed { + address, + target, + was_destroyed, + had_balance, + } + } + + fn account_touched(address: Address) -> Self { + JournalEntry::AccountTouched { address } + } + + fn balance_transfer(from: Address, to: Address, balance: U256) -> Self { + JournalEntry::BalanceTransfer { from, to, balance } + } + + fn account_created(address: Address) -> Self { + JournalEntry::AccountCreated { address } + } + + fn storage_changed(address: Address, key: U256, had_value: U256) -> Self { + JournalEntry::StorageChanged { + address, + key, + had_value, + } + } + + fn nonce_changed(address: Address) -> Self { + JournalEntry::NonceChange { address } + } + + fn storage_warmed(address: Address, key: U256) -> Self { + JournalEntry::StorageWarmed { address, key } + } + + fn transient_storage_changed(address: Address, key: U256, had_value: U256) -> Self { + JournalEntry::TransientStorageChange { + address, + key, + had_value, + } + } + + fn code_changed(address: Address) -> Self { + JournalEntry::CodeChange { address } + } + + fn revert( + self, + state: &mut EvmState, + transient_storage: &mut TransientStorage, + is_spurious_dragon_enabled: bool, + ) { + match self { + JournalEntry::AccountWarmed { address } => { + state.get_mut(&address).unwrap().mark_cold(); + } + JournalEntry::AccountTouched { address } => { + if is_spurious_dragon_enabled && address == PRECOMPILE3 { + return; + } + // remove touched status + state.get_mut(&address).unwrap().unmark_touch(); + } + JournalEntry::AccountDestroyed { + address, + target, + was_destroyed, + had_balance, + } => { + let account = state.get_mut(&address).unwrap(); + // set previous state of selfdestructed flag, as there could be multiple + // selfdestructs in one transaction. + if was_destroyed { + // flag is still selfdestructed + account.mark_selfdestruct(); + } else { + // flag that is not selfdestructed + account.unmark_selfdestruct(); + } + account.info.balance += had_balance; + + if address != target { + let target = state.get_mut(&target).unwrap(); + target.info.balance -= had_balance; + } + } + JournalEntry::BalanceTransfer { from, to, balance } => { + // we don't need to check overflow and underflow when adding and subtracting the balance. + let from = state.get_mut(&from).unwrap(); + from.info.balance += balance; + let to = state.get_mut(&to).unwrap(); + to.info.balance -= balance; + } + JournalEntry::NonceChange { address } => { + state.get_mut(&address).unwrap().info.nonce -= 1; + } + JournalEntry::AccountCreated { address } => { + let account = &mut state.get_mut(&address).unwrap(); + account.unmark_created(); + account + .storage + .values_mut() + .for_each(|slot| slot.mark_cold()); + account.info.nonce = 0; + } + JournalEntry::StorageWarmed { address, key } => { + state + .get_mut(&address) + .unwrap() + .storage + .get_mut(&key) + .unwrap() + .mark_cold(); + } + JournalEntry::StorageChanged { + address, + key, + had_value, + } => { + state + .get_mut(&address) + .unwrap() + .storage + .get_mut(&key) + .unwrap() + .present_value = had_value; + } + JournalEntry::TransientStorageChange { + address, + key, + had_value, + } => { + let tkey = (address, key); + if had_value.is_zero() { + // if previous value is zero, remove it + transient_storage.remove(&tkey); + } else { + // if not zero, reinsert old value to transient storage. + transient_storage.insert(tkey, had_value); + } + } + JournalEntry::CodeChange { address } => { + let acc = state.get_mut(&address).unwrap(); + acc.info.code_hash = KECCAK_EMPTY; + acc.info.code = None; + } + } + } +} diff --git a/crates/context/src/journaled_state/init.rs b/crates/context/src/journaled_state/init.rs new file mode 100644 index 0000000000..7392ecbd03 --- /dev/null +++ b/crates/context/src/journaled_state/init.rs @@ -0,0 +1,49 @@ +use super::Journal; +use database_interface::EmptyDB; + +/// A clonable version of JournaledState that uses EmptyDB. +/// Used to clone the journaled state and for initialization of new journaled state. +pub type JournalInit = Journal; + +impl Journal { + /// Creates a new JournalInit by moving all internal state data (state, storage, logs, etc) into a new + /// journal with an empty database. This consumes the original journal. + /// + /// This is useful when you want to transfer the current state to a new execution context that doesn't + /// need access to the original database, like when snapshotting state or forking execution. + /// + /// If you need to preserve the original journal, use [`Self::to_init`] instead which clones the state. + pub fn into_init(self) -> JournalInit { + JournalInit { + database: EmptyDB::default(), + state: self.state, + transient_storage: self.transient_storage, + logs: self.logs, + depth: self.depth, + journal: self.journal, + spec: self.spec, + warm_preloaded_addresses: self.warm_preloaded_addresses, + precompiles: self.precompiles, + } + } + + /// Creates a new JournalInit by cloning all internal state data (state, storage, logs, etc) + /// but using an empty database. This allows creating a new journaled state with the same + /// state data but without carrying over the original database. + /// + /// This is useful when you want to reuse the current state for a new transaction or + /// execution context, but want to start with a fresh database. + pub fn to_init(&self) -> JournalInit { + JournalInit { + database: EmptyDB::default(), + state: self.state.clone(), + transient_storage: self.transient_storage.clone(), + logs: self.logs.clone(), + depth: self.depth, + journal: self.journal.clone(), + spec: self.spec, + warm_preloaded_addresses: self.warm_preloaded_addresses.clone(), + precompiles: self.precompiles.clone(), + } + } +} diff --git a/crates/context/src/lib.rs b/crates/context/src/lib.rs index 22072f55f4..368964b46f 100644 --- a/crates/context/src/lib.rs +++ b/crates/context/src/lib.rs @@ -11,14 +11,12 @@ pub mod block; pub mod cfg; pub mod context; pub mod evm; -mod journal_init; pub mod journaled_state; pub mod tx; pub use block::BlockEnv; pub use cfg::{Cfg, CfgEnv}; pub use context::*; -pub use journal_init::JournalInit; pub use journaled_state::*; pub use tx::TxEnv; pub mod setters; diff --git a/crates/context/src/setters.rs b/crates/context/src/setters.rs index 5777d19e3a..278fd40d74 100644 --- a/crates/context/src/setters.rs +++ b/crates/context/src/setters.rs @@ -1,6 +1,6 @@ use crate::Context; use auto_impl::auto_impl; -use context_interface::{Block, Cfg, Database, Journal, Transaction}; +use context_interface::{Block, Cfg, Database, JournalTr, Transaction}; /// Setters for the context. #[auto_impl(&mut, Box)] @@ -24,7 +24,7 @@ where TX: Transaction, CFG: Cfg, DB: Database, - JOURNAL: Journal, + JOURNAL: JournalTr, { type Tx = TX; type Block = BLOCK; diff --git a/crates/handler/src/evm.rs b/crates/handler/src/evm.rs index 1fd2d3c4f2..53b893029a 100644 --- a/crates/handler/src/evm.rs +++ b/crates/handler/src/evm.rs @@ -6,16 +6,13 @@ use auto_impl::auto_impl; use context::{ result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, ResultAndState}, setters::ContextSetters, - ContextTr, Database, Evm, Journal, + ContextTr, Database, Evm, JournalOutput, JournalTr, }; use database_interface::DatabaseCommit; use interpreter::{ interpreter::EthInterpreter, Interpreter, InterpreterAction, InterpreterResult, InterpreterTypes, }; -use primitives::Log; -use state::EvmState; -use std::vec::Vec; /// Main trait that combines the context, instructions and precompiles and allows execution of interpreter. #[auto_impl(&mut, Box)] @@ -125,7 +122,7 @@ where impl ExecuteEvm for Evm, PRECOMPILES> where - CTX: ContextSetters + ContextTr)>>, + CTX: ContextSetters + ContextTr>, PRECOMPILES: PrecompileProvider, { type Output = Result< @@ -143,7 +140,7 @@ impl ExecuteCommitEvm for Evm, PRECOMPILES> where CTX: ContextSetters - + ContextTr)>, Db: DatabaseCommit>, + + ContextTr, Db: DatabaseCommit>, PRECOMPILES: PrecompileProvider, { type CommitOutput = Result< diff --git a/crates/handler/src/frame.rs b/crates/handler/src/frame.rs index 4710647198..01359d6844 100644 --- a/crates/handler/src/frame.rs +++ b/crates/handler/src/frame.rs @@ -6,7 +6,7 @@ use crate::{ use bytecode::{Eof, EOF_MAGIC_BYTES}; use context_interface::ContextTr; use context_interface::{ - journaled_state::{Journal, JournalCheckpoint}, + journaled_state::{JournalCheckpoint, JournalTr}, Cfg, Database, Transaction, }; use core::{cell::RefCell, cmp::min}; @@ -744,7 +744,7 @@ where } } -pub fn return_create( +pub fn return_create( journal: &mut JOURNAL, checkpoint: JournalCheckpoint, interpreter_result: &mut InterpreterResult, @@ -800,7 +800,7 @@ pub fn return_create( interpreter_result.result = InstructionResult::Return; } -pub fn return_eofcreate( +pub fn return_eofcreate( journal: &mut JOURNAL, checkpoint: JournalCheckpoint, interpreter_result: &mut InterpreterResult, diff --git a/crates/handler/src/handler.rs b/crates/handler/src/handler.rs index 4a09199d03..84b3c84dbb 100644 --- a/crates/handler/src/handler.rs +++ b/crates/handler/src/handler.rs @@ -3,16 +3,15 @@ use crate::{ execution, post_execution, pre_execution, validation, Frame, FrameInitOrResult, FrameOrResult, FrameResult, ItemOrResult, }; +use context::JournalOutput; use context_interface::ContextTr; use context_interface::{ result::{HaltReasonTr, InvalidHeader, InvalidTransaction, ResultAndState}, - Cfg, Database, Journal, Transaction, + Cfg, Database, JournalTr, Transaction, }; use core::mem; use interpreter::{FrameInput, Gas, InitialAndFloorGas}; use precompile::PrecompileError; -use primitives::Log; -use state::EvmState; use std::{vec, vec::Vec}; pub trait EvmTrError: @@ -34,7 +33,7 @@ impl< } pub trait Handler { - type Evm: EvmTr)>>>; + type Evm: EvmTr>>; type Error: EvmTrError; // TODO `FrameResult` should be a generic trait. // TODO `FrameInit` should be a generic. diff --git a/crates/handler/src/mainnet_builder.rs b/crates/handler/src/mainnet_builder.rs index 9688b0ec32..8e712518e4 100644 --- a/crates/handler/src/mainnet_builder.rs +++ b/crates/handler/src/mainnet_builder.rs @@ -1,12 +1,9 @@ use crate::{instructions::EthInstructions, EthPrecompiles}; -use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, EvmData, JournaledState, TxEnv}; -use context_interface::{Block, Database, Journal, Transaction}; +use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, EvmData, Journal, JournalOutput, TxEnv}; +use context_interface::{Block, Database, JournalTr, Transaction}; use database_interface::EmptyDB; use interpreter::interpreter::EthInterpreter; -use primitives::Log; use specification::hardfork::SpecId; -use state::EvmState; -use std::vec::Vec; pub type MainnetEvm = Evm, EthPrecompiles>; @@ -26,7 +23,7 @@ where TX: Transaction, CFG: Cfg, DB: Database, - JOURNAL: Journal)>, + JOURNAL: JournalTr, { type Context = Self; @@ -61,7 +58,7 @@ pub trait MainContext { fn mainnet() -> Self; } -impl MainContext for Context, ()> { +impl MainContext for Context, ()> { fn mainnet() -> Self { Context::new(EmptyDB::new(), SpecId::LATEST) } diff --git a/crates/handler/src/mainnet_handler.rs b/crates/handler/src/mainnet_handler.rs index 25ecbc2b09..781b6d6cc9 100644 --- a/crates/handler/src/mainnet_handler.rs +++ b/crates/handler/src/mainnet_handler.rs @@ -1,10 +1,8 @@ use super::{EvmTrError, Handler}; use crate::{EvmTr, Frame, FrameResult}; -use context_interface::{result::HaltReason, ContextTr, Journal}; +use context::JournalOutput; +use context_interface::{result::HaltReason, ContextTr, JournalTr}; use interpreter::FrameInput; -use primitives::Log; -use state::EvmState; -use std::vec::Vec; pub struct MainnetHandler { pub _phantom: core::marker::PhantomData<(CTX, ERROR, FRAME)>, @@ -12,7 +10,7 @@ pub struct MainnetHandler { impl Handler for MainnetHandler where - EVM: EvmTr)>>>, + EVM: EvmTr>>, ERROR: EvmTrError, // TODO `FrameResult` should be a generic trait. // TODO `FrameInit` should be a generic. diff --git a/crates/handler/src/post_execution.rs b/crates/handler/src/post_execution.rs index 3a1d1dc47c..c715ce6fc8 100644 --- a/crates/handler/src/post_execution.rs +++ b/crates/handler/src/post_execution.rs @@ -1,15 +1,14 @@ use super::frame_data::FrameResult; +use context::JournalOutput; use context_interface::ContextTr; use context_interface::{ - journaled_state::Journal, + journaled_state::JournalTr, result::{ExecutionResult, HaltReasonTr, ResultAndState}, Block, Cfg, Database, Transaction, }; use interpreter::{Gas, InitialAndFloorGas, SuccessOrHalt}; -use primitives::{Log, U256}; +use primitives::U256; use specification::hardfork::SpecId; -use state::EvmState; -use std::vec::Vec; pub fn eip7623_check_gas_floor(gas: &mut Gas, init_and_floor_gas: InitialAndFloorGas) { // EIP-7623: Increase calldata cost @@ -88,7 +87,7 @@ pub fn reward_beneficiary( /// /// TODO make Journal FinalOutput more generic. pub fn output< - CTX: ContextTr)>>, + CTX: ContextTr>, HALTREASON: HaltReasonTr, >( context: &mut CTX, @@ -103,7 +102,7 @@ pub fn output< let instruction_result = result.into_interpreter_result(); // Reset journal and return present state. - let (state, logs) = context.journal().finalize(); + let JournalOutput { state, logs } = context.journal().finalize(); let result = match SuccessOrHalt::::from(instruction_result.result) { SuccessOrHalt::Success(reason) => ExecutionResult::Success { diff --git a/crates/handler/src/pre_execution.rs b/crates/handler/src/pre_execution.rs index 5873aec514..e6c0c8254a 100644 --- a/crates/handler/src/pre_execution.rs +++ b/crates/handler/src/pre_execution.rs @@ -6,7 +6,7 @@ use bytecode::Bytecode; use context_interface::transaction::{AccessListTr, AuthorizationTr}; use context_interface::ContextTr; use context_interface::{ - journaled_state::Journal, + journaled_state::JournalTr, result::InvalidTransaction, transaction::{Transaction, TransactionType}, Block, Cfg, Database, diff --git a/crates/handler/src/validation.rs b/crates/handler/src/validation.rs index 3f7e32b085..a4653bdc94 100644 --- a/crates/handler/src/validation.rs +++ b/crates/handler/src/validation.rs @@ -1,7 +1,7 @@ use context_interface::transaction::AccessListTr; use context_interface::ContextTr; use context_interface::{ - journaled_state::Journal, + journaled_state::JournalTr, result::{InvalidHeader, InvalidTransaction}, transaction::{Transaction, TransactionType}, Block, Cfg, Database, diff --git a/crates/inspector/src/eip3155.rs b/crates/inspector/src/eip3155.rs index 18f78d0b82..03fa8604fc 100644 --- a/crates/inspector/src/eip3155.rs +++ b/crates/inspector/src/eip3155.rs @@ -1,6 +1,6 @@ use crate::inspectors::GasInspector; use crate::Inspector; -use context::{Cfg, ContextTr, Journal, Transaction}; +use context::{Cfg, ContextTr, JournalTr, Transaction}; use interpreter::{ interpreter_types::{Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr, SubRoutineStack}, CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, diff --git a/crates/inspector/src/inspector.rs b/crates/inspector/src/inspector.rs index db40cad519..a2f3b4db3a 100644 --- a/crates/inspector/src/inspector.rs +++ b/crates/inspector/src/inspector.rs @@ -1,7 +1,7 @@ use crate::{InspectorEvmTr, InspectorFrame}; use auto_impl::auto_impl; use context::{ - result::ResultAndState, Cfg, ContextTr, Database, JournalEntry, JournaledState, Transaction, + result::ResultAndState, Cfg, ContextTr, Database, Journal, JournalEntry, Transaction, }; use handler::{ execution, EvmTr, Frame, FrameInitOrResult, FrameOrResult, FrameResult, Handler, ItemOrResult, @@ -157,7 +157,7 @@ pub trait JournalExt { fn evm_state_mut(&mut self) -> &mut EvmState; } -impl JournalExt for JournaledState { +impl JournalExt for Journal { #[inline] fn logs(&self) -> &[Log] { &self.logs diff --git a/crates/inspector/src/mainnet_inspect.rs b/crates/inspector/src/mainnet_inspect.rs index 7ed9807d52..4853d5dca1 100644 --- a/crates/inspector/src/mainnet_inspect.rs +++ b/crates/inspector/src/mainnet_inspect.rs @@ -1,13 +1,10 @@ -use context::{setters::ContextSetters, ContextTr, Evm, Journal}; +use context::{setters::ContextSetters, ContextTr, Evm, JournalOutput, JournalTr}; use database_interface::DatabaseCommit; use handler::{ instructions::EthInstructions, EthFrame, EvmTr, EvmTrError, Frame, FrameResult, Handler, MainnetHandler, PrecompileProvider, }; use interpreter::{interpreter::EthInterpreter, FrameInput, InterpreterResult}; -use primitives::Log; -use state::EvmState; -use std::vec::Vec; use crate::{ inspect::{InspectCommitEvm, InspectEvm}, @@ -17,7 +14,7 @@ use crate::{ impl InspectorHandler for MainnetHandler where EVM: InspectorEvmTr< - Context: ContextTr)>>, + Context: ContextTr>, Inspector: Inspector<<::Evm as EvmTr>::Context, EthInterpreter>, >, ERROR: EvmTrError, @@ -30,8 +27,7 @@ where impl InspectEvm for Evm, PRECOMPILES> where - CTX: ContextSetters - + ContextTr)> + JournalExt>, + CTX: ContextSetters + ContextTr + JournalExt>, INSP: Inspector, PRECOMPILES: PrecompileProvider, { @@ -54,10 +50,7 @@ impl InspectCommitEvm for Evm, PRECOMPILES> where CTX: ContextSetters - + ContextTr< - Journal: Journal)> + JournalExt, - Db: DatabaseCommit, - >, + + ContextTr + JournalExt, Db: DatabaseCommit>, INSP: Inspector, PRECOMPILES: PrecompileProvider, { diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs index 2d4ee59348..9066d09eb0 100644 --- a/crates/interpreter/src/host.rs +++ b/crates/interpreter/src/host.rs @@ -1,7 +1,7 @@ use context_interface::{ context::{ContextTr, SStoreResult, SelfDestructResult, StateLoad}, journaled_state::AccountLoad, - Block, Cfg, Database, Journal, Transaction, TransactionType, + Block, Cfg, Database, JournalTr, Transaction, TransactionType, }; use primitives::{Address, Bytes, Log, B256, U256}; diff --git a/crates/optimism/Cargo.toml b/crates/optimism/Cargo.toml index 2616add3ed..3e083556cc 100644 --- a/crates/optimism/Cargo.toml +++ b/crates/optimism/Cargo.toml @@ -23,9 +23,7 @@ all = "warn" [dependencies] # revm -revm.workspace = true -precompile = { workspace = true, features = ["secp256r1"] } -inspector.workspace = true +revm = { workspace = true, features = ["secp256r1"] } auto_impl.workspace = true # static precompile sets. @@ -35,7 +33,6 @@ once_cell = { workspace = true, features = ["alloc"] } serde = { workspace = true, features = ["derive", "rc"], optional = true } [dev-dependencies] -database.workspace = true anyhow.workspace = true indicatif.workspace = true rstest.workspace = true @@ -43,7 +40,7 @@ alloy-sol-types.workspace = true [features] default = ["std", "c-kzg", "secp256k1", "portable", "blst"] -std = ["serde?/std", "revm/std", "precompile/std"] +std = ["serde?/std", "revm/std"] hashbrown = ["revm/hashbrown"] serde = ["dep:serde", "revm/serde"] portable = ["revm/portable"] diff --git a/crates/optimism/src/api/builder.rs b/crates/optimism/src/api/builder.rs index 931df3d04f..74ce1e3cb0 100644 --- a/crates/optimism/src/api/builder.rs +++ b/crates/optimism/src/api/builder.rs @@ -1,14 +1,11 @@ use crate::{evm::OpEvm, transaction::OpTxTr, L1BlockInfo, OpSpecId, OpTransaction}; -use precompile::Log; use revm::{ - context::{BlockEnv, Cfg, CfgEnv, TxEnv}, - context_interface::{Block, Journal}, + context::{BlockEnv, Cfg, CfgEnv, JournalOutput, TxEnv}, + context_interface::{Block, JournalTr}, handler::instructions::EthInstructions, interpreter::interpreter::EthInterpreter, - state::EvmState, - Context, Database, JournaledState, + Context, Database, Journal, }; -use std::vec::Vec; pub trait OpBuilder: Sized { type Context; @@ -27,7 +24,7 @@ where TX: OpTxTr, CFG: Cfg, DB: Database, - JOURNAL: Journal)>, + JOURNAL: JournalTr, { type Context = Self; @@ -44,4 +41,4 @@ where } pub type OpContext = - Context, CfgEnv, DB, JournaledState, L1BlockInfo>; + Context, CfgEnv, DB, Journal, L1BlockInfo>; diff --git a/crates/optimism/src/api/default_ctx.rs b/crates/optimism/src/api/default_ctx.rs index 53daf31c11..024d160e99 100644 --- a/crates/optimism/src/api/default_ctx.rs +++ b/crates/optimism/src/api/default_ctx.rs @@ -2,7 +2,7 @@ use crate::{L1BlockInfo, OpSpecId, OpTransaction}; use revm::{ context::{BlockEnv, CfgEnv, TxEnv}, database_interface::EmptyDB, - Context, JournaledState, MainContext, + Context, Journal, MainContext, }; pub trait DefaultOp { @@ -11,7 +11,7 @@ pub trait DefaultOp { OpTransaction, CfgEnv, EmptyDB, - JournaledState, + Journal, L1BlockInfo, >; } @@ -22,7 +22,7 @@ impl DefaultOp OpTransaction, CfgEnv, EmptyDB, - JournaledState, + Journal, L1BlockInfo, > { @@ -38,8 +38,10 @@ impl DefaultOp mod test { use super::*; use crate::api::builder::OpBuilder; - use inspector::{InspectEvm, NoOpInspector}; - use revm::ExecuteEvm; + use revm::{ + inspector::{InspectEvm, NoOpInspector}, + ExecuteEvm, + }; #[test] fn default_run_op() { diff --git a/crates/optimism/src/api/exec.rs b/crates/optimism/src/api/exec.rs index abb4a9c7f0..0782f12345 100644 --- a/crates/optimism/src/api/exec.rs +++ b/crates/optimism/src/api/exec.rs @@ -2,19 +2,17 @@ use crate::{ evm::OpEvm, handler::OpHandler, transaction::OpTxTr, L1BlockInfo, OpHaltReason, OpSpecId, OpTransactionError, }; -use inspector::{InspectCommitEvm, InspectEvm, Inspector, JournalExt}; -use precompile::Log; use revm::{ + context::JournalOutput, context_interface::{ result::{EVMError, ExecutionResult, ResultAndState}, - Block, Cfg, ContextTr, Database, Journal, + Block, Cfg, ContextTr, Database, JournalTr, }, handler::{instructions::EthInstructions, EthFrame, EvmTr, Handler, PrecompileProvider}, + inspector::{InspectCommitEvm, InspectEvm, Inspector, JournalExt}, interpreter::{interpreter::EthInterpreter, InterpreterResult}, - state::EvmState, Context, DatabaseCommit, ExecuteCommitEvm, ExecuteEvm, }; -use std::vec::Vec; impl ExecuteEvm for OpEvm< @@ -28,7 +26,7 @@ where TX: OpTxTr, CFG: Cfg, DB: Database, - JOURNAL: Journal)>, + JOURNAL: JournalTr, PRECOMPILE: PrecompileProvider< Context = Context, Output = InterpreterResult, @@ -55,7 +53,7 @@ where TX: OpTxTr, CFG: Cfg, DB: Database + DatabaseCommit, - JOURNAL: Journal)> + JournalExt, + JOURNAL: JournalTr + JournalExt, PRECOMPILE: PrecompileProvider< Context = Context, Output = InterpreterResult, @@ -86,7 +84,7 @@ where TX: OpTxTr, CFG: Cfg, DB: Database, - JOURNAL: Journal)> + JournalExt, + JOURNAL: JournalTr + JournalExt, INSP: Inspector, EthInterpreter>, PRECOMPILE: PrecompileProvider< Context = Context, @@ -117,7 +115,7 @@ where TX: OpTxTr, CFG: Cfg, DB: Database + DatabaseCommit, - JOURNAL: Journal)> + JournalExt, + JOURNAL: JournalTr + JournalExt, INSP: Inspector, EthInterpreter>, PRECOMPILE: PrecompileProvider< Context = Context, diff --git a/crates/optimism/src/bn128.rs b/crates/optimism/src/bn128.rs index 4e807a0e69..8bdd40f139 100644 --- a/crates/optimism/src/bn128.rs +++ b/crates/optimism/src/bn128.rs @@ -1,4 +1,4 @@ -use precompile::{ +use revm::precompile::{ bn128, {PrecompileError, PrecompileResult, PrecompileWithAddress}, }; diff --git a/crates/optimism/src/evm.rs b/crates/optimism/src/evm.rs index 82f4cf725a..3d0f014f95 100644 --- a/crates/optimism/src/evm.rs +++ b/crates/optimism/src/evm.rs @@ -88,12 +88,11 @@ mod tests { transaction::deposit::DEPOSIT_TRANSACTION_TYPE, DefaultOp, OpBuilder, OpHaltReason, OpSpecId, }; - use database::{BenchmarkDB, BENCH_CALLER, BENCH_CALLER_BALANCE, BENCH_TARGET}; - use precompile::Address; use revm::{ bytecode::opcode, context::result::ExecutionResult, - primitives::{TxKind, U256}, + database::{BenchmarkDB, BENCH_CALLER, BENCH_CALLER_BALANCE, BENCH_TARGET}, + primitives::{Address, TxKind, U256}, state::Bytecode, Context, ExecuteEvm, }; diff --git a/crates/optimism/src/fast_lz.rs b/crates/optimism/src/fast_lz.rs index 16becf04c4..b5a4de4c56 100644 --- a/crates/optimism/src/fast_lz.rs +++ b/crates/optimism/src/fast_lz.rs @@ -108,20 +108,18 @@ fn u24(input: &[u8], idx: u32) -> u32 { #[cfg(test)] mod tests { - use crate::api::builder::OpBuilder; - use super::*; + use crate::api::{builder::OpBuilder, default_ctx::DefaultOp}; use alloy_sol_types::sol; use alloy_sol_types::SolCall; - use database::BenchmarkDB; - use database::EEADDRESS; use revm::{ bytecode::Bytecode, + database::{BenchmarkDB, EEADDRESS, FFADDRESS}, primitives::{bytes, Bytes, TxKind, U256}, }; - use std::vec::Vec; - + use revm::{Context, ExecuteEvm}; use rstest::rstest; + use std::vec::Vec; #[rstest] #[case::empty(&[], 0)] @@ -158,11 +156,6 @@ mod tests { fn test_flz_native_evm_parity(#[case] input: Bytes) { // This bytecode and ABI is for a contract, which wraps the LibZip library for easier fuzz testing. // The source of this contract is here: https://github.com/danyalprout/fastlz/blob/main/src/FastLz.sol#L6-L10 - - use database::FFADDRESS; - use revm::{Context, ExecuteEvm}; - - use crate::api::default_ctx::DefaultOp; sol! { interface FastLz { function fastLz(bytes input) external view returns (uint256); diff --git a/crates/optimism/src/handler.rs b/crates/optimism/src/handler.rs index 291a86d134..77b93af7f1 100644 --- a/crates/optimism/src/handler.rs +++ b/crates/optimism/src/handler.rs @@ -10,24 +10,23 @@ use crate::{ }, L1BlockInfo, OpHaltReason, OpSpecId, }; -use inspector::{Inspector, InspectorEvmTr, InspectorFrame, InspectorHandler}; -use precompile::Log; use revm::{ + context::JournalOutput, context_interface::{ result::{EVMError, ExecutionResult, FromStringError, ResultAndState}, - Block, Cfg, ContextTr, Journal, Transaction, + Block, Cfg, ContextTr, JournalTr, Transaction, }, handler::{ handler::EvmTrError, validation::validate_tx_against_account, EvmTr, Frame, FrameResult, Handler, MainnetHandler, }, + inspector::{Inspector, InspectorEvmTr, InspectorFrame, InspectorHandler}, interpreter::{interpreter::EthInterpreter, FrameInput, Gas}, primitives::{HashMap, U256}, specification::hardfork::SpecId, - state::{Account, EvmState}, + state::Account, Database, }; -use std::vec::Vec; pub struct OpHandler { pub mainnet: MainnetHandler, @@ -63,7 +62,7 @@ impl Handler for OpHandler where EVM: EvmTr< Context: ContextTr< - Journal: Journal)>, + Journal: JournalTr, Tx: OpTxTr, Cfg: Cfg, Chain = L1BlockInfo, @@ -463,7 +462,7 @@ impl InspectorHandler for OpHandler where EVM: InspectorEvmTr< Context: ContextTr< - Journal: Journal)>, + Journal: JournalTr, Tx: OpTxTr, Cfg: Cfg, Chain = L1BlockInfo, @@ -486,13 +485,12 @@ where #[cfg(test)] mod tests { - use crate::{DefaultOp, OpBuilder, OpContext}; - use super::*; - use database::InMemoryDB; + use crate::{DefaultOp, OpBuilder, OpContext}; use revm::{ context::Context, context_interface::result::InvalidTransaction, + database::InMemoryDB, database_interface::EmptyDB, handler::EthFrame, interpreter::{CallOutcome, InstructionResult, InterpreterResult}, diff --git a/crates/optimism/src/handler/precompiles.rs b/crates/optimism/src/handler/precompiles.rs index b67a5c6235..a872810795 100644 --- a/crates/optimism/src/handler/precompiles.rs +++ b/crates/optimism/src/handler/precompiles.rs @@ -1,11 +1,11 @@ use crate::OpSpecId; use once_cell::race::OnceBox; -use precompile::{secp256r1, PrecompileError, Precompiles}; use revm::{ context::Cfg, context_interface::ContextTr, handler::{EthPrecompiles, PrecompileProvider}, interpreter::InterpreterResult, + precompile::{self, secp256r1, PrecompileError, Precompiles}, }; use std::boxed::Box; diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index ddffc7c395..3b8e8481b1 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -65,8 +65,6 @@ alloydb = ["database/alloydb"] # Enables serde-json inside inspector crate serde-json = ["serde", "inspector/serde-json"] -test-utils = [] - dev = [ "memory_limit", "optional_balance_check", @@ -80,9 +78,12 @@ optional_block_gas_limit = ["context/optional_block_gas_limit"] optional_eip3607 = ["context/optional_eip3607"] optional_no_base_fee = ["context/optional_no_base_fee"] -# See comments in `precompile` -secp256k1 = ["precompile/secp256k1"] -c-kzg = ["precompile/c-kzg"] -# `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. +# Precompiles features + +secp256k1 = ["precompile/secp256k1"] # See comments in `precompile` +c-kzg = [ + "precompile/c-kzg", +] # `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. kzg-rs = ["precompile/kzg-rs"] blst = ["precompile/blst"] +secp256r1 = ["precompile/secp256r1"] diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 8336610552..58172279f1 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -18,7 +18,7 @@ pub use state; // Export items. -pub use context::journaled_state::{JournalEntry, JournaledState}; +pub use context::journaled_state::{Journal, JournalEntry}; pub use context::Context; pub use database_interface::{Database, DatabaseCommit, DatabaseRef}; pub use handler::{ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, MainnetEvm}; diff --git a/examples/cheatcode_inspector/src/main.rs b/examples/cheatcode_inspector/src/main.rs index 4d7d15bdf9..b090896846 100644 --- a/examples/cheatcode_inspector/src/main.rs +++ b/examples/cheatcode_inspector/src/main.rs @@ -56,7 +56,7 @@ impl Backend { impl Journal for Backend { type Database = InMemoryDB; - type FinalOutput = (EvmState, Vec); + type FinalOutput = JournalOutputs; fn new(database: InMemoryDB) -> Self { Self::new(SpecId::LATEST, database) diff --git a/examples/erc20_gas/src/exec.rs b/examples/erc20_gas/src/exec.rs index d2371815fe..c24cbde2dc 100644 --- a/examples/erc20_gas/src/exec.rs +++ b/examples/erc20_gas/src/exec.rs @@ -1,8 +1,9 @@ use crate::handler::Erc20MainetHandler; use revm::{ + context::JournalOutput, context_interface::{ result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, ResultAndState}, - ContextTr, Journal, + ContextTr, JournalTr, }, database_interface::DatabaseCommit, handler::{ @@ -10,8 +11,6 @@ use revm::{ PrecompileProvider, }, interpreter::{interpreter::EthInterpreter, InterpreterResult}, - primitives::Log, - state::EvmState, }; pub fn transact_erc20evm( @@ -19,7 +18,7 @@ pub fn transact_erc20evm( ) -> Result, EVMError, InvalidTransaction>> where EVM: EvmTr< - Context: ContextTr)>>, + Context: ContextTr>, Precompiles: PrecompileProvider, Instructions: InstructionProvider< Context = EVM::Context, @@ -35,10 +34,7 @@ pub fn transact_erc20evm_commit( ) -> Result, EVMError, InvalidTransaction>> where EVM: EvmTr< - Context: ContextTr< - Journal: Journal)>, - Db: DatabaseCommit, - >, + Context: ContextTr, Db: DatabaseCommit>, Precompiles: PrecompileProvider, Instructions: InstructionProvider< Context = EVM::Context, diff --git a/examples/erc20_gas/src/handler.rs b/examples/erc20_gas/src/handler.rs index 9e349fb07e..c46d7948c9 100644 --- a/examples/erc20_gas/src/handler.rs +++ b/examples/erc20_gas/src/handler.rs @@ -1,15 +1,14 @@ use core::cmp::Ordering; use revm::{ - context::Cfg, + context::{Cfg, JournalOutput}, context_interface::{ result::{HaltReason, InvalidTransaction}, - Block, ContextTr, Journal, Transaction, TransactionType, + Block, ContextTr, JournalTr, Transaction, TransactionType, }, handler::{EvmTr, EvmTrError, Frame, FrameResult, Handler}, interpreter::FrameInput, - primitives::{Log, U256}, + primitives::U256, specification::hardfork::SpecId, - state::EvmState, }; use crate::{erc_address_storage, token_operation, TOKEN, TREASURY}; @@ -34,7 +33,7 @@ impl Default for Erc20MainetHandler { impl Handler for Erc20MainetHandler where - EVM: EvmTr)>>>, + EVM: EvmTr>>, FRAME: Frame, ERROR: EvmTrError, { diff --git a/examples/erc20_gas/src/main.rs b/examples/erc20_gas/src/main.rs index 6660e3a0fa..55b53bda8f 100644 --- a/examples/erc20_gas/src/main.rs +++ b/examples/erc20_gas/src/main.rs @@ -11,7 +11,7 @@ use exec::transact_erc20evm_commit; use revm::{ context_interface::{ result::{InvalidHeader, InvalidTransaction}, - ContextTr, Journal, + ContextTr, JournalTr, }, database::{AlloyDB, BlockId, CacheDB}, database_interface::WrapDatabaseAsync,