diff --git a/Cargo.lock b/Cargo.lock index 5a98d1e54f..bd0320c6df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addchain" @@ -1453,6 +1453,41 @@ dependencies = [ "tokio", ] +[[package]] +name = "ext-trait" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5" +dependencies = [ + "ext-trait-proc_macros", +] + +[[package]] +name = "ext-trait-proc_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "extension-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537" +dependencies = [ + "ext-trait", +] + +[[package]] +name = "extern-c" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320bea982e85d42441eb25c49b41218e7eaa2657e8f90bc4eca7437376751e23" + [[package]] name = "eyre" version = "0.6.12" @@ -2145,6 +2180,22 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "macro_rules_attribute" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" + [[package]] name = "memchr" version = "2.7.4" @@ -2635,6 +2686,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -2901,9 +2962,12 @@ dependencies = [ name = "revm" version = "14.0.1" dependencies = [ + "alloy-eips", "alloy-provider", "alloy-sol-types", + "alloy-transport-http", "anyhow", + "bytes", "criterion", "derive-where", "dyn-clone", @@ -2921,6 +2985,7 @@ dependencies = [ "revm-transaction", "revm-wiring", "rstest", + "safer-ffi", "serde", ] @@ -3374,6 +3439,37 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "safer-ffi" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435fdd58b61a6f1d8545274c1dfa458e905ff68c166e65e294a0130ef5e675bd" +dependencies = [ + "extern-c", + "libc", + "macro_rules_attribute", + "paste", + "safer_ffi-proc_macros", + "scopeguard", + "stabby", + "uninit", + "unwind_safe", + "with_builtin_macros", +] + +[[package]] +name = "safer_ffi-proc_macros" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f25be5ba5f319542edb31925517e0380245ae37df50a9752cdbc05ef948156" +dependencies = [ + "macro_rules_attribute", + "prettyplease", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3558,6 +3654,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" @@ -3674,6 +3776,40 @@ dependencies = [ "der", ] +[[package]] +name = "stabby" +version = "36.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311d6bcf0070c462ff626122ec2246f42bd2acd44b28908eedbfd07d500c7d99" +dependencies = [ + "rustversion", + "stabby-abi", +] + +[[package]] +name = "stabby-abi" +version = "36.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6daae1a0707399f56d27fce7f212e50e31d215112a447e1bbcd837ae1bf5f49" +dependencies = [ + "rustversion", + "sha2-const-stable", + "stabby-macros", +] + +[[package]] +name = "stabby-macros" +version = "36.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cf89a0cc9131279235baf8599b0e073fbcb096419204de0cc5d1a48ae73f74" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "rand", + "syn 1.0.109", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4119,12 +4255,27 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "uninit" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e130f2ed46ca5d8ec13c7ff95836827f92f5f5f37fd2b2bf16f33c408d98bb6" +dependencies = [ + "extension-traits", +] + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unwind_safe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0976c77def3f1f75c4ef892a292c31c0bbe9e3d0702c63044d7c76db298171a3" + [[package]] name = "url" version = "2.5.2" @@ -4400,6 +4551,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "with_builtin_macros" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a59d55032495429b87f9d69954c6c8602e4d3f3e0a747a12dea6b0b23de685da" +dependencies = [ + "with_builtin_macros-proc_macros", +] + +[[package]] +name = "with_builtin_macros-proc_macros" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bd7679c15e22924f53aee34d4e448c45b674feb6129689af88593e129f8f42" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 7c832a4e32..e83b73456b 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -21,28 +21,44 @@ rust_2018_idioms = "deny" [lints.rustdoc] all = "warn" +[lib] +crate-type = [ + "staticlib", # Ensure it gets compiled as a (static) C library + "cdylib", # If you want a shared/dynamic C library (advanced) + "lib", # For `generate-headers` and other downstream rust dependents + # such as integration `tests/`, doctests, and `examples/` +] + + [dependencies] # revm interpreter.workspace = true precompile.workspace = true wiring.workspace = true primitives.workspace = true -database-interface.workspace = true state.workspace = true specification.workspace = true bytecode.workspace = true -database = { workspace = true, optional = true } +database-interface = {workspace = true, features = ["asyncdb"]} transaction.workspace = true +database.workspace = true +alloy-provider = "0.4.2" +alloy-eips = { version = "0.4.2" } +alloy-transport-http = "0.4.2" +reqwest = { version = "0.12" } +safer-ffi = "0.1.10-rc4" # misc derive-where = { version = "1.2.7", default-features = false } dyn-clone = "1.0" + # Optional serde = { version = "1.0", default-features = false, features = [ "derive", "rc", ], optional = true } +bytes = "1.7.1" [dev-dependencies] database.workspace = true @@ -53,11 +69,11 @@ ethers-contract = { version = "2.0.14", default-features = false } anyhow = "1.0.89" criterion = "0.5" indicatif = "0.17" -reqwest = { version = "0.12" } rstest = "0.22.0" alloy-provider = "0.4.2" + [features] default = ["std", "c-kzg", "secp256k1", "portable", "blst"] std = ["serde?/std", "interpreter/std", "precompile/std"] @@ -72,7 +88,7 @@ arbitrary = ["primitives/arbitrary"] asm-keccak = ["primitives/asm-keccak"] portable = ["wiring/portable"] -test-utils = ["database"] +test-utils = [] dev = [ "memory_limit", diff --git a/crates/revm/src/ffi.rs b/crates/revm/src/ffi.rs new file mode 100644 index 0000000000..dfebe577aa --- /dev/null +++ b/crates/revm/src/ffi.rs @@ -0,0 +1,163 @@ +use safer_ffi::prelude::*; +use core::ffi::c_char; +use core::ffi::c_void; +use core::ptr; +use std::boxed::Box; + + +use alloy_transport_http::Http; + +use alloy_provider::{Provider, ProviderBuilder, ReqwestProvider}; +use database::{AlloyDB, CacheDB, State, StateBuilder}; +use crate::database_interface::async_db::WrapDatabaseAsync; +use alloy_eips::{BlockId}; +use alloy_provider::network::Ethereum; +use alloy_sol_types::private::Address; +use reqwest::Client; +use primitives::Bytes; +use database::InMemoryDB; +use primitives::alloy_primitives::BlockNumber; +use primitives::{TxKind, U256}; +use crate::evm::Evm; +use wiring::default::TxEnv; +use crate::EvmWiring; +use wiring::result::{EVMError, EVMResult, EVMResultGeneric, ExecutionResult, ResultAndState}; +use wiring::{EthereumWiring}; +use crate::specification::hardfork::SpecId; + +// FFI-friendly enum for #[derive(Debug)] +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum Hardfork { + Istanbul, + Berlin, + London, +} + +// Define a struct for call parameters if necessary +#[derive_ReprC] +#[repr(C)] +pub struct CallParams { + pub from: [u8; 20], //Address in bytes + pub to: [u8; 20], // Address in bytes + pub data: *const u8, // Pointer to data + pub data_len: usize, // Length of data + pub gas: u64, // Gas limit + pub value: u64, +} + +// Define a struct to hold the result +#[repr(C)] +pub struct REVMResult { + pub status_code: i32, + pub output: *const c_char, +} + +// // Function to create an Evm instance based on hardfork and in-memory database +// #[ffi_export] +fn create_evm(hard_fork: u8, rpc_url: char_p::Ref<'_>) + -> *mut c_void { + // Set up an in-memory database + let db = InMemoryDB::default(); + let rpc_url = rpc_url.to_str(); + + // Map the FFI-friendly Hardfork to SpecId + let spec_id = SpecId::try_from_u8(hard_fork).unwrap_or_else(|| { SpecId::CANCUN }); + + // Create the EvmHandler with the specified hardfork + let handler = EthereumWiring::handler(spec_id); + // Convert the C string to a Rust string + + + let client = ProviderBuilder::new().on_http(rpc_url.parse().unwrap()); + + let block_number = match client.get_block_number().as_ready() { + None => { BlockNumber::from(0u64) } + Some(res) => { + let i = res.as_ref().unwrap(); + *i + } + }; + let state_db = WrapDatabaseAsync::new(AlloyDB::new(client, BlockId::from(block_number))).unwrap(); + let cache_db: CacheDB<_> = CacheDB::new(state_db); + let mut state = StateBuilder::new_with_database(cache_db).build(); + + // let mainnet = EvmHandler::<'_, EthereumWiring>::mainnet_with_spec(SpecId::CANCUN); + + + let mut evm: Evm<'_, EthereumWiring<&mut State, Ethereum, ReqwestProvider>>>>, ()>> = Evm::builder(). + with_handler(handler). + with_db(&mut state).build(); + // Set up the EVM context + + + // Return a raw pointer to the Evm instance + Box::into_raw(Box::new(evm)) as *mut c_void +} + +#[derive_ReprC] +#[repr(C)] +pub struct CallResult { + pub success: bool, + pub gas_used: u64, + pub output_data: *const u8, + pub output_len: usize, +} + +impl From, Ethereum, ReqwestProvider>>>>, ()>>> for CallResult { + fn from(result: EVMResult, Ethereum, ReqwestProvider>>>>, ()>>) -> Self { + match result { + Ok(execution_result) => { + let output = execution_result.result.output().unwrap().to_vec(); + let output_len = output.len(); + let output_data = output.into_boxed_slice().as_ptr(); + + Self { + success: true, + gas_used: execution_result.result.gas_used(), + output_data, + output_len, + } + } + Err(err) => { + Self { + success: false, + gas_used: 0, + output_data: ptr::null(), + output_len: 0, + } + } + } + } +} +#[ffi_export] +fn evm_call(evm_ptr: *mut c_void, params: CallParams) -> repr_c::Box { + // Safety: Convert raw pointer to a mutable reference to Evm + let mut evm = unsafe { *(evm_ptr as *mut Evm, Ethereum, ReqwestProvider>>>>, ()>>) }; + let res = evm.transact().unwrap(); + // Parse the address and data from params + let to = if let Some(to_slice) = params.to.as_ref() { + TxKind::Call(Address::from_slice(to_slice)) + } else { + TxKind::Create + }; + let caller = Address::from_slice(¶ms.from); + let data = unsafe { std::slice::from_raw_parts(params.data, params.data_len) }; + let calldata = Bytes::from(data.to_vec()); + // Set up TxEnv for the transaction + let tx_env = TxEnv { + caller, // Set the caller if available + gas_limit: params.gas.into(), + value: U256::from(params.value), + transact_to: to, + data: Bytes::from(calldata), + ..Default::default() + }; + evm = evm.modify().with_tx_env(tx_env).build(); + let result = evm.transact().unwrap(); + // Return the result in an FFI-compatible structure + repr_c::Box::new(CallResult::from(result)) +} + + + diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index c1663e252d..f1a6746b7c 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -5,6 +5,8 @@ #[macro_use] #[cfg(not(feature = "std"))] extern crate alloc as std; +extern crate core; +extern crate core; // reexport dependencies pub use bytecode; @@ -23,12 +25,14 @@ mod context; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; -mod evm; +pub mod evm; mod evm_wiring; mod frame; pub mod handler; mod journaled_state; +pub mod ffi; +mod new_fii; // Export items. pub use builder::EvmBuilder; diff --git a/crates/revm/src/new_fii.rs b/crates/revm/src/new_fii.rs new file mode 100644 index 0000000000..0c80279ce7 --- /dev/null +++ b/crates/revm/src/new_fii.rs @@ -0,0 +1,71 @@ +// use std::sync::Arc; +// use ethers_providers::{Http, Provider, Middleware}; +// use ethers_core::types::{BlockId, BlockNumberOrTag, U256}; +// use evm::{ +// Evm, Context, State, StateBuilder, CacheDB, +// database_interface::WrapDatabaseAsync, +// precompiles::EthereumWiring, +// }; +// +// // FFI-friendly enum for specifying the hardfork +// #[repr(C)] +// #[derive(Debug, Clone, Copy)] +// pub enum Hardfork { +// Istanbul, +// Berlin, +// London, +// } +// +// #[ffi_export] +// fn create_evm( +// hardfork: Hardfork, +// rpc_url: char_p::Ref<'_>, +// block_number: u64, +// ) -> repr_c::Box>, ()>>>> { +// // Convert the FFI-compatible char_p::Ref to a Rust &str +// let rpc_url = rpc_url.to_str(); +// +// // Set up the HTTP transport for the RPC client +// let provider = Provider::::try_from(rpc_url).expect("Failed to create provider"); +// let client = Arc::new(provider); +// +// // Fetch the block synchronously +// let block = match client +// .get_block_by_number(BlockNumberOrTag::Number(block_number)) +// .expect("Failed to send request") +// { +// Some(block) => block, +// None => { +// eprintln!("Block not found"); +// return repr_c::Box::null(); +// } +// }; +// +// let previous_block_number = block_number - 1; +// let prev_id: BlockId = previous_block_number.into(); +// +// // Create the state database with caching +// let state_db = WrapDatabaseAsync::new(AlloyDB::new(client.clone(), prev_id)) +// .expect("Failed to create state database"); +// let cache_db: CacheDB<_> = CacheDB::new(state_db); +// let mut state = StateBuilder::new_with_database(cache_db).build(); +// +// // Create the EVM instance +// let mut evm = Evm::>::builder() +// .with_db(&mut state) +// .modify_block_env(|b| { +// b.number = U256::from(block.header.number); +// b.coinbase = block.header.miner; +// b.timestamp = U256::from(block.header.timestamp); +// b.difficulty = block.header.difficulty; +// b.gas_limit = U256::from(block.header.gas_limit); +// b.basefee = block.header.base_fee_per_gas.map(U256::from).unwrap_or_default(); +// }) +// .modify_cfg_env(|c| { +// c.chain_id = 1; // Set the chain ID to 1 (Ethereum Mainnet) +// }) +// .build(); +// +// // Return the EVM instance wrapped in repr_c::Box +// repr_c::Box::new(evm) +// } \ No newline at end of file diff --git a/crates/statetest-types/src/lib.rs b/crates/statetest-types/src/lib.rs index 578df9555c..fcf9764871 100644 --- a/crates/statetest-types/src/lib.rs +++ b/crates/statetest-types/src/lib.rs @@ -8,7 +8,7 @@ mod account_info; mod deserializer; -mod env; +pub mod env; mod spec; mod test; mod test_authorization;