diff --git a/src/call_forwarder.rs b/src/call_forwarder.rs index c6f7118de..86be70d9e 100644 --- a/src/call_forwarder.rs +++ b/src/call_forwarder.rs @@ -1,6 +1,10 @@ use alloy_eips::BlockId; use alloy_primitives::{Bytes, U256}; -use alloy_rpc_types_eth::{state::StateOverride, transaction::TransactionRequest, BlockOverrides}; +use alloy_rpc_types_eth::{ + state::{EvmOverrides, StateOverride}, + transaction::TransactionRequest, + BlockOverrides, +}; use jsonrpsee::{ http_client::{HttpClient, HttpClientBuilder}, proc_macros::rpc, @@ -8,6 +12,7 @@ use jsonrpsee::{ types::{error::INTERNAL_ERROR_CODE, ErrorObject}, }; use jsonrpsee_core::{async_trait, client::ClientT, ClientError, RpcResult}; +use reth_rpc_eth_api::helpers::EthCall; #[rpc(server, namespace = "eth")] pub(crate) trait CallForwarderApi { @@ -32,21 +37,25 @@ pub(crate) trait CallForwarderApi { ) -> RpcResult; } -pub struct CallForwarderExt { - client: HttpClient, +pub struct CallForwarderExt { + upstream_client: HttpClient, + eth_api: EthApi, } -impl CallForwarderExt { - pub fn new(upstream_rpc_url: String) -> Self { - let client = +impl CallForwarderExt { + pub fn new(upstream_rpc_url: String, eth_api: EthApi) -> Self { + let upstream_client = HttpClientBuilder::default().build(upstream_rpc_url).expect("Failed to build client"); - Self { client } + Self { upstream_client, eth_api } } } #[async_trait] -impl CallForwarderApiServer for CallForwarderExt { +impl CallForwarderApiServer for CallForwarderExt +where + EthApi: EthCall + Send + Sync + 'static, +{ async fn call( &self, request: TransactionRequest, @@ -54,22 +63,35 @@ impl CallForwarderApiServer for CallForwarderExt { state_overrides: Option, block_overrides: Option>, ) -> RpcResult { - let result = self - .client - .clone() - .request( - "eth_call", - rpc_params![request, block_number, state_overrides, block_overrides], + let is_latest = block_number.as_ref().map(|b| b.is_latest()).unwrap_or(true); + let result = if is_latest { + self.upstream_client + .request( + "eth_call", + rpc_params![request, block_number, state_overrides, block_overrides], + ) + .await + .map_err(|e| match e { + ClientError::Call(e) => e, + _ => ErrorObject::owned( + INTERNAL_ERROR_CODE, + format!("Failed to call: {e:?}"), + Some(()), + ), + })? + } else { + EthCall::call( + &self.eth_api, + request, + block_number, + EvmOverrides::new(state_overrides, block_overrides), ) .await - .map_err(|e| match e { - ClientError::Call(e) => e, - _ => ErrorObject::owned( - INTERNAL_ERROR_CODE, - format!("Failed to call: {e:?}"), - Some(()), - ), - })?; + .map_err(|e| { + ErrorObject::owned(INTERNAL_ERROR_CODE, format!("Failed to call: {e:?}"), Some(())) + })? + }; + Ok(result) } @@ -79,19 +101,36 @@ impl CallForwarderApiServer for CallForwarderExt { block_number: Option, state_override: Option, ) -> RpcResult { - let result = self - .client - .clone() - .request("eth_estimateGas", rpc_params![request, block_number, state_override]) + let is_latest = block_number.as_ref().map(|b| b.is_latest()).unwrap_or(true); + let result = if is_latest { + self.upstream_client + .request("eth_estimateGas", rpc_params![request, block_number, state_override]) + .await + .map_err(|e| match e { + ClientError::Call(e) => e, + _ => ErrorObject::owned( + INTERNAL_ERROR_CODE, + format!("Failed to estimate gas: {e:?}"), + Some(()), + ), + })? + } else { + EthCall::estimate_gas_at( + &self.eth_api, + request, + block_number.unwrap_or_default(), + state_override, + ) .await - .map_err(|e| match e { - ClientError::Call(e) => e, - _ => ErrorObject::owned( + .map_err(|e| { + ErrorObject::owned( INTERNAL_ERROR_CODE, format!("Failed to estimate gas: {e:?}"), Some(()), - ), - })?; + ) + })? + }; + Ok(result) } } diff --git a/src/main.rs b/src/main.rs index 8dbfd516e..73caebf0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,11 @@ fn main() -> eyre::Result<()> { if ext.forward_call { ctx.modules.replace_configured( - call_forwarder::CallForwarderExt::new(upstream_rpc_url.clone()).into_rpc(), + call_forwarder::CallForwarderExt::new( + upstream_rpc_url.clone(), + ctx.registry.eth_api().clone(), + ) + .into_rpc(), )?; info!("Call/gas estimation will be forwarded to {}", upstream_rpc_url); }