2022-08-26 22:13:35 +00:00
|
|
|
use std::{str::FromStr, thread};
|
2022-08-24 01:33:48 +00:00
|
|
|
|
|
|
|
use bytes::Bytes;
|
2022-08-26 01:18:47 +00:00
|
|
|
use ethers::prelude::{Address, H160, H256, U256};
|
2022-08-24 01:33:48 +00:00
|
|
|
use eyre::Result;
|
2022-08-26 01:18:47 +00:00
|
|
|
use revm::{AccountInfo, Bytecode, Database, Env, TransactOut, TransactTo, EVM};
|
|
|
|
use tokio::runtime::Runtime;
|
2022-08-24 01:33:48 +00:00
|
|
|
|
2022-08-29 17:31:17 +00:00
|
|
|
use consensus::types::ExecutionPayload;
|
|
|
|
|
2022-09-01 19:58:45 +00:00
|
|
|
use crate::types::CallOpts;
|
|
|
|
|
2022-08-24 01:33:48 +00:00
|
|
|
use super::ExecutionClient;
|
|
|
|
|
|
|
|
pub struct Evm {
|
2022-08-26 01:18:47 +00:00
|
|
|
evm: EVM<ProofDB>,
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Evm {
|
2022-08-26 22:13:35 +00:00
|
|
|
pub fn new(execution: ExecutionClient, payload: ExecutionPayload) -> Self {
|
2022-08-24 01:33:48 +00:00
|
|
|
let mut evm: EVM<ProofDB> = EVM::new();
|
|
|
|
let db = ProofDB::new(execution, payload);
|
|
|
|
evm.database(db);
|
|
|
|
|
|
|
|
Evm { evm }
|
|
|
|
}
|
|
|
|
|
2022-09-01 19:58:45 +00:00
|
|
|
pub fn call(&mut self, opts: &CallOpts) -> Result<Vec<u8>> {
|
2022-08-24 01:33:48 +00:00
|
|
|
let mut env = Env::default();
|
2022-09-01 19:58:45 +00:00
|
|
|
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![]));
|
2022-08-24 01:33:48 +00:00
|
|
|
|
|
|
|
self.evm.env = env;
|
|
|
|
|
|
|
|
let output = self.evm.transact().1;
|
|
|
|
|
|
|
|
if let Some(err) = &self.evm.db.as_ref().unwrap().error {
|
|
|
|
return Err(eyre::eyre!(err.clone()));
|
|
|
|
}
|
|
|
|
|
|
|
|
match output {
|
|
|
|
TransactOut::None => Err(eyre::eyre!("Invalid Call")),
|
|
|
|
TransactOut::Create(..) => Err(eyre::eyre!("Invalid Call")),
|
|
|
|
TransactOut::Call(bytes) => Ok(bytes.to_vec()),
|
|
|
|
}
|
|
|
|
}
|
2022-08-27 20:43:27 +00:00
|
|
|
|
2022-09-01 19:58:45 +00:00
|
|
|
pub fn estimate_gas(&mut self, opts: &CallOpts) -> Result<u64> {
|
2022-08-27 20:43:27 +00:00
|
|
|
let mut env = Env::default();
|
2022-09-01 19:58:45 +00:00
|
|
|
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![]));
|
2022-08-27 20:43:27 +00:00
|
|
|
|
|
|
|
self.evm.env = env;
|
|
|
|
|
|
|
|
let gas = self.evm.transact().2;
|
|
|
|
|
|
|
|
if let Some(err) = &self.evm.db.as_ref().unwrap().error {
|
|
|
|
return Err(eyre::eyre!(err.clone()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(gas)
|
|
|
|
}
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ProofDB {
|
2022-08-26 22:13:35 +00:00
|
|
|
execution: ExecutionClient,
|
2022-08-24 01:33:48 +00:00
|
|
|
payload: ExecutionPayload,
|
|
|
|
error: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProofDB {
|
2022-08-26 22:13:35 +00:00
|
|
|
pub fn new(execution: ExecutionClient, payload: ExecutionPayload) -> Self {
|
2022-08-24 01:33:48 +00:00
|
|
|
ProofDB {
|
|
|
|
execution,
|
|
|
|
payload,
|
|
|
|
error: None,
|
|
|
|
}
|
|
|
|
}
|
2022-08-24 16:28:43 +00:00
|
|
|
|
|
|
|
pub fn safe_unwrap<T: Default>(&mut self, res: Result<T>) -> T {
|
|
|
|
match res {
|
|
|
|
Ok(value) => value,
|
|
|
|
Err(err) => {
|
|
|
|
self.error = Some(err.to_string());
|
|
|
|
T::default()
|
2022-08-26 01:18:47 +00:00
|
|
|
}
|
2022-08-24 16:28:43 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Database for ProofDB {
|
|
|
|
fn basic(&mut self, address: H160) -> AccountInfo {
|
|
|
|
if is_precompile(&address) {
|
2022-08-26 01:18:47 +00:00
|
|
|
return AccountInfo::default();
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 01:18:47 +00:00
|
|
|
let execution = self.execution.clone();
|
|
|
|
let addr = address.clone();
|
|
|
|
let payload = self.payload.clone();
|
|
|
|
|
|
|
|
let handle = thread::spawn(move || {
|
|
|
|
let account_fut = execution.get_account(&addr, None, &payload);
|
|
|
|
let runtime = Runtime::new()?;
|
|
|
|
runtime.block_on(account_fut)
|
|
|
|
});
|
|
|
|
|
|
|
|
let account = self.safe_unwrap(handle.join().unwrap());
|
2022-08-24 01:33:48 +00:00
|
|
|
|
2022-08-26 01:18:47 +00:00
|
|
|
let execution = self.execution.clone();
|
|
|
|
let addr = address.clone();
|
|
|
|
let payload = self.payload.clone();
|
|
|
|
|
|
|
|
let handle = thread::spawn(move || {
|
|
|
|
let code_fut = execution.get_code(&addr, &payload);
|
|
|
|
let runtime = Runtime::new()?;
|
|
|
|
runtime.block_on(code_fut)
|
|
|
|
});
|
|
|
|
|
|
|
|
let bytecode = self.safe_unwrap(handle.join().unwrap());
|
2022-08-24 01:33:48 +00:00
|
|
|
let bytecode = Bytecode::new_raw(Bytes::from(bytecode));
|
|
|
|
|
|
|
|
AccountInfo::new(account.balance, account.nonce.as_u64(), bytecode)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn block_hash(&mut self, _number: U256) -> H256 {
|
|
|
|
H256::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn storage(&mut self, address: H160, slot: U256) -> U256 {
|
2022-08-26 01:18:47 +00:00
|
|
|
let execution = self.execution.clone();
|
|
|
|
let addr = address.clone();
|
2022-08-24 01:33:48 +00:00
|
|
|
let slots = [slot];
|
2022-08-26 01:18:47 +00:00
|
|
|
let payload = self.payload.clone();
|
|
|
|
|
|
|
|
let handle = thread::spawn(move || {
|
|
|
|
let account_fut = execution.get_account(&addr, Some(&slots), &payload);
|
|
|
|
let runtime = Runtime::new()?;
|
|
|
|
runtime.block_on(account_fut)
|
|
|
|
});
|
2022-08-24 01:33:48 +00:00
|
|
|
|
2022-08-26 01:18:47 +00:00
|
|
|
let account = self.safe_unwrap(handle.join().unwrap());
|
2022-09-01 00:31:02 +00:00
|
|
|
let value = account.slots.get(&slot);
|
|
|
|
match value {
|
|
|
|
Some(value) => *value,
|
|
|
|
None => {
|
|
|
|
self.error = Some("slot not found".to_string());
|
|
|
|
U256::default()
|
|
|
|
}
|
|
|
|
}
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn code_by_hash(&mut self, _code_hash: H256) -> Bytecode {
|
|
|
|
panic!("should never be called");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_precompile(address: &Address) -> bool {
|
|
|
|
address.le(&Address::from_str("0x0000000000000000000000000000000000000009").unwrap())
|
|
|
|
}
|