diff --git a/Cargo.toml b/Cargo.toml index 41d125b..7faa65b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trevm" -version = "0.20.11" +version = "0.23.0" rust-version = "1.83.0" edition = "2021" authors = ["init4"] @@ -26,24 +26,37 @@ use-self = "warn" option-if-let-else = "warn" redundant-clone = "warn" +[[example]] +name = "basic_transact" + +[[example]] +name = "fork_ref_transact" +required-features = ["alloy-db"] + [dependencies] -alloy = { version = "0.12.6", default-features = false, features = ["consensus", "rpc-types-mev", "eips", "k256", "std", "rlp", "sol-types"] } +alloy = { version = "1.0.5", default-features = false, features = [ + "consensus", + "rpc-types-mev", + "eips", + "k256", + "std", + "rlp", + "sol-types", +] } -revm = { version = "20.0.0", default-features = false } +revm = { version = "23.1.0", default-features = false } dashmap = { version = "6.1.0", optional = true } -tracing = { version = "0.1.41", optional = true} +tracing = { version = "0.1.41", optional = true } thiserror = "2.0.11" +tokio = { version = "1.44", optional = true } + [dev-dependencies] -revm = { version = "20.0.0", features = [ - "serde-json", - "std", - "alloydb", -] } +revm = { version = "23.1.0", features = ["serde-json", "std", "alloydb"] } trevm = { path = ".", features = ["test-utils"] } -alloy = { version = "0.12.6", features = ["providers"]} +alloy = { version = "1.0.5", features = ["providers", "transports"] } # misc eyre = "0.6" @@ -63,6 +76,8 @@ default = [ "revm/secp256k1", ] +alloy-db = ["dep:tokio"] + call = ["optional_eip3607", "optional_no_base_fee"] concurrent-db = ["dep:dashmap"] diff --git a/examples/fork_ref_transact.rs b/examples/fork_ref_transact.rs index 3687950..b0cfcfb 100644 --- a/examples/fork_ref_transact.rs +++ b/examples/fork_ref_transact.rs @@ -1,7 +1,5 @@ //! This example demonstrates how to query storage slots of a contract, using -//! [`AlloyDB`]. - -//! This example is currently disabled while waiting for revm @ 14.0.4 +//! [`AlloyDb`]. use alloy::{ eips::BlockId, @@ -11,10 +9,7 @@ use alloy::{ sol_types::SolCall, }; use revm::{context::TxEnv, database::WrapDatabaseAsync}; -use trevm::{ - revm::database::{AlloyDB, CacheDB}, - NoopBlock, NoopCfg, TrevmBuilder, Tx, -}; +use trevm::{db::alloy::AlloyDb, revm::database::CacheDB, NoopBlock, NoopCfg, TrevmBuilder, Tx}; sol! { #[allow(missing_docs)] @@ -42,7 +37,7 @@ async fn main() -> eyre::Result<()> { // create ethers client and wrap it in Arc let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; - let client = ProviderBuilder::new().on_http(rpc_url.parse()?); + let client = ProviderBuilder::new().connect_http(rpc_url.parse()?); // ----------------------------------------------------------- // // Storage slots of UniV2Pair contract // @@ -57,7 +52,7 @@ async fn main() -> eyre::Result<()> { // =========================================================== // // initialize new AlloyDB - let alloydb = WrapDatabaseAsync::new(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); @@ -78,7 +73,7 @@ async fn main() -> eyre::Result<()> { let output = evm.output().expect("Execution halted"); // decode bytes to reserves + ts via alloy's abi decode - let return_vals = getReservesCall::abi_decode_returns(output, true)?; + let return_vals = getReservesCall::abi_decode_returns_validate(output)?; // Print emulated getReserves() call output println!("Reserve0: {:#?}", return_vals.reserve0); diff --git a/src/db/alloy.rs b/src/db/alloy.rs new file mode 100644 index 0000000..8de2d14 --- /dev/null +++ b/src/db/alloy.rs @@ -0,0 +1,154 @@ +use alloy::{ + eips::BlockId, + primitives::{StorageValue, U256}, + providers::{ + network::{primitives::HeaderResponse, BlockResponse}, + Network, Provider, + }, + transports::TransportError, +}; +use core::error::Error; +use revm::{ + database_interface::{async_db::DatabaseAsyncRef, DBErrorMarker}, + primitives::{Address, B256}, + state::{AccountInfo, Bytecode}, +}; +use std::fmt::Display; + +/// A type alias for the storage key used in the database. +/// We use this instead of alloy's [`alloy::primitives::StorageKey`] as Revm requires +/// the actual type to be an [`U256`] instead of a [`B256`]. +pub type StorageKey = U256; + +/// An error that can occur when using [`AlloyDb`]. +#[derive(Debug)] +pub struct DBTransportError(pub TransportError); + +impl DBErrorMarker for DBTransportError {} + +impl Display for DBTransportError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Transport error: {}", self.0) + } +} + +impl Error for DBTransportError {} + +impl From for DBTransportError { + fn from(e: TransportError) -> Self { + Self(e) + } +} + +/// An alloy-powered REVM [`Database`][revm::database_interface::Database]. +/// +/// When accessing the database, it'll use the given provider to fetch the corresponding account's data. +#[derive(Debug)] +pub struct AlloyDb> { + /// The provider to fetch the data from. + provider: P, + /// The block number on which the queries will be based on. + block_number: BlockId, + _marker: core::marker::PhantomData N>, +} + +impl> AlloyDb { + /// Creates a new AlloyDB instance, with a [`Provider`] and a block. + pub fn new(provider: P, block_number: BlockId) -> Self { + Self { provider, block_number, _marker: core::marker::PhantomData } + } + + /// Sets the block number on which the queries will be based on. + pub const fn set_block_number(&mut self, block_number: BlockId) { + self.block_number = block_number; + } +} + +impl> DatabaseAsyncRef for AlloyDb { + type Error = DBTransportError; + + async fn basic_async_ref(&self, address: Address) -> Result, Self::Error> { + let nonce = self.provider.get_transaction_count(address).block_id(self.block_number); + let balance = self.provider.get_balance(address).block_id(self.block_number); + let code = self.provider.get_code_at(address).block_id(self.block_number); + + let (nonce, balance, code) = tokio::join!(nonce, balance, code,); + + let balance = balance?; + let code = Bytecode::new_raw(code?.0.into()); + let code_hash = code.hash_slow(); + let nonce = nonce?; + + Ok(Some(AccountInfo::new(balance, nonce, code_hash, code))) + } + + async fn block_hash_async_ref(&self, number: u64) -> Result { + let block = self + .provider + // We know number <= u64::MAX, so we can safely convert it to u64 + .get_block_by_number(number.into()) + .await?; + // If the number is given, the block is supposed to be finalized, so unwrapping is safe. + Ok(B256::new(*block.unwrap().header().hash())) + } + + async fn code_by_hash_async_ref(&self, _code_hash: B256) -> Result { + panic!("This should not be called, as the code is already loaded"); + // This is not needed, as the code is already loaded with basic_ref + } + + async fn storage_async_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + Ok(self.provider.get_storage_at(address, index).block_id(self.block_number).await?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy::providers::ProviderBuilder; + use revm::database_interface::{DatabaseRef, WrapDatabaseAsync}; + + #[test] + #[ignore = "flaky RPC"] + fn can_get_basic() { + let client = ProviderBuilder::new().connect_http( + "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27".parse().unwrap(), + ); + let alloydb = AlloyDb::new(client, BlockId::from(16148323)); + let wrapped_alloydb = WrapDatabaseAsync::new(alloydb).unwrap(); + + // ETH/USDT pair on Uniswap V2 + let address: Address = "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852".parse().unwrap(); + + let acc_info = wrapped_alloydb.basic_ref(address).unwrap().unwrap(); + assert!(acc_info.exists()); + } +} + +// This code has been reproduced from the original AlloyDB implementation +// contained in revm. +// +// The original license is included below: +// +// MIT License +// Copyright (c) 2021-2025 draganrakita +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. diff --git a/src/db/mod.rs b/src/db/mod.rs index f6e07b8..aad4c92 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -9,3 +9,7 @@ pub use traits::{ArcUpgradeError, CachingDb, StateAcc, TryCachingDb, TryStateAcc /// Cache-on-write database. A memory cache that caches only on write, not on /// read. Intended to wrap some other caching database. pub mod cow; + +#[cfg(feature = "alloy-db")] +/// Alloy-powered revm Database implementation that fetches data over the network. +pub mod alloy; diff --git a/src/driver/alloy.rs b/src/driver/alloy.rs index dcd6fa3..565f754 100644 --- a/src/driver/alloy.rs +++ b/src/driver/alloy.rs @@ -4,7 +4,10 @@ use crate::{ trevm_bail, trevm_ensure, trevm_try, Block, BundleDriver, DriveBundleResult, }; use alloy::{ - consensus::{Transaction, TxEip4844Variant, TxEnvelope}, + consensus::{ + crypto::RecoveryError, transaction::SignerRecoverable, Transaction, TxEip4844Variant, + TxEnvelope, + }, eips::{eip2718::Decodable2718, BlockNumberOrTag}, primitives::{bytes::Buf, keccak256, Address, Bytes, TxKind, U256}, rpc::types::mev::{ @@ -35,7 +38,7 @@ pub enum BundleError { /// An error occurred while decoding a transaction contained in the bundle. TransactionDecodingError(alloy::eips::eip2718::Eip2718Error), /// An error occurred while recovering the sender of a transaction. - TransactionSenderRecoveryError(alloy::primitives::SignatureError), + TransactionSenderRecoveryError(alloy::consensus::crypto::RecoveryError), /// An error occurred while running the EVM. EVMError { /// The error that occurred while running the EVM. @@ -71,7 +74,7 @@ impl From for BundleError impl From for BundleError { fn from(err: alloy::primitives::SignatureError) -> Self { - Self::TransactionSenderRecoveryError(err) + Self::TransactionSenderRecoveryError(err.into()) } } @@ -91,6 +94,12 @@ impl std::error::Error for BundleError { } } +impl From for BundleError { + fn from(err: RecoveryError) -> Self { + Self::TransactionSenderRecoveryError(err) + } +} + impl core::fmt::Debug for BundleError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { diff --git a/src/evm.rs b/src/evm.rs index a44ff07..50a7ebd 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -96,12 +96,12 @@ where /// Deconstruct the [`Trevm`] into the backing DB, dropping all other types. pub fn into_db(self) -> Db { - self.inner.data.ctx.journaled_state.database + self.inner.ctx.journaled_state.database } /// Get the id of the currently running hardfork spec. pub fn spec_id(&self) -> SpecId { - self.inner.data.ctx.cfg().spec() + self.inner.ctx.cfg().spec() } /// Set the [SpecId], modifying the EVM handlers accordingly. This function @@ -712,7 +712,7 @@ where /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 pub fn set_code_size_limit(&mut self, limit: usize) -> Option { let mut csl = None; - self.inner.data.ctx.modify_cfg(|cfg| { + self.inner.ctx.modify_cfg(|cfg| { csl = cfg.limit_contract_code_size.replace(limit); }); csl @@ -724,7 +724,7 @@ where /// [`Eip-170`]: https://eips.ethereum.org/EIPS/eip-170 pub fn disable_code_size_limit(&mut self) -> Option { let mut csl = None; - self.inner.data.ctx.modify_cfg(|cfg| csl = cfg.limit_contract_code_size.take()); + self.inner.ctx.modify_cfg(|cfg| csl = cfg.limit_contract_code_size.take()); csl } @@ -766,7 +766,7 @@ where cfg.fill_cfg(&mut self.inner); let mut this = f(self); - this.inner.data.ctx.modify_cfg(|cfg| *cfg = previous); + this.inner.ctx.modify_cfg(|cfg| *cfg = previous); this } @@ -810,10 +810,7 @@ where #[cfg(feature = "memory_limit")] pub fn set_memory_limit(&mut self, new_limit: u64) -> u64 { let mut ml = 0; - self.inner - .data - .ctx - .modify_cfg(|cfg| ml = core::mem::replace(&mut cfg.memory_limit, new_limit)); + self.inner.ctx.modify_cfg(|cfg| ml = core::mem::replace(&mut cfg.memory_limit, new_limit)); ml } @@ -822,13 +819,13 @@ where /// execution doesn't fail. #[cfg(feature = "optional_balance_check")] pub fn disable_balance_check(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = true) + self.inner.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.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = false) + self.inner.ctx.modify_cfg(|cfg| cfg.disable_balance_check = false) } /// Run a closure with balance checks disabled, then restore the previous @@ -841,7 +838,7 @@ where let previous = self.inner.cfg().disable_balance_check; self.disable_balance_check(); let mut new = f(self); - new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_balance_check = previous); + new.inner.ctx.modify_cfg(|cfg| cfg.disable_balance_check = previous); new } @@ -850,13 +847,13 @@ where /// simulating large transactions like forge scripts. #[cfg(feature = "optional_block_gas_limit")] pub fn disable_block_gas_limit(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = true); + self.inner.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.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = false); + self.inner.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = false); } /// Run a closure with block gas limits disabled, then restore the previous @@ -869,7 +866,7 @@ where let previous = self.inner.cfg().disable_block_gas_limit; self.disable_block_gas_limit(); let mut new = f(self); - new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = previous); + new.inner.ctx.modify_cfg(|cfg| cfg.disable_block_gas_limit = previous); new } @@ -879,7 +876,7 @@ where /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 #[cfg(feature = "optional_eip3607")] pub fn disable_eip3607(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = true); + self.inner.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = true); } /// Enable [EIP-3607]. See [`Self::disable_eip3607`]. @@ -887,7 +884,7 @@ where /// [EIP-3607]: https://eips.ethereum.org/EIPS/eip-3607 #[cfg(feature = "optional_eip3607")] pub fn enable_eip3607(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = false); + self.inner.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = false); } /// Run a closure with [EIP-3607] disabled, then restore the previous @@ -901,7 +898,7 @@ where self.disable_eip3607(); let mut new = f(self); - new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = previous); + new.inner.ctx.modify_cfg(|cfg| cfg.disable_eip3607 = previous); new } @@ -911,7 +908,7 @@ where /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 #[cfg(feature = "optional_no_base_fee")] pub fn disable_base_fee(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_base_fee = true) + self.inner.ctx.modify_cfg(|cfg| cfg.disable_base_fee = true) } /// Enable [EIP-1559] base fee checks. See [`Self::disable_base_fee`]. @@ -919,7 +916,7 @@ where /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 #[cfg(feature = "optional_no_base_fee")] pub fn enable_base_fee(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_base_fee = false) + self.inner.ctx.modify_cfg(|cfg| cfg.disable_base_fee = false) } /// Run a closure with [EIP-1559] base fee checks disabled, then restore the @@ -935,19 +932,19 @@ where self.disable_base_fee(); let mut new = f(self); - new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_base_fee = previous); + new.inner.ctx.modify_cfg(|cfg| cfg.disable_base_fee = previous); new } /// Disable nonce checks. This allows transactions to be sent with /// incorrect nonces, and is useful for things like system transactions. pub fn disable_nonce_check(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = true) + self.inner.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = true) } /// Enable nonce checks. See [`Self::disable_nonce_check`]. pub fn enable_nonce_check(&mut self) { - self.inner.data.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = false) + self.inner.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = false) } /// Run a closure with nonce checks disabled, then restore the previous @@ -961,7 +958,7 @@ where self.disable_nonce_check(); let mut new = f(self); - new.inner.data.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = previous); + new.inner.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = previous); new } } @@ -1080,7 +1077,7 @@ where b.fill_block(&mut self.inner); let mut this = f(self); - this.inner.data.ctx.set_block(previous); + this.inner.ctx.set_block(previous); this } @@ -1100,11 +1097,11 @@ where match f(self) { Ok(mut evm) => { - evm.inner.data.ctx.set_block(previous); + evm.inner.ctx.set_block(previous); Ok(evm) } Err(mut evm) => { - evm.inner.data.ctx.set_block(previous); + evm.inner.ctx.set_block(previous); Err(evm) } } @@ -1363,7 +1360,7 @@ where let previous = self.inner.tx().clone(); t.fill_tx(&mut self.inner); let mut this = f(self); - this.inner.data.ctx.set_tx(previous); + this.inner.ctx.set_tx(previous); this } @@ -1383,11 +1380,11 @@ where t.fill_tx(&mut self.inner); match f(self) { Ok(mut evm) => { - evm.inner.data.ctx.set_tx(previous); + evm.inner.ctx.set_tx(previous); Ok(evm) } Err(mut evm) => { - evm.inner.data.ctx.set_tx(previous); + evm.inner.ctx.set_tx(previous); Err(evm) } } @@ -1983,7 +1980,11 @@ where where T::Return: alloy::sol_types::SolType, { - self.output().map(|output| T::abi_decode_returns(output, validate)) + if validate { + return self.output().map(|output| T::abi_decode_returns_validate(output)); + } + + self.output().map(|output| T::abi_decode_returns(output)) } /// Get the gas used by the transaction. diff --git a/src/ext.rs b/src/ext.rs index 34613db..8e3e304 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -176,6 +176,6 @@ where Ctx: ContextTr, { fn db_mut_ext(&mut self) -> &mut Ctx::Db { - self.data.ctx.db() + self.ctx.db() } } diff --git a/src/fill/alloy.rs b/src/fill/alloy.rs index 8d8d9ff..723b67d 100644 --- a/src/fill/alloy.rs +++ b/src/fill/alloy.rs @@ -337,7 +337,13 @@ impl Tx for alloy::rpc::types::TransactionRequest { *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(); + *authorization_list = self + .authorization_list + .iter() + .flatten() + .cloned() + .map(revm::context::either::Either::Left) + .collect(); } } diff --git a/src/fill/fillers.rs b/src/fill/fillers.rs index 3474911..f917a85 100644 --- a/src/fill/fillers.rs +++ b/src/fill/fillers.rs @@ -73,11 +73,11 @@ impl Cfg for GasEstimationFiller { &self, evm: &mut revm::context::Evm, Insp, Inst, Prec>, ) { - evm.data.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); + evm.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); - let chain_id = evm.data.ctx.cfg.chain_id; + let chain_id = evm.ctx.cfg.chain_id; - evm.data.ctx.modify_tx(|tx_env| { + evm.ctx.modify_tx(|tx_env| { tx_env.chain_id = Some(chain_id); }); } @@ -107,11 +107,11 @@ impl Cfg for CallFiller { &self, evm: &mut revm::context::Evm, Insp, Inst, Prec>, ) { - evm.data.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); + evm.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); - let chain_id = evm.data.ctx.cfg.chain_id; + let chain_id = evm.ctx.cfg.chain_id; - evm.data.ctx.modify_tx(|tx_env| { + evm.ctx.modify_tx(|tx_env| { tx_env.chain_id = Some(chain_id); }); } diff --git a/src/fill/traits.rs b/src/fill/traits.rs index 242e8f3..ddab8ca 100644 --- a/src/fill/traits.rs +++ b/src/fill/traits.rs @@ -23,7 +23,7 @@ pub trait Tx: Send + Sync { where Self: Sized, { - evm.data.ctx.modify_tx(|tx_env| self.fill_tx_env(tx_env)); + evm.ctx.modify_tx(|tx_env| self.fill_tx_env(tx_env)); } } @@ -71,7 +71,7 @@ pub trait Block: Send + Sync { where Self: Sized, { - evm.data.ctx.modify_block(|block_env| self.fill_block_env(block_env)); + evm.ctx.modify_block(|block_env| self.fill_block_env(block_env)); } /// Get the transaction count hint from the filler. This can be used for @@ -134,7 +134,7 @@ pub trait Cfg: Send + Sync { where Self: Sized, { - evm.data.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); + evm.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env)); } } diff --git a/src/inspectors/spanning.rs b/src/inspectors/spanning.rs index b39f06a..18fe1d8 100644 --- a/src/inspectors/spanning.rs +++ b/src/inspectors/spanning.rs @@ -1,8 +1,9 @@ -use alloy::hex; +use alloy::{consensus::constants::SELECTOR_LEN, hex}; use revm::{ + context::{ContextTr, LocalContextTr}, interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, Interpreter, - InterpreterTypes, + CallInput, CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, + Interpreter, InterpreterTypes, }, Inspector, }; @@ -112,14 +113,17 @@ impl SpanningInspector { } /// Create a span for a `CALL`-family opcode. - fn span_call(&self, _context: &Ctx, inputs: &CallInputs) -> Span { - let mut selector = inputs.input.clone(); - selector.truncate(4); + fn span_call(&self, context: &mut Ctx, inputs: &CallInputs) -> Span + where + Ctx: ContextTr, + { + let selector = resolve_selector(inputs, context).map(hex::encode); + runtime_level_span!( self.level, "call", input_len = inputs.input.len(), - selector = hex::encode(&selector), + selector, gas_limit = inputs.gas_limit, bytecode_address = %inputs.bytecode_address, target_addrses = %inputs.target_address, @@ -130,7 +134,10 @@ impl SpanningInspector { } /// Create, enter, and store a span for a `CALL`-family opcode. - fn enter_call(&mut self, context: &Ctx, inputs: &CallInputs) { + fn enter_call(&mut self, context: &mut Ctx, inputs: &CallInputs) + where + Ctx: ContextTr, + { self.active.push(self.span_call(context, inputs).entered()) } @@ -172,6 +179,7 @@ impl SpanningInspector { impl Inspector for SpanningInspector where Int: InterpreterTypes, + Ctx: ContextTr, { fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut Ctx) { self.init(interp, context); @@ -218,3 +226,17 @@ where self.exit_span(); } } + +/// Resolve a selector from the [CallInputs]. +fn resolve_selector(inputs: &CallInputs, ctx: &mut impl ContextTr) -> Option<[u8; SELECTOR_LEN]> { + match &inputs.input { + CallInput::SharedBuffer(range) => { + let raw = ctx.local().shared_memory_buffer_slice(range.clone()); + + raw?.get(..SELECTOR_LEN).map(TryInto::try_into).and_then(Result::ok) + } + CallInput::Bytes(bytes) => { + bytes.as_ref().get(..SELECTOR_LEN).map(TryInto::try_into).and_then(Result::ok) + } + } +} diff --git a/src/system/eip6110.rs b/src/system/eip6110.rs index 2c26917..d92a9a3 100644 --- a/src/system/eip6110.rs +++ b/src/system/eip6110.rs @@ -60,7 +60,7 @@ where logs.into_iter().filter(|log| log.address == MAINNET_DEPOSIT_CONTRACT_ADDRESS).map(|log| { // We assume that the log is valid because it was emitted by the // deposit contract. - let decoded_log = DepositEvent::decode_log(log, false).expect("invalid log"); + let decoded_log = DepositEvent::decode_log(log).expect("invalid log"); parse_deposit_from_log(&decoded_log) }) } @@ -74,7 +74,7 @@ pub fn accumulate_deposits_from_logs<'a>( |log| { // We assume that the log is valid because it was emitted by the // deposit contract. - let decoded_log = DepositEvent::decode_log(log, false).expect("invalid log"); + let decoded_log = DepositEvent::decode_log(log).expect("invalid log"); accumulate_deposit_from_log(&decoded_log, out); }, ); diff --git a/src/system/mod.rs b/src/system/mod.rs index 721cf33..e996655 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -108,7 +108,7 @@ fn cleanup_syscall( }); // Restore the nonce check - evm.data.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = previous_nonce_check); + evm.ctx.modify_cfg(|cfg| cfg.disable_nonce_check = previous_nonce_check); // Remove the system caller and fees from the state let state = &mut result.state; @@ -136,18 +136,18 @@ where let limit = evm.tx().gas_limit(); - let block = &mut evm.data.ctx.block; + let block = &mut evm.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 previous_nonce_check = std::mem::replace(&mut evm.ctx.cfg.disable_nonce_check, true); let mut result = evm.inspect_replay()?; // Cleanup the syscall. cleanup_syscall(evm, &mut result, syscall, old_gas_limit, old_base_fee, previous_nonce_check); - evm.data.ctx.db().commit(result.state); + evm.ctx.db().commit(result.state); // apply result, remove receipt from block outputs. Ok(result.result)