From 3c77dd9e2faa76fa192462b59042dee9a84a6c45 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 22 Feb 2023 23:59:19 +0100 Subject: [PATCH] feat(rpc): initial work in eth_call+estimate (#1514) --- Cargo.lock | 2 + crates/rpc/rpc/Cargo.toml | 4 ++ crates/rpc/rpc/src/eth/api/call.rs | 64 ++++++++++++++++++++++++++++++ crates/rpc/rpc/src/eth/api/mod.rs | 11 +++++ 4 files changed, 81 insertions(+) create mode 100644 crates/rpc/rpc/src/eth/api/call.rs diff --git a/Cargo.lock b/Cargo.lock index 3b72b16fbd..e0a6b59d4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4903,6 +4903,7 @@ dependencies = [ "jsonwebtoken", "pin-project", "rand 0.8.5", + "reth-executor", "reth-interfaces", "reth-network-api", "reth-primitives", @@ -4913,6 +4914,7 @@ dependencies = [ "reth-rpc-types", "reth-tasks", "reth-transaction-pool", + "revm", "secp256k1 0.26.0", "serde", "serde_json", diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 4719d79aeb..35897baacf 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -19,8 +19,12 @@ reth-provider = { path = "../../storage/provider", features = ["test-utils"] } reth-transaction-pool = { path = "../../transaction-pool", features = ["test-utils"]} reth-network-api = { path = "../../net/network-api", features = ["test-utils"] } reth-rpc-engine-api = { path = "../rpc-engine-api" } +reth-executor = { path = "../../executor" } reth-tasks = { path = "../../tasks" } +# eth +revm = "3.0.0" + # rpc jsonrpsee = { version = "0.16" } http = "0.2.8" diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs new file mode 100644 index 0000000000..fad0984e45 --- /dev/null +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -0,0 +1,64 @@ +//! Contains RPC handler implementations specific to endpoints that call/execute within evm. + +#![allow(unused)] // TODO rm later + +use crate::{eth::error::EthResult, EthApi}; +use reth_executor::revm_wrap::{State, SubState}; +use reth_primitives::{BlockId, U256}; +use reth_provider::{BlockProvider, StateProvider, StateProviderFactory}; +use reth_rpc_types::CallRequest; +use revm::primitives::{BlockEnv, Env, ResultAndState}; + +impl EthApi +where + Client: BlockProvider + StateProviderFactory + 'static, +{ + /// Creates the [Env] used by the [EVM](revm::EVM) when executing a call. + fn build_call_env(&self, request: CallRequest, block_env: BlockEnv) -> Env { + todo!() + } + + /// Executes the call request against the given `state` without committing any changes to the + /// database + pub(crate) fn call_with( + &self, + request: CallRequest, + state: S, + block_env: BlockEnv, + // TODO add overrides + ) -> EthResult + where + S: StateProvider, + { + // the revm database impl + let mut db = SubState::new(State::new(state)); + let mut evm = revm::EVM::new(); + evm.env = self.build_call_env(request, block_env); + evm.database(db); + // TODO error conversion from EMVError to EthApiErr + let res = evm.transact_ref().unwrap(); + Ok(res) + } + + /// Estimate gas needed for execution of the `request` at the [BlockId] . + pub(crate) fn estimate_gas_at(&self, mut request: CallRequest, at: BlockId) -> EthResult { + // TODO get a StateProvider for the given blockId and BlockEnv + todo!() + } + + /// Estimates the gas usage of the `request` with the state. + fn estimate_gas_with( + &self, + mut request: CallRequest, + state: S, + block_env: BlockEnv, + ) -> EthResult + where + S: StateProvider, + { + // TODO: check if transfer + // binary search over range to find best gas + + todo!() + } +} diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 176d40ce3e..4d635cf682 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -13,11 +13,14 @@ use reth_primitives::{ use reth_provider::{BlockProvider, StateProviderFactory}; use std::num::NonZeroUsize; +use crate::eth::error::EthResult; +use reth_provider::providers::ChainState; use reth_rpc_types::FeeHistoryCache; use reth_transaction_pool::TransactionPool; use std::sync::Arc; mod block; +mod call; mod server; mod state; mod transactions; @@ -100,6 +103,14 @@ where self.client().convert_block_number(num) } + /// Helper function to execute a closure with the database at a specific block. + pub(crate) fn with_state_at(&self, _at: BlockId, _f: F) -> EthResult + where + F: FnOnce(ChainState<'_>) -> T, + { + unimplemented!() + } + /// Returns the state at the given [BlockId] enum or the latest. pub(crate) fn state_at_block_id_or_latest( &self,