diff --git a/Cargo.lock b/Cargo.lock index be30d586ab..3a3d145e4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,6 +356,7 @@ dependencies = [ "hex", "itertools 0.10.5", "lazy_static", + "linked-hash-map", "log", "mock", "pretty_assertions", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index d58111b309..f44c979173 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -22,6 +22,9 @@ strum = "0.24" strum_macros = "0.24" revm-precompile = { version = "=2.2.0", default-features = false, optional = true } +tokio = { version = "1.16.1", features = ["macros", "rt-multi-thread"] } +linked-hash-map = "0.5.6" + [dev-dependencies] hex = "0.4.3" pretty_assertions = "1.0.0" diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 6861a870ae..97c142e6ac 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -26,7 +26,7 @@ use core::fmt::Debug; use eth_types::{ self, geth_types, sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}, - Address, GethExecStep, GethExecTrace, ToWord, Word, + Address, GethExecStep, GethExecTrace, Hash, ToWord, Word, H160, H256, }; use ethers_providers::JsonRpcClient; pub use execution::{ @@ -34,14 +34,26 @@ pub use execution::{ }; pub use input_state_ref::CircuitInputStateRef; use itertools::Itertools; +use lazy_static::lazy_static; +use linked_hash_map::LinkedHashMap; use log::warn; use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap}, ops::Deref, + sync::Arc, }; +use tokio::sync::Mutex; pub use transaction::{Transaction, TransactionContext}; pub use withdrawal::{Withdrawal, WithdrawalContext}; +lazy_static! { + /// cached parent state_root. + pub static ref PARENT_STATE_ROOT: Arc> = Arc::new(Mutex::new(Word::zero())) ; + /// cached + pub static ref ANCESTOR_BLOCKS: Arc>> = + Arc::new(Mutex::new(LinkedHashMap::new())); +} + /// Runtime Config /// /// Default to mainnet block @@ -707,26 +719,44 @@ impl BuilderClient

{ let mut next_hash = eth_block.parent_hash; let mut prev_state_root: Option = None; let mut history_hashes = vec![Word::default(); n_blocks]; + while n_blocks > 0 { n_blocks -= 1; - // TODO: consider replacing it with `eth_getHeaderByHash`, it's faster - let header = self.cli.get_block_by_hash(next_hash).await?; + // Here we use cache-and-get: check if the parent_hash in cache, if not, query and cache + // it. Then we can obtain all it from cache. + let mut acestor_block_map = ANCESTOR_BLOCKS.lock().await; + if !acestor_block_map.contains_key(&next_hash) { + // TODO: consider replacing it with `eth_getHeaderByHash`, it's faster + let header = self.cli.get_block_by_hash(next_hash.clone()).await?; + let parent_hash = header.parent_hash; + acestor_block_map.insert(next_hash.clone(), parent_hash); + + if prev_state_root.is_none() { + let mut parent_block = PARENT_STATE_ROOT.lock().await; + *parent_block = header.state_root.to_word(); + } + } - // set the previous state root + // set the previous state root only for the latest parent header. if prev_state_root.is_none() { - prev_state_root = Some(header.state_root.to_word()); + let parent_block = PARENT_STATE_ROOT.lock().await; + prev_state_root = Some(parent_block.to_word()); } - // latest block hash is the last item - let block_hash = header - .hash - .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))? - .to_word(); - history_hashes[n_blocks] = block_hash; + history_hashes[n_blocks] = next_hash.to_word(); + + // continue, naxt_hash = next_parent_hash + next_hash = *acestor_block_map.get(&next_hash).unwrap(); - // continue - next_hash = header.parent_hash; + // remove the oldest block, as we at most need 256. + // For now, I've resize the map to 2*256, Here's some waste. + if acestor_block_map.len() > 2 * 256 { + for _ in 0..(acestor_block_map.len() - 256) { + // acestor_block_map.pop_front(); + let value = acestor_block_map.pop_front(); + } + } } Ok((