diff --git a/Cargo.lock b/Cargo.lock index 1ef97790c..59bcee4bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4851,6 +4851,24 @@ dependencies = [ "reth-interfaces", "reth-primitives", "reth-provider", + "reth-revm-primitives", + "revm", +] + +[[package]] +name = "reth-revm-inspectors" +version = "0.1.0" +dependencies = [ + "hashbrown 0.13.2", + "reth-primitives", + "revm", +] + +[[package]] +name = "reth-revm-primitives" +version = "0.1.0" +dependencies = [ + "reth-primitives", "revm", ] diff --git a/Cargo.toml b/Cargo.toml index d505dc105..32c3f42c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,8 @@ members = [ "crates/net/downloaders", "crates/primitives", "crates/revm", + "crates/revm/revm-primitives", + "crates/revm/revm-inspectors", "crates/rlp", "crates/rlp/rlp-derive", "crates/rpc/ipc", diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 1f740e83a..de419c346 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -11,5 +11,6 @@ description = "reth specific revm utilities" reth-primitives = { path = "../primitives" } reth-interfaces = { path = "../interfaces" } reth-provider = { path = "../storage/provider" } +reth-revm-primitives = { path = "./revm-primitives" } revm = { version = "3.0.0"} \ No newline at end of file diff --git a/crates/revm/revm-inspectors/Cargo.toml b/crates/revm/revm-inspectors/Cargo.toml new file mode 100644 index 000000000..5f21a007b --- /dev/null +++ b/crates/revm/revm-inspectors/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "reth-revm-inspectors" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/paradigmxyz/reth" +description = "revm inspector implementations used by reth" + +[dependencies] +# reth +reth-primitives = { path = "../../primitives" } + +revm = { version = "3.0.0" } +# remove from reth and reexport from revm +hashbrown = "0.13" \ No newline at end of file diff --git a/crates/revm/revm-inspectors/src/access_list.rs b/crates/revm/revm-inspectors/src/access_list.rs new file mode 100644 index 000000000..5aa7ef32e --- /dev/null +++ b/crates/revm/revm-inspectors/src/access_list.rs @@ -0,0 +1,108 @@ +use hashbrown::{HashMap, HashSet}; +use reth_primitives::{AccessList, AccessListItem, Address, H256}; +use revm::{ + interpreter::{opcode, InstructionResult, Interpreter}, + Database, EVMData, Inspector, +}; + +/// An [Inspector] that collects touched accounts and storage slots. +/// +/// This can be used to construct an [AccessList] for a transaction via `eth_createAccessList` +#[derive(Default, Debug)] +pub struct AccessListInspector { + /// All addresses that should be excluded from the final accesslist + excluded: HashSet
, + /// All addresses and touched slots + access_list: HashMap>, +} + +impl AccessListInspector { + /// Creates a new inspector instance + /// + /// The `access_list` is the provided access list from the call request + pub fn new( + access_list: AccessList, + from: Address, + to: Address, + precompiles: Vec
, + ) -> Self { + AccessListInspector { + excluded: vec![from, to].iter().chain(precompiles.iter()).copied().collect(), + access_list: access_list + .0 + .iter() + .map(|v| (v.address, v.storage_keys.iter().copied().collect())) + .collect(), + } + } + + /// Returns list of addresses and storage keys used by the transaction. It gives you the list of + /// addresses and storage keys that were touched during execution. + pub fn into_access_list(self) -> AccessList { + let items = self.access_list.into_iter().map(|(address, slots)| AccessListItem { + address, + storage_keys: slots.into_iter().collect(), + }); + AccessList(items.collect()) + } + + /// Returns list of addresses and storage keys used by the transaction. It gives you the list of + /// addresses and storage keys that were touched during execution. + pub fn access_list(&self) -> AccessList { + let items = self.access_list.iter().map(|(address, slots)| AccessListItem { + address: *address, + storage_keys: slots.iter().copied().collect(), + }); + AccessList(items.collect()) + } +} + +impl Inspector for AccessListInspector +where + DB: Database, +{ + fn step( + &mut self, + interpreter: &mut Interpreter, + _data: &mut EVMData<'_, DB>, + _is_static: bool, + ) -> InstructionResult { + let pc = interpreter.program_counter(); + let op = interpreter.contract.bytecode.bytecode()[pc]; + + match op { + opcode::SLOAD | opcode::SSTORE => { + if let Ok(slot) = interpreter.stack().peek(0) { + let cur_contract = interpreter.contract.address; + self.access_list + .entry(cur_contract) + .or_default() + .insert(H256::from(slot.to_be_bytes())); + } + } + opcode::EXTCODECOPY | + opcode::EXTCODEHASH | + opcode::EXTCODESIZE | + opcode::BALANCE | + opcode::SELFDESTRUCT => { + if let Ok(slot) = interpreter.stack().peek(0) { + let addr: Address = H256::from(slot.to_be_bytes()).into(); + if !self.excluded.contains(&addr) { + self.access_list.entry(addr).or_default(); + } + } + } + opcode::DELEGATECALL | opcode::CALL | opcode::STATICCALL | opcode::CALLCODE => { + if let Ok(slot) = interpreter.stack().peek(1) { + let addr: Address = H256::from(slot.to_be_bytes()).into(); + if !self.excluded.contains(&addr) { + self.access_list.entry(addr).or_default(); + } + } + } + _ => (), + } + + InstructionResult::Continue + } +} diff --git a/crates/revm/revm-inspectors/src/lib.rs b/crates/revm/revm-inspectors/src/lib.rs new file mode 100644 index 000000000..cec3a9d09 --- /dev/null +++ b/crates/revm/revm-inspectors/src/lib.rs @@ -0,0 +1,11 @@ +#![warn(missing_docs, unreachable_pub, unused_crate_dependencies)] +#![deny(unused_must_use, rust_2018_idioms)] +#![doc(test( + no_crate_inject, + attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) +))] + +//! revm [Inspector](revm::Inspector) implementations + +/// An inspector implementation for an EIP2930 Accesslist +pub mod access_list; diff --git a/crates/revm/revm-primitives/Cargo.toml b/crates/revm/revm-primitives/Cargo.toml new file mode 100644 index 000000000..57ccc160e --- /dev/null +++ b/crates/revm/revm-primitives/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "reth-revm-primitives" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/paradigmxyz/reth" +description = "core reth specific revm utilities" + +[dependencies] +# reth +reth-primitives = { path = "../../primitives" } + +revm = { version = "3.0.0" } \ No newline at end of file diff --git a/crates/revm/src/compat.rs b/crates/revm/revm-primitives/src/compat.rs similarity index 100% rename from crates/revm/src/compat.rs rename to crates/revm/revm-primitives/src/compat.rs diff --git a/crates/revm/src/config.rs b/crates/revm/revm-primitives/src/config.rs similarity index 100% rename from crates/revm/src/config.rs rename to crates/revm/revm-primitives/src/config.rs diff --git a/crates/revm/src/env.rs b/crates/revm/revm-primitives/src/env.rs similarity index 100% rename from crates/revm/src/env.rs rename to crates/revm/revm-primitives/src/env.rs diff --git a/crates/revm/revm-primitives/src/lib.rs b/crates/revm/revm-primitives/src/lib.rs new file mode 100644 index 000000000..a989c0b65 --- /dev/null +++ b/crates/revm/revm-primitives/src/lib.rs @@ -0,0 +1,17 @@ +#![warn(missing_docs, unreachable_pub, unused_crate_dependencies)] +#![deny(unused_must_use, rust_2018_idioms)] +#![doc(test( + no_crate_inject, + attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) +))] + +//! revm utils and implementations specific to reth. + +pub mod config; + +/// Helpers for configuring revm [Env](revm::primitives::Env) +pub mod env; + +/// Helpers for type compatibility between reth and revm types +mod compat; +pub use compat::*; diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 642c2890e..21cc3790a 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -7,14 +7,8 @@ //! revm utils and implementations specific to reth. -pub mod config; - /// Contains glue code for integrating reth database into revm's [Database](revm::Database). pub mod database; -/// Helpers for configuring revm [Env](revm::primitives::Env) -pub mod env; - -/// Helpers for type compatibility between reth and revm types -mod compat; -pub use compat::*; +/// reexport for convenience +pub use reth_revm_primitives::*;