diff --git a/Cargo.toml b/Cargo.toml index 72abf5bc..63e66b09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "era_test_node" -version = "0.1.0-alpha.21" +version = "0.1.0-alpha.23" edition = "2018" authors = ["The Matter Labs Team "] homepage = "https://zksync.io/" diff --git a/src/fork.rs b/src/fork.rs index 6dc4ccb4..502559bb 100644 --- a/src/fork.rs +++ b/src/fork.rs @@ -33,9 +33,12 @@ use zksync_web3_decl::{ }; use zksync_web3_decl::{namespaces::EthNamespaceClient, types::Index}; -use crate::system_contracts; use crate::{cache::CacheConfig, node::TEST_NODE_NETWORK_ID}; use crate::{deps::InMemoryStorage, http_fork_source::HttpForkSource}; +use crate::{ + node::{DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, DEFAULT_ESTIMATE_GAS_SCALE_FACTOR}, + system_contracts, +}; pub fn block_on(future: F) -> F::Output where @@ -52,6 +55,40 @@ where .unwrap() } +/// The possible networks to fork from. +#[derive(Debug, Clone)] +pub enum ForkNetwork { + Mainnet, + SepoliaTestnet, + GoerliTestnet, + Other(String), +} + +impl ForkNetwork { + /// Return the URL for the underlying fork source. + pub fn to_url(&self) -> &str { + match self { + ForkNetwork::Mainnet => "https://mainnet.era.zksync.io:443", + ForkNetwork::SepoliaTestnet => "https://sepolia.era.zksync.dev:443", + ForkNetwork::GoerliTestnet => "https://testnet.era.zksync.dev:443", + ForkNetwork::Other(url) => url, + } + } + + /// Returns the local gas scale factors currently in use by the upstream network. + pub fn local_gas_scale_factors(&self) -> (f64, f32) { + match self { + ForkNetwork::Mainnet => (1.5, 1.2), + ForkNetwork::SepoliaTestnet => (2.0, 1.2), + ForkNetwork::GoerliTestnet => (1.2, 1.2), + ForkNetwork::Other(_) => ( + DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, + DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, + ), + } + } +} + /// In memory storage, that allows 'forking' from other network. /// If forking is enabled, it reads missing data from remote location. /// S - is a struct that is used for source of the fork. @@ -100,61 +137,61 @@ impl ForkStorage { } } - fn read_value_internal(&self, key: &StorageKey) -> zksync_types::StorageValue { + pub fn read_value_internal( + &self, + key: &StorageKey, + ) -> eyre::Result { let mut mutator = self.inner.write().unwrap(); let local_storage = mutator.raw_storage.read_value(key); if let Some(fork) = &mutator.fork { if !H256::is_zero(&local_storage) { - return local_storage; + return Ok(local_storage); } if let Some(value) = mutator.value_read_cache.get(key) { - return *value; + return Ok(*value); } let l2_miniblock = fork.l2_miniblock; let key_ = *key; - let result = fork - .fork_source - .get_storage_at( - *key_.account().address(), - h256_to_u256(*key_.key()), - Some(BlockIdVariant::BlockNumber(BlockNumber::Number(U64::from( - l2_miniblock, - )))), - ) - .unwrap(); + let result = fork.fork_source.get_storage_at( + *key_.account().address(), + h256_to_u256(*key_.key()), + Some(BlockIdVariant::BlockNumber(BlockNumber::Number(U64::from( + l2_miniblock, + )))), + )?; mutator.value_read_cache.insert(*key, result); - result + Ok(result) } else { - local_storage + Ok(local_storage) } } - fn load_factory_dep_internal(&self, hash: H256) -> Option> { + pub fn load_factory_dep_internal(&self, hash: H256) -> eyre::Result>> { let mut mutator = self.inner.write().unwrap(); let local_storage = mutator.raw_storage.load_factory_dep(hash); if let Some(fork) = &mutator.fork { if local_storage.is_some() { - return local_storage; + return Ok(local_storage); } if let Some(value) = mutator.factory_dep_cache.get(&hash) { - return value.clone(); + return Ok(value.clone()); } - let result = fork.fork_source.get_bytecode_by_hash(hash).unwrap(); + let result = fork.fork_source.get_bytecode_by_hash(hash)?; mutator.factory_dep_cache.insert(hash, result.clone()); - result + Ok(result) } else { - local_storage + Ok(local_storage) } } /// Check if this is the first time when we're ever writing to this key. /// This has impact on amount of pubdata that we have to spend for the write. - fn is_write_initial_internal(&self, key: &StorageKey) -> bool { + pub fn is_write_initial_internal(&self, key: &StorageKey) -> eyre::Result { // Currently we don't have the zks API to return us the information on whether a given // key was written to before a given block. // This means, we have to depend on the following heuristic: we'll read the value of the slot. @@ -162,15 +199,15 @@ impl ForkStorage { // - but if the value = 0 - there is a chance, that slot was written to in the past - and later was reset. // but unfortunately we cannot detect that with the current zks api, so we'll attempt to do it // only on local storage. - let value = self.read_value_internal(key); + let value = self.read_value_internal(key)?; if value != H256::zero() { - return false; + return Ok(false); } // If value was 0, there is still a chance, that the slot was written to in the past - and only now set to 0. // We unfortunately don't have the API to check it on the fork, but we can at least try to check it on local storage. let mut mutator = self.inner.write().unwrap(); - mutator.raw_storage.is_write_initial(key) + Ok(mutator.raw_storage.is_write_initial(key)) } /// Retrieves the enumeration index for a given `key`. @@ -182,15 +219,15 @@ impl ForkStorage { impl ReadStorage for ForkStorage { fn is_write_initial(&mut self, key: &StorageKey) -> bool { - self.is_write_initial_internal(key) + self.is_write_initial_internal(key).unwrap() } fn load_factory_dep(&mut self, hash: H256) -> Option> { - self.load_factory_dep_internal(hash) + self.load_factory_dep_internal(hash).unwrap() } fn read_value(&mut self, key: &StorageKey) -> zksync_types::StorageValue { - self.read_value_internal(key) + self.read_value_internal(key).unwrap() } fn get_enumeration_index(&mut self, key: &StorageKey) -> Option { @@ -200,15 +237,15 @@ impl ReadStorage for ForkStorage { impl ReadStorage for &ForkStorage { fn read_value(&mut self, key: &StorageKey) -> zksync_types::StorageValue { - self.read_value_internal(key) + self.read_value_internal(key).unwrap() } fn is_write_initial(&mut self, key: &StorageKey) -> bool { - self.is_write_initial_internal(key) + self.is_write_initial_internal(key).unwrap() } fn load_factory_dep(&mut self, hash: H256) -> Option> { - self.load_factory_dep_internal(hash) + self.load_factory_dep_internal(hash).unwrap() } fn get_enumeration_index(&mut self, key: &StorageKey) -> Option { @@ -321,6 +358,10 @@ pub struct ForkDetails { pub overwrite_chain_id: Option, pub l1_gas_price: u64, pub l2_fair_gas_price: u64, + /// L1 Gas Price Scale Factor for gas estimation. + pub estimate_gas_price_scale_factor: f64, + /// The factor by which to scale the gasLimit. + pub estimate_gas_scale_factor: f32, } const SUPPORTED_VERSIONS: &[ProtocolVersionId] = &[ @@ -356,13 +397,14 @@ pub fn supported_versions_to_string() -> String { } impl ForkDetails { - pub async fn from_url_and_miniblock_and_chain( - url: &str, + pub async fn from_network_and_miniblock_and_chain( + network: ForkNetwork, client: Client, miniblock: u64, chain_id: Option, cache_config: CacheConfig, ) -> Self { + let url = network.to_url(); let block_details = client .get_block_details(L2BlockNumber(miniblock as u32)) .await @@ -402,6 +444,8 @@ impl ForkDetails { ); } + let (estimate_gas_price_scale_factor, estimate_gas_scale_factor) = + network.local_gas_scale_factors(); ForkDetails { fork_source: HttpForkSource::new(url.to_owned(), cache_config), l1_block: l1_batch_number, @@ -412,23 +456,32 @@ impl ForkDetails { overwrite_chain_id: chain_id, l1_gas_price: block_details.base.l1_gas_price, l2_fair_gas_price: block_details.base.l2_fair_gas_price, + estimate_gas_price_scale_factor, + estimate_gas_scale_factor, } } /// Create a fork from a given network at a given height. pub async fn from_network(fork: &str, fork_at: Option, cache_config: CacheConfig) -> Self { - let (url, client) = Self::fork_to_url_and_client(fork); + let (network, client) = Self::fork_network_and_client(fork); let l2_miniblock = if let Some(fork_at) = fork_at { fork_at } else { client.get_block_number().await.unwrap().as_u64() }; - Self::from_url_and_miniblock_and_chain(url, client, l2_miniblock, None, cache_config).await + Self::from_network_and_miniblock_and_chain( + network, + client, + l2_miniblock, + None, + cache_config, + ) + .await } /// Create a fork from a given network, at a height BEFORE a transaction. /// This will allow us to apply this transaction locally on top of this fork. pub async fn from_network_tx(fork: &str, tx: H256, cache_config: CacheConfig) -> Self { - let (url, client) = Self::fork_to_url_and_client(fork); + let (network, client) = Self::fork_network_and_client(fork); let tx_details = client.get_transaction_by_hash(tx).await.unwrap().unwrap(); let overwrite_chain_id = Some( L2ChainId::try_from(tx_details.chain_id.as_u64()).unwrap_or_else(|err| { @@ -439,8 +492,8 @@ impl ForkDetails { // We have to sync to the one-miniblock before the one where transaction is. let l2_miniblock = miniblock_number.saturating_sub(1) as u64; - Self::from_url_and_miniblock_and_chain( - url, + Self::from_network_and_miniblock_and_chain( + network, client, l2_miniblock, overwrite_chain_id, @@ -451,22 +504,23 @@ impl ForkDetails { } impl ForkDetails { - /// Return URL and HTTP client for a given fork name. - pub fn fork_to_url_and_client(fork: &str) -> (&str, Client) { - let url = match fork { - "mainnet" => "https://mainnet.era.zksync.io:443", - "sepolia-testnet" => "https://sepolia.era.zksync.dev:443", - "goerli-testnet" => "https://testnet.era.zksync.dev:443", - _ => fork, + /// Return [`ForkNetwork`] and HTTP client for a given fork name. + pub fn fork_network_and_client(fork: &str) -> (ForkNetwork, Client) { + let network = match fork { + "mainnet" => ForkNetwork::Mainnet, + "sepolia-testnet" => ForkNetwork::SepoliaTestnet, + "goerli-testnet" => ForkNetwork::GoerliTestnet, + _ => ForkNetwork::Other(fork.to_string()), }; + let url = network.to_url(); let parsed_url = SensitiveUrl::from_str(url) .unwrap_or_else(|_| panic!("Unable to parse client URL: {}", &url)); let client = Client::http(parsed_url) .unwrap_or_else(|_| panic!("Unable to create a client for fork: {}", &url)) .build(); - (url, client) + (network, client) } /// Returns transactions that are in the same L2 miniblock as replay_tx, but were executed before it. @@ -508,7 +562,14 @@ mod tests { use zksync_state::ReadStorage; use zksync_types::{api::TransactionVariant, StorageKey}; - use crate::{deps::InMemoryStorage, node::DEFAULT_L2_GAS_PRICE, system_contracts, testing}; + use crate::{ + deps::InMemoryStorage, + node::{ + DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, + DEFAULT_L2_GAS_PRICE, + }, + system_contracts, testing, + }; use super::{ForkDetails, ForkStorage}; @@ -538,6 +599,8 @@ mod tests { overwrite_chain_id: None, l1_gas_price: 100, l2_fair_gas_price: DEFAULT_L2_GAS_PRICE, + estimate_gas_price_scale_factor: DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, + estimate_gas_scale_factor: DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, }; let mut fork_storage = ForkStorage::new(Some(fork_details), &options); diff --git a/src/node/eth.rs b/src/node/eth.rs index aeb61750..3a0e3366 100644 --- a/src/node/eth.rs +++ b/src/node/eth.rs @@ -9,7 +9,6 @@ use zksync_basic_types::{ web3::{self, Bytes}, AccountTreeId, Address, H160, H256, U256, U64, }; -use zksync_state::ReadStorage; use zksync_types::{ api::{Block, BlockIdVariant, BlockNumber, TransactionVariant}, fee::Fee, @@ -30,7 +29,10 @@ use crate::{ fork::ForkSource, namespaces::{EthNamespaceT, EthTestNodeNamespaceT, RpcResult}, node::{InMemoryNode, TransactionResult, MAX_TX_SIZE, PROTOCOL_VERSION}, - utils::{self, h256_to_u64, into_jsrpc_error, not_implemented, IntoBoxedFuture}, + utils::{ + self, h256_to_u64, into_jsrpc_error, not_implemented, report_into_jsrpc_error, + IntoBoxedFuture, + }, }; impl EthNamespaceT @@ -137,9 +139,11 @@ impl EthNamespa ); match inner.write() { - Ok(mut inner_guard) => { - let balance = inner_guard.fork_storage.read_value(&balance_key); - Ok(h256_to_u256(balance)) + Ok(inner_guard) => { + match inner_guard.fork_storage.read_value_internal(&balance_key) { + Ok(balance) => Ok(h256_to_u256(balance)), + Err(error) => Err(report_into_jsrpc_error(error)), + } } Err(_) => { let error_message = "Error acquiring write lock for balance retrieval"; @@ -259,16 +263,18 @@ impl EthNamespa let code_key = get_code_key(&address); match inner.write() { - Ok(mut guard) => { - let code_hash = guard.fork_storage.read_value(&code_key); - - let code = guard - .fork_storage - .load_factory_dep(code_hash) - .unwrap_or_default(); - - Ok(Bytes::from(code)) - } + Ok(guard) => match guard.fork_storage.read_value_internal(&code_key) { + Ok(code_hash) => { + match guard.fork_storage.load_factory_dep_internal(code_hash) { + Ok(raw_code) => { + let code = raw_code.unwrap_or_default(); + Ok(Bytes::from(code)) + } + Err(error) => Err(report_into_jsrpc_error(error)), + } + } + Err(error) => Err(report_into_jsrpc_error(error)), + }, Err(_) => Err(into_jsrpc_error(Web3Error::InternalError( anyhow::Error::msg("Failed to acquire write lock for code retrieval"), ))), @@ -297,10 +303,10 @@ impl EthNamespa let nonce_key = get_nonce_key(&address); match inner.write() { - Ok(mut guard) => { - let result = guard.fork_storage.read_value(&nonce_key); - Ok(h256_to_u64(result).into()) - } + Ok(guard) => match guard.fork_storage.read_value_internal(&nonce_key) { + Ok(result) => Ok(h256_to_u64(result).into()), + Err(error) => Err(report_into_jsrpc_error(error)), + }, Err(_) => Err(into_jsrpc_error(Web3Error::InternalError( anyhow::Error::msg("Failed to acquire write lock for nonce retrieval"), ))), @@ -1020,7 +1026,7 @@ impl EthNamespa let inner = self.get_inner().clone(); Box::pin(async move { - let mut writer = match inner.write() { + let writer = match inner.write() { Ok(r) => r, Err(_) => { return Err(into_jsrpc_error(Web3Error::InternalError( @@ -1058,7 +1064,10 @@ impl EthNamespa .unwrap_or_else(|| Ok(U64::from(writer.current_miniblock)))?; if block_number.as_u64() == writer.current_miniblock { - Ok(H256(writer.fork_storage.read_value(&storage_key).0)) + match writer.fork_storage.read_value_internal(&storage_key) { + Ok(value) => Ok(H256(value.0)), + Err(error) => Err(report_into_jsrpc_error(error)), + } } else if writer.block_hashes.contains_key(&block_number.as_u64()) { let value = writer .block_hashes @@ -1069,7 +1078,10 @@ impl EthNamespa .unwrap_or_default(); if value.is_zero() { - Ok(H256(writer.fork_storage.read_value(&storage_key).0)) + match writer.fork_storage.read_value_internal(&storage_key) { + Ok(value) => Ok(H256(value.0)), + Err(error) => Err(report_into_jsrpc_error(error)), + } } else { Ok(value) } diff --git a/src/node/fee_model.rs b/src/node/fee_model.rs index 88e7bf3a..75600b8b 100644 --- a/src/node/fee_model.rs +++ b/src/node/fee_model.rs @@ -7,13 +7,24 @@ use zksync_types::L1_GAS_PER_PUBDATA_BYTE; pub struct TestNodeFeeInputProvider { pub l1_gas_price: u64, pub l2_gas_price: u64, + /// L1 Gas Price Scale Factor for gas estimation. + pub estimate_gas_price_scale_factor: f64, + /// The factor by which to scale the gasLimit. + pub estimate_gas_scale_factor: f32, } impl TestNodeFeeInputProvider { - pub fn new(l1_gas_price: u64, l2_gas_price: u64) -> Self { + pub fn new( + l1_gas_price: u64, + l2_gas_price: u64, + estimate_gas_price_scale_factor: f64, + estimate_gas_scale_factor: f32, + ) -> Self { Self { l1_gas_price, l2_gas_price, + estimate_gas_price_scale_factor, + estimate_gas_scale_factor, } } diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index a53b8e22..795c8ba0 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -79,11 +79,11 @@ pub const L1_GAS_PRICE: u64 = 50_000_000_000; /// The default L2 Gas Price to be used if not supplied via the CLI argument. pub const DEFAULT_L2_GAS_PRICE: u64 = 25_000_000; /// L1 Gas Price Scale Factor for gas estimation. -pub const ESTIMATE_GAS_PRICE_SCALE_FACTOR: f64 = 1.5; +pub const DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR: f64 = 1.5; /// Acceptable gas overestimation limit. pub const ESTIMATE_GAS_ACCEPTABLE_OVERESTIMATION: u64 = 1_000; /// The factor by which to scale the gasLimit. -pub const ESTIMATE_GAS_SCALE_FACTOR: f32 = 1.3; +pub const DEFAULT_ESTIMATE_GAS_SCALE_FACTOR: f32 = 1.3; /// The maximum number of previous blocks to store the state for. pub const MAX_PREVIOUS_STATES: u16 = 128; /// The zks protocol version. @@ -455,8 +455,8 @@ impl InMemoryNodeInner { let fee_input = block_on(async move { fee_input_provider .get_batch_fee_input_scaled( - ESTIMATE_GAS_PRICE_SCALE_FACTOR, - ESTIMATE_GAS_PRICE_SCALE_FACTOR, + fee_input_provider.estimate_gas_price_scale_factor, + fee_input_provider.estimate_gas_price_scale_factor, ) .await .unwrap() @@ -584,11 +584,15 @@ impl InMemoryNodeInner { tracing::trace!("Gas Estimation Values:"); tracing::trace!(" Final upper_bound: {}", upper_bound); - tracing::trace!(" ESTIMATE_GAS_SCALE_FACTOR: {}", ESTIMATE_GAS_SCALE_FACTOR); + tracing::trace!( + " ESTIMATE_GAS_SCALE_FACTOR: {}", + self.fee_input_provider.estimate_gas_scale_factor + ); tracing::trace!(" MAX_L2_TX_GAS_LIMIT: {}", MAX_L2_TX_GAS_LIMIT); let tx_body_gas_limit = upper_bound; - let suggested_gas_limit = - ((upper_bound + additional_gas_for_pubdata) as f32 * ESTIMATE_GAS_SCALE_FACTOR) as u64; + let suggested_gas_limit = ((upper_bound + additional_gas_for_pubdata) as f32 + * self.fee_input_provider.estimate_gas_scale_factor) + as u64; let estimate_gas_result = InMemoryNodeInner::estimate_gas_step( l2_tx.clone(), @@ -953,6 +957,8 @@ impl InMemoryNode { fee_input_provider: TestNodeFeeInputProvider::new( f.l1_gas_price, config.l2_fair_gas_price, + f.estimate_gas_price_scale_factor, + f.estimate_gas_scale_factor, ), tx_results: Default::default(), blocks, @@ -990,6 +996,8 @@ impl InMemoryNode { fee_input_provider: TestNodeFeeInputProvider::new( L1_GAS_PRICE, config.l2_fair_gas_price, + DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, + DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, ), tx_results: Default::default(), blocks, @@ -1894,6 +1902,8 @@ mod tests { overwrite_chain_id: None, l1_gas_price: 1000, l2_fair_gas_price: DEFAULT_L2_GAS_PRICE, + estimate_gas_price_scale_factor: DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, + estimate_gas_scale_factor: DEFAULT_ESTIMATE_GAS_SCALE_FACTOR, }), None, Default::default(), diff --git a/src/node/in_memory_ext.rs b/src/node/in_memory_ext.rs index 2cb10ecb..a25e2b25 100644 --- a/src/node/in_memory_ext.rs +++ b/src/node/in_memory_ext.rs @@ -1,6 +1,5 @@ use anyhow::anyhow; use zksync_basic_types::{Address, U256, U64}; -use zksync_state::ReadStorage; use zksync_types::{ get_code_key, get_nonce_key, utils::{decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance}, @@ -210,7 +209,12 @@ impl InMemoryNo .map_err(|err| anyhow!("failed acquiring lock: {:?}", err)) .and_then(|mut writer| { let nonce_key = get_nonce_key(&address); - let full_nonce = writer.fork_storage.read_value(&nonce_key); + let full_nonce = match writer.fork_storage.read_value_internal(&nonce_key) { + Ok(full_nonce) => full_nonce, + Err(error) => { + return Err(anyhow!(error.to_string())); + } + }; let (mut account_nonce, mut deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce)); if account_nonce >= nonce { diff --git a/src/node/zks.rs b/src/node/zks.rs index e21ed855..0fda2e81 100644 --- a/src/node/zks.rs +++ b/src/node/zks.rs @@ -4,7 +4,6 @@ use bigdecimal::BigDecimal; use colored::Colorize; use futures::FutureExt; use zksync_basic_types::{AccountTreeId, Address, L1BatchNumber, L2BlockNumber, H256, U256}; -use zksync_state::ReadStorage; use zksync_types::{ api::{ BlockDetails, BlockDetailsBase, BlockStatus, BridgeAddresses, Proof, ProtocolVersion, @@ -22,8 +21,8 @@ use crate::{ namespaces::{RpcResult, ZksNamespaceT}, node::{InMemoryNode, TransactionResult}, utils::{ - internal_error, into_jsrpc_error, not_implemented, utc_datetime_from_epoch_ms, - IntoBoxedFuture, + internal_error, into_jsrpc_error, not_implemented, report_into_jsrpc_error, + utc_datetime_from_epoch_ms, IntoBoxedFuture, }, }; @@ -295,7 +294,7 @@ impl ZksNamespa })?; let balances = { - let mut writer = inner.write().map_err(|_e| { + let writer = inner.write().map_err(|_e| { let error_message = "Failed to acquire lock. Please ensure the lock is not being held by another process or thread.".to_string(); into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg(error_message))) })?; @@ -305,7 +304,12 @@ impl ZksNamespa AccountTreeId::new(token.l2_address), &address, ); - let balance = writer.fork_storage.read_value(&balance_key); + let balance = match writer.fork_storage.read_value_internal(&balance_key) { + Ok(balance) => balance, + Err(error) => { + return Err(report_into_jsrpc_error(error)); + } + }; if !balance.is_zero() { balances.insert(token.l2_address, h256_to_u256(balance)); } @@ -513,24 +517,41 @@ impl ZksNamespa fn get_bytecode_by_hash(&self, hash: zksync_basic_types::H256) -> RpcResult>> { let inner = self.get_inner().clone(); Box::pin(async move { - let mut writer = inner.write().map_err(|_e| { + let writer = inner.write().map_err(|_e| { into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg( "Failed to acquire write lock for bytecode retrieval.", ))) })?; - let maybe_bytecode = writer.fork_storage.load_factory_dep(hash).or_else(|| { - writer - .fork_storage - .inner - .read() - .expect("failed reading fork storage") - .fork - .as_ref() - .and_then(|fork| fork.fork_source.get_bytecode_by_hash(hash).ok().flatten()) - }); - - Ok(maybe_bytecode) + let maybe_bytecode = match writer.fork_storage.load_factory_dep_internal(hash) { + Ok(maybe_bytecode) => maybe_bytecode, + Err(error) => { + return Err(report_into_jsrpc_error(error)); + } + }; + + if maybe_bytecode.is_some() { + return Ok(maybe_bytecode); + } + + let maybe_fork_details = &writer + .fork_storage + .inner + .read() + .expect("failed reading fork storage") + .fork; + if let Some(fork_details) = maybe_fork_details { + let maybe_bytecode = match fork_details.fork_source.get_bytecode_by_hash(hash) { + Ok(maybe_bytecode) => maybe_bytecode, + Err(error) => { + return Err(report_into_jsrpc_error(error)); + } + }; + + Ok(maybe_bytecode) + } else { + Ok(None) + } }) } diff --git a/src/utils.rs b/src/utils.rs index 68e35e43..959eeb55 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -256,6 +256,12 @@ pub fn utc_datetime_from_epoch_ms(millis: u64) -> DateTime { DateTime::::from_timestamp(secs as i64, nanos as u32).expect("valid timestamp") } +pub fn report_into_jsrpc_error(error: eyre::Report) -> Error { + into_jsrpc_error(Web3Error::InternalError(anyhow::Error::msg( + error.to_string(), + ))) +} + pub fn into_jsrpc_error(err: Web3Error) -> Error { Error { code: match err {