From dc0e31ceddec825d5ca167184492666c33696548 Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Thu, 1 Sep 2022 15:58:45 -0400 Subject: [PATCH] fix: allow from in eth_call and eth_estimateGas (#4) * fix gas esimtation in uniswap frontend * calculate empty account --- client/src/client.rs | 16 +++++----------- client/src/rpc.rs | 40 +++++++--------------------------------- execution/src/evm.rs | 24 ++++++++++++------------ execution/src/proof.rs | 20 ++++++++++++++++++-- execution/src/types.rs | 24 ++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 58 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index b4aed2b..9218dcc 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -8,7 +8,7 @@ use config::Config; use consensus::types::{ExecutionPayload, Header}; use consensus::ConsensusClient; use execution::evm::Evm; -use execution::types::ExecutionBlock; +use execution::types::{CallOpts, ExecutionBlock}; use execution::ExecutionClient; pub struct Client { @@ -68,22 +68,16 @@ impl Client { Ok(()) } - pub fn call( - &self, - to: &Address, - calldata: &Vec, - value: U256, - block: &Option, - ) -> Result> { + pub fn call(&self, opts: &CallOpts, block: &Option) -> Result> { let payload = self.get_payload(block)?; let mut evm = Evm::new(self.execution.clone(), payload); - evm.call(to, calldata, value) + evm.call(opts) } - pub fn estimate_gas(&self, to: &Address, calldata: &Vec, value: U256) -> Result { + pub fn estimate_gas(&self, opts: &CallOpts) -> Result { let payload = self.get_payload(&None)?; let mut evm = Evm::new(self.execution.clone(), payload); - evm.estimate_gas(to, calldata, value) + evm.estimate_gas(opts) } pub async fn get_balance(&self, address: &Address, block: &Option) -> Result { diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 972c388..307f935 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -1,9 +1,5 @@ -use ethers::{ - abi::AbiEncode, - types::{Address, U256}, -}; +use ethers::{abi::AbiEncode, types::Address}; use eyre::Result; -use serde::{Deserialize, Serialize}; use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc}; use tokio::sync::Mutex; @@ -14,8 +10,8 @@ use jsonrpsee::{ }; use super::Client; -use common::utils::{hex_str_to_bytes, u64_to_hex_string}; -use execution::types::ExecutionBlock; +use common::utils::u64_to_hex_string; +use execution::types::{CallOpts, ExecutionBlock}; pub struct Rpc { client: Arc>, @@ -110,29 +106,16 @@ impl EthRpcServer for RpcInner { async fn call(&self, opts: CallOpts, block: &str) -> Result { let block = convert_err(decode_block(block))?; - let to = convert_err(Address::from_str(&opts.to))?; - let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?; - let value = convert_err(U256::from_str_radix( - &opts.value.unwrap_or("0x0".to_string()), - 16, - ))?; - let client = self.client.lock().await; - let res = convert_err(client.call(&to, &data, value, &block))?; + let res = convert_err(client.call(&opts, &block))?; - Ok(hex::encode(res)) + Ok(format!("0x{}", hex::encode(res))) } async fn estimate_gas(&self, opts: CallOpts) -> Result { - let to = convert_err(Address::from_str(&opts.to))?; - let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?; - let value = convert_err(U256::from_str_radix( - &opts.value.unwrap_or("0x0".to_string()), - 16, - ))?; - let client = self.client.lock().await; - let gas = convert_err(client.estimate_gas(&to, &data, value))?; + let gas = convert_err(client.estimate_gas(&opts))?; + Ok(u64_to_hex_string(gas)) } @@ -221,12 +204,3 @@ fn decode_block(block: &str) -> Result> { } } } - -#[derive(Deserialize, Serialize)] -pub struct CallOpts { - from: Option, - to: String, - gas: Option, - value: Option, - data: Option, -} diff --git a/execution/src/evm.rs b/execution/src/evm.rs index d416c1e..25c7629 100644 --- a/execution/src/evm.rs +++ b/execution/src/evm.rs @@ -8,6 +8,8 @@ use tokio::runtime::Runtime; use consensus::types::ExecutionPayload; +use crate::types::CallOpts; + use super::ExecutionClient; pub struct Evm { @@ -23,13 +25,12 @@ impl Evm { Evm { evm } } - pub fn call(&mut self, to: &Address, calldata: &Vec, value: U256) -> Result> { + pub fn call(&mut self, opts: &CallOpts) -> Result> { let mut env = Env::default(); - let mut tx = revm::TxEnv::default(); - tx.transact_to = TransactTo::Call(*to); - tx.data = Bytes::from(calldata.clone()); - tx.value = value; - env.tx = tx; + env.tx.transact_to = TransactTo::Call(opts.to); + env.tx.caller = opts.from.unwrap_or(Address::zero()); + env.tx.value = opts.value.unwrap_or(U256::from(0)); + env.tx.data = Bytes::from(opts.data.clone().unwrap_or(vec![])); self.evm.env = env; @@ -46,13 +47,12 @@ impl Evm { } } - pub fn estimate_gas(&mut self, to: &Address, calldata: &Vec, value: U256) -> Result { + pub fn estimate_gas(&mut self, opts: &CallOpts) -> Result { let mut env = Env::default(); - let mut tx = revm::TxEnv::default(); - tx.transact_to = TransactTo::Call(*to); - tx.data = Bytes::from(calldata.clone()); - tx.value = value; - env.tx = tx; + env.tx.transact_to = TransactTo::Call(opts.to); + env.tx.caller = opts.from.unwrap_or(Address::zero()); + env.tx.value = opts.value.unwrap_or(U256::from(0)); + env.tx.data = Bytes::from(opts.data.clone().unwrap_or(vec![])); self.evm.env = env; diff --git a/execution/src/proof.rs b/execution/src/proof.rs index fb6b935..7b8ba91 100644 --- a/execution/src/proof.rs +++ b/execution/src/proof.rs @@ -20,7 +20,7 @@ pub fn verify_proof(proof: &Vec>, root: &Vec, path: &Vec, value: let nibble = get_nibble(&path, path_offset); let node = &node_list[nibble as usize]; - if node.len() == 0 && value[0] == 0x80 { + if node.len() == 0 && is_empty_value(value) { return true; } } else { @@ -34,7 +34,7 @@ pub fn verify_proof(proof: &Vec>, root: &Vec, path: &Vec, value: if i == proof.len() - 1 { // exclusion proof if &node_list[0][skip_length(&node_list[0])..] != &path[path_offset..] - && value[0] == 0x80 + && is_empty_value(value) { return true; } @@ -57,6 +57,22 @@ pub fn verify_proof(proof: &Vec>, root: &Vec, path: &Vec, value: false } +fn is_empty_value(value: &Vec) -> bool { + let mut stream = RlpStream::new(); + stream.begin_list(4); + stream.append_empty_data(); + stream.append_empty_data(); + let empty_storage_hash = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; + stream.append(&hex::decode(empty_storage_hash).unwrap()); + let empty_code_hash = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; + stream.append(&hex::decode(empty_code_hash).unwrap()); + let empty_account = stream.out(); + + let is_empty_slot = value.len() == 1 && value[0] == 0x80; + let is_empty_account = value == &empty_account; + is_empty_slot || is_empty_account +} + fn shared_prefix_length(path: &Vec, path_offset: usize, node_path: &Vec) -> usize { let skip_length = skip_length(node_path); let mut node_decoded = vec![]; diff --git a/execution/src/types.rs b/execution/src/types.rs index 253cf8c..6dc313b 100644 --- a/execution/src/types.rs +++ b/execution/src/types.rs @@ -72,6 +72,30 @@ pub struct ExecutionBlock { pub uncles: Vec, } +#[derive(Deserialize, Serialize, Debug)] +pub struct CallOpts { + pub from: Option
, + pub to: Address, + pub gas: Option, + pub value: Option, + #[serde(default, deserialize_with = "bytes_deserialize")] + pub data: Option>, +} + +fn bytes_deserialize<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: serde::Deserializer<'de>, +{ + let bytes: Option = serde::Deserialize::deserialize(deserializer)?; + match bytes { + Some(bytes) => { + let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap(); + Ok(Some(bytes.to_vec())) + } + None => Ok(None), + } +} + fn serialize_bytes(bytes: &Vec, s: S) -> Result where S: serde::Serializer,