From 0706755ec27703ccc84cce3704d18889a71da838 Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Fri, 4 Nov 2022 16:37:30 -0400 Subject: [PATCH] fix: correct blockhash access in calls (#88) --- README.md | 2 +- client/src/node.rs | 14 +++++++++-- execution/src/evm.rs | 55 +++++++++++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c9e604c..ce66eb8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Helios will now run a local RPC server at `http://127.0.0.1:8545`. `--rpc-port` or `-p` sets the port that the local RPC should run on. The default value is `8545`. -`--data-dir` or `d` sets the directory that Helios should use to store cached weak subjectivity checkpoints in. Each network only stores the latest checkpoint, which is just 32 bytes. +`--data-dir` or `-d` sets the directory that Helios should use to store cached weak subjectivity checkpoints in. Each network only stores the latest checkpoint, which is just 32 bytes. ### Configuration Files All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file: diff --git a/client/src/node.rs b/client/src/node.rs index 5e47d1d..48c6966 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -102,7 +102,12 @@ impl Node { self.check_blocktag_age(&block)?; let payload = self.get_payload(block)?; - let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id()); + let mut evm = Evm::new( + self.execution.clone(), + &payload, + &self.payloads, + self.chain_id(), + ); evm.call(opts).await } @@ -110,7 +115,12 @@ impl Node { self.check_head_age()?; let payload = self.get_payload(BlockTag::Latest)?; - let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id()); + let mut evm = Evm::new( + self.execution.clone(), + &payload, + &self.payloads, + self.chain_id(), + ); evm.estimate_gas(opts).await } diff --git a/execution/src/evm.rs b/execution/src/evm.rs index acf280c..b40cb34 100644 --- a/execution/src/evm.rs +++ b/execution/src/evm.rs @@ -1,6 +1,13 @@ -use std::{cmp, collections::HashMap, str::FromStr, sync::Arc, thread}; +use std::{ + cmp, + collections::{BTreeMap, HashMap}, + str::FromStr, + sync::Arc, + thread, +}; use bytes::Bytes; +use common::{errors::BlockNotFoundError, types::BlockTag}; use ethers::{ abi::ethereum_types::BigEndianHash, prelude::{Address, H160, H256, U256}, @@ -21,19 +28,20 @@ use crate::{ use super::ExecutionClient; -pub struct Evm { - evm: EVM>, +pub struct Evm<'a, R: ExecutionRpc> { + evm: EVM>, chain_id: u64, } -impl Evm { +impl<'a, R: ExecutionRpc> Evm<'a, R> { pub fn new( execution: Arc>, - payload: ExecutionPayload, + current_payload: &'a ExecutionPayload, + payloads: &'a BTreeMap, chain_id: u64, ) -> Self { let mut evm: EVM> = EVM::new(); - let db = ProofDB::new(execution, payload); + let db = ProofDB::new(execution, current_payload, payloads); evm.database(db); Evm { evm, chain_id } @@ -105,9 +113,9 @@ impl Evm { async fn batch_fetch_accounts(&self, opts: &CallOpts) -> Result> { let db = self.evm.db.as_ref().unwrap(); let rpc = db.execution.rpc.clone(); - let payload = db.payload.clone(); + let payload = db.current_payload.clone(); let execution = db.execution.clone(); - let block = db.payload.block_number; + let block = db.current_payload.block_number; let opts_moved = CallOpts { from: opts.from, @@ -173,7 +181,7 @@ impl Evm { fn get_env(&self, opts: &CallOpts) -> Env { let mut env = Env::default(); - let payload = &self.evm.db.as_ref().unwrap().payload; + let payload = &self.evm.db.as_ref().unwrap().current_payload; env.tx.transact_to = TransactTo::Call(opts.to); env.tx.caller = opts.from.unwrap_or(Address::zero()); @@ -193,18 +201,24 @@ impl Evm { } } -struct ProofDB { +struct ProofDB<'a, R: ExecutionRpc> { execution: Arc>, - payload: ExecutionPayload, + current_payload: &'a ExecutionPayload, + payloads: &'a BTreeMap, accounts: HashMap, error: Option, } -impl ProofDB { - pub fn new(execution: Arc>, payload: ExecutionPayload) -> Self { +impl<'a, R: ExecutionRpc> ProofDB<'a, R> { + pub fn new( + execution: Arc>, + current_payload: &'a ExecutionPayload, + payloads: &'a BTreeMap, + ) -> Self { ProofDB { execution, - payload, + current_payload, + payloads, accounts: HashMap::new(), error: None, } @@ -217,7 +231,7 @@ impl ProofDB { fn get_account(&mut self, address: Address, slots: &[H256]) -> Result { let execution = self.execution.clone(); let addr = address.clone(); - let payload = self.payload.clone(); + let payload = self.current_payload.clone(); let slots = slots.to_owned(); let handle = thread::spawn(move || { @@ -230,7 +244,7 @@ impl ProofDB { } } -impl Database for ProofDB { +impl<'a, R: ExecutionRpc> Database for ProofDB<'a, R> { type Error = Report; fn basic(&mut self, address: H160) -> Result, Report> { @@ -256,8 +270,13 @@ impl Database for ProofDB { ))) } - fn block_hash(&mut self, _number: U256) -> Result { - Ok(H256::default()) + fn block_hash(&mut self, number: U256) -> Result { + let number = number.as_u64(); + let payload = self + .payloads + .get(&number) + .ok_or(BlockNotFoundError::new(BlockTag::Number(number)))?; + Ok(H256::from_slice(&payload.block_hash)) } fn storage(&mut self, address: H160, slot: U256) -> Result {