fix: allow from in eth_call and eth_estimateGas (#4)

* fix gas esimtation in uniswap frontend

* calculate empty account
This commit is contained in:
Noah Citron 2022-09-01 15:58:45 -04:00 committed by GitHub
parent b1d33bb9af
commit dc0e31cedd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 58 deletions

View File

@ -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<u8>,
value: U256,
block: &Option<u64>,
) -> Result<Vec<u8>> {
pub fn call(&self, opts: &CallOpts, block: &Option<u64>) -> Result<Vec<u8>> {
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<u8>, value: U256) -> Result<u64> {
pub fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
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<u64>) -> Result<U256> {

View File

@ -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<Mutex<Client>>,
@ -110,29 +106,16 @@ impl EthRpcServer for RpcInner {
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
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<String, Error> {
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<Option<u64>> {
}
}
}
#[derive(Deserialize, Serialize)]
pub struct CallOpts {
from: Option<String>,
to: String,
gas: Option<String>,
value: Option<String>,
data: Option<String>,
}

View File

@ -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<u8>, value: U256) -> Result<Vec<u8>> {
pub fn call(&mut self, opts: &CallOpts) -> Result<Vec<u8>> {
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<u8>, value: U256) -> Result<u64> {
pub fn estimate_gas(&mut self, opts: &CallOpts) -> Result<u64> {
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;

View File

@ -20,7 +20,7 @@ pub fn verify_proof(proof: &Vec<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, 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<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, 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<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, value:
false
}
fn is_empty_value(value: &Vec<u8>) -> 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<u8>, path_offset: usize, node_path: &Vec<u8>) -> usize {
let skip_length = skip_length(node_path);
let mut node_decoded = vec![];

View File

@ -72,6 +72,30 @@ pub struct ExecutionBlock {
pub uncles: Vec<H256>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct CallOpts {
pub from: Option<Address>,
pub to: Address,
pub gas: Option<U256>,
pub value: Option<U256>,
#[serde(default, deserialize_with = "bytes_deserialize")]
pub data: Option<Vec<u8>>,
}
fn bytes_deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
where
D: serde::Deserializer<'de>,
{
let bytes: Option<String> = 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<S>(bytes: &Vec<u8>, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,