diff --git a/Cargo.toml b/Cargo.toml index f2fa0f2..803ba11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trevm" -version = "0.19.12" +version = "0.20.0" rust-version = "1.83.0" edition = "2021" authors = ["init4"] @@ -27,21 +27,23 @@ option-if-let-else = "warn" redundant-clone = "warn" [dependencies] -alloy = { version = "=0.11.1", default-features = false, features = ["consensus", "rpc-types-mev", "eips", "k256", "std", "rlp", "sol-types"] } +alloy = { version = "0.12.6", default-features = false, features = ["consensus", "rpc-types-mev", "eips", "k256", "std", "rlp", "sol-types"] } -revm = { version = "19.5.0", default-features = false, features = ["std"] } +revm = { version = "20.0.0", default-features = false } dashmap = { version = "6.1.0", optional = true } tracing = { version = "0.1.41", optional = true} thiserror = "2.0.11" [dev-dependencies] -revm = { version = "19.5.0", features = [ - "test-utils", +revm = { version = "20.0.0", features = [ "serde-json", "std", "alloydb", ] } +trevm = { path = ".", features = ["test-utils"] } + +alloy = { version = "*", features = ["providers"]} # misc eyre = "0.6" @@ -67,7 +69,7 @@ concurrent-db = ["dep:dashmap"] estimate_gas = ["optional_eip3607", "optional_no_base_fee", "dep:tracing"] -test-utils = ["revm/test-utils", "revm/std", "revm/serde-json", "revm/alloydb"] +test-utils = ["revm/std", "revm/serde-json", "revm/alloydb"] secp256k1 = ["revm/secp256k1"] c-kzg = ["revm/c-kzg"] @@ -80,23 +82,17 @@ dev = [ "optional_balance_check", "optional_block_gas_limit", "optional_eip3607", - "optional_gas_refund", "optional_no_base_fee", - "optional_beneficiary_reward", ] memory_limit = ["revm/memory_limit"] optional_balance_check = ["revm/optional_balance_check"] -optional_beneficiary_reward = ["revm/optional_beneficiary_reward"] optional_block_gas_limit = ["revm/optional_block_gas_limit"] optional_eip3607 = ["revm/optional_eip3607"] -optional_gas_refund = ["revm/optional_gas_refund"] optional_no_base_fee = ["revm/optional_no_base_fee"] full_env_cfg = [ "optional_balance_check", "optional_block_gas_limit", "optional_eip3607", - "optional_gas_refund", "optional_no_base_fee", - "optional_beneficiary_reward", ] diff --git a/examples/basic_transact.rs b/examples/basic_transact.rs index 77d76b3..1ca0245 100644 --- a/examples/basic_transact.rs +++ b/examples/basic_transact.rs @@ -1,12 +1,14 @@ //! Simple TREVM example that demonstrates how to execute a transaction on a contract. //! It simply loads the contract bytecode and executes a transaction. +use revm::context::TransactTo; use trevm::{ revm::{ - inspector_handle_register, - inspectors::TracerEip3155, - primitives::{hex, AccountInfo, Address, Bytecode, TransactTo, U256}, - EvmBuilder, InMemoryDB, + bytecode::Bytecode, + database::InMemoryDB, + inspector::inspectors::TracerEip3155, + primitives::{hex, Address, U256}, + state::AccountInfo, }, trevm_aliases, NoopBlock, NoopCfg, TrevmBuilder, Tx, }; @@ -27,9 +29,9 @@ const CALLER_ADDR: Address = Address::with_last_byte(1); struct SampleTx; impl Tx for SampleTx { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut revm::context::TxEnv) { tx_env.caller = CALLER_ADDR; - tx_env.transact_to = TransactTo::Call(CONTRACT_ADDR); + tx_env.kind = TransactTo::Call(CONTRACT_ADDR); tx_env.data = hex::decode(PROGRAM_INPUT).unwrap().into(); } } @@ -37,8 +39,8 @@ impl Tx for SampleTx { // Produce aliases for the Trevm type trevm_aliases!(TracerEip3155, InMemoryDB); -fn main() { - let mut db = revm::InMemoryDB::default(); +fn main() -> Result<(), Box> { + let mut db = revm::database::InMemoryDB::default(); let bytecode = Bytecode::new_raw(hex::decode(CONTRACT_BYTECODE).unwrap().into()); let acc_info = AccountInfo::new(U256::ZERO, 1, bytecode.hash_slow(), bytecode); @@ -47,18 +49,19 @@ fn main() { db.insert_contract(&mut acc_info.clone()); db.insert_account_info(CONTRACT_ADDR, acc_info); - let evm = EvmBuilder::default() + let insp = TracerEip3155::new(Box::new(std::io::stdout())); + + let trevm = TrevmBuilder::new() .with_db(db) - .with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))) - .append_handler_register(inspector_handle_register) - .build_trevm() + .with_insp(insp) + .build_trevm()? .fill_cfg(&NoopCfg) .fill_block(&NoopBlock); - let account = evm.read_account_ref(CONTRACT_ADDR).unwrap(); + let account = trevm.read_account_ref(CONTRACT_ADDR).unwrap(); println!("account: {account:?}"); - let evm = evm.fill_tx(&SampleTx).run(); + let evm = trevm.fill_tx(&SampleTx).run(); match evm { Ok(res) => { @@ -69,4 +72,6 @@ fn main() { println!("Execution error: {e:?}"); } }; + + Ok(()) } diff --git a/examples/fork_ref_transact.rs.bak b/examples/fork_ref_transact.rs similarity index 84% rename from examples/fork_ref_transact.rs.bak rename to examples/fork_ref_transact.rs index 10a6e76..3687950 100644 --- a/examples/fork_ref_transact.rs.bak +++ b/examples/fork_ref_transact.rs @@ -3,14 +3,16 @@ //! This example is currently disabled while waiting for revm @ 14.0.4 -use alloy::{eips::BlockId, providers::ProviderBuilder}; -use alloy_primitives::{address, Address, TxKind, U256}; -use alloy_sol_types::{sol, SolCall}; +use alloy::{ + eips::BlockId, + primitives::{address, Address, TxKind, U256}, + providers::ProviderBuilder, + sol, + sol_types::SolCall, +}; +use revm::{context::TxEnv, database::WrapDatabaseAsync}; use trevm::{ - revm::{ - db::{AlloyDB, CacheDB}, - Evm, - }, + revm::database::{AlloyDB, CacheDB}, NoopBlock, NoopCfg, TrevmBuilder, Tx, }; @@ -22,10 +24,10 @@ sol! { struct GetReservesFiller; impl Tx for GetReservesFiller { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { tx_env.caller = Address::with_last_byte(0); // ETH/USDT pair on Uniswap V2 - tx_env.transact_to = TxKind::Call(POOL_ADDRESS); + tx_env.kind = TxKind::Call(POOL_ADDRESS); // calldata formed via alloy's abi encoder tx_env.data = getReservesCall::new(()).abi_encode().into(); // transaction value in wei @@ -55,15 +57,15 @@ async fn main() -> eyre::Result<()> { // =========================================================== // // initialize new AlloyDB - let alloydb = AlloyDB::new(client, BlockId::default()).unwrap(); + let alloydb = WrapDatabaseAsync::new(AlloyDB::new(client, BlockId::default())).unwrap(); // initialise empty in-memory-db let cache_db = CacheDB::new(alloydb); // initialise an empty (default) EVM - let evm = Evm::builder() + let evm = TrevmBuilder::new() .with_db(cache_db) - .build_trevm() + .build_trevm()? .fill_cfg(&NoopCfg) .fill_block(&NoopBlock) .fill_tx(&GetReservesFiller) diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..b470a18 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,61 @@ +use crate::{evm::Trevm, helpers::Ctx, states::EvmNeedsCfg}; +use revm::{ + database::in_memory_db::InMemoryDB, primitives::hardfork::SpecId, Database, MainBuilder, +}; + +/// Error that can occur when building a Trevm instance. +#[derive(Debug, Clone, thiserror::Error)] +#[non_exhaustive] +pub enum TrevmBuilderError { + /// Database not set. + #[error("Database not set")] + DatabaseNotSet, +} + +/// A builder for [`Trevm`] that allows configuring the EVM. +#[derive(Debug, Clone)] +pub struct TrevmBuilder { + pub(crate) db: Option, + pub(crate) insp: Insp, + pub(crate) spec: SpecId, +} + +impl TrevmBuilder { + /// Create a new builder with the default database and inspector. + #[allow(clippy::new_without_default)] // default would make bad devex :( + pub const fn new() -> Self { + Self { db: None, insp: (), spec: SpecId::PRAGUE } + } +} + +impl TrevmBuilder { + /// Set the database for the EVM. + pub fn with_db(self, db: Odb) -> TrevmBuilder + where + Db: Database, + { + TrevmBuilder { db: Some(db), insp: self.insp, spec: self.spec } + } + + /// Set the inspector for the EVM. + pub fn with_insp(self, insp: OInsp) -> TrevmBuilder { + TrevmBuilder { db: self.db, insp, spec: self.spec } + } + + /// Set the spec id for the EVM. + pub const fn with_spec_id(mut self, spec: SpecId) -> Self { + self.spec = spec; + self + } + + /// Build the Trevm instance. + pub fn build_trevm(self) -> Result, TrevmBuilderError> + where + Db: Database, + { + let db = self.db.ok_or(TrevmBuilderError::DatabaseNotSet)?; + let ctx = Ctx::new(db, self.spec); + let evm = ctx.build_mainnet_with_inspector(self.insp); + Ok(Trevm::from(evm)) + } +} diff --git a/src/connect.rs b/src/connect.rs index 2313e8c..9fd552f 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -3,7 +3,7 @@ use crate::{ }; use core::convert::Infallible; use revm::{ - primitives::{EVMError, ResultAndState}, + context::result::{EVMError, ResultAndState}, Database, }; use std::format; @@ -18,7 +18,7 @@ use std::format; /// connector. E.g. the connector may contain some `Db` and the resulting Db may /// contain `&Db`. This allows for (e.g.) shared caches between DBs on multiple /// threads. -pub trait DbConnect<'a>: Sync { +pub trait DbConnect: Sync { /// The database type returned when connecting. type Database: Database; @@ -26,10 +26,10 @@ pub trait DbConnect<'a>: Sync { type Error: core::error::Error; /// Connect to the database. - fn connect(&'a self) -> Result; + fn connect(&self) -> Result; } -impl DbConnect<'_> for Db +impl DbConnect for Db where Db: Database + Clone + Sync, { @@ -44,8 +44,8 @@ where /// Trait for types that can create EVM instances. /// -/// Factories should contain configuration information like chain `EXT` types, -/// and database connections. They are intended to enable parallel instantiation +/// Factories should contain configuration information like `Insp` types, and +/// database connections. They are intended to enable parallel instantiation /// of multiple EVMs in multiple threads sharing some configuration or backing /// store. /// @@ -53,19 +53,19 @@ where /// connector. E.g. the connector may contain some `Db` and the resulting EVM /// may contain `&Db`. This allows for (e.g.) shared caches between EVMs on /// multiple threads. -pub trait EvmFactory<'a>: DbConnect<'a> { - /// The `Ext` type used in the resulting EVM. - type Ext: Sync; +pub trait EvmFactory: DbConnect { + /// The `Insp` type used in the resulting EVM. + type Insp: Sync; /// Create a new EVM instance with the given database connection and /// extension. - fn create(&'a self) -> Result, Self::Error>; + fn create(&self) -> Result, Self::Error>; /// Create a new EVM instance and parameterize it with a [`Cfg`]. fn create_with_cfg( - &'a self, + &self, cfg: &C, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where C: Cfg, { @@ -75,10 +75,10 @@ pub trait EvmFactory<'a>: DbConnect<'a> { /// Create a new EVM instance and parameterize it with a [`Cfg`] and a /// [`Block`]. fn create_with_block( - &'a self, + &self, cfg: &C, block: &B, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where C: Cfg, B: Block, @@ -89,11 +89,11 @@ pub trait EvmFactory<'a>: DbConnect<'a> { /// Create a new EVM instance, and parameterize it with a [`Cfg`], a /// [`Block`], and a [`Tx`], yielding an [`EvmReady`]. fn create_with_tx( - &'a self, + &self, cfg: &C, block: &B, tx: &T, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where C: Cfg, B: Block, @@ -107,15 +107,12 @@ pub trait EvmFactory<'a>: DbConnect<'a> { /// [`EvmTransacted`] or [`EvmErrored`]. #[allow(clippy::type_complexity)] fn transact( - &'a self, + &self, cfg: &C, block: &B, tx: &T, ) -> Result< - Result< - EvmTransacted<'a, Self::Ext, Self::Database>, - EvmErrored<'a, Self::Ext, Self::Database>, - >, + Result, EvmErrored>, Self::Error, > where @@ -130,7 +127,7 @@ pub trait EvmFactory<'a>: DbConnect<'a> { /// Run a transaction, take the [`ResultAndState`], and discard the Evm. /// This is a high-level shortcut function. fn run( - &'a self, + &self, cfg: &C, block: &B, tx: &T, diff --git a/src/db/mod.rs b/src/db/mod.rs index 612c33b..1f255bc 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,4 +1,4 @@ -/// Concurrent version of [`revm::db::State`] +/// Concurrent version of [`revm::database::State`] #[cfg(feature = "concurrent-db")] pub mod sync; diff --git a/src/db/sync/builder.rs b/src/db/sync/builder.rs index 2f2fa97..d94f4fc 100644 --- a/src/db/sync/builder.rs +++ b/src/db/sync/builder.rs @@ -1,10 +1,10 @@ use crate::db::sync::ConcurrentState; use revm::{ - db::{ + database::{ states::{BundleState, TransitionState}, - EmptyDB, + DatabaseRef, EmptyDB, }, - primitives::{db::DatabaseRef, B256}, + primitives::B256, }; use std::collections::BTreeMap; diff --git a/src/db/sync/cache.rs b/src/db/sync/cache.rs index 3ab7e2d..7d6ea47 100644 --- a/src/db/sync/cache.rs +++ b/src/db/sync/cache.rs @@ -3,12 +3,14 @@ use alloy::primitives::{Address, B256}; use dashmap::DashMap; use revm::{ - db::states::{plain_account::PlainStorage, CacheAccount}, - primitives::{Account, AccountInfo, Bytecode, EvmState}, - CacheState, TransitionAccount, + database::{ + states::{plain_account::PlainStorage, CacheAccount}, + CacheState, TransitionAccount, + }, + state::{Account, AccountInfo, Bytecode, EvmState}, }; -/// A concurrent version of [`revm::db::CacheState`]. +/// A concurrent version of [`revm::database::CacheState`]. /// /// Most of the code for this has been reproduced from revm. #[derive(Debug, Clone)] diff --git a/src/db/sync/mod.rs b/src/db/sync/mod.rs index 1add9a3..8820900 100644 --- a/src/db/sync/mod.rs +++ b/src/db/sync/mod.rs @@ -12,7 +12,7 @@ pub use state::{Child, ConcurrentState, ConcurrentStateInfo}; use crate::db::StateAcc; use revm::{ - db::{states::bundle_state::BundleRetention, BundleState}, + database::{states::bundle_state::BundleRetention, BundleState}, primitives::B256, DatabaseRef, }; diff --git a/src/db/sync/state.rs b/src/db/sync/state.rs index 9e84eaa..470215f 100644 --- a/src/db/sync/state.rs +++ b/src/db/sync/state.rs @@ -2,12 +2,12 @@ use crate::db::sync::{ConcurrentCacheState, ConcurrentStateError}; use alloy::primitives::{Address, B256, U256}; use dashmap::mapref::one::RefMut; use revm::{ - db::{ + database::{ states::{bundle_state::BundleRetention, plain_account::PlainStorage, CacheAccount}, - BundleState, State, + BundleState, State, TransitionAccount, TransitionState, }, - primitives::{Account, AccountInfo, Bytecode}, - Database, DatabaseCommit, DatabaseRef, TransitionAccount, TransitionState, + state::{Account, AccountInfo, Bytecode}, + Database, DatabaseCommit, DatabaseRef, }; use std::{ collections::{hash_map, BTreeMap}, @@ -21,7 +21,7 @@ pub type Child = ConcurrentState>>; /// State of the blockchain. /// -/// A version of [`revm::db::State`] that can be shared between threads. +/// A version of [`revm::database::State`] that can be shared between threads. #[derive(Debug)] pub struct ConcurrentState { database: Db, @@ -104,7 +104,6 @@ impl ConcurrentState { } } - // TODO make cache aware of transitions dropping by having global transition counter. /// Takes the [`BundleState`] changeset from the [`ConcurrentState`], /// replacing it /// with an empty one. @@ -112,9 +111,9 @@ impl ConcurrentState { /// This will not apply any pending [`TransitionState`]. It is recommended /// to call [`ConcurrentState::merge_transitions`] before taking the bundle. /// - /// If the `State` has been built with the - /// [`revm::StateBuilder::with_bundle_prestate`] option, the pre-state will be - /// taken along with any changes made by + /// If the [`State`] has been built with the + /// [`revm::database::StateBuilder::with_bundle_prestate`] option, the + /// pre-state will be taken along with any changes made by /// [`ConcurrentState::merge_transitions`]. pub fn take_bundle(&mut self) -> BundleState { core::mem::take(&mut self.info.bundle_state) @@ -428,7 +427,7 @@ pub struct ConcurrentStateInfo { #[cfg(test)] mod test { use super::*; - use revm::db::EmptyDB; + use revm::database::EmptyDB; #[test] const fn assert_child_trait_impls() { diff --git a/src/db/traits.rs b/src/db/traits.rs index 81abfa4..2baff8b 100644 --- a/src/db/traits.rs +++ b/src/db/traits.rs @@ -1,6 +1,7 @@ use revm::{ - db::{states::bundle_state::BundleRetention, BundleState, State}, - primitives::{Account, Address, B256}, + database::{states::bundle_state::BundleRetention, BundleState, State}, + primitives::{Address, B256}, + state::Account, Database, DatabaseCommit, }; use std::{collections::BTreeMap, convert::Infallible, sync::Arc}; diff --git a/src/driver/alloy.rs b/src/driver/alloy.rs index fde13b2..2b6685f 100644 --- a/src/driver/alloy.rs +++ b/src/driver/alloy.rs @@ -12,7 +12,8 @@ use alloy::{ }, }; use revm::{ - primitives::{EVMError, ExecutionResult, SpecId}, + context::result::{EVMError, ExecutionResult}, + primitives::hardfork::SpecId, Database, DatabaseCommit, }; @@ -182,7 +183,7 @@ impl BundleProcessor { tx: &TxEnvelope, pre_sim_coinbase_balance: U256, post_sim_coinbase_balance: U256, - basefee: U256, + basefee: u64, execution_result: ExecutionResult, ) -> Result<(EthCallBundleTransactionResult, U256), BundleError> { let gas_used = execution_result.gas_used(); @@ -191,15 +192,13 @@ impl BundleProcessor { let gas_price = match tx { TxEnvelope::Legacy(tx) => U256::from(tx.tx().gas_price), TxEnvelope::Eip2930(tx) => U256::from(tx.tx().gas_price), - TxEnvelope::Eip1559(tx) => { - U256::from(tx.tx().effective_gas_price(Some(basefee.to::()))) - } + TxEnvelope::Eip1559(tx) => U256::from(tx.tx().effective_gas_price(Some(basefee))), TxEnvelope::Eip4844(tx) => match tx.tx() { TxEip4844Variant::TxEip4844(tx) => { - U256::from(tx.effective_gas_price(Some(basefee.to::()))) + U256::from(tx.effective_gas_price(Some(basefee))) } TxEip4844Variant::TxEip4844WithSidecar(tx) => { - U256::from(tx.tx.effective_gas_price(Some(basefee.to::()))) + U256::from(tx.tx.effective_gas_price(Some(basefee))) } }, _ => return Err(BundleError::UnsupportedTransactionType), @@ -210,17 +209,14 @@ impl BundleProcessor { TxEnvelope::Legacy(tx) => U256::from(tx.tx().gas_price) * U256::from(gas_used), TxEnvelope::Eip2930(tx) => U256::from(tx.tx().gas_price) * U256::from(gas_used), TxEnvelope::Eip1559(tx) => { - U256::from(tx.tx().effective_gas_price(Some(basefee.to::()))) - * U256::from(gas_used) + U256::from(tx.tx().effective_gas_price(Some(basefee))) * U256::from(gas_used) } TxEnvelope::Eip4844(tx) => match tx.tx() { TxEip4844Variant::TxEip4844(tx) => { - U256::from(tx.effective_gas_price(Some(basefee.to::()))) - * U256::from(gas_used) + U256::from(tx.effective_gas_price(Some(basefee))) * U256::from(gas_used) } TxEip4844Variant::TxEip4844WithSidecar(tx) => { - U256::from(tx.tx.effective_gas_price(Some(basefee.to::()))) - * U256::from(gas_used) + U256::from(tx.tx.effective_gas_price(Some(basefee))) * U256::from(gas_used) } }, _ => return Err(BundleError::UnsupportedTransactionType), @@ -259,16 +255,16 @@ impl BundleProcessor { } } -impl BundleDriver for BundleProcessor { +impl BundleDriver for BundleProcessor { type Error = BundleError; - fn run_bundle<'a, Db: Database + revm::DatabaseCommit>( + fn run_bundle( &mut self, - trevm: crate::EvmNeedsTx<'a, Ext, Db>, - ) -> DriveBundleResult<'a, Ext, Db, Self> { + trevm: crate::EvmNeedsTx, + ) -> DriveBundleResult { // Check if the block we're in is valid for this bundle. Both must match trevm_ensure!( - trevm.inner().block().number.to::() == self.bundle.block_number, + trevm.inner().block.number == self.bundle.block_number, trevm, BundleError::BlockNumberMismatch ); @@ -285,11 +281,8 @@ impl BundleDriver for BundleProcessor()); + self.response.state_block_number = + self.bundle.state_block_number.as_number().unwrap_or(trevm.inner().block.number); let bundle_filler = BundleBlockFiller::from(&self.bundle); @@ -303,9 +296,9 @@ impl BundleDriver for BundleProcessor BundleDriver for BundleProcessor BundleDriver for BundleProcessor( + fn post_bundle( &mut self, - _trevm: &crate::EvmNeedsTx<'_, Ext, Db>, + _trevm: &crate::EvmNeedsTx, ) -> Result<(), Self::Error> { Ok(()) } } -impl BundleDriver for BundleProcessor { +impl BundleDriver for BundleProcessor { type Error = BundleError; - fn run_bundle<'a, Db: Database + revm::DatabaseCommit>( + fn run_bundle( &mut self, - trevm: crate::EvmNeedsTx<'a, Ext, Db>, - ) -> DriveBundleResult<'a, Ext, Db, Self> { + trevm: crate::EvmNeedsTx, + ) -> DriveBundleResult { { // Check if the block we're in is valid for this bundle. Both must match trevm_ensure!( - trevm.inner().block().number.to::() == self.bundle.block_number, + trevm.inner().block.number == self.bundle.block_number, trevm, BundleError::BlockNumberMismatch ); @@ -418,7 +409,7 @@ impl BundleDriver for BundleProcessor { // Check for start timestamp range validity if let Some(min_timestamp) = self.bundle.min_timestamp { trevm_ensure!( - trevm.inner().block().timestamp.to::() >= min_timestamp, + trevm.inner().block.timestamp >= min_timestamp, trevm, BundleError::TimestampOutOfRange ); @@ -427,7 +418,7 @@ impl BundleDriver for BundleProcessor { // Check for end timestamp range validity if let Some(max_timestamp) = self.bundle.max_timestamp { trevm_ensure!( - trevm.inner().block().timestamp.to::() <= max_timestamp, + trevm.inner().block.timestamp <= max_timestamp, trevm, BundleError::TimestampOutOfRange ); @@ -479,9 +470,9 @@ impl BundleDriver for BundleProcessor { } } - fn post_bundle( + fn post_bundle( &mut self, - _trevm: &crate::EvmNeedsTx<'_, Ext, Db>, + _trevm: &crate::EvmNeedsTx, ) -> Result<(), Self::Error> { Ok(()) } @@ -498,23 +489,23 @@ struct BundleBlockFiller { } impl Block for BundleBlockFiller { - fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { + fn fill_block_env(&self, block_env: &mut revm::context::block::BlockEnv) { if let Some(timestamp) = self.timestamp { - block_env.timestamp = U256::from(timestamp); + block_env.timestamp = timestamp; } else { - block_env.timestamp += U256::from(12); + block_env.timestamp += 12; } if let Some(gas_limit) = self.gas_limit { - block_env.gas_limit = U256::from(gas_limit); + block_env.gas_limit = gas_limit; } if let Some(difficulty) = self.difficulty { block_env.difficulty = difficulty; } if let Some(base_fee) = self.base_fee { - block_env.basefee = U256::from(base_fee); + block_env.basefee = base_fee.try_into().unwrap_or(u64::MAX); } if let Some(block_number) = self.block_number.as_number() { - block_env.number = U256::from(block_number); + block_env.number = block_number; } } } @@ -543,16 +534,16 @@ impl From for BundleBlockFiller { } } -impl BundleDriver for EthCallBundle { +impl BundleDriver for EthCallBundle { type Error = BundleError; - fn run_bundle<'a, Db: Database + revm::DatabaseCommit>( + fn run_bundle( &mut self, - trevm: crate::EvmNeedsTx<'a, Ext, Db>, - ) -> DriveBundleResult<'a, Ext, Db, Self> { + trevm: crate::EvmNeedsTx, + ) -> DriveBundleResult { // Check if the block we're in is valid for this bundle. Both must match trevm_ensure!( - trevm.inner().block().number.to::() == self.block_number, + trevm.inner().block.number == self.block_number, trevm, BundleError::BlockNumberMismatch ); @@ -622,9 +613,9 @@ impl BundleDriver for EthCallBundle { } } - fn post_bundle( + fn post_bundle( &mut self, - _trevm: &crate::EvmNeedsTx<'_, Ext, Db>, + _trevm: &crate::EvmNeedsTx, ) -> Result<(), Self::Error> { Ok(()) } @@ -633,16 +624,19 @@ impl BundleDriver for EthCallBundle { /// An implementation of [BundleDriver] for [EthSendBundle]. /// This allows us to drive a bundle of transactions and accumulate the resulting state in the EVM. /// Allows to simply take an [EthSendBundle] and get the resulting EVM state. -impl BundleDriver for EthSendBundle { +impl BundleDriver for EthSendBundle { type Error = BundleError; - fn run_bundle<'a, Db: Database + revm::DatabaseCommit>( + fn run_bundle( &mut self, - trevm: crate::EvmNeedsTx<'a, Ext, Db>, - ) -> DriveBundleResult<'a, Ext, Db, Self> { + trevm: crate::EvmNeedsTx, + ) -> DriveBundleResult + where + Db: Database + DatabaseCommit, + { // Check if the block we're in is valid for this bundle. Both must match trevm_ensure!( - trevm.inner().block().number.to::() == self.block_number, + trevm.inner().block.number == self.block_number, trevm, BundleError::BlockNumberMismatch ); @@ -651,7 +645,7 @@ impl BundleDriver for EthSendBundle { if let Some(min_timestamp) = self.min_timestamp { trevm_ensure!( - trevm.inner().block().timestamp.to::() >= min_timestamp, + trevm.inner().block.timestamp >= min_timestamp, trevm, BundleError::TimestampOutOfRange ); @@ -660,7 +654,7 @@ impl BundleDriver for EthSendBundle { // Check for end timestamp range validity if let Some(max_timestamp) = self.max_timestamp { trevm_ensure!( - trevm.inner().block().timestamp.to::() <= max_timestamp, + trevm.inner().block.timestamp <= max_timestamp, trevm, BundleError::TimestampOutOfRange ); @@ -727,9 +721,9 @@ impl BundleDriver for EthSendBundle { Ok(t) } - fn post_bundle( + fn post_bundle( &mut self, - _trevm: &crate::EvmNeedsTx<'_, Ext, Db>, + _trevm: &crate::EvmNeedsTx, ) -> Result<(), Self::Error> { Ok(()) } diff --git a/src/driver/block.rs b/src/driver/block.rs index fcab7a0..6145891 100644 --- a/src/driver/block.rs +++ b/src/driver/block.rs @@ -1,18 +1,18 @@ use crate::{Block, EvmBlockDriverErrored, EvmNeedsBlock, EvmNeedsTx}; -use revm::{primitives::EVMError, Database, DatabaseCommit}; +use revm::{context::result::EVMError, Database, DatabaseCommit}; /// The result of running transactions for a block driver. -pub type RunTxResult<'a, Ext, Db, T> = - Result, EvmBlockDriverErrored<'a, Ext, Db, T>>; +pub type RunTxResult = + Result, EvmBlockDriverErrored>; /// The result of driving a block to completion. -pub type DriveBlockResult<'a, Ext, Db, T> = - Result, EvmBlockDriverErrored<'a, Ext, Db, T>>; +pub type DriveBlockResult = + Result, EvmBlockDriverErrored>; /// Driver for a single trevm block. This trait allows a type to specify the /// entire lifecycle of a trevm block, from opening the block to driving the /// trevm to completion. -pub trait BlockDriver { +pub trait BlockDriver { /// The [`Block`] filler for this driver. type Block: Block; @@ -23,14 +23,14 @@ pub trait BlockDriver { fn block(&self) -> &Self::Block; /// Run the transactions for the block. - fn run_txns<'a, Db: Database + DatabaseCommit>( + fn run_txns( &mut self, - trevm: EvmNeedsTx<'a, Ext, Db>, - ) -> RunTxResult<'a, Ext, Db, Self>; + trevm: EvmNeedsTx, + ) -> RunTxResult; /// Run post fn post_block( &mut self, - trevm: &EvmNeedsBlock<'_, Ext, Db>, + trevm: &EvmNeedsBlock, ) -> Result<(), Self::Error>; } diff --git a/src/driver/bundle.rs b/src/driver/bundle.rs index 4d9026e..ebe9a1b 100644 --- a/src/driver/bundle.rs +++ b/src/driver/bundle.rs @@ -1,25 +1,23 @@ use crate::{states::EvmBundleDriverErrored, EvmNeedsTx}; -use revm::{primitives::EVMError, Database, DatabaseCommit}; +use revm::{context::result::EVMError, Database, DatabaseCommit}; /// The result of driving a bundle to completion. -pub type DriveBundleResult<'a, Ext, Db, T> = - Result, EvmBundleDriverErrored<'a, Ext, Db, T>>; +pub type DriveBundleResult = + Result, EvmBundleDriverErrored>; /// Driver for a bundle of transactions. This trait allows a type to specify the /// entire lifecycle of a bundle, simulating the entire list of transactions. -pub trait BundleDriver { +pub trait BundleDriver { /// An error type for this driver. type Error: core::error::Error + From>; /// Run the transactions contained in the bundle. - fn run_bundle<'a, Db: Database + DatabaseCommit>( - &mut self, - trevm: EvmNeedsTx<'a, Ext, Db>, - ) -> DriveBundleResult<'a, Ext, Db, Self>; + fn run_bundle(&mut self, trevm: EvmNeedsTx) -> DriveBundleResult + where + Db: Database + DatabaseCommit; /// Run post - fn post_bundle( - &mut self, - trevm: &EvmNeedsTx<'_, Ext, Db>, - ) -> Result<(), Self::Error>; + fn post_bundle(&mut self, trevm: &EvmNeedsTx) -> Result<(), Self::Error> + where + Db: Database + DatabaseCommit; } diff --git a/src/driver/chain.rs b/src/driver/chain.rs index c3d53e9..40a2295 100644 --- a/src/driver/chain.rs +++ b/src/driver/chain.rs @@ -1,25 +1,22 @@ use crate::{BlockDriver, EvmChainDriverErrored, EvmNeedsBlock}; -use revm::{ - primitives::{EVMError, SpecId}, - Database, DatabaseCommit, -}; +use revm::{context::result::EVMError, primitives::hardfork::SpecId, Database, DatabaseCommit}; /// The result of driving a chain to completion. -pub type DriveChainResult<'a, Ext, Db, D> = - Result, EvmChainDriverErrored<'a, Ext, Db, D>>; +pub type DriveChainResult = + Result, EvmChainDriverErrored>; /// Driver for a chain of blocks. -pub trait ChainDriver { +pub trait ChainDriver { /// The block driver for this chain. - type BlockDriver: BlockDriver; + type BlockDriver: BlockDriver; /// An error type for this driver. type Error: core::error::Error + From> - + From<>::Error>; + + From<>::Error>; /// Get the spec id for a block. - fn spec_id_for(&self, block: &>::Block) -> SpecId; + fn spec_id_for(&self, block: &>::Block) -> SpecId; /// Get the blocks in this chain. The blocks should be in order, and this /// function MUST NOT return an empty slice. @@ -31,7 +28,7 @@ pub trait ChainDriver { /// The `idx` parameter is the index of the block in the chain. fn interblock( &mut self, - trevm: &EvmNeedsBlock<'_, Ext, Db>, + trevm: &EvmNeedsBlock, idx: usize, ) -> Result<(), Self::Error>; } diff --git a/src/est.rs b/src/est.rs index 1da67e4..ed0e7e2 100644 --- a/src/est.rs +++ b/src/est.rs @@ -1,4 +1,7 @@ -use revm::primitives::{Bytes, ExecutionResult, HaltReason, Output}; +use revm::{ + context::result::{ExecutionResult, HaltReason, Output}, + primitives::Bytes, +}; use std::ops::Range; /// Simple wrapper around a range of u64 values, with convenience methods for diff --git a/src/evm.rs b/src/evm.rs index 5df3919..74df754 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -1,6 +1,7 @@ use crate::{ db::{StateAcc, TryDatabaseCommit, TryStateAcc}, driver::DriveBlockResult, + helpers::Evm, Block, BlockDriver, BundleDriver, Cfg, ChainDriver, DriveBundleResult, DriveChainResult, ErroredState, EvmErrored, EvmExtUnchecked, EvmNeedsBlock, EvmNeedsCfg, EvmNeedsTx, EvmReady, EvmTransacted, HasBlock, HasCfg, HasTx, NeedsCfg, NeedsTx, TransactedState, Tx, @@ -11,120 +12,89 @@ use alloy::{ }; use core::{convert::Infallible, fmt}; use revm::{ - db::{states::bundle_state::BundleRetention, BundleState}, - interpreter::gas::calculate_initial_tx_gas, - primitives::{ - AccountInfo, AuthorizationList, BlockEnv, Bytecode, EVMError, Env, EvmState, - ExecutionResult, InvalidTransaction, ResultAndState, SpecId, TxEnv, TxKind, + context::{ + result::{EVMError, ExecutionResult, InvalidTransaction, ResultAndState}, + Block as _, BlockEnv, Cfg as _, ContextSetters, ContextTr, Transaction as _, TxEnv, }, - Database, DatabaseCommit, DatabaseRef, Evm, + database::{states::bundle_state::BundleRetention, BundleState}, + interpreter::gas::calculate_initial_tx_gas_for_tx, + primitives::{hardfork::SpecId, TxKind}, + state::{AccountInfo, Bytecode, EvmState}, + Database, DatabaseCommit, DatabaseRef, ExecuteEvm, }; /// Trevm provides a type-safe interface to the EVM, using the typestate pattern. /// /// See the [crate-level documentation](crate) for more information. -pub struct Trevm<'a, Ext, Db: Database, TrevmState> { - pub(crate) inner: Box>, +pub struct Trevm { + pub(crate) inner: Box>, pub(crate) state: TrevmState, } -impl fmt::Debug for Trevm<'_, Ext, Db, TrevmState> { +impl fmt::Debug for Trevm { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Trevm").finish_non_exhaustive() } } -impl<'a, Ext, Db: Database, TrevmState> AsRef> for Trevm<'a, Ext, Db, TrevmState> { - fn as_ref(&self) -> &Evm<'a, Ext, Db> { +impl AsRef> for Trevm { + fn as_ref(&self) -> &Evm { &self.inner } } -impl<'a, Ext, Db: Database> From> for EvmNeedsCfg<'a, Ext, Db> { - fn from(inner: Evm<'a, Ext, Db>) -> Self { +impl From> for EvmNeedsCfg { + fn from(inner: Evm) -> Self { Self { inner: Box::new(inner), state: NeedsCfg::new() } } } // --- ALL STATES -impl<'a, Ext, Db: Database, TrevmState> Trevm<'a, Ext, Db, TrevmState> { +impl Trevm { /// Get a reference to the current [`Evm`]. - pub fn inner(&self) -> &Evm<'a, Ext, Db> { + /// + /// [`Evm`]: revm::context::Evm + pub fn inner(&self) -> &Evm { self.as_ref() } /// Get a mutable reference to the current [`Evm`]. This should be used with - /// caution, as modifying the EVM may lead to inconsistent Trevmstate or invalid - /// execution. - pub fn inner_mut_unchecked(&mut self) -> &mut Evm<'a, Ext, Db> { + /// caution, as modifying the EVM may lead to inconsistent Trevmstate or + /// invalid execution. + /// + /// [`Evm`]: revm::context::Evm + pub fn inner_mut_unchecked(&mut self) -> &mut Evm { &mut self.inner } /// Destructure the [`Trevm`] into its inner EVM. - pub fn into_inner(self) -> Box> { + pub fn into_inner(self) -> Box> { self.inner } - /// Deconstruct the [`Trevm`] into the backing DB, dropping the EVM handler - /// table and any `Ext` type. - /// - /// This is a wrapper for [`Evm::into_db_and_env_with_handler_cfg`], and - /// then dropping the [`EnvWithHandlerCfg`]. If you need to retain the - /// [`EnvWithHandlerCfg`], use [`Self::into_inner`] and then call - /// [`Evm::into_db_and_env_with_handler_cfg`] on the inner EVM. - /// - /// [`EnvWithHandlerCfg`]: revm::primitives::EnvWithHandlerCfg + /// Deconstruct the [`Trevm`] into the backing DB, dropping all other types. pub fn into_db(self) -> Db { - self.inner.into_db_and_env_with_handler_cfg().0 - } - - /// Get a reference to the inner env. This contains the current - /// [`BlockEnv`], [`TxEnv`], and [`CfgEnv`]. - /// - /// These values may be meaningless, stale, or otherwise incorrect. Reading - /// them should be done with caution, as it may lead to logic bugs. - /// - /// [`CfgEnv`]: revm::primitives::CfgEnv - pub fn env_unchecked(&self) -> &Env { - &self.inner().context.evm.inner.env - } - - /// Get a mutable reference to the inner env. This contains the current - /// [`BlockEnv`], [`TxEnv`], and [`CfgEnv`]. - /// - /// These values may be meaningless, stale, or otherwise incorrect. Reading - /// them should be done with caution, as it may lead to logic bugs. - /// Modifying these values may lead to inconsistent state or invalid - /// execution. - /// - /// [`CfgEnv`]: revm::primitives::CfgEnv - pub fn env_mut_unchecked(&mut self) -> &mut Env { - &mut self.inner_mut_unchecked().context.evm.inner.env + self.inner.data.ctx.journaled_state.database } - /// Get the id of the currently running hardfork spec. Convenience function - /// calling [`Evm::spec_id`]. + /// Get the id of the currently running hardfork spec. pub fn spec_id(&self) -> SpecId { - self.inner.spec_id() + self.inner.data.ctx.cfg().spec() } /// Set the [SpecId], modifying the EVM handlers accordingly. This function /// should be called at hardfork boundaries when running multi-block trevm /// flows. pub fn set_spec_id(&mut self, spec_id: SpecId) { - self.inner.modify_spec_id(spec_id) + self.inner.modify_cfg(|cfg| cfg.spec = spec_id); } /// Run a closure with a different [SpecId], then restore the previous /// setting. - pub fn with_spec_id( - mut self, - spec_id: SpecId, - f: F, - ) -> Trevm<'a, Ext, Db, NewState> + pub fn with_spec_id(mut self, spec_id: SpecId, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let old = self.spec_id(); self.set_spec_id(spec_id); @@ -134,7 +104,7 @@ impl<'a, Ext, Db: Database, TrevmState> Trevm<'a, Ext, Db, TrevmState> { } /// Convert self into [`EvmErrored`] by supplying an error - pub fn errored(self, error: E) -> EvmErrored<'a, Ext, Db, E> { + pub fn errored(self, error: E) -> EvmErrored { EvmErrored { inner: self.inner, state: ErroredState { error } } } @@ -143,7 +113,7 @@ impl<'a, Ext, Db: Database, TrevmState> Trevm<'a, Ext, Db, TrevmState> { pub fn apply_state_overrides( mut self, overrides: &StateOverride, - ) -> Result> + ) -> Result::Error>> where Db: DatabaseCommit, { @@ -182,7 +152,7 @@ impl<'a, Ext, Db: Database, TrevmState> Trevm<'a, Ext, Db, TrevmState> { pub fn maybe_apply_state_overrides( self, overrides: Option<&StateOverride>, - ) -> Result> + ) -> Result::Error>> where Db: DatabaseCommit, { @@ -195,42 +165,52 @@ impl<'a, Ext, Db: Database, TrevmState> Trevm<'a, Ext, Db, TrevmState> { } // Fallible DB Reads with &mut self -impl Trevm<'_, Ext, Db, TrevmState> { +impl Trevm { /// Get the current account info for a specific address. /// /// Note: due to revm's DB model, this requires a mutable pointer. - pub fn try_read_account(&mut self, address: Address) -> Result, Db::Error> { - self.inner.db_mut().basic(address) + pub fn try_read_account( + &mut self, + address: Address, + ) -> Result, ::Error> { + self.inner.db().basic(address) } /// Get the current nonce for a specific address /// /// Note: due to revm's DB model, this requires a mutable pointer. - pub fn try_read_nonce(&mut self, address: Address) -> Result { + pub fn try_read_nonce(&mut self, address: Address) -> Result::Error> { self.try_read_account(address).map(|a| a.map(|a| a.nonce).unwrap_or_default()) } /// Get the current nonce for a specific address /// /// Note: due to revm's DB model, this requires a mutable pointer. - pub fn try_read_balance(&mut self, address: Address) -> Result { + pub fn try_read_balance(&mut self, address: Address) -> Result::Error> { self.try_read_account(address).map(|a| a.map(|a| a.balance).unwrap_or_default()) } /// Get the value of a storage slot. /// /// Note: due to revm's DB model, this requires a mutable pointer. - pub fn try_read_storage(&mut self, address: Address, slot: U256) -> Result { - self.inner.db_mut().storage(address, slot) + pub fn try_read_storage( + &mut self, + address: Address, + slot: U256, + ) -> Result::Error> { + self.inner.db().storage(address, slot) } /// Get the code at the given account, if any. /// /// Note: due to revm's DB model, this requires a mutable pointer. - pub fn try_read_code(&mut self, address: Address) -> Result, Db::Error> { + pub fn try_read_code( + &mut self, + address: Address, + ) -> Result, ::Error> { let acct_info = self.try_read_account(address)?; match acct_info { - Some(acct) => Ok(Some(self.inner.db_mut().code_by_hash(acct.code_hash)?)), + Some(acct) => Ok(Some(self.inner.db().code_by_hash(acct.code_hash)?)), None => Ok(None), } } @@ -239,9 +219,9 @@ impl Trevm<'_, Ext, Db, TrevmState> { pub fn try_gas_allowance( &mut self, caller: Address, - gas_price: U256, - ) -> Result { - if gas_price.is_zero() { + gas_price: u128, + ) -> Result::Error> { + if gas_price == 0 { return Ok(u64::MAX); } let gas_price = U256::from(gas_price); @@ -251,13 +231,16 @@ impl Trevm<'_, Ext, Db, TrevmState> { } // Fallible DB Reads with &self -impl Trevm<'_, Ext, Db, TrevmState> { +impl Trevm +where + Db: Database + DatabaseRef, +{ /// Get the current account info for a specific address. pub fn try_read_account_ref( &self, address: Address, ) -> Result, ::Error> { - self.inner.db().basic_ref(address) + self.inner.db_ref().basic_ref(address) } /// Get the current nonce for a specific address @@ -283,7 +266,7 @@ impl Trevm<'_, Ext, Db, TrevmState> address: Address, slot: U256, ) -> Result::Error> { - self.inner.db().storage_ref(address, slot) + self.inner.db_ref().storage_ref(address, slot) } /// Get the code at the given account, if any. @@ -293,7 +276,7 @@ impl Trevm<'_, Ext, Db, TrevmState> ) -> Result, ::Error> { let acct_info = self.try_read_account_ref(address)?; match acct_info { - Some(acct) => Ok(Some(self.inner.db().code_by_hash_ref(acct.code_hash)?)), + Some(acct) => Ok(Some(self.inner.db_ref().code_by_hash_ref(acct.code_hash)?)), None => Ok(None), } } @@ -314,12 +297,15 @@ impl Trevm<'_, Ext, Db, TrevmState> } // Infallible DB Reads with &mut self -impl, TrevmState> Trevm<'_, Ext, Db, TrevmState> { +impl Trevm +where + Db: Database, +{ /// Get the current account info for a specific address. /// /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_account(&mut self, address: Address) -> Option { - self.inner.db_mut().basic(address).expect("infallible") + self.inner.db().basic(address).expect("infallible") } /// Get the current nonce for a specific address @@ -340,7 +326,7 @@ impl, TrevmState> Trevm<'_, Ext, Db, Trevm /// /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_storage(&mut self, address: Address, slot: U256) -> U256 { - self.inner.db_mut().storage(address, slot).expect("infallible") + self.inner.db().storage(address, slot).expect("infallible") } /// Get the code at the given account, if any. @@ -348,19 +334,20 @@ impl, TrevmState> Trevm<'_, Ext, Db, Trevm /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_code(&mut self, address: Address) -> Option { let acct_info = self.read_account(address)?; - Some(self.inner.db_mut().code_by_hash(acct_info.code_hash).expect("infallible")) + Some(self.inner.db().code_by_hash(acct_info.code_hash).expect("infallible")) } } // Infalible DB Reads with &self -impl + DatabaseRef, TrevmState> - Trevm<'_, Ext, Db, TrevmState> +impl Trevm +where + Db: DatabaseRef, { /// Get the current account info for a specific address. /// /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_account_ref(&self, address: Address) -> Option { - self.inner.db().basic_ref(address).expect("infallible") + self.inner.db_ref().basic_ref(address).expect("infallible") } /// Get the current nonce for a specific address @@ -377,7 +364,7 @@ impl + DatabaseRef, Tr /// /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_storage_ref(&self, address: Address, slot: U256) -> U256 { - self.inner.db().storage_ref(address, slot).expect("infallible") + self.inner.db_ref().storage_ref(address, slot).expect("infallible") } /// Get the code at the given account, if any. @@ -385,11 +372,11 @@ impl + DatabaseRef, Tr /// Note: due to revm's DB model, this requires a mutable pointer. pub fn read_code_ref(&self, address: Address) -> Option { let acct_info = self.read_account_ref(address)?; - Some(self.inner.db().code_by_hash_ref(acct_info.code_hash).expect("infallible")) + Some(self.inner.db_ref().code_by_hash_ref(acct_info.code_hash).expect("infallible")) } } -impl Trevm<'_, Ext, Db, TrevmState> { +impl Trevm { /// Commit a set of state changes to the database. This is a low-level API, /// and is not intended for general use. Regular users should prefer /// executing a transaction. @@ -397,7 +384,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { where Db: DatabaseCommit, { - self.inner.db_mut().commit(state); + self.inner.db().commit(state); } /// Modify an account with a closure and commit the modified account. This @@ -406,7 +393,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, f: F, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -419,7 +406,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, nonce: u64, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -431,7 +418,10 @@ impl Trevm<'_, Ext, Db, TrevmState> { /// /// If the nonce is already at the maximum value, it will not be /// incremented. - pub fn try_increment_nonce_unchecked(&mut self, address: Address) -> Result + pub fn try_increment_nonce_unchecked( + &mut self, + address: Address, + ) -> Result::Error> where Db: DatabaseCommit, { @@ -442,7 +432,10 @@ impl Trevm<'_, Ext, Db, TrevmState> { /// a low-level API, and is not intended for general use. /// /// If the nonce is already 0, it will not be decremented. - pub fn try_decrement_nonce_unchecked(&mut self, address: Address) -> Result + pub fn try_decrement_nonce_unchecked( + &mut self, + address: Address, + ) -> Result::Error> where Db: DatabaseCommit, { @@ -456,7 +449,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { address: Address, slot: U256, value: U256, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -470,7 +463,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, bytecode: Bytecode, - ) -> Result, Db::Error> + ) -> Result, ::Error> where Db: DatabaseCommit, { @@ -486,7 +479,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, amount: U256, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -501,7 +494,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, amount: U256, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -514,7 +507,7 @@ impl Trevm<'_, Ext, Db, TrevmState> { &mut self, address: Address, amount: U256, - ) -> Result + ) -> Result::Error> where Db: DatabaseCommit, { @@ -522,7 +515,10 @@ impl Trevm<'_, Ext, Db, TrevmState> { } } -impl, TrevmState> Trevm<'_, Ext, Db, TrevmState> { +impl Trevm +where + Db: Database, +{ /// Modify an account with a closure and commit the modified account. This /// is a low-level API, and is not intended for general use. pub fn modify_account_unchecked( @@ -621,15 +617,21 @@ impl, TrevmState> Trevm<'_, Ext, Db, Trevm // --- ALL STATES, WITH State -impl Trevm<'_, Ext, Db, TrevmState> { +impl Trevm +where + Db: StateAcc, +{ /// Set the [EIP-161] state clear flag, activated in the Spurious Dragon /// hardfork. pub fn set_state_clear_flag(&mut self, flag: bool) { - self.inner.db_mut().set_state_clear_flag(flag) + self.inner.db().set_state_clear_flag(flag) } } -impl Trevm<'_, Ext, Db, TrevmState> { +impl Trevm +where + Db: TryStateAcc, +{ /// Fallibly set the [EIP-161] state clear flag, activated in the Spurious /// Dragon hardfork. This function is intended to be used by shared states, /// where mutable access may fail, e.g. an `Arc`. @@ -639,15 +641,15 @@ impl Trevm<'_, Ext, Db, TrevmState> &mut self, flag: bool, ) -> Result<(), ::Error> { - self.inner.db_mut().try_set_state_clear_flag(flag) + self.inner.db().try_set_state_clear_flag(flag) } } // --- NEEDS CFG -impl<'a, Ext, Db: Database> EvmNeedsCfg<'a, Ext, Db> { +impl EvmNeedsCfg { /// Fill the configuration environment. - pub fn fill_cfg(mut self, filler: &T) -> EvmNeedsBlock<'a, Ext, Db> { + pub fn fill_cfg(mut self, filler: &T) -> EvmNeedsBlock { filler.fill_cfg(&mut self.inner); // SAFETY: Same size and repr. Only phantomdata type changes unsafe { core::mem::transmute(self) } @@ -656,7 +658,7 @@ impl<'a, Ext, Db: Database> EvmNeedsCfg<'a, Ext, Db> { // --- HAS CFG -impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { +impl Trevm { /// Set the [EIP-170] contract code size limit. By default this is set to /// 0x6000 bytes (~25KiB). Contracts whose bytecode is larger than this /// limit cannot be deployed and will produce a [`CreateInitCodeSizeLimit`] @@ -665,8 +667,11 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// [`CreateInitCodeSizeLimit`]: InvalidTransaction::CreateInitCodeSizeLimit /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 pub fn set_code_size_limit(&mut self, limit: usize) -> Option { - let cfg = self.inner.cfg_mut(); - cfg.limit_contract_code_size.replace(limit) + let mut csl = None; + self.inner.data.ctx.modify_cfg(|cfg| { + csl = cfg.limit_contract_code_size.replace(limit); + }); + csl } /// Disable the [EIP-170] contract code size limit, returning the previous @@ -674,17 +679,16 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 pub fn disable_code_size_limit(&mut self) -> Option { - self.inner.cfg_mut().limit_contract_code_size.take() + let mut csl = None; + self.inner.data.ctx.modify_cfg(|cfg| csl = cfg.limit_contract_code_size.take()); + csl } /// Run a closure with the code size limit disabled, then restore the /// previous setting. - pub fn without_code_size_limit( - mut self, - f: F, - ) -> Trevm<'a, Ext, Db, NewState> + pub fn without_code_size_limit(mut self, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let limit = self.disable_code_size_limit(); let mut new = f(self); @@ -708,16 +712,17 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// Run a function with the provided configuration, then restore the /// previous configuration. This will not affect the block and tx, if those /// have been filled. - pub fn with_cfg(mut self, cfg: &C, f: F) -> Trevm<'a, Ext, Db, NewState> + pub fn with_cfg(mut self, cfg: &C, f: F) -> Trevm where C: Cfg, - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, NewState: HasCfg, { - let previous = self.inner.cfg_mut().clone(); - cfg.fill_cfg_env(self.inner.cfg_mut()); + let previous = self.inner.cfg().clone(); + cfg.fill_cfg(&mut self.inner); + let mut this = f(self); - *this.inner.cfg_mut() = previous; + this.inner.data.ctx.modify_cfg(|cfg| *cfg = previous); this } @@ -728,39 +733,27 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { mut self, cfg: &C, f: F, - ) -> Result, EvmErrored<'a, Ext, Db, E>> + ) -> Result, EvmErrored> where C: Cfg, - F: FnOnce(Self) -> Result, EvmErrored<'a, Ext, Db, E>>, + F: FnOnce(Self) -> Result, EvmErrored>, NewState: HasCfg, { - let previous = self.inner.cfg_mut().clone(); - cfg.fill_cfg_env(self.inner.cfg_mut()); + let previous = self.inner.cfg().clone(); + cfg.fill_cfg(&mut self.inner); + match f(self) { Ok(mut evm) => { - *evm.inner.cfg_mut() = previous; + evm.inner.modify_cfg(|cfg| *cfg = previous); Ok(evm) } Err(mut evm) => { - *evm.inner.cfg_mut() = previous; + evm.inner.modify_cfg(|cfg| *cfg = previous); Err(evm) } } } - /// Set the KZG settings used for point evaluation precompiles. By default - /// this is set to the settings used in the Ethereum mainnet. - /// - /// This is a low-level API, and is not intended for general use. - #[cfg(feature = "c-kzg")] - pub fn set_kzg_settings( - &mut self, - settings: revm::primitives::EnvKzgSettings, - ) -> revm::primitives::EnvKzgSettings { - let cfg = self.inner.cfg_mut(); - core::mem::replace(&mut cfg.kzg_settings, settings) - } - /// Set a limit beyond which a callframe's memory cannot be resized. /// Attempting to resize beyond this limit will result in a /// [OutOfGasError::Memory] error. @@ -769,11 +762,15 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// recommended to set this to a sane value to prevent memory allocation /// panics. Defaults to `2^32 - 1` bytes per EIP-1985. /// - /// [OutOfGasError::Memory]: revm::primitives::OutOfGasError::Memory + /// [OutOfGasError::Memory]: revm::context::result::OutOfGasError::Memory #[cfg(feature = "memory_limit")] pub fn set_memory_limit(&mut self, new_limit: u64) -> u64 { - let cfg = self.inner.cfg_mut(); - core::mem::replace(&mut cfg.memory_limit, new_limit) + let mut ml = 0; + self.inner + .data + .ctx + .modify_cfg(|cfg| ml = core::mem::replace(&mut cfg.memory_limit, new_limit)); + ml } /// Disable balance checks. If the sender does not have enough balance to @@ -781,29 +778,26 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// execution doesn't fail. #[cfg(feature = "optional_balance_check")] pub fn disable_balance_check(&mut self) { - self.inner.cfg_mut().disable_balance_check = true + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = true) } /// Enable balance checks. See [`Self::disable_balance_check`]. #[cfg(feature = "optional_balance_check")] pub fn enable_balance_check(&mut self) { - self.inner.cfg_mut().disable_balance_check = false + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = false) } /// Run a closure with balance checks disabled, then restore the previous /// setting. #[cfg(feature = "optional_balance_check")] - pub fn without_balance_check( - mut self, - f: F, - ) -> Trevm<'a, Ext, Db, NewState> + pub fn without_balance_check(mut self, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let previous = self.inner.cfg().disable_balance_check; self.disable_balance_check(); let mut new = f(self); - new.inner.cfg_mut().disable_balance_check = previous; + new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = previous); new } @@ -812,29 +806,26 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// simulating large transactions like forge scripts. #[cfg(feature = "optional_block_gas_limit")] pub fn disable_block_gas_limit(&mut self) { - self.inner.cfg_mut().disable_beneficiary_reward = true + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = true); } /// Enable block gas limits. See [`Self::disable_block_gas_limit`]. #[cfg(feature = "optional_block_gas_limit")] pub fn enable_block_gas_limit(&mut self) { - self.inner.cfg_mut().disable_beneficiary_reward = false + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = false); } /// Run a closure with block gas limits disabled, then restore the previous /// setting. #[cfg(feature = "optional_block_gas_limit")] - pub fn without_block_gas_limit( - mut self, - f: F, - ) -> Trevm<'a, Ext, Db, NewState> + pub fn without_block_gas_limit(mut self, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let previous = self.inner.cfg().disable_block_gas_limit; self.disable_block_gas_limit(); let mut new = f(self); - new.inner.cfg_mut().disable_block_gas_limit = previous; + new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = previous); new } @@ -844,7 +835,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 #[cfg(feature = "optional_eip3607")] pub fn disable_eip3607(&mut self) { - self.inner.cfg_mut().disable_eip3607 = true + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = true); } /// Enable [EIP-3607]. See [`Self::disable_eip3607`]. @@ -852,51 +843,21 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 #[cfg(feature = "optional_eip3607")] pub fn enable_eip3607(&mut self) { - self.inner.cfg_mut().disable_eip3607 = false + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = false); } /// Run a closure with [EIP-3607] disabled, then restore the previous /// setting. #[cfg(feature = "optional_eip3607")] - pub fn without_eip3607(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> + pub fn without_eip3607(mut self, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let previous = self.inner.cfg().disable_eip3607; self.disable_eip3607(); - let mut new = f(self); - new.inner.cfg_mut().disable_eip3607 = previous; - new - } - /// Disables all gas refunds. This is useful when using chains that have - /// gas refunds disabled e.g. Avalanche. Reasoning behind removing gas - /// refunds can be found in [EIP-3298]. - /// By default, it is set to `false`. - /// - /// [EIP-3298]: https://eips.ethereum.org/EIPS/eip-3298 - #[cfg(feature = "optional_gas_refund")] - pub fn disable_gas_refund(&mut self) { - self.inner.cfg_mut().disable_gas_refund = true - } - - /// Enable gas refunds. See [`Self::disable_gas_refund`]. - #[cfg(feature = "optional_gas_refund")] - pub fn enable_gas_refund(&mut self) { - self.inner.cfg_mut().disable_gas_refund = false - } - - /// Run a closure with gas refunds disabled, then restore the previous - /// setting. - #[cfg(feature = "optional_gas_refund")] - pub fn without_gas_refund(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> - where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, - { - let previous = self.inner.cfg().disable_gas_refund; - self.disable_gas_refund(); let mut new = f(self); - new.inner.cfg_mut().disable_gas_refund = previous; + new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = previous); new } @@ -906,7 +867,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 #[cfg(feature = "optional_no_base_fee")] pub fn disable_base_fee(&mut self) { - self.inner.cfg_mut().disable_base_fee = true; + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_base_fee = true) } /// Enable [EIP-1559] base fee checks. See [`Self::disable_base_fee`]. @@ -914,7 +875,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 #[cfg(feature = "optional_no_base_fee")] pub fn enable_base_fee(&mut self) { - self.inner.cfg_mut().disable_base_fee = false + self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_base_fee = false) } /// Run a closure with [EIP-1559] base fee checks disabled, then restore the @@ -922,56 +883,29 @@ impl<'a, Ext, Db: Database, TrevmState: HasCfg> Trevm<'a, Ext, Db, TrevmState> { /// /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 #[cfg(feature = "optional_no_base_fee")] - pub fn without_base_fee(mut self, f: F) -> Trevm<'a, Ext, Db, NewState> + pub fn without_base_fee(mut self, f: F) -> Trevm where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, { let previous = self.inner.cfg().disable_base_fee; self.disable_base_fee(); - let mut new = f(self); - new.inner.cfg_mut().disable_base_fee = previous; - new - } - /// Disable the payout of the block and gas fees to the block beneficiary. - #[cfg(feature = "optional_beneficiary_reward")] - pub fn disable_beneficiary_reward(&mut self) { - self.inner.cfg_mut().disable_beneficiary_reward = true; - } - - /// Enable the payout of the block and gas fees to the block beneficiary. - /// See [`Self::disable_beneficiary_reward`]. - #[cfg(feature = "optional_beneficiary_reward")] - pub fn enable_beneficiary_reward(&mut self) { - self.inner.cfg_mut().disable_beneficiary_reward = false - } - - /// Run a closure with the block and gas fees payout disabled, then restore - /// the previous setting. - #[cfg(feature = "optional_beneficiary_reward")] - pub fn without_beneficiary_reward( - mut self, - f: F, - ) -> Trevm<'a, Ext, Db, NewState> - where - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, - { - let previous = self.inner.cfg().disable_beneficiary_reward; - self.disable_beneficiary_reward(); let mut new = f(self); - new.inner.cfg_mut().disable_beneficiary_reward = previous; + if !previous { + new.enable_base_fee(); + } new } } // --- NEEDS BLOCK -impl<'a, Ext, Db: Database> EvmNeedsBlock<'a, Ext, Db> { +impl EvmNeedsBlock { /// Open a block, apply some logic, and return the EVM ready for the next /// block. - pub fn drive_block(self, driver: &mut D) -> DriveBlockResult<'a, Ext, Db, D> + pub fn drive_block(self, driver: &mut D) -> DriveBlockResult where - D: BlockDriver, + D: BlockDriver, Db: DatabaseCommit, { let trevm = self.fill_block(driver.block()); @@ -990,16 +924,16 @@ impl<'a, Ext, Db: Database> EvmNeedsBlock<'a, Ext, Db> { /// # Panics /// /// If the driver contains no blocks. - pub fn drive_chain(self, driver: &mut D) -> DriveChainResult<'a, Ext, Db, D> + pub fn drive_chain(self, driver: &mut D) -> DriveChainResult where - D: ChainDriver, + D: ChainDriver, Db: DatabaseCommit, { let block_count = driver.blocks().len(); let mut trevm = self .drive_block(&mut driver.blocks()[0]) - .map_err(EvmErrored::err_into::<>::Error>)?; + .map_err(EvmErrored::err_into::<>::Error>)?; if let Err(e) = driver.interblock(&trevm, 0) { return Err(trevm.errored(e)); @@ -1009,7 +943,7 @@ impl<'a, Ext, Db: Database> EvmNeedsBlock<'a, Ext, Db> { trevm = { let trevm = trevm .drive_block(&mut driver.blocks()[i]) - .map_err(EvmErrored::err_into::<>::Error>)?; + .map_err(EvmErrored::err_into::<>::Error>)?; if let Err(e) = driver.interblock(&trevm, i) { return Err(trevm.errored(e)); } @@ -1023,7 +957,7 @@ impl<'a, Ext, Db: Database> EvmNeedsBlock<'a, Ext, Db> { /// /// This does not perform any pre- or post-block logic. To manage block /// lifecycles, use [`Self::drive_block`] or [`Self::drive_chain`] instead. - pub fn fill_block(mut self, filler: &B) -> EvmNeedsTx<'a, Ext, Db> { + pub fn fill_block(mut self, filler: &B) -> EvmNeedsTx { filler.fill_block(self.inner_mut_unchecked()); // SAFETY: Same size and repr. Only phantomdata type changes unsafe { core::mem::transmute(self) } @@ -1032,43 +966,47 @@ impl<'a, Ext, Db: Database> EvmNeedsBlock<'a, Ext, Db> { // --- HAS BLOCK -impl<'a, Ext, Db: Database, TrevmState: HasBlock> Trevm<'a, Ext, Db, TrevmState> { +impl Trevm +where + TrevmState: HasBlock, +{ /// Get a reference to the current block environment. pub fn block(&self) -> &BlockEnv { self.inner.block() } /// Get the current block gas limit. - pub fn block_gas_limit(&self) -> U256 { - self.block().gas_limit + pub fn block_gas_limit(&self) -> u64 { + self.block().gas_limit() } /// Get the current block number. - pub fn block_number(&self) -> U256 { - self.block().number + pub fn block_number(&self) -> u64 { + self.block().number() } /// Get the current block timestamp. - pub fn block_timestamp(&self) -> U256 { - self.block().timestamp + pub fn block_timestamp(&self) -> u64 { + self.block().timestamp() } /// Get the block beneficiary address. pub fn beneficiary(&self) -> Address { - self.block().coinbase + self.block().beneficiary() } /// Run a function with the provided block, then restore the previous block. - pub fn with_block(mut self, b: &B, f: F) -> Trevm<'a, Ext, Db, NewState> + pub fn with_block(mut self, b: &B, f: F) -> Trevm where B: Block, - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, NewState: HasBlock, { - let previous = self.inner.block_mut().clone(); - b.fill_block_env(self.inner.block_mut()); + let previous = self.inner.block().clone(); + b.fill_block(&mut self.inner); + let mut this = f(self); - *this.inner.block_mut() = previous; + this.inner.data.ctx.set_block(previous); this } @@ -1077,21 +1015,22 @@ impl<'a, Ext, Db: Database, TrevmState: HasBlock> Trevm<'a, Ext, Db, TrevmState> mut self, b: &B, f: F, - ) -> Result, EvmErrored<'a, Ext, Db, E>> + ) -> Result, EvmErrored> where - F: FnOnce(Self) -> Result, EvmErrored<'a, Ext, Db, E>>, + F: FnOnce(Self) -> Result, EvmErrored>, B: Block, NewState: HasBlock, { - let previous = self.inner.block_mut().clone(); - b.fill_block_env(self.inner.block_mut()); + let previous = self.inner.block().clone(); + b.fill_block(&mut self.inner); + match f(self) { Ok(mut evm) => { - *evm.inner.block_mut() = previous; + evm.inner.data.ctx.set_block(previous); Ok(evm) } Err(mut evm) => { - *evm.inner.block_mut() = previous; + evm.inner.data.ctx.set_block(previous); Err(evm) } } @@ -1100,43 +1039,43 @@ impl<'a, Ext, Db: Database, TrevmState: HasBlock> Trevm<'a, Ext, Db, TrevmState> // --- Needs Block with State -impl EvmNeedsBlock<'_, Ext, Db> { +impl EvmNeedsBlock { /// Finish execution and return the outputs. /// /// If the State has not been built with - /// [revm::StateBuilder::with_bundle_update] then the returned + /// [revm::database::StateBuilder::with_bundle_update] then the returned /// [`BundleState`] will be meaningless. /// /// See [`State::merge_transitions`] and [`State::take_bundle`]. /// - /// [`State::merge_transitions`]: revm::db::State::merge_transitions - /// [`State::take_bundle`]: revm::db::State::take_bundle + /// [`State::merge_transitions`]: revm::database::State::merge_transitions + /// [`State::take_bundle`]: revm::database::State::take_bundle pub fn finish(self) -> BundleState { let Self { inner: mut evm, .. } = self; - evm.db_mut().merge_transitions(BundleRetention::Reverts); - let bundle = evm.db_mut().take_bundle(); + evm.db().merge_transitions(BundleRetention::Reverts); + let bundle = evm.db().take_bundle(); bundle } } -impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsBlock<'a, Ext, Db> { +impl EvmNeedsBlock { /// Fallibly finish execution and return the outputs. This function is /// intended to be used by shared states, where mutable access may fail, e. /// g. an `Arc`. Prefer [`Self::finish`] when available. /// /// If the State has not been built with - /// [revm::StateBuilder::with_bundle_update] then the returned + /// [revm::database::StateBuilder::with_bundle_update] then the returned /// [`BundleState`] will be meaningless. /// /// See [`State::merge_transitions`] and [`State::take_bundle`]. /// - /// [`State::merge_transitions`]: revm::db::State::merge_transitions - /// [`State::take_bundle`]: revm::db::State::take_bundle + /// [`State::merge_transitions`]: revm::database::State::merge_transitions + /// [`State::take_bundle`]: revm::database::State::take_bundle pub fn try_finish( mut self, - ) -> Result::Error>> { - let db = self.inner.db_mut(); + ) -> Result::Error>> { + let db = self.inner.db(); trevm_try!(db.try_merge_transitions(BundleRetention::Reverts), self); @@ -1148,18 +1087,18 @@ impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsBlock<'a, Ext, Db> { // --- NEEDS TX -impl<'a, Ext, Db: Database> EvmNeedsTx<'a, Ext, Db> { +impl EvmNeedsTx { /// Close the current block, returning the EVM ready for the next block. - pub fn close_block(self) -> EvmNeedsBlock<'a, Ext, Db> { + pub fn close_block(self) -> EvmNeedsBlock { // SAFETY: Same size and repr. Only phantomdata type changes unsafe { core::mem::transmute(self) } } /// Drive a bundle to completion, apply some post-bundle logic, and return the /// EVM ready for the next bundle or tx. - pub fn drive_bundle(self, driver: &mut D) -> DriveBundleResult<'a, Ext, Db, D> + pub fn drive_bundle(self, driver: &mut D) -> DriveBundleResult where - D: BundleDriver, + D: BundleDriver, Db: DatabaseCommit, { let trevm = driver.run_bundle(self)?; @@ -1171,7 +1110,7 @@ impl<'a, Ext, Db: Database> EvmNeedsTx<'a, Ext, Db> { } /// Fill the transaction environment. - pub fn fill_tx(mut self, filler: &T) -> EvmReady<'a, Ext, Db> { + pub fn fill_tx(mut self, filler: &T) -> EvmReady { filler.fill_tx(&mut self.inner); // SAFETY: Same size and repr. Only phantomdata type changes unsafe { core::mem::transmute(self) } @@ -1181,7 +1120,7 @@ impl<'a, Ext, Db: Database> EvmNeedsTx<'a, Ext, Db> { pub fn run_tx( self, filler: &T, - ) -> Result, EvmErrored<'a, Ext, Db>> { + ) -> Result, EvmErrored> { self.fill_tx(filler).run() } @@ -1197,7 +1136,7 @@ impl<'a, Ext, Db: Database> EvmNeedsTx<'a, Ext, Db> { pub fn call_tx( self, filler: &T, - ) -> Result<(ExecutionResult, Self), EvmErrored<'a, Ext, Db>> { + ) -> Result<(ExecutionResult, Self), EvmErrored> { self.fill_tx(filler).call() } @@ -1210,38 +1149,22 @@ impl<'a, Ext, Db: Database> EvmNeedsTx<'a, Ext, Db> { pub fn estimate_tx_gas( self, filler: &T, - ) -> Result<(crate::EstimationResult, EvmReady<'a, Ext, Db>), EvmErrored<'a, Ext, Db>> { + ) -> Result<(crate::EstimationResult, EvmReady), EvmErrored> { self.fill_tx(filler).estimate_gas() } } // --- HAS TX -impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { +impl Trevm { #[cfg(feature = "call")] fn try_with_call_filler( self, filler: &crate::fillers::CallFiller, - f: impl FnOnce(Self) -> Result, EvmErrored<'a, Ext, Db>>, - ) -> Result, EvmErrored<'a, Ext, Db>> { + f: impl FnOnce(Self) -> Result, EvmErrored>, + ) -> Result, EvmErrored> { // override all relevant env bits - self.try_with_cfg(filler, |this| { - this.try_with_block(filler, |mut this| { - // reproducing code from `try_with_tx` to avoid trait bounds - let previous = this.inner.tx_mut().clone(); - filler.fill_tx_env(this.inner.tx_mut()); - match f(this) { - Ok(mut evm) => { - *evm.inner.tx_mut() = previous; - Ok(evm) - } - Err(mut evm) => { - *evm.inner.tx_mut() = previous; - Err(evm) - } - } - }) - }) + self.try_with_cfg(filler, |this| this.try_with_block(filler, f)) } /// Convenience function to use the estimator to fill both Cfg and Tx, and @@ -1250,8 +1173,8 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { fn try_with_estimate_gas_filler( self, filler: &crate::fillers::GasEstimationFiller, - f: impl FnOnce(Self) -> Result>, - ) -> Result> { + f: impl FnOnce(Self) -> Result>, + ) -> Result> { self.try_with_cfg(filler, |this| this.try_with_tx(filler, f)) } @@ -1261,7 +1184,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { } /// True if the transaction is a simple transfer. pub fn is_transfer(&self) -> bool { - self.inner.tx().data.is_empty() && self.to().is_call() + self.inner.tx().input().is_empty() && self.to().is_call() } /// True if the transaction is a contract creation. @@ -1271,37 +1194,37 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// Get a reference to the transaction input data, which will be used as /// calldata or initcode during EVM execution. - pub fn data(&self) -> &Bytes { - &self.tx().data + pub fn input(&self) -> &Bytes { + self.tx().input() } /// Read the target of the transaction. pub fn to(&self) -> TxKind { - self.tx().transact_to + self.tx().kind() } /// Read the value in wei of the transaction. pub fn value(&self) -> U256 { - self.tx().value + self.tx().value() } /// Get the gas limit of the loaded transaction. pub fn gas_limit(&self) -> u64 { - self.tx().gas_limit + self.tx().gas_limit() } /// Get the gas price of the loaded transaction. - pub fn gas_price(&self) -> U256 { - self.tx().gas_price + pub fn gas_price(&self) -> u128 { + self.tx().gas_price() } /// Get the address of the caller. pub fn caller(&self) -> Address { - self.tx().caller + self.tx().caller() } /// Get the account of the caller. Error if the DB errors. - pub fn caller_account(&mut self) -> Result> { + pub fn caller_account(&mut self) -> Result::Error>> { self.try_read_account(self.caller()) .map(Option::unwrap_or_default) .map_err(EVMError::Database) @@ -1318,7 +1241,9 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// - if `Self::is_create` is true, `Ok(None)` /// - if the callee account does not exist, `Ok(AccountInfo::default())` /// - if the DB errors, `Err(EVMError::Database(err))` - pub fn callee_account(&mut self) -> Result, EVMError> { + pub fn callee_account( + &mut self, + ) -> Result, EVMError<::Error>> { self.callee().map_or(Ok(None), |addr| { self.try_read_account(addr) .map(Option::unwrap_or_default) @@ -1338,16 +1263,16 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// Run a function with the provided transaction, then restore the previous /// transaction. - pub fn with_tx(mut self, t: &T, f: F) -> Trevm<'a, Ext, Db, NewState> + pub fn with_tx(mut self, t: &T, f: F) -> Trevm where T: Tx, - F: FnOnce(Self) -> Trevm<'a, Ext, Db, NewState>, + F: FnOnce(Self) -> Trevm, NewState: HasTx, { - let previous = self.inner.tx_mut().clone(); - t.fill_tx_env(self.inner.tx_mut()); + let previous = self.inner.tx().clone(); + t.fill_tx(&mut self.inner); let mut this = f(self); - *this.inner.tx_mut() = previous; + this.inner.data.ctx.set_tx(previous); this } @@ -1357,21 +1282,21 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { mut self, t: &T, f: F, - ) -> Result, EvmErrored<'a, Ext, Db, E>> + ) -> Result, EvmErrored> where T: Tx, - F: FnOnce(Self) -> Result, EvmErrored<'a, Ext, Db, E>>, + F: FnOnce(Self) -> Result, EvmErrored>, NewState: HasTx, { - let previous = self.inner.tx_mut().clone(); - t.fill_tx_env(self.inner.tx_mut()); + let previous = self.inner.tx().clone(); + t.fill_tx(&mut self.inner); match f(self) { Ok(mut evm) => { - *evm.inner.tx_mut() = previous; + evm.inner.data.ctx.set_tx(previous); Ok(evm) } Err(mut evm) => { - *evm.inner.tx_mut() = previous; + evm.inner.data.ctx.set_tx(previous); Err(evm) } } @@ -1379,7 +1304,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// Return the maximum gas that the caller can purchase. This is the balance /// of the caller divided by the gas price. - pub fn caller_gas_allowance(&mut self) -> Result> { + pub fn caller_gas_allowance(&mut self) -> Result::Error>> { // Avoid DB read if gas price is zero let gas_price = self.gas_price(); self.try_gas_allowance(self.caller(), gas_price).map_err(EVMError::Database) @@ -1395,11 +1320,12 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// # Returns /// /// The gas limit after the operation. - pub fn cap_tx_gas_to_allowance(&mut self) -> Result> { + pub fn cap_tx_gas_to_allowance(&mut self) -> Result::Error>> { let allowance = self.caller_gas_allowance()?; - let tx = self.inner_mut_unchecked().tx_mut(); - tx.gas_limit = tx.gas_limit.min(allowance); - Ok(tx.gas_limit) + + self.inner.modify_tx(|tx| tx.gas_limit = tx.gas_limit.min(allowance)); + + Ok(self.gas_limit()) } /// Cap the gas limit of the transaction to the minimum of the block gas @@ -1412,10 +1338,11 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// /// The gas limit after the operation. pub fn cap_tx_gas_to_block_limit(&mut self) -> u64 { - let block_gas_limit = self.block_gas_limit().saturating_to(); - let tx = self.inner_mut_unchecked().tx_mut(); - tx.gas_limit = tx.gas_limit.min(block_gas_limit); - tx.gas_limit + let block_gas_limit = self.block_gas_limit(); + + self.inner.modify_tx(|tx| tx.gas_limit = tx.gas_limit.min(block_gas_limit)); + + self.tx().gas_limit } /// This function caps the gas limit of the transaction to the minimum of @@ -1427,7 +1354,7 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { /// # Returns /// /// The gas limit after the operation. - pub fn cap_tx_gas(&mut self) -> Result> { + pub fn cap_tx_gas(&mut self) -> Result::Error>> { self.cap_tx_gas_to_block_limit(); self.cap_tx_gas_to_allowance() } @@ -1435,7 +1362,10 @@ impl<'a, Ext, Db: Database, TrevmState: HasTx> Trevm<'a, Ext, Db, TrevmState> { // -- NEEDS TX with State -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx +where + Db: Database + StateAcc, +{ /// Apply block overrides to the current block. /// /// Note that this is NOT reversible. The overrides are applied directly to @@ -1443,12 +1373,12 @@ impl EvmNeedsTx<'_, Ext, Db> { /// important that you have access to the pre-change state, you should wrap /// the existing DB in a new [`State`] and apply the overrides to that. /// - /// [`State`]: revm::db::State + /// [`State`]: revm::database::State pub fn apply_block_overrides(mut self, overrides: &BlockOverrides) -> Self { overrides.fill_block(&mut self.inner); if let Some(hashes) = overrides.block_hash.as_ref() { - self.inner.db_mut().set_block_hashes(hashes) + self.inner.db().set_block_hashes(hashes) } self @@ -1461,7 +1391,7 @@ impl EvmNeedsTx<'_, Ext, Db> { /// important that you have access to the pre-change state, you should wrap /// the existing DB in a new [`State`] and apply the overrides to that. /// - /// [`State`]: revm::db::State + /// [`State`]: revm::database::State pub fn maybe_apply_block_overrides(self, overrides: Option<&BlockOverrides>) -> Self { if let Some(overrides) = overrides { self.apply_block_overrides(overrides) @@ -1471,7 +1401,10 @@ impl EvmNeedsTx<'_, Ext, Db> { } } -impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsTx<'a, Ext, Db> { +impl EvmNeedsTx +where + Db: Database + TryStateAcc, +{ /// Apply block overrides to the current block. This function is /// intended to be used by shared states, where mutable access may fail, e. /// g. an `Arc`. Prefer [`Self::apply_block_overrides`] when @@ -1482,15 +1415,15 @@ impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsTx<'a, Ext, Db> { /// important that you have access to the pre-change state, you should wrap /// the existing DB in a new [`State`] and apply the overrides to that. /// - /// [`State`]: revm::db::State + /// [`State`]: revm::database::State pub fn try_apply_block_overrides( mut self, overrides: &BlockOverrides, - ) -> Result::Error>> { + ) -> Result::Error>> { overrides.fill_block(&mut self.inner); if let Some(hashes) = overrides.block_hash.as_ref() { - trevm_try!(self.inner.db_mut().try_set_block_hashes(hashes), self); + trevm_try!(self.inner.db().try_set_block_hashes(hashes), self); } Ok(self) @@ -1506,11 +1439,11 @@ impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsTx<'a, Ext, Db> { /// important that you have access to the pre-change state, you should wrap /// the existing DB in a new [`State`] and apply the overrides to that. /// - /// [`State`]: revm::db::State + /// [`State`]: revm::database::State pub fn try_maybe_apply_block_overrides( self, overrides: Option<&BlockOverrides>, - ) -> Result::Error>> { + ) -> Result::Error>> { if let Some(overrides) = overrides { self.try_apply_block_overrides(overrides) } else { @@ -1521,9 +1454,9 @@ impl<'a, Ext, Db: Database + TryStateAcc> EvmNeedsTx<'a, Ext, Db> { // --- READY -impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { +impl EvmReady { /// Clear the current transaction environment. - pub fn clear_tx(self) -> EvmNeedsTx<'a, Ext, Db> { + pub fn clear_tx(self) -> EvmNeedsTx { // NB: we do not clear the tx env here, as we may read it during post-tx // logic in a block driver @@ -1534,10 +1467,10 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// Execute the loaded transaction. This is a wrapper around /// [`Evm::transact`] and produces either [`EvmTransacted`] or /// [`EvmErrored`]. - pub fn run(mut self) -> Result, EvmErrored<'a, Ext, Db>> { - let result = self.inner.transact(); + pub fn run(mut self) -> Result, EvmErrored> { + let result = self.inner.replay(); - let Trevm { inner, .. } = self; + let Self { inner, .. } = self; match result { Ok(result) => Ok(Trevm { inner, state: TransactedState { result } }), @@ -1554,9 +1487,7 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 #[cfg(feature = "call")] - pub fn call( - self, - ) -> Result<(ExecutionResult, EvmNeedsTx<'a, Ext, Db>), EvmErrored<'a, Ext, Db>> { + pub fn call(self) -> Result<(ExecutionResult, EvmNeedsTx), EvmErrored> { let mut output = std::mem::MaybeUninit::uninit(); let gas_limit = self.tx().gas_limit; @@ -1576,8 +1507,8 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// Calculate the minimum gas required to start EVM execution. /// - /// This uses [`calculate_initial_tx_gas`] to calculate the initial gas. - /// Its output is dependent on + /// This uses [`calculate_initial_tx_gas_for_tx`] to calculate the initial + /// gas. Its output is dependent on /// - the EVM spec /// - the input data /// - whether the transaction is a contract creation or a call @@ -1587,15 +1518,7 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930 /// [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702 pub fn calculate_initial_gas(&self) -> u64 { - calculate_initial_tx_gas( - self.spec_id(), - &[], - false, - &self.tx().access_list, - self.tx().authorization_list.as_ref().map(AuthorizationList::len).unwrap_or_default() - as u64, - ) - .initial_gas + calculate_initial_tx_gas_for_tx(self.tx(), self.spec_id()).initial_gas } /// Estimate gas for a simple transfer. This will @@ -1604,7 +1527,9 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// - Check that the target is not a contract. /// - Return the minimum gas required for the transfer. #[cfg(feature = "estimate_gas")] - fn estimate_gas_simple_transfer(&mut self) -> Result, EVMError> { + fn estimate_gas_simple_transfer( + &mut self, + ) -> Result, EVMError<::Error>> { use alloy::consensus::constants::KECCAK_EMPTY; use tracing::trace; @@ -1632,7 +1557,7 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { fn run_estimate( self, filler: &crate::fillers::GasEstimationFiller, - ) -> Result<(crate::EstimationResult, Self), EvmErrored<'a, Ext, Db>> { + ) -> Result<(crate::EstimationResult, Self), EvmErrored> { let mut estimation = std::mem::MaybeUninit::uninit(); let this = self.try_with_estimate_gas_filler(filler, |this| match this.run() { @@ -1702,9 +1627,7 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { /// [`EstimationREsult`]: crate::EstimationResult /// [`MIN_TRANSACTION_GAS`]: crate::MIN_TRANSACTION_GAS #[cfg(feature = "estimate_gas")] - pub fn estimate_gas( - mut self, - ) -> Result<(crate::EstimationResult, Self), EvmErrored<'a, Ext, Db>> { + pub fn estimate_gas(mut self) -> Result<(crate::EstimationResult, Self), EvmErrored> { use tracing::{debug, enabled}; if let Some(est) = crate::trevm_try!(self.estimate_gas_simple_transfer(), self) { @@ -1797,7 +1720,7 @@ impl<'a, Ext, Db: Database> EvmReady<'a, Ext, Db> { // --- ERRORED -impl<'a, Ext, Db: Database, E> EvmErrored<'a, Ext, Db, E> { +impl EvmErrored { /// Get a reference to the error. pub const fn error(&self) -> &E { &self.state.error @@ -1812,7 +1735,7 @@ impl<'a, Ext, Db: Database, E> EvmErrored<'a, Ext, Db, E> { } /// Discard the error and return the EVM. - pub fn discard_error(self) -> EvmNeedsTx<'a, Ext, Db> { + pub fn discard_error(self) -> EvmNeedsTx { Trevm { inner: self.inner, state: NeedsTx::new() } } @@ -1823,18 +1746,18 @@ impl<'a, Ext, Db: Database, E> EvmErrored<'a, Ext, Db, E> { /// Reset the EVM, returning the error and the EVM ready for the next /// transaction. - pub fn take_err(self) -> (E, EvmNeedsTx<'a, Ext, Db>) { - let Trevm { inner, state: ErroredState { error } } = self; + pub fn take_err(self) -> (E, EvmNeedsTx) { + let Self { inner, state: ErroredState { error } } = self; (error, Trevm { inner, state: NeedsTx::new() }) } /// Transform the error into a new error type. - pub fn err_into>(self) -> EvmErrored<'a, Ext, Db, NewErr> { + pub fn err_into>(self) -> EvmErrored { self.map_err(Into::into) } /// Map the error to a new error type. - pub fn map_err(self, f: F) -> EvmErrored<'a, Ext, Db, NewErr> + pub fn map_err(self, f: F) -> EvmErrored where F: FnOnce(E) -> NewErr, { @@ -1842,7 +1765,7 @@ impl<'a, Ext, Db: Database, E> EvmErrored<'a, Ext, Db, E> { } } -impl<'a, Ext, Db: Database> EvmErrored<'a, Ext, Db> { +impl EvmErrored { /// Check if the error is a transaction error. This is provided as a /// convenience function for common cases, as Transaction errors should /// usually be discarded. @@ -1860,7 +1783,7 @@ impl<'a, Ext, Db: Database> EvmErrored<'a, Ext, Db> { /// Discard the error if it is a transaction error, returning the EVM. If /// the error is not a transaction error, return self - pub fn discard_transaction_error(self) -> Result, Self> { + pub fn discard_transaction_error(self) -> Result, Self> { if self.is_transaction_error() { Ok(self.discard_error()) } else { @@ -1871,19 +1794,19 @@ impl<'a, Ext, Db: Database> EvmErrored<'a, Ext, Db> { // --- TRANSACTED -impl AsRef for EvmTransacted<'_, Ext, Db> { +impl AsRef for EvmTransacted { fn as_ref(&self) -> &ResultAndState { &self.state.result } } -impl AsRef for EvmTransacted<'_, Ext, Db> { +impl AsRef for EvmTransacted { fn as_ref(&self) -> &ExecutionResult { &self.state.result.result } } -impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { +impl EvmTransacted { /// Get a reference to the result. pub fn result(&self) -> &ExecutionResult { self.as_ref() @@ -1952,7 +1875,7 @@ impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { } /// Discard the state changes and return the EVM. - pub fn reject(self) -> EvmNeedsTx<'a, Ext, Db> { + pub fn reject(self) -> EvmNeedsTx { Trevm { inner: self.inner, state: NeedsTx::new() } } @@ -1962,27 +1885,27 @@ impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { } /// Take the [`ResultAndState`] and return the EVM. - pub fn take_result_and_state(self) -> (ResultAndState, EvmNeedsTx<'a, Ext, Db>) { - let Trevm { inner, state: TransactedState { result } } = self; + pub fn take_result_and_state(self) -> (ResultAndState, EvmNeedsTx) { + let Self { inner, state: TransactedState { result } } = self; (result, Trevm { inner, state: NeedsTx::new() }) } /// Take the [`ExecutionResult`], discard the [`EvmState`] and return the /// EVM. - pub fn take_result(self) -> (ExecutionResult, EvmNeedsTx<'a, Ext, Db>) { - let Trevm { inner, state: TransactedState { result } } = self; + pub fn take_result(self) -> (ExecutionResult, EvmNeedsTx) { + let Self { inner, state: TransactedState { result } } = self; (result.result, Trevm { inner, state: NeedsTx::new() }) } /// Accept the state changes, commiting them to the database, and return the /// EVM with the [`ExecutionResult`]. - pub fn accept(self) -> (ExecutionResult, EvmNeedsTx<'a, Ext, Db>) + pub fn accept(self) -> (ExecutionResult, EvmNeedsTx) where Db: DatabaseCommit, { - let Trevm { mut inner, state: TransactedState { result } } = self; + let Self { mut inner, state: TransactedState { result } } = self; - inner.db_mut().commit(result.state); + inner.db().commit(result.state); (result.result, Trevm { inner, state: NeedsTx::new() }) } @@ -1997,21 +1920,21 @@ impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { pub fn try_accept( self, ) -> Result< - (ExecutionResult, EvmNeedsTx<'a, Ext, Db>), - EvmErrored<'a, Ext, Db, ::Error>, + (ExecutionResult, EvmNeedsTx), + EvmErrored::Error>, > where Db: TryDatabaseCommit, { - let Trevm { mut inner, state: TransactedState { result } } = self; + let Self { mut inner, state: TransactedState { result } } = self; - trevm_try!(inner.db_mut().try_commit(result.state), Trevm { inner, state: NeedsTx::new() }); + trevm_try!(inner.db().try_commit(result.state), Trevm { inner, state: NeedsTx::new() }); Ok((result.result, Trevm { inner, state: NeedsTx::new() })) } /// Accept the state changes, commiting them to the database. Do not return /// the [`ExecutionResult.`] - pub fn accept_state(self) -> EvmNeedsTx<'a, Ext, Db> + pub fn accept_state(self) -> EvmNeedsTx where Db: DatabaseCommit, { @@ -2025,7 +1948,7 @@ impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { /// [`Self::accept_state`] when possible. pub fn try_accept_state( self, - ) -> Result, EvmErrored<'a, Ext, Db, ::Error>> + ) -> Result, EvmErrored::Error>> where Db: TryDatabaseCommit, { @@ -2048,7 +1971,7 @@ impl<'a, Ext, Db: Database> EvmTransacted<'a, Ext, Db> { /// /// [`EstimationResult`]: crate::EstimationResult #[cfg(feature = "estimate_gas")] - pub fn take_estimation(self) -> (crate::EstimationResult, EvmReady<'a, Ext, Db>) { + pub fn take_estimation(self) -> (crate::EstimationResult, EvmReady) { let estimation = self.estimation(); (estimation, Trevm { inner: self.inner, state: crate::Ready::new() }) } diff --git a/src/ext.rs b/src/ext.rs index aebd56f..34613db 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -1,11 +1,13 @@ use alloy::primitives::{Address, B256, U256}; use revm::{ - primitives::{Account, AccountInfo, Bytecode, EvmState, EvmStorageSlot, HashMap}, + context::{ContextTr, Evm}, + primitives::HashMap, + state::{Account, AccountInfo, Bytecode, EvmState, EvmStorageSlot}, Database, DatabaseCommit, }; -/// Extension trait for [`revm::Evm`] with convenience functions for reading -/// and modifying state. +/// Extension trait for [`revm::context::Evm`] with convenience functions for +/// reading and modifying state. pub trait EvmExtUnchecked { /// Get a mutable reference to the database. fn db_mut_ext(&mut self) -> &mut Db; @@ -169,8 +171,11 @@ pub trait EvmExtUnchecked { } } -impl EvmExtUnchecked for revm::Evm<'_, Ext, Db> { - fn db_mut_ext(&mut self) -> &mut Db { - self.db_mut() +impl EvmExtUnchecked for Evm +where + Ctx: ContextTr, +{ + fn db_mut_ext(&mut self) -> &mut Ctx::Db { + self.data.ctx.db() } } diff --git a/src/fill/alloy.rs b/src/fill/alloy.rs index 51eb20a..8d8d9ff 100644 --- a/src/fill/alloy.rs +++ b/src/fill/alloy.rs @@ -1,15 +1,22 @@ -use alloy::{consensus::Signed, primitives::U256}; -use revm::primitives::{BlobExcessGasAndPrice, BlockEnv, TxEnv}; +use alloy::{ + consensus::{Signed, TxType}, + primitives::U256, +}; +use revm::{ + context::{BlockEnv, TxEnv}, + context_interface::block::BlobExcessGasAndPrice, +}; use crate::{Block, Tx}; impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -20,29 +27,31 @@ impl Tx for Signed { max_fee_per_blob_gas, authorization_list, } = tx_env; + *tx_type = TxType::Legacy as u8; *caller = self.recover_signer().unwrap(); *gas_limit = self.tx().gas_limit; - *gas_price = U256::from(self.tx().gas_price); - *transact_to = self.tx().to; + *gas_price = self.tx().gas_price; + *kind = self.tx().to; *value = self.tx().value; *data = self.tx().input.clone(); - *nonce = Some(self.tx().nonce); + *nonce = self.tx().nonce; *chain_id = self.tx().chain_id; - access_list.clear(); + access_list.0.clear(); gas_priority_fee.take(); blob_hashes.clear(); - max_fee_per_blob_gas.take(); - authorization_list.take(); + *max_fee_per_blob_gas = 0; + authorization_list.clear(); } } impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -53,29 +62,31 @@ impl Tx for Signed { max_fee_per_blob_gas, authorization_list, } = tx_env; + *tx_type = TxType::Eip2930 as u8; *caller = self.recover_signer().unwrap(); *gas_limit = self.tx().gas_limit; - *gas_price = U256::from(self.tx().gas_price); - *transact_to = self.tx().to; + *gas_price = self.tx().gas_price; + *kind = self.tx().to; *value = self.tx().value; *data = self.tx().input.clone(); - *nonce = Some(self.tx().nonce); + *nonce = self.tx().nonce; *chain_id = Some(self.tx().chain_id); - access_list.clone_from(&self.tx().access_list.0); + access_list.clone_from(&self.tx().access_list); gas_priority_fee.take(); blob_hashes.clear(); - max_fee_per_blob_gas.take(); - authorization_list.take(); + *max_fee_per_blob_gas = 0; + authorization_list.clear(); } } impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -86,29 +97,31 @@ impl Tx for Signed { max_fee_per_blob_gas, authorization_list, } = tx_env; + *tx_type = TxType::Eip1559 as u8; *caller = self.recover_signer().unwrap(); *gas_limit = self.tx().gas_limit; - *gas_price = U256::from(self.tx().max_fee_per_gas); - *transact_to = self.tx().to; + *gas_price = self.tx().max_fee_per_gas; + *kind = self.tx().to; *value = self.tx().value; *data = self.tx().input.clone(); - *nonce = Some(self.tx().nonce); + *nonce = self.tx().nonce; *chain_id = Some(self.tx().chain_id); - access_list.clone_from(&self.tx().access_list.0); - *gas_priority_fee = Some(U256::from(self.tx().max_priority_fee_per_gas)); + access_list.clone_from(&self.tx().access_list); + *gas_priority_fee = Some(self.tx().max_priority_fee_per_gas); blob_hashes.clear(); - max_fee_per_blob_gas.take(); - authorization_list.take(); + *max_fee_per_blob_gas = 0; + authorization_list.clear(); } } impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -119,29 +132,31 @@ impl Tx for Signed { max_fee_per_blob_gas, authorization_list, } = tx_env; + *tx_type = TxType::Eip4844 as u8; *caller = self.recover_signer().unwrap(); *gas_limit = self.tx().gas_limit; - *gas_price = U256::from(self.tx().max_fee_per_gas); - *transact_to = self.tx().to.into(); + *gas_price = self.tx().max_fee_per_gas; + *kind = self.tx().to.into(); *value = self.tx().value; *data = self.tx().input.clone(); - *nonce = Some(self.tx().nonce); + *nonce = self.tx().nonce; *chain_id = Some(self.tx().chain_id); - access_list.clone_from(&self.tx().access_list.0); - *gas_priority_fee = Some(U256::from(self.tx().max_priority_fee_per_gas)); + access_list.clone_from(&self.tx().access_list); + *gas_priority_fee = Some(self.tx().max_priority_fee_per_gas); blob_hashes.clone_from(&self.tx().blob_versioned_hashes); - *max_fee_per_blob_gas = Some(U256::from(self.tx().max_fee_per_blob_gas)); - authorization_list.take(); + *max_fee_per_blob_gas = self.tx().max_fee_per_blob_gas; + authorization_list.clear(); } } impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -152,29 +167,31 @@ impl Tx for Signed { max_fee_per_blob_gas, authorization_list, } = tx_env; + *tx_type = TxType::Eip4844 as u8; *caller = self.recover_signer().unwrap(); *gas_limit = self.tx().tx.gas_limit; - *gas_price = U256::from(self.tx().tx.max_fee_per_gas); - *transact_to = self.tx().tx.to.into(); + *gas_price = self.tx().tx.max_fee_per_gas; + *kind = self.tx().tx.to.into(); *value = self.tx().tx.value; *data = self.tx().tx.input.clone(); - *nonce = Some(self.tx().tx.nonce); + *nonce = self.tx().tx.nonce; *chain_id = Some(self.tx().tx.chain_id); - access_list.clone_from(&self.tx().tx.access_list.0); - *gas_priority_fee = Some(U256::from(self.tx().tx.max_priority_fee_per_gas)); + access_list.clone_from(&self.tx().tx.access_list); + *gas_priority_fee = Some(self.tx().tx.max_priority_fee_per_gas); blob_hashes.clone_from(&self.tx().tx.blob_versioned_hashes); - *max_fee_per_blob_gas = Some(U256::from(self.tx().tx.max_fee_per_blob_gas)); - authorization_list.take(); + *max_fee_per_blob_gas = self.tx().tx.max_fee_per_blob_gas; + authorization_list.clear(); } } impl Tx for Signed { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -189,24 +206,25 @@ impl Tx for Signed { alloy::consensus::TxEip4844Variant::TxEip4844(tx) => tx, alloy::consensus::TxEip4844Variant::TxEip4844WithSidecar(tx) => &tx.tx, }; + *tx_type = TxType::Eip4844 as u8; *caller = self.recover_signer().unwrap(); *gas_limit = tx.gas_limit; - *gas_price = U256::from(tx.max_fee_per_gas); - *transact_to = tx.to.into(); + *gas_price = tx.max_fee_per_gas; + *kind = tx.to.into(); *value = tx.value; *data = tx.input.clone(); - *nonce = Some(tx.nonce); + *nonce = tx.nonce; *chain_id = Some(tx.chain_id); - access_list.clone_from(&tx.access_list.0); - *gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); + access_list.clone_from(&tx.access_list); + *gas_priority_fee = Some(tx.max_priority_fee_per_gas); blob_hashes.clone_from(&tx.blob_versioned_hashes); - *max_fee_per_blob_gas = Some(U256::from(tx.max_fee_per_blob_gas)); - authorization_list.take(); + *max_fee_per_blob_gas = tx.max_fee_per_blob_gas; + authorization_list.clear(); } } impl Tx for alloy::consensus::TxEnvelope { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { match self { Self::Legacy(t) => t.fill_tx_env(tx_env), Self::Eip2930(t) => t.fill_tx_env(tx_env), @@ -218,10 +236,10 @@ impl Tx for alloy::consensus::TxEnvelope { } impl Block for alloy::consensus::Header { - fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { + fn fill_block_env(&self, block_env: &mut BlockEnv) { let BlockEnv { number, - coinbase, + beneficiary, timestamp, gas_limit, basefee, @@ -229,11 +247,11 @@ impl Block for alloy::consensus::Header { prevrandao, blob_excess_gas_and_price: _, } = block_env; - *number = U256::from(self.number); - *coinbase = self.beneficiary; - *timestamp = U256::from(self.timestamp); - *gas_limit = U256::from(self.gas_limit); - *basefee = self.base_fee_per_gas.map_or_else(Default::default, U256::from); + *number = self.number; + *beneficiary = self.beneficiary; + *timestamp = self.timestamp; + *gas_limit = self.gas_limit; + *basefee = self.base_fee_per_gas.unwrap_or_default(); *difficulty = self.difficulty; *prevrandao = Some(self.mix_hash); @@ -250,10 +268,10 @@ impl Block for alloy::consensus::Header { } impl Block for alloy::rpc::types::eth::Header { - fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { + fn fill_block_env(&self, block_env: &mut BlockEnv) { let BlockEnv { number, - coinbase, + beneficiary, timestamp, gas_limit, basefee, @@ -261,12 +279,12 @@ impl Block for alloy::rpc::types::eth::Header { prevrandao, blob_excess_gas_and_price, } = block_env; - *number = U256::from(self.number); - *coinbase = self.beneficiary; - *timestamp = U256::from(self.timestamp); - *gas_limit = U256::from(self.gas_limit); - *basefee = U256::from(self.base_fee_per_gas.unwrap_or_default()); - *difficulty = U256::from(self.difficulty); + *number = self.number; + *beneficiary = self.beneficiary; + *timestamp = self.timestamp; + *gas_limit = self.gas_limit; + *basefee = self.base_fee_per_gas.unwrap_or_default(); + *difficulty = self.difficulty; *prevrandao = Some(self.mix_hash); *blob_excess_gas_and_price = self .blob_gas_used @@ -275,7 +293,7 @@ impl Block for alloy::rpc::types::eth::Header { } impl Block for alloy::rpc::types::eth::Block { - fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { + fn fill_block_env(&self, block_env: &mut BlockEnv) { self.header.fill_block_env(block_env); } @@ -287,10 +305,11 @@ impl Block for alloy::rpc::types::eth::Block { impl Tx for alloy::rpc::types::TransactionRequest { fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -306,38 +325,19 @@ impl Tx for alloy::rpc::types::TransactionRequest { // NB: this is set to max if not provided, as users will typically // intend that to mean "as much as possible" + *tx_type = self.transaction_type.unwrap_or(TxType::Eip1559 as u8); *gas_limit = self.gas.unwrap_or(u64::MAX); - *gas_price = U256::from(self.gas_price.unwrap_or_default()); - *transact_to = self.to.unwrap_or_default(); + *gas_price = self.gas_price.unwrap_or_default(); + *kind = self.to.unwrap_or_default(); *value = self.value.unwrap_or_default(); *data = self.input.input().cloned().unwrap_or_default(); - *nonce = self.nonce; + *nonce = self.nonce.unwrap_or_default(); // TODO: IS THIS CORRECT? *chain_id = self.chain_id; - if let Some(al) = &self.access_list { - access_list.clone_from(al); - } else { - access_list.clear(); - } - if let Some(gpf) = &self.max_priority_fee_per_gas { - *gas_priority_fee = Some(U256::from(*gpf)); - } else { - gas_priority_fee.take(); - } - if let Some(bh) = &self.blob_versioned_hashes { - blob_hashes.clone_from(bh); - } else { - blob_hashes.clear(); - } - if let Some(mfbg) = &self.max_fee_per_blob_gas { - *max_fee_per_blob_gas = Some(U256::from(*mfbg)); - } else { - max_fee_per_blob_gas.take(); - } - if let Some(al) = &self.authorization_list { - *authorization_list = Some(al.clone().into()); - } else { - authorization_list.take(); - } + *access_list = self.access_list.clone().unwrap_or_default(); + *gas_priority_fee = self.max_priority_fee_per_gas; + *blob_hashes = self.blob_versioned_hashes.clone().unwrap_or_default(); + *max_fee_per_blob_gas = self.max_fee_per_blob_gas.unwrap_or_default(); + *authorization_list = self.authorization_list.clone().unwrap_or_default(); } } @@ -345,7 +345,7 @@ impl Block for alloy::rpc::types::BlockOverrides { fn fill_block_env(&self, block_env: &mut BlockEnv) { let BlockEnv { number, - coinbase, + beneficiary, timestamp, gas_limit, basefee, @@ -354,37 +354,36 @@ impl Block for alloy::rpc::types::BlockOverrides { blob_excess_gas_and_price: _, } = block_env; if let Some(n) = &self.number { - *number = U256::from(*n); + *number = n.saturating_to(); } if let Some(d) = &self.difficulty { *difficulty = U256::from(*d); } if let Some(t) = &self.time { - *timestamp = U256::from(*t); + *timestamp = *t; } if let Some(g) = &self.gas_limit { - *gas_limit = U256::from(*g); + *gas_limit = *g; } if let Some(c) = &self.coinbase { - *coinbase = *c; + *beneficiary = *c; } if let Some(r) = self.random { *prevrandao = Some(r); } if let Some(b) = &self.base_fee { - *basefee = U256::from(*b); + *basefee = b.saturating_to(); } } } #[cfg(test)] mod tests { - use crate::{NoopBlock, NoopCfg, TrevmBuilder}; + use crate::{test_utils::test_trevm, NoopBlock, NoopCfg}; use alloy::{ consensus::{Header, TxEnvelope, EMPTY_ROOT_HASH}, rlp::Decodable, }; - use revm::{Evm, InMemoryDB}; #[test] // Test vector from https://etherscan.io/tx/0xce4dc6d7a7549a98ee3b071b67e970879ff51b5b95d1c340bacd80fa1e1aab31 @@ -392,12 +391,7 @@ mod tests { let raw_tx = alloy::primitives::hex::decode("02f86f0102843b9aca0085029e7822d68298f094d9e1459a7a482635700cbc20bbaf52d495ab9c9680841b55ba3ac080a0c199674fcb29f353693dd779c017823b954b3c69dffa3cd6b2a6ff7888798039a028ca912de909e7e6cdef9cdcaf24c54dd8c1032946dfa1d85c206b32a9064fe8").unwrap(); let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); - let _ = Evm::builder() - .with_db(InMemoryDB::default()) - .build_trevm() - .fill_cfg(&NoopCfg) - .fill_block(&NoopBlock) - .fill_tx(&tx); + let _ = test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock).fill_tx(&tx); } #[test] @@ -406,12 +400,7 @@ mod tests { let raw_tx = alloy::primitives::hex::decode("f9015482078b8505d21dba0083022ef1947a250d5630b4cf539739df2c5dacb4c659f2488d880c46549a521b13d8b8e47ff36ab50000000000000000000000000000000000000000000066ab5a608bd00a23f2fe000000000000000000000000000000000000000000000000000000000000008000000000000000000000000048c04ed5691981c42154c6167398f95e8f38a7ff00000000000000000000000000000000000000000000000000000000632ceac70000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006c6ee5e31d828de241282b9606c8e98ea48526e225a0c9077369501641a92ef7399ff81c21639ed4fd8fc69cb793cfa1dbfab342e10aa0615facb2f1bcf3274a354cfe384a38d0cc008a11c2dd23a69111bc6930ba27a8").unwrap(); let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); - let _ = Evm::builder() - .with_db(InMemoryDB::default()) - .build_trevm() - .fill_cfg(&NoopCfg) - .fill_block(&NoopBlock) - .fill_tx(&tx); + let _ = test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock).fill_tx(&tx); } #[test] @@ -421,12 +410,7 @@ mod tests { let raw_tx = alloy::primitives::hex::decode("0x03f9011d83aa36a7820fa28477359400852e90edd0008252089411e9ca82a3a762b4b5bd264d4173a242e7a770648080c08504a817c800f8a5a0012ec3d6f66766bedb002a190126b3549fce0047de0d4c25cffce0dc1c57921aa00152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4a0013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7a001148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1a0011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e654901a0c8de4cced43169f9aa3d36506363b2d2c44f6c49fc1fd91ea114c86f3757077ea01e11fdd0d1934eda0492606ee0bb80a7bf8f35cc5f86ec60fe5031ba48bfd544").unwrap(); let tx = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); - let _ = Evm::builder() - .with_db(InMemoryDB::default()) - .build_trevm() - .fill_cfg(&NoopCfg) - .fill_block(&NoopBlock) - .fill_tx(&tx); + let _ = test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock).fill_tx(&tx); } #[test] @@ -442,10 +426,6 @@ mod tests { assert_eq!(json, raw); // Fill using the constructed header - let _ = Evm::builder() - .with_db(InMemoryDB::default()) - .build_trevm() - .fill_cfg(&NoopCfg) - .fill_block(&header); + let _ = test_trevm().fill_cfg(&NoopCfg).fill_block(&header); } } diff --git a/src/fill/fillers.rs b/src/fill/fillers.rs index b733b98..08241f8 100644 --- a/src/fill/fillers.rs +++ b/src/fill/fillers.rs @@ -1,5 +1,5 @@ use crate::fill::traits::{Cfg, Tx}; -use revm::primitives::{CfgEnv, TxEnv}; +use revm::context::{BlockEnv, CfgEnv, TxEnv}; /// A [`Cfg`] that disables gas-related checks and payment of the /// beneficiary reward, while leaving other cfg options unchanged. @@ -24,14 +24,6 @@ impl Cfg for DisableGasChecks { { cfg_env.disable_balance_check = true; } - #[cfg(feature = "optional_beneficiary_reward")] - { - cfg_env.disable_beneficiary_reward = true; - } - #[cfg(feature = "optional_gas_refund")] - { - cfg_env.disable_gas_refund = true; - } #[cfg(feature = "optional_no_base_fee")] { cfg_env.disable_base_fee = true; @@ -39,15 +31,15 @@ impl Cfg for DisableGasChecks { } } -/// A [`Tx`] that disables the nonce check, while leaving other [`TxEnv`] +/// A [`Cfg`] that disables the nonce check, while leaving other [`CfgEnv`] /// attributes untouched. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct DisableNonceCheck; -impl Tx for DisableNonceCheck { +impl Cfg for DisableNonceCheck { #[allow(unused_variables)] - fn fill_tx_env(&self, tx_env: &mut TxEnv) { - tx_env.nonce = None; + fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) { + cfg_env.disable_nonce_check = true; } } @@ -74,13 +66,13 @@ impl Cfg for GasEstimationFiller { fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) { cfg_env.disable_base_fee = true; cfg_env.disable_eip3607 = true; + DisableNonceCheck.fill_cfg_env(cfg_env); } } #[cfg(feature = "estimate_gas")] impl Tx for GasEstimationFiller { fn fill_tx_env(&self, tx_env: &mut TxEnv) { - DisableNonceCheck.fill_tx_env(tx_env); tx_env.gas_limit = self.gas_limit; } } @@ -95,19 +87,13 @@ impl Cfg for CallFiller { fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) { cfg_env.disable_base_fee = true; cfg_env.disable_eip3607 = true; + DisableNonceCheck.fill_cfg_env(cfg_env); } } #[cfg(feature = "call")] impl crate::Block for CallFiller { - fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) { - block_env.gas_limit = alloy::primitives::U256::from(self.gas_limit); - } -} - -#[cfg(feature = "call")] -impl Tx for CallFiller { - fn fill_tx_env(&self, tx_env: &mut TxEnv) { - DisableNonceCheck.fill_tx_env(tx_env); + fn fill_block_env(&self, block_env: &mut BlockEnv) { + block_env.gas_limit = self.gas_limit; } } diff --git a/src/fill/noop.rs b/src/fill/noop.rs index a32f08b..d71b873 100644 --- a/src/fill/noop.rs +++ b/src/fill/noop.rs @@ -1,4 +1,4 @@ -use revm::primitives::{BlockEnv, CfgEnv}; +use revm::context::{BlockEnv, CfgEnv}; use crate::{Block, Cfg}; diff --git a/src/fill/traits.rs b/src/fill/traits.rs index 68fb3c2..1350122 100644 --- a/src/fill/traits.rs +++ b/src/fill/traits.rs @@ -1,6 +1,7 @@ +use crate::helpers::Ctx; use revm::{ - primitives::{BlockEnv, CfgEnv, TxEnv}, - Database, Evm, + context::{BlockEnv, CfgEnv, Evm, TxEnv}, + Database, }; /// Types that can fill the EVM transaction environment [`TxEnv`]. @@ -17,9 +18,8 @@ pub trait Tx: Send + Sync { fn fill_tx_env(&self, tx_env: &mut TxEnv); /// Fill the transaction environment on the EVM. - fn fill_tx(&self, evm: &mut Evm<'_, Ext, Db>) { - let tx_env: &mut TxEnv = evm.tx_mut(); - self.fill_tx_env(tx_env); + fn fill_tx(&self, evm: &mut Evm, Insp, Inst, Prec>) { + evm.data.ctx.modify_tx(|tx_env| self.fill_tx_env(tx_env)); } } @@ -45,9 +45,8 @@ pub trait Block: Send + Sync { fn fill_block_env(&self, block_env: &mut BlockEnv); /// Fill the block environment on the EVM. - fn fill_block(&self, evm: &mut Evm<'_, Ext, Db>) { - let block_env: &mut BlockEnv = evm.block_mut(); - self.fill_block_env(block_env); + fn fill_block(&self, evm: &mut Evm, Insp, Inst, Prec>) { + evm.data.ctx.modify_block(|block_env| self.fill_block_env(block_env)); } /// Get the transaction count hint from the filler. This can be used for @@ -88,9 +87,8 @@ pub trait Cfg: Send + Sync { fn fill_cfg_env(&self, cfg_env: &mut CfgEnv); /// Fill the configuration environment on the EVM. - fn fill_cfg(&self, evm: &mut Evm<'_, Ext, Db>) { - let cfg_env: &mut CfgEnv = evm.cfg_mut(); - self.fill_cfg_env(cfg_env); + fn fill_cfg(&self, evm: &mut Evm, Insp, Inst, Prec>) { + evm.data.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); } } @@ -109,7 +107,10 @@ mod test { consensus::constants::GWEI_TO_WEI, primitives::{B256, U256}, }; - use revm::primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv}; + use revm::{ + context::{BlockEnv, CfgEnv}, + context_interface::block::BlobExcessGasAndPrice, + }; use super::*; @@ -117,7 +118,7 @@ mod test { fn fill_block_env(&self, block_env: &mut BlockEnv) { let BlockEnv { number, - coinbase, + beneficiary, timestamp, gas_limit, basefee, @@ -125,11 +126,11 @@ mod test { prevrandao, blob_excess_gas_and_price, } = block_env; - *number = U256::from(1); - *coinbase = Default::default(); - *timestamp = U256::from(1720450148); // Time when I was writing the test code - *gas_limit = U256::from(30_000_000); - *basefee = U256::from(5 * GWEI_TO_WEI); + *number = 1; + *beneficiary = Default::default(); + *timestamp = 1720450148; // Time when I was writing the test code + *gas_limit = 30_000_000; + *basefee = 5 * GWEI_TO_WEI; let diff = B256::repeat_byte(0xab); *prevrandao = Some(diff); diff --git a/src/helpers.rs b/src/helpers.rs new file mode 100644 index 0000000..3e60947 --- /dev/null +++ b/src/helpers.rs @@ -0,0 +1,18 @@ +use revm::{ + context::{BlockEnv, CfgEnv, TxEnv}, + handler::{instructions::EthInstructions, EthPrecompiles}, + inspector::NoOpInspector, + interpreter::interpreter::EthInterpreter, + Context, Journal, +}; + +/// [`revm::Context`] with default env types and adjustable DB +pub type Ctx, C = ()> = Context; + +/// EVM with default env types and adjustable DB. +pub type Evm< + Db, + Insp = NoOpInspector, + Inst = EthInstructions>, + Prec = EthPrecompiles, +> = revm::context::Evm, Insp, Inst, Prec>; diff --git a/src/journal/coder.rs b/src/journal/coder.rs index b5f9508..34c0252 100644 --- a/src/journal/coder.rs +++ b/src/journal/coder.rs @@ -4,10 +4,13 @@ use alloy::{ rlp::{Buf, BufMut}, }; use revm::{ - db::{states::StorageSlot, BundleState}, - primitives::{ - eof::EofDecodeError, AccountInfo, Bytecode, Eip7702Bytecode, Eip7702DecodeError, Eof, + bytecode::{ + eip7702::{Eip7702Bytecode, Eip7702DecodeError}, + eof::EofDecodeError, + Eof, }, + database::{states::StorageSlot, BundleState}, + state::{AccountInfo, Bytecode}, }; use std::{ borrow::{Cow, ToOwned}, @@ -356,17 +359,19 @@ impl JournalEncode for AcctDiff<'_> { impl JournalEncode for Bytecode { fn serialized_size(&self) -> usize { // tag + u32 for len + len of raw - 1 + 4 + self.bytes().len() + 1 + 4 + self.original_bytes().len() } fn encode(&self, buf: &mut dyn BufMut) { match self { - Self::LegacyRaw(_) | Self::LegacyAnalyzed(_) => buf.put_u8(TAG_BYTECODE_RAW), + Self::LegacyAnalyzed(_) => buf.put_u8(TAG_BYTECODE_RAW), Self::Eof(_) => buf.put_u8(TAG_BYTECODE_EOF), Self::Eip7702(_) => buf.put_u8(TAG_BYTECODE_7702), } - let raw = self.bytes(); + let raw = self.original_bytes(); + dbg!(raw.len()); + dbg!(&raw); buf.put_u32(raw.len() as u32); buf.put_slice(raw.as_ref()); } @@ -574,7 +579,7 @@ impl JournalDecode for AcctDiff<'static> { impl JournalDecode for Bytecode { fn decode(buf: &mut &[u8]) -> Result { - let tag = JournalDecode::decode(buf)?; + let tag: u8 = JournalDecode::decode(buf)?; let len: u32 = JournalDecode::decode(buf)?; check_len!(buf, "BytecodeBody", len as usize); @@ -624,11 +629,13 @@ impl JournalDecode for BundleState { mod test { use super::*; + #[track_caller] fn roundtrip(expected: &T) { let enc = JournalEncode::encoded(expected); - assert_eq!(enc.len(), expected.serialized_size(), "{}", core::any::type_name::()); + let ty_name = core::any::type_name::(); + assert_eq!(enc.len(), expected.serialized_size(), "{ty_name}"); let dec = T::decode(&mut enc.as_slice()).expect("decoding failed"); - assert_eq!(&dec, expected); + assert_eq!(&dec, expected, "{ty_name}"); } #[test] diff --git a/src/journal/index.rs b/src/journal/index.rs index 3605a9d..5f12c0a 100644 --- a/src/journal/index.rs +++ b/src/journal/index.rs @@ -1,7 +1,9 @@ use alloy::primitives::{Address, Sign, B256, I256, U256}; use revm::{ - db::{states::StorageSlot, AccountStatus, BundleAccount, BundleState}, - primitives::{AccountInfo, Bytecode, HashMap}, + bytecode::Bytecode, + database::{states::StorageSlot, AccountStatus, BundleAccount, BundleState}, + primitives::HashMap, + state::AccountInfo, }; use std::{borrow::Cow, collections::BTreeMap}; @@ -151,7 +153,7 @@ impl From> for BundleAccount { /// # Example /// /// ``` -/// # use revm::db::BundleState; +/// # use revm::database::BundleState; /// # use trevm::journal::{BundleStateIndex, JournalEncode, JournalDecode, JournalDecodeError}; /// # fn make_index(bundle_state: &BundleState) -> Result<(), JournalDecodeError> { /// let index = BundleStateIndex::from(bundle_state); diff --git a/src/journal/mod.rs b/src/journal/mod.rs index 37c9d0b..e3f3465 100644 --- a/src/journal/mod.rs +++ b/src/journal/mod.rs @@ -23,7 +23,7 @@ //! # Usage Example //! //! ``` -//! # use revm::db::BundleState; +//! # use revm::database::BundleState; //! # use trevm::journal::{BundleStateIndex, JournalEncode, JournalDecode, JournalDecodeError}; //! # fn make_index(bundle_state: &BundleState) -> Result<(), JournalDecodeError> { //! // Make an index over a bundle state. @@ -46,9 +46,9 @@ //! # } //! ``` //! -//! [`StateBuilder::with_bundle_update`]: revm::db::StateBuilder::with_bundle_update -//! [`State`]: revm::db::State -//! [`BundleState`]: revm::db::BundleState +//! [`StateBuilder::with_bundle_update`]: revm::database::StateBuilder::with_bundle_update +//! [`State`]: revm::database::State +//! [`BundleState`]: revm::database::BundleState //! [reth]: https://github.com/paradigmxyz/reth mod coder; diff --git a/src/lib.rs b/src/lib.rs index 9f9d2af..e3c3375 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,8 @@ //! //! ## Quickstart //! -//! To get started, use a [`revm::EvmBuilder`] to configure the EVM, then call -//! [`TrevmBuilder::build_trevm`] to construct the [`Trevm`] instance. From -//! there, you should do the following: +//! To get started, use [`TrevmBuilder`] to configure and construct the EVM. +//! From there, you should do the following: //! //! - Fill a Cfg by calling [`Trevm::fill_cfg`] with a [`Cfg`]. //! - Open a block by calling [`Trevm::fill_block`] with a [`Block`]. @@ -39,14 +38,14 @@ //! Running transactions is simple with Trevm. Here's a basic example: //! //! ``` -//! use revm::{EvmBuilder, db::InMemoryDB}; +//! use revm::{database::in_memory_db::InMemoryDB}; //! use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx}; //! //! # fn t(cfg: &C, block: &B, tx: &T) //! # -> Result<(), Box> { -//! EvmBuilder::default() +//! TrevmBuilder::new() //! .with_db(InMemoryDB::default()) -//! .build_trevm() +//! .build_trevm()? //! .fill_cfg(cfg) //! .fill_block(block) //! .run_tx(tx); @@ -61,22 +60,26 @@ //! ## Writing an application //! //! When writing your code, we strongly recommend using the `Evm____` type -//! aliases to simplify your code. +//! aliases to simplify your code. These types come with 2 generics: `Db` and +//! `Insp`. `Db` is the database type, and `Insp` is the inspector type. Most +//! users will want to use `()` for `Insp`, unless specifically using an +//! inspector or a customized EVM. //! -//! We also recommend defining concrete types for `Ext` and `Db` whenever +//! We also recommend defining concrete types for `Insp` and `Db` whenever //! possible, to simplify your code and remove bounds. Most users will want -//! `()` for `Ext`, unless specifically using an inspector or a customized EVM. +//! `()` for `Insp`, unless specifically using an inspector or a customized EVM. //! //! To help you use concrete types, we provide the [`trevm_aliases`] macro. This -//! macro generates type aliases for the Trevm states with concrete `Ext` and `Db` types. +//! macro generates type aliases for the Trevm states with concrete `Insp` and +//! `Db` types. //! //! ``` //! use trevm::trevm_aliases; -//! use revm::db::InMemoryDB; +//! use revm::database::in_memory_db::InMemoryDB; //! //! // produces types that look like this: -//! // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, (), InMemoryDB>; -//! trevm_aliases!(revm::db::InMemoryDB); +//! // type EvmNeedsCfg = trevm::EvmNeedsCfg, (); +//! trevm_aliases!(revm::database::in_memory_db::InMemoryDB); //! ``` //! //! ### [`BlockDriver`] and [`ChainDriver`] @@ -112,14 +115,14 @@ //! statistics or indices that are only available after the block is closed. //! //! ``` -//! # use revm::{EvmBuilder, db::InMemoryDB}; +//! # use revm::{database::in_memory_db::InMemoryDB}; //! # use trevm::{TrevmBuilder, EvmErrored, Cfg, BlockDriver}; //! # use alloy::primitives::B256; //! # fn t>(cfg: &C, mut driver: D) //! # -> Result<(), Box> { -//! let trevm = EvmBuilder::default() +//! let trevm = TrevmBuilder::new() //! .with_db(InMemoryDB::default()) -//! .build_trevm() +//! .build_trevm()? //! .fill_cfg(cfg) //! .drive_block(&mut driver); //! # Ok(()) @@ -127,8 +130,8 @@ //! ``` //! //! [`BlockDriver`] and [`ChainDriver`] implementations are generic over the -//! `Ext` type. This means that you can use customized revm extensions and -//! inspectors in your driver logic. +//! `Insp` type. This means that you can use customized revm inspectors in your +//! driver logic. //! //! ### Handling execution errors //! @@ -142,14 +145,14 @@ //! type is generic over the error type, so you can use it with any error type. //! //! ``` -//! # use revm::{EvmBuilder, db::InMemoryDB}; +//! # use revm::{database::in_memory_db::InMemoryDB}; //! # use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx}; //! # use alloy::primitives::B256; //! # fn t(cfg: &C, block: &B, tx: &T) //! # -> Result<(), Box> { -//! let trevm = match EvmBuilder::default() +//! let trevm = match TrevmBuilder::new() //! .with_db(InMemoryDB::default()) -//! .build_trevm() +//! .build_trevm()? //! .fill_cfg(cfg) //! .fill_block(block) //! .fill_tx(tx) @@ -165,7 +168,8 @@ //! //! Trevm has a few extension points: //! -//! - Build the [`revm::Evm`] with a [`revm::Inspector`] and use it in trevm. +//! - Build trevm with a [`revm::Inspector`] and use it in your +//! [`BlockDriver`] implementation. //! - Implement the [`PostTx`] trait to apply post-transaction logic/changes. //! - Implement your own [`Cfg`], [`Block`], and //! [`Tx`] to fill the EVM from your own data structures. @@ -180,11 +184,11 @@ //! pub struct MyTx; //! //! impl Tx for MyTx { -//! fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { +//! fn fill_tx_env(&self, tx_env: &mut revm::context::TxEnv) { //! // fill the tx_env with your data //! // we recommend destructuring here to safeguard against future changes //! // to the TxEnv struct -//! let revm::primitives::TxEnv { +//! let revm::context::TxEnv { //! caller, //! .. //! } = tx_env; @@ -237,8 +241,8 @@ //! Here's an example, with states written out: //! //! ``` -//! # use revm::{EvmBuilder, db::{InMemoryDB, BundleState}, State, -//! # StateBuilder}; +//! # use revm::{database::{in_memory_db::InMemoryDB, BundleState, +//! # State, StateBuilder}}; //! # use trevm::{TrevmBuilder, EvmErrored, Cfg, Block, Tx, BlockOutput, //! # EvmNeedsCfg, EvmNeedsBlock, EvmNeedsTx, EvmReady, EvmTransacted}; //! # fn t(cfg: &C, block: &B, tx: &T) @@ -246,36 +250,36 @@ //! let state = StateBuilder::new_with_database(InMemoryDB::default()).build(); //! //! // Trevm starts in `EvmNeedsCfg`. -//! let trevm: EvmNeedsCfg<'_, _, _> = EvmBuilder::default() +//! let trevm: EvmNeedsCfg<_, _> = TrevmBuilder::new() //! .with_db(state) -//! .build_trevm(); +//! .build_trevm()?; //! //! // Once the cfg is filled, we move to `EvmNeedsBlock`. -//! let trevm: EvmNeedsBlock<'_, _, _> = trevm.fill_cfg(cfg); +//! let trevm: EvmNeedsBlock<_, _> = trevm.fill_cfg(cfg); //! //! // Filling the block gets us to `EvmNeedsTx`. -//! let trevm: EvmNeedsTx<'_, _, _> = trevm.fill_block( +//! let trevm: EvmNeedsTx<_, _> = trevm.fill_block( //! block, //! ); //! // Filling the tx gets us to `EvmReady`. -//! let trevm: EvmReady<'_, _, _> = trevm.fill_tx(tx); +//! let trevm: EvmReady<_, _> = trevm.fill_tx(tx); //! //! let res: Result< -//! EvmTransacted<'_, _, _>, -//! EvmErrored<'_, _, _, _>, +//! EvmTransacted<_, _>, +//! EvmErrored<_, _, _>, //! > = trevm.run(); //! //! //! // Applying the tx or ignoring the error gets us back to `EvmNeedsTx`. //! // You could also make additional checks and discard the success result here -//! let trevm: EvmNeedsTx<'_, _, _> = match res { +//! let trevm: EvmNeedsTx<_, _> = match res { //! Ok(trevm) => trevm.accept_state(), //! Err(e) => e.discard_error(), //! }; //! //! // Clearing or closing a block gets us to `EvmNeedsBlock`, ready for the //! // next block. -//! let trevm: EvmNeedsBlock<'_, _, _> = trevm +//! let trevm: EvmNeedsBlock<_, _> = trevm //! .close_block(); //! //! // Finishing the EVM gets us the final changes and a list of block outputs @@ -334,7 +338,7 @@ //! let (bundle, outputs) = evm.close_block(block, post_block_logic).finish(); //! ``` //! -//! [`EVMError`]: revm::primitives::EVMError +//! [`EVMError`]: revm::context::result::EVMError //! [typestate pattern]: https://cliffle.com/blog/rust-typestate/ //! [crate readme]: https://github.com/init4tech/trevm //! [EIP-2537]: https://eips.ethereum.org/EIPS/eip-2537 @@ -364,6 +368,9 @@ #[macro_use] mod macros; +mod builder; +pub use builder::{TrevmBuilder, TrevmBuilderError}; + mod connect; pub use connect::{DbConnect, EvmFactory}; @@ -390,6 +397,9 @@ pub use ext::EvmExtUnchecked; mod fill; pub use fill::{fillers, Block, Cfg, NoopBlock, NoopCfg, Tx}; +/// Type aliases for constraining revm context. +pub mod helpers; + pub mod journal; mod lifecycle; @@ -410,21 +420,5 @@ pub use revm; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; -use revm::{Database, EvmBuilder}; - /// The minimum gas required for a transaction. pub const MIN_TRANSACTION_GAS: u64 = 21_000; - -/// Ext trait for [`EvmBuilder`] that builds a [`Trevm`], and adds features for -/// [`DbConnect`]. -pub trait TrevmBuilder<'a, Ext, Db: Database> { - /// Builds the [`Trevm`]. - fn build_trevm(self) -> EvmNeedsCfg<'a, Ext, Db>; -} - -impl<'a, Stage, Ext, Db: Database> TrevmBuilder<'a, Ext, Db> for EvmBuilder<'a, Stage, Ext, Db> { - /// Builds the [`Trevm`]. - fn build_trevm(self) -> EvmNeedsCfg<'a, Ext, Db> { - Trevm::from(self.build()) - } -} diff --git a/src/lifecycle/postflight.rs b/src/lifecycle/postflight.rs index c5d804e..04abb9a 100644 --- a/src/lifecycle/postflight.rs +++ b/src/lifecycle/postflight.rs @@ -1,4 +1,4 @@ -use revm::primitives::ResultAndState; +use revm::context::result::ResultAndState; /// Control flow for transaction execution. /// diff --git a/src/lifecycle/receipt.rs b/src/lifecycle/receipt.rs index 6f57314..004f917 100644 --- a/src/lifecycle/receipt.rs +++ b/src/lifecycle/receipt.rs @@ -1,5 +1,5 @@ use alloy::consensus::{Receipt, ReceiptWithBloom}; -use revm::primitives::ExecutionResult; +use revm::context::result::ExecutionResult; /// Create an Ethereum [`ReceiptEnvelope`] from an execution result. /// diff --git a/src/states.rs b/src/states.rs index e56c9e7..de9732a 100644 --- a/src/states.rs +++ b/src/states.rs @@ -1,5 +1,5 @@ use crate::{driver::BundleDriver, BlockDriver, ChainDriver, Trevm}; -use revm::{primitives::EVMError, Database}; +use revm::{context::result::EVMError, Database}; use sealed::*; /// A [`Trevm`] that requires a [`Cfg`]. @@ -8,7 +8,7 @@ use sealed::*; /// - [`EvmNeedsCfg::fill_cfg`] /// /// [`Cfg`]: crate::Cfg -pub type EvmNeedsCfg<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsCfg>; +pub type EvmNeedsCfg = Trevm; /// A [`Trevm`] that requires a [`Block`] and contains no /// outputs. This EVM has not yet executed any transactions or state changes. @@ -19,7 +19,7 @@ pub type EvmNeedsCfg<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsCfg>; /// - [`EvmNeedsBlock::drive_chain`] /// /// [`Block`]: crate::Block -pub type EvmNeedsBlock<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsBlock>; +pub type EvmNeedsBlock = Trevm; /// A [`Trevm`] that requires a [`Tx`]. /// @@ -29,13 +29,13 @@ pub type EvmNeedsBlock<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsBlock>; /// - [`EvmNeedsTx::finish`] /// /// [`Tx`]: crate::Tx -pub type EvmNeedsTx<'a, Ext, Db> = Trevm<'a, Ext, Db, NeedsTx>; +pub type EvmNeedsTx = Trevm; /// A [`Trevm`] that is ready to execute a transaction. /// /// The transaction may be executed with [`EvmReady::run`] or cleared /// with [`EvmReady::clear_tx`] -pub type EvmReady<'a, Ext, Db> = Trevm<'a, Ext, Db, Ready>; +pub type EvmReady = Trevm; /// A [`Trevm`] that run a transaction, and contains the resulting execution /// details and state. @@ -43,37 +43,37 @@ pub type EvmReady<'a, Ext, Db> = Trevm<'a, Ext, Db, Ready>; /// Expected continuations include: /// - [`EvmTransacted::reject`] /// - [`EvmTransacted::accept`] -pub type EvmTransacted<'a, Ext, Db> = Trevm<'a, Ext, Db, TransactedState>; +pub type EvmTransacted = Trevm; /// A [`Trevm`] that encountered an error during transaction execution. /// /// Expected continuations include: /// - [`EvmErrored::discard_error`] /// - [`EvmErrored::into_error`] -pub type EvmErrored<'a, Ext, Db, E = EVMError<::Error>> = - Trevm<'a, Ext, Db, ErroredState>; +pub type EvmErrored::Error>> = + Trevm>; /// A [`Trevm`] that encountered an error during [`BlockDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. -pub type EvmBlockDriverErrored<'a, Ext, Db, T> = - EvmErrored<'a, Ext, Db, >::Error>; +pub type EvmBlockDriverErrored = + EvmErrored>::Error>; /// A [`Trevm`] that encountered an error during [`ChainDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. -pub type EvmChainDriverErrored<'a, Ext, Db, T> = - EvmErrored<'a, Ext, Db, >::Error>; +pub type EvmChainDriverErrored = + EvmErrored>::Error>; /// A [`Trevm`] that encountered an error during [`BundleDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. -pub type EvmBundleDriverErrored<'a, Ext, Db, T> = - EvmErrored<'a, Ext, Db, >::Error>; +pub type EvmBundleDriverErrored = + EvmErrored>::Error>; #[allow(unnameable_types, dead_code, unreachable_pub)] pub(crate) mod sealed { - use revm::primitives::ResultAndState; + use revm::context::result::ResultAndState; macro_rules! states { ($($name:ident),+) => { @@ -157,11 +157,11 @@ pub(crate) mod sealed { /// /// ``` /// use trevm::trevm_aliases; -/// use revm::db::InMemoryDB; +/// use revm::database::in_memory_db::InMemoryDB; /// /// // produces types that look like this: -/// // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, (), InMemoryDB>; -/// trevm_aliases!(revm::db::InMemoryDB); +/// // type EvmNeedsCfg = trevm::EvmNeedsCfg +/// trevm_aliases!(revm::database::in_memory_db::InMemoryDB); /// ``` /// /// Invoking with an ext and DB type will use the provided ext type and the @@ -170,24 +170,11 @@ pub(crate) mod sealed { /// ``` /// # mod t { /// # use trevm::trevm_aliases; -/// # use revm::db::InMemoryDB; +/// # use revm::database::in_memory_db::InMemoryDB; /// # pub struct SomeExtType; /// // produces types that look like this: -/// // type EvmNeedsCfg = trevm::EvmNeedsCfg<'static, SomeExtType, InMemoryDB>; -/// trevm_aliases!(SomeExtType, InMemoryDB); -/// # } -/// ``` -/// -/// To add a lifetime to the ext type, add the word lifetime: -/// -/// ``` -/// # mod t { -/// # use trevm::trevm_aliases; -/// # use revm::db::InMemoryDB; -/// # pub struct SomeExtType; -/// // produces types that look like this: -/// // type EvmNeedsCfg<'a> = trevm::EvmNeedsCfg<'a, SomeExtType, InMemoryDB>; -/// trevm_aliases!(lifetime: SomeExtType, InMemoryDB); +/// // type EvmNeedsCfg = trevm::EvmNeedsCfg +/// trevm_aliases!(revm::database::in_memory_db::InMemoryDB, SomeExtType); /// # } /// ``` macro_rules! trevm_aliases { @@ -195,89 +182,7 @@ macro_rules! trevm_aliases { trevm_aliases!((), $db); }; - (lifetime: $ext:ty, $db:ty) => { - #[allow(unused_imports, unreachable_pub, dead_code)] - pub use __aliases::*; - - #[allow(unused_imports, unreachable_pub, dead_code)] - mod __aliases { - use super::*; - // bring these in scope so that doclinks work in generated docs - use $crate::{Block, BlockDriver, ChainDriver, Trevm, Tx}; - - /// A [`Trevm`] that requires a [`Cfg`]. - /// - /// Expected continuations include: - /// - [`Trevm::fill_cfg`] - /// - /// [`Cfg`]: crate::Cfg - /// [`Trevm`]: crate::Trevm - pub type EvmNeedsCfg<'a> = $crate::EvmNeedsCfg<'a, $ext, $db>; - - /// A [`Trevm`] that requires a [`Block`] and contains no - /// outputs. This EVM has not yet executed any transactions or state changes. - /// - /// Expected continuations include: - /// - [`EvmNeedsBlock::open_block`] - /// - [`EvmNeedsBlock::drive_block`] - /// - [`EvmNeedsBlock::drive_chain`] - /// - /// [`Block`]: crate::Block - pub type EvmNeedsBlock<'a> = $crate::EvmNeedsBlock<'a, $ext, $db>; - - /// A [`Trevm`] that requires a [`Tx`]. - /// - /// Expected continuations include: - /// - [`EvmNeedsTx::fill_tx`] - /// - [`EvmNeedsTx::execute_tx`] - /// - [`EvmNeedsTx::apply_tx`] - /// - [`EvmNeedsTx::finish`] - /// - /// [`Tx`]: crate::Tx - pub type EvmNeedsTx<'a> = $crate::EvmNeedsTx<'a, $ext, $db>; - - /// A [`Trevm`] that is ready to execute a transaction. - /// - /// The transaction may be executed with [`Trevm::execute_tx`] or - /// cleared with [`Trevm::clear_tx`] - pub type EvmReady<'a> = $crate::EvmReady<'a, $ext, $db>; - - /// A [`Trevm`] that encountered an error during transaction execution. - /// - /// Expected continuations include: - /// - [`EvmTransacted::reject`] - /// - [`EvmTransacted::accept`] - pub type EvmTransacted<'a> = $crate::EvmTransacted<'a, $ext, $db>; - - /// A [`Trevm`] that encountered an error during transaction execution. - /// - /// Expected continuations include: - /// - [`EvmErrored::discard_error`] - /// - [`EvmErrored::into_error`] - pub type EvmErrored< - 'a, - E = $crate::revm::primitives::EVMError<<$db as $crate::revm::Database>::Error>, - > = $crate::EvmErrored<'a, $ext, $db, E>; - - /// A [`Trevm`] that encountered an error during [`BlockDriver`] execution. - /// - /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmBlockDriverErrored<'a, T> = $crate::EvmBlockDriverErrored<'a, $ext, $db, T>; - - /// A [`Trevm`] that encountered an error during [`ChainDriver`] execution. - /// - /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmChainDriverErrored<'a, T> = $crate::EvmChainDriverErrored<'a, $ext, $db, T>; - - /// A [`Trevm`] that encountered an error during [`BundleDriver`] execution. - /// - /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmBundleDriverErrored<'a, T> = - $crate::EvmBundleDriverErrored<'a, $ext, $db, T>; - } - }; - - ($ext:ty, $db:ty) => { + ($db:ty, $insp:ty) => { #[allow(unused_imports, unreachable_pub, dead_code)] pub use __aliases::*; @@ -294,7 +199,7 @@ macro_rules! trevm_aliases { /// /// [`Cfg`]: crate::Cfg /// [`Trevm`]: crate::Trevm - pub type EvmNeedsCfg = $crate::EvmNeedsCfg<'static, $ext, $db>; + pub type EvmNeedsCfg = $crate::EvmNeedsCfg<$db, $insp>; /// A [`Trevm`] that requires a [`Block`]. /// @@ -302,7 +207,7 @@ macro_rules! trevm_aliases { /// - [`EvmNeedsBlock::open_block`] /// /// [`Block`]: crate::Block - pub type EvmNeedsBlock = $crate::EvmNeedsBlock<'static, $ext, $db>; + pub type EvmNeedsBlock = $crate::EvmNeedsBlock<$db, $insp>; /// A [`Trevm`] that requires a [`Tx`]. // @@ -313,45 +218,42 @@ macro_rules! trevm_aliases { /// - [`EvmNeedsTx::finish`] /// /// [`Tx`]: crate::Tx - pub type EvmNeedsTx = $crate::EvmNeedsTx<'static, $ext, $db>; + pub type EvmNeedsTx = $crate::EvmNeedsTx<$db, $insp>; /// A [`Trevm`] that is ready to execute a transaction. /// /// The transaction may be executed with [`Trevm::execute_tx`] or /// cleared with [`Trevm::clear_tx`] - pub type EvmReady = $crate::EvmReady<'static, $ext, $db>; + pub type EvmReady = $crate::EvmReady<$db, $insp>; /// A [`Trevm`] that encountered an error during transaction execution. /// /// Expected continuations include: /// - [`EvmTransacted::reject`] /// - [`EvmTransacted::accept`] - pub type EvmTransacted = $crate::EvmTransacted<'static, $ext, $db>; + pub type EvmTransacted = $crate::EvmTransacted<$db, $insp>; /// A [`Trevm`] that encountered an error during transaction execution. /// /// Expected continuations include: /// - [`EvmErrored::discard_error`] /// - [`EvmErrored::into_error`] - pub type EvmErrored = $crate::EvmErrored<'static, $ext, $db, E>; + pub type EvmErrored = $crate::EvmErrored<$db, $insp, E>; /// A [`Trevm`] that encountered an error during [`BlockDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmBlockDriverErrored<'a, T> = - $crate::EvmBlockDriverErrored<'static, $ext, $db, T>; + pub type EvmBlockDriverErrored = $crate::EvmBlockDriverErrored<$db, $insp, T>; /// A [`Trevm`] that encountered an error during [`ChainDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmChainDriverErrored<'a, T> = - $crate::EvmChainDriverErrored<'static, $ext, $db, T>; + pub type EvmChainDriverErrored = $crate::EvmChainDriverErrored<$db, $insp, T>; /// A [`Trevm`] that encountered an error during [`BundleDriver`] execution. /// /// This is an [`EvmErrored`] parameterized with the driver's error type. - pub type EvmBundleDriverErrored<'a, T> = - $crate::EvmBundleDriverErrored<'static, $ext, $db, T>; + pub type EvmBundleDriverErrored = $crate::EvmBundleDriverErrored<$db, $insp, T>; } }; } diff --git a/src/system/eip2935.rs b/src/system/eip2935.rs index c63d4a9..a8b2b6c 100644 --- a/src/system/eip2935.rs +++ b/src/system/eip2935.rs @@ -1,11 +1,14 @@ use crate::EvmNeedsTx; use alloy::primitives::U256; use revm::{ - primitives::{EVMError, SpecId, BLOCKHASH_SERVE_WINDOW}, + context::{result::EVMError, ContextTr}, + primitives::hardfork::SpecId, Database, DatabaseCommit, }; -pub use alloy::eips::eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}; +pub use alloy::eips::eip2935::{ + HISTORY_SERVE_WINDOW, HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE, +}; use super::checked_insert_code; @@ -13,10 +16,10 @@ use super::checked_insert_code; /// /// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 pub fn eip2935_slot(block_num: u64) -> U256 { - U256::from(block_num % BLOCKHASH_SERVE_WINDOW as u64) + U256::from(block_num % HISTORY_SERVE_WINDOW as u64) } -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx { /// Apply the pre-block logic for [EIP-2935]. This logic was introduced in /// Prague and updates historical block hashes in a special system /// contract. Unlike other system actions, this is NOT modeled as a @@ -24,7 +27,7 @@ impl EvmNeedsTx<'_, Ext, Db> { /// /// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 pub fn apply_eip2935(&mut self) -> Result<(), EVMError> { - if self.spec_id() < SpecId::PRAGUE || self.inner().block().number.is_zero() { + if self.spec_id() < SpecId::PRAGUE || self.block().number == 0 { return Ok(()); } @@ -34,17 +37,14 @@ impl EvmNeedsTx<'_, Ext, Db> { &HISTORY_STORAGE_CODE, )?; - let block_num = self.inner().block().number.as_limbs()[0]; + let block_num = self.block().number; let prev_block = block_num.saturating_sub(1); // Update the EVM state with the new value. let slot = eip2935_slot(prev_block); - let parent_block_hash = self - .inner_mut_unchecked() - .db_mut() - .block_hash(prev_block) - .map_err(EVMError::Database)?; + let parent_block_hash = + self.inner_mut_unchecked().db().block_hash(prev_block).map_err(EVMError::Database)?; self.try_set_storage_unchecked(HISTORY_STORAGE_ADDRESS, slot, parent_block_hash.into()) .map_err(EVMError::Database)?; @@ -58,22 +58,25 @@ mod test { use super::*; use crate::{NoopBlock, NoopCfg}; use alloy::primitives::B256; - use revm::primitives::Bytecode; + use revm::bytecode::Bytecode; #[test] fn test_eip2935() { - let block_num = U256::from(5); + let block_num = 5; let prev_block_num = U256::from(4); let prev_hash = B256::repeat_byte(0xaa); let slot = eip2935_slot(prev_block_num.to()); // we create a trevm instance with the block number set to 1 let mut trevm = crate::test_utils::test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock); - trevm.inner_mut_unchecked().block_mut().number = block_num; + + trevm.inner_mut_unchecked().modify_block(|block| { + block.number = block_num; + }); // we set the previous block hash in the cachedb, as it will be loaded // during eip application - trevm.inner_mut_unchecked().db_mut().block_hashes.insert(prev_block_num, prev_hash); + trevm.inner_mut_unchecked().db().cache.block_hashes.insert(prev_block_num, prev_hash); trevm.apply_eip2935().unwrap(); diff --git a/src/system/eip4788.rs b/src/system/eip4788.rs index df5c96c..30e1b2a 100644 --- a/src/system/eip4788.rs +++ b/src/system/eip4788.rs @@ -1,10 +1,7 @@ use super::{checked_insert_code, execute_system_tx}; use crate::{system::SystemTx, EvmNeedsTx}; use alloy::primitives::{Address, Bytes, B256, U256}; -use revm::{ - primitives::{EVMError, SpecId}, - Database, DatabaseCommit, -}; +use revm::{context::result::EVMError, primitives::hardfork::SpecId, Database, DatabaseCommit}; /// The number of beacon roots to store in the beacon roots contract. pub const HISTORY_BUFFER_LENGTH: u64 = 8191; @@ -55,7 +52,7 @@ pub fn eip4788_root_slot(timestamp: u64) -> U256 { eip4788_timestamp_slot(timestamp) + U256::from(HISTORY_BUFFER_LENGTH) } -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx { /// Apply a system transaction as specified in [EIP-4788]. The EIP-4788 /// pre-block action was introduced in Cancun, and calls the beacon root /// contract to update the historical beacon root. @@ -77,14 +74,17 @@ mod test { use super::*; use crate::{NoopBlock, NoopCfg}; use alloy::primitives::U256; - use revm::primitives::Bytecode; + use revm::bytecode::Bytecode; #[test] fn test_eip4788() { let timestamp = 8; let mut trevm = crate::test_utils::test_trevm().fill_cfg(&NoopCfg).fill_block(&NoopBlock); - trevm.inner_mut_unchecked().block_mut().timestamp = U256::from(timestamp); + + trevm.inner_mut_unchecked().modify_block(|block| { + block.timestamp = timestamp; + }); let parent_beacon_root = B256::repeat_byte(0xaa); diff --git a/src/system/eip4895.rs b/src/system/eip4895.rs index a1119e7..8b183fb 100644 --- a/src/system/eip4895.rs +++ b/src/system/eip4895.rs @@ -3,9 +3,12 @@ use alloy::{ eips::eip4895::Withdrawal, primitives::{map::HashMap, U256}, }; -use revm::{primitives::EVMError, Database, DatabaseCommit}; +use revm::{context::result::EVMError, Database, DatabaseCommit}; -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx +where + Db: Database + DatabaseCommit, +{ /// Apply the withdrawals to the EVM state. pub fn apply_withdrawals<'b>( &mut self, diff --git a/src/system/eip7002.rs b/src/system/eip7002.rs index 26da061..028dfc2 100644 --- a/src/system/eip7002.rs +++ b/src/system/eip7002.rs @@ -2,10 +2,7 @@ use super::{checked_insert_code, execute_system_tx}; use crate::{system::SystemTx, EvmNeedsTx}; use alloy::eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_CODE; use alloy::primitives::{Address, Bytes}; -use revm::{ - primitives::{EVMError, SpecId}, - Database, DatabaseCommit, -}; +use revm::{context::result::EVMError, primitives::hardfork::SpecId, Database, DatabaseCommit}; /// The address for the [EIP-7002] withdrawal requests contract. /// @@ -42,7 +39,7 @@ impl SystemTx { } } -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx { /// Apply a system transaction as specified in [EIP-7002]. The EIP-7002 /// post-block action was introduced in Prague, and calls the withdrawal /// request contract to accumulate withdrawal requests. @@ -86,6 +83,7 @@ mod test { consensus::constants::ETH_TO_WEI, primitives::{fixed_bytes, FixedBytes, TxKind, U256}, }; + use revm::context::TxEnv; use crate::{NoopBlock, NoopCfg, Tx}; @@ -96,13 +94,13 @@ mod test { struct WithdrawalTx; impl Tx for WithdrawalTx { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { // https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64 let input: Bytes = [&VALIDATOR_PUBKEY[..], &WITHDRAWAL_AMOUNT[..]].concat().into(); tx_env.caller = WITHDRAWAL_ADDR; tx_env.data = input; - tx_env.transact_to = TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS); + tx_env.kind = TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS); // `MIN_WITHDRAWAL_REQUEST_FEE` tx_env.value = U256::from(1); } diff --git a/src/system/eip7251.rs b/src/system/eip7251.rs index c033299..d55cc8b 100644 --- a/src/system/eip7251.rs +++ b/src/system/eip7251.rs @@ -4,10 +4,7 @@ use alloy::{ eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_CODE, primitives::{Address, Bytes}, }; -use revm::{ - primitives::{EVMError, SpecId}, - Database, DatabaseCommit, -}; +use revm::{context::result::EVMError, primitives::hardfork::SpecId, Database, DatabaseCommit}; /// The address for the [EIP-7251] consolidation requests contract /// @@ -44,7 +41,10 @@ impl SystemTx { } } -impl EvmNeedsTx<'_, Ext, Db> { +impl EvmNeedsTx +where + Db: Database + DatabaseCommit, +{ /// Apply a system transaction as specified in [EIP-7251]. The EIP-7251 /// post-block action calls the consolidation request contract to process /// consolidation requests. @@ -81,12 +81,12 @@ impl EvmNeedsTx<'_, Ext, Db> { #[cfg(test)] mod test { use super::*; + use crate::{NoopBlock, NoopCfg, Tx}; use alloy::{ consensus::constants::ETH_TO_WEI, primitives::{fixed_bytes, FixedBytes, TxKind, U256}, }; - - use crate::{NoopBlock, NoopCfg, Tx}; + use revm::context::TxEnv; const WITHDRAWAL_ADDR: Address = Address::with_last_byte(0x42); const VALIDATOR_PUBKEY: FixedBytes<48> = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); @@ -95,13 +95,13 @@ mod test { struct ConsolidationTx; impl Tx for ConsolidationTx { - fn fill_tx_env(&self, tx_env: &mut revm::primitives::TxEnv) { + fn fill_tx_env(&self, tx_env: &mut TxEnv) { let input: Bytes = [&VALIDATOR_PUBKEY[..], &TARGET_VALIDATOR_PUBKEY[..]].concat().into(); tx_env.caller = WITHDRAWAL_ADDR; tx_env.data = input; - tx_env.transact_to = TxKind::Call(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS); + tx_env.kind = TxKind::Call(CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS); // `MIN_CONSOLIDATION_REQUEST_FEE` tx_env.value = U256::from(1); } diff --git a/src/system/fill.rs b/src/system/fill.rs index babd923..4d32fe1 100644 --- a/src/system/fill.rs +++ b/src/system/fill.rs @@ -1,6 +1,6 @@ use crate::Tx; use alloy::primitives::{address, Address, Bytes, U256}; -use revm::primitives::TxEnv; +use revm::context::{TransactionType, TxEnv}; /// System smart contract calls as specified in [EIP-4788], [EIP-7002], /// and [EIP-7251]. @@ -44,10 +44,11 @@ impl SystemTx { impl Tx for SystemTx { fn fill_tx_env(&self, tx_env: &mut TxEnv) { let TxEnv { + tx_type, caller, gas_limit, gas_price, - transact_to, + kind, value, data, nonce, @@ -58,25 +59,28 @@ impl Tx for SystemTx { max_fee_per_blob_gas, authorization_list, } = tx_env; + + *tx_type = TransactionType::Custom as u8; + *caller = self.caller; *gas_limit = 30_000_000; // 0 gas price - *gas_price = U256::ZERO; - *transact_to = self.target.into(); + *gas_price = 0; + *kind = self.target.into(); *value = U256::ZERO; *data = self.input.clone(); - // disable revm nonce checks - nonce.take(); + *nonce = 0; + // disable chain id checks chain_id.take(); // set priority fee to 0 gas_priority_fee.take(); // disable eip-2930 - access_list.clear(); + access_list.0.clear(); // disable eip-4844 blob_hashes.clear(); - max_fee_per_blob_gas.take(); + *max_fee_per_blob_gas = 0; // disable eip-7702 - authorization_list.take(); + authorization_list.clear(); } } diff --git a/src/system/mod.rs b/src/system/mod.rs index bbf60fb..d56d3f7 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -59,18 +59,26 @@ pub const MAX_BLOB_GAS_PER_BLOCK_CANCUN: u64 = 786_432; /// The maximum blob gas limit for a block in Prague. pub const MAX_BLOB_GAS_PER_BLOCK_PRAGUE: u64 = 1_179_648; -use crate::{EvmExtUnchecked, Tx}; -use alloy::primitives::{Address, Bytes, U256}; +use crate::{helpers::Evm, EvmExtUnchecked, Tx}; +use alloy::primitives::{Address, Bytes}; use revm::{ - primitives::{Bytecode, EVMError, ExecutionResult, ResultAndState, KECCAK_EMPTY}, - Database, DatabaseCommit, Evm, + bytecode::Bytecode, + context::{ + result::{EVMError, ExecutionResult, ResultAndState}, + Block, ContextTr, Transaction, + }, + primitives::KECCAK_EMPTY, + Database, DatabaseCommit, ExecuteEvm, }; -fn checked_insert_code( - evm: &mut Evm<'_, Ext, Db>, +fn checked_insert_code( + evm: &mut Evm, address: Address, code: &Bytes, -) -> Result<(), EVMError> { +) -> Result<(), EVMError> +where + Db: Database + DatabaseCommit, +{ if evm.account(address).map_err(EVMError::Database)?.info.code_hash == KECCAK_EMPTY { evm.set_bytecode(address, Bytecode::new_raw(code.clone())).map_err(EVMError::Database)?; } @@ -78,20 +86,28 @@ fn checked_insert_code( } /// Clean up the system call, restoring the block env. -fn cleanup_syscall( - evm: &mut Evm<'_, Ext, Db>, +fn cleanup_syscall( + evm: &mut Evm, result: &mut ResultAndState, syscall: &SystemTx, - old_gas_limit: U256, - old_base_fee: U256, + old_gas_limit: u64, + old_base_fee: u64, + previous_nonce_check: bool, ) where Db: Database + DatabaseCommit, { - evm.block_mut().gas_limit = old_gas_limit; - evm.block_mut().basefee = old_base_fee; + let coinbase = evm.block().beneficiary(); + + // Restore the block environment + evm.modify_block(|block| { + block.gas_limit = old_gas_limit; + block.basefee = old_base_fee; + }); + + // Restore the nonce check + evm.data.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = previous_nonce_check); // Remove the system caller and fees from the state - let coinbase = evm.block().coinbase; let state = &mut result.state; state.remove(&syscall.caller); state.remove(&coinbase); @@ -105,24 +121,29 @@ fn cleanup_syscall( /// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 /// [EIP-7002]: https://eips.ethereum.org/EIPS/eip-7002 /// [EIP-7251]: https://eips.ethereum.org/EIPS/eip-7251 -pub(crate) fn execute_system_tx( - evm: &mut Evm<'_, Ext, Db>, +pub(crate) fn execute_system_tx( + evm: &mut Evm, syscall: &SystemTx, ) -> Result> where Db: Database + DatabaseCommit, { - let limit = U256::from(evm.tx().gas_limit); - let old_gas_limit = core::mem::replace(&mut evm.block_mut().gas_limit, limit); - let old_base_fee = core::mem::replace(&mut evm.block_mut().basefee, U256::ZERO); - syscall.fill_tx(evm); - let mut result = evm.transact()?; + + let limit = evm.tx().gas_limit(); + + let block = &mut evm.data.ctx.block; + let old_gas_limit = core::mem::replace(&mut block.gas_limit, limit); + let old_base_fee = core::mem::take(&mut block.basefee); + + let previous_nonce_check = std::mem::replace(&mut evm.data.ctx.cfg.disable_nonce_check, true); + + let mut result = evm.replay()?; // Cleanup the syscall. - cleanup_syscall(evm, &mut result, syscall, old_gas_limit, old_base_fee); + cleanup_syscall(evm, &mut result, syscall, old_gas_limit, old_base_fee, previous_nonce_check); - evm.db_mut().commit(result.state); + evm.data.ctx.db().commit(result.state); // apply result, remove receipt from block outputs. Ok(result.result) diff --git a/src/test_utils.rs b/src/test_utils.rs index cbefc0e..6e5ca78 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -1,17 +1,15 @@ -use crate::{EvmNeedsCfg, Trevm, TrevmBuilder}; +use crate::{EvmNeedsCfg, Trevm}; use alloy::primitives::{Address, U256}; use revm::{ - db::{CacheDB, EmptyDB, InMemoryDB, State}, - inspector_handle_register, - primitives::{AccountInfo, Bytecode}, - EvmBuilder, GetInspector, + bytecode::Bytecode, + database::{CacheDB, EmptyDB, InMemoryDB, State}, + inspector::inspectors::TracerEip3155, + primitives::hardfork::SpecId, + state::AccountInfo, + Context, MainBuilder, }; -use revm::inspectors::TracerEip3155; - -pub use revm::test_utils as revm_test_utils; - -impl Trevm<'_, Ext, InMemoryDB, State> { +impl Trevm { /// Modify an account with the provide closure. Returns the original /// account info pub fn test_modify_account(&mut self, address: Address, f: F) -> AccountInfo @@ -75,21 +73,9 @@ impl Trevm<'_, Ext, InMemoryDB, State> { } } -/// Make a new [`Trevm`] with the given inspector and an in-memory database. -pub fn test_trevm_with_inspector(inspector: I) -> EvmNeedsCfg<'static, I, CacheDB> -where - I: GetInspector, -{ - EvmBuilder::default() - .with_db(CacheDB::new(EmptyDB::default())) - .with_external_context(inspector) - .append_handler_register(inspector_handle_register) - .build_trevm() -} - /// Make a new [`Trevm`], funding the provided accounts with the given /// amounts. -pub fn test_trevm_with_funds<'b, I>(i: I) -> EvmNeedsCfg<'static, (), InMemoryDB> +pub fn test_trevm_with_funds<'b, I>(i: I) -> EvmNeedsCfg where I: IntoIterator, { @@ -103,17 +89,22 @@ where } /// Make a new [`Trevm`] with an in-memory database. -pub fn test_trevm() -> EvmNeedsCfg<'static, (), CacheDB> { - EvmBuilder::default().with_db(CacheDB::new(EmptyDB::default())).build_trevm() +pub fn test_trevm() -> EvmNeedsCfg, ()> { + Trevm::from(Context::new(CacheDB::new(EmptyDB::default()), SpecId::PRAGUE).build_mainnet()) } /// Make a new [`Trevm`] with an in-memory database wrapped in a [`State`]. -pub fn test_state_trevm() -> EvmNeedsCfg<'static, (), State> { - EvmBuilder::default().with_db(State::builder().with_bundle_update().build()).build_trevm() +pub fn test_state_trevm() -> EvmNeedsCfg, ()> { + Trevm::from( + Context::new(State::builder().with_bundle_update().build(), SpecId::PRAGUE).build_mainnet(), + ) } /// Make a new [`Trevm`] with an in-memory database and a tracer inspector. /// The tracer will print all EVM instructions to stdout. -pub fn test_trevm_tracing() -> EvmNeedsCfg<'static, TracerEip3155, CacheDB> { - test_trevm_with_inspector(TracerEip3155::new(Box::new(std::io::stdout()))) +pub fn test_trevm_tracing() -> EvmNeedsCfg, TracerEip3155> { + Trevm::from( + Context::new(CacheDB::new(EmptyDB::default()), SpecId::PRAGUE) + .build_mainnet_with_inspector(TracerEip3155::new(Box::new(std::io::stdout()))), + ) }