feat(rpc): create revm env on demand (#13017)

Co-authored-by: dkathiriya <lakshya-sky@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Darshan Kathiriya
2024-11-30 12:27:20 -05:00
committed by GitHub
parent 3dc6f506b0
commit 890f082453
14 changed files with 91 additions and 123 deletions

1
Cargo.lock generated
View File

@ -9028,7 +9028,6 @@ dependencies = [
"reth-chain-state", "reth-chain-state",
"reth-chainspec", "reth-chainspec",
"reth-errors", "reth-errors",
"reth-evm",
"reth-execution-types", "reth-execution-types",
"reth-metrics", "reth-metrics",
"reth-primitives", "reth-primitives",

View File

@ -381,8 +381,8 @@ RPC State Cache:
[default: 2000] [default: 2000]
--rpc-cache.max-envs <MAX_ENVS> --rpc-cache.max-envs <MAX_HEADERS>
Max number of bytes for cached env data Max number of headers in cache
[default: 1000] [default: 1000]

View File

@ -1,6 +1,6 @@
use clap::Args; use clap::Args;
use reth_rpc_server_types::constants::cache::{ use reth_rpc_server_types::constants::cache::{
DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_ENV_CACHE_MAX_LEN, DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_HEADER_CACHE_MAX_LEN,
DEFAULT_RECEIPT_CACHE_MAX_LEN, DEFAULT_RECEIPT_CACHE_MAX_LEN,
}; };
@ -22,12 +22,12 @@ pub struct RpcStateCacheArgs {
)] )]
pub max_receipts: u32, pub max_receipts: u32,
/// Max number of bytes for cached env data. /// Max number of headers in cache.
#[arg( #[arg(
long = "rpc-cache.max-envs", long = "rpc-cache.max-envs",
default_value_t = DEFAULT_ENV_CACHE_MAX_LEN, default_value_t = DEFAULT_HEADER_CACHE_MAX_LEN,
)] )]
pub max_envs: u32, pub max_headers: u32,
/// Max number of concurrent database requests. /// Max number of concurrent database requests.
#[arg( #[arg(
@ -42,7 +42,7 @@ impl Default for RpcStateCacheArgs {
Self { Self {
max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN, max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN,
max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN, max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN,
max_envs: DEFAULT_ENV_CACHE_MAX_LEN, max_headers: DEFAULT_HEADER_CACHE_MAX_LEN,
max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS, max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS,
} }
} }

View File

@ -113,7 +113,7 @@ impl RethRpcServerConfig for RpcServerArgs {
EthStateCacheConfig { EthStateCacheConfig {
max_blocks: self.rpc_state_cache.max_blocks, max_blocks: self.rpc_state_cache.max_blocks,
max_receipts: self.rpc_state_cache.max_receipts, max_receipts: self.rpc_state_cache.max_receipts,
max_envs: self.rpc_state_cache.max_envs, max_headers: self.rpc_state_cache.max_headers,
max_concurrent_db_requests: self.rpc_state_cache.max_concurrent_db_requests, max_concurrent_db_requests: self.rpc_state_cache.max_concurrent_db_requests,
} }
} }

View File

@ -65,12 +65,7 @@ where
EvmConfig: ConfigureEvm<Header = Header>, EvmConfig: ConfigureEvm<Header = Header>,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
{ {
let cache = EthStateCache::spawn_with( let cache = EthStateCache::spawn_with(provider.clone(), config.cache, executor.clone());
provider.clone(),
config.cache,
executor.clone(),
evm_config.clone(),
);
let new_canonical_blocks = events.canonical_state_stream(); let new_canonical_blocks = events.canonical_state_stream();
let c = cache.clone(); let c = cache.clone();

View File

@ -259,7 +259,7 @@ where
Some(block_number.into()), Some(block_number.into()),
) )
.await .await
.unwrap(); .unwrap_err();
EthApiClient::<Transaction, Block, Receipt>::estimate_gas( EthApiClient::<Transaction, Block, Receipt>::estimate_gas(
client, client,
call_request.clone(), call_request.clone(),
@ -267,7 +267,7 @@ where
None, None,
) )
.await .await
.unwrap(); .unwrap_err();
EthApiClient::<Transaction, Block, Receipt>::call( EthApiClient::<Transaction, Block, Receipt>::call(
client, client,
call_request.clone(), call_request.clone(),
@ -276,7 +276,7 @@ where
None, None,
) )
.await .await
.unwrap(); .unwrap_err();
EthApiClient::<Transaction, Block, Receipt>::syncing(client).await.unwrap(); EthApiClient::<Transaction, Block, Receipt>::syncing(client).await.unwrap();
EthApiClient::<Transaction, Block, Receipt>::send_transaction( EthApiClient::<Transaction, Block, Receipt>::send_transaction(
client, client,
@ -368,13 +368,15 @@ where
.unwrap_err(); .unwrap_err();
TraceApiClient::trace_call_many(client, vec![], Some(BlockNumberOrTag::Latest.into())) TraceApiClient::trace_call_many(client, vec![], Some(BlockNumberOrTag::Latest.into()))
.await .await
.unwrap(); .unwrap_err();
TraceApiClient::replay_transaction(client, B256::default(), HashSet::default()) TraceApiClient::replay_transaction(client, B256::default(), HashSet::default())
.await .await
.err() .err()
.unwrap(); .unwrap();
TraceApiClient::trace_block(client, block_id).await.unwrap(); TraceApiClient::trace_block(client, block_id).await.unwrap_err();
TraceApiClient::replay_block_transactions(client, block_id, HashSet::default()).await.unwrap(); TraceApiClient::replay_block_transactions(client, block_id, HashSet::default())
.await
.unwrap_err();
TraceApiClient::trace_filter(client, trace_filter).await.unwrap(); TraceApiClient::trace_filter(client, trace_filter).await.unwrap();
} }

View File

@ -12,8 +12,8 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_errors::RethError; use reth_errors::RethError;
use reth_evm::ConfigureEvmEnv; use reth_evm::ConfigureEvmEnv;
use reth_provider::{ use reth_provider::{
BlockIdReader, BlockNumReader, ChainSpecProvider, StateProvider, StateProviderBox, BlockIdReader, BlockNumReader, ChainSpecProvider, EvmEnvProvider as _, StateProvider,
StateProviderFactory, StateProviderBox, StateProviderFactory,
}; };
use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError}; use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError};
use reth_transaction_pool::TransactionPool; use reth_transaction_pool::TransactionPool;
@ -229,12 +229,15 @@ pub trait LoadState:
.block_hash_for_id(at) .block_hash_for_id(at)
.map_err(Self::Error::from_eth_err)? .map_err(Self::Error::from_eth_err)?
.ok_or(EthApiError::HeaderNotFound(at))?; .ok_or(EthApiError::HeaderNotFound(at))?;
let (cfg, env) = self
.cache() let header =
.get_evm_env(block_hash) self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
.await let evm_config = self.evm_config().clone();
let (cfg, block_env) = self
.provider()
.env_with_header(&header, evm_config)
.map_err(Self::Error::from_eth_err)?; .map_err(Self::Error::from_eth_err)?;
Ok((cfg, env, block_hash.into())) Ok((cfg, block_env, block_hash.into()))
} }
} }
} }

View File

@ -15,7 +15,6 @@ workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-chain-state.workspace = true reth-chain-state.workspace = true
reth-errors.workspace = true reth-errors.workspace = true
reth-evm.workspace = true
reth-execution-types.workspace = true reth-execution-types.workspace = true
reth-metrics.workspace = true reth-metrics.workspace = true
reth-primitives = { workspace = true, features = ["secp256k1"] } reth-primitives = { workspace = true, features = ["secp256k1"] }

View File

@ -3,7 +3,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use reth_rpc_server_types::constants::cache::{ use reth_rpc_server_types::constants::cache::{
DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_ENV_CACHE_MAX_LEN, DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_HEADER_CACHE_MAX_LEN,
DEFAULT_RECEIPT_CACHE_MAX_LEN, DEFAULT_RECEIPT_CACHE_MAX_LEN,
}; };
@ -19,10 +19,10 @@ pub struct EthStateCacheConfig {
/// ///
/// Default is 2000. /// Default is 2000.
pub max_receipts: u32, pub max_receipts: u32,
/// Max number of bytes for cached env data. /// Max number of headers in cache.
/// ///
/// Default is 1000. /// Default is 1000.
pub max_envs: u32, pub max_headers: u32,
/// Max number of concurrent database requests. /// Max number of concurrent database requests.
/// ///
/// Default is 512. /// Default is 512.
@ -34,7 +34,7 @@ impl Default for EthStateCacheConfig {
Self { Self {
max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN, max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN,
max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN, max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN,
max_envs: DEFAULT_ENV_CACHE_MAX_LEN, max_headers: DEFAULT_HEADER_CACHE_MAX_LEN,
max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS, max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS,
} }
} }

View File

@ -1,17 +1,16 @@
//! Async caching support for eth RPC //! Async caching support for eth RPC
use super::{EthStateCacheConfig, MultiConsumerLruCache};
use alloy_consensus::Header; use alloy_consensus::Header;
use alloy_eips::BlockHashOrNumber; use alloy_eips::BlockHashOrNumber;
use alloy_primitives::B256; use alloy_primitives::B256;
use futures::{future::Either, Stream, StreamExt}; use futures::{future::Either, Stream, StreamExt};
use reth_chain_state::CanonStateNotification; use reth_chain_state::CanonStateNotification;
use reth_errors::{ProviderError, ProviderResult}; use reth_errors::{ProviderError, ProviderResult};
use reth_evm::{provider::EvmEnvProvider, ConfigureEvm};
use reth_execution_types::Chain; use reth_execution_types::Chain;
use reth_primitives::{Receipt, SealedBlockWithSenders, TransactionSigned}; use reth_primitives::{Receipt, SealedBlockWithSenders, TransactionSigned};
use reth_storage_api::{BlockReader, StateProviderFactory, TransactionVariant}; use reth_storage_api::{BlockReader, StateProviderFactory, TransactionVariant};
use reth_tasks::{TaskSpawner, TokioTaskExecutor}; use reth_tasks::{TaskSpawner, TokioTaskExecutor};
use revm::primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId};
use schnellru::{ByLength, Limiter}; use schnellru::{ByLength, Limiter};
use std::{ use std::{
future::Future, future::Future,
@ -25,8 +24,6 @@ use tokio::sync::{
}; };
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use super::{EthStateCacheConfig, MultiConsumerLruCache};
pub mod config; pub mod config;
pub mod db; pub mod db;
pub mod metrics; pub mod metrics;
@ -43,8 +40,8 @@ type BlockWithSendersResponseSender =
/// The type that can send the response to the requested receipts of a block. /// The type that can send the response to the requested receipts of a block.
type ReceiptsResponseSender = oneshot::Sender<ProviderResult<Option<Arc<Vec<Receipt>>>>>; type ReceiptsResponseSender = oneshot::Sender<ProviderResult<Option<Arc<Vec<Receipt>>>>>;
/// The type that can send the response to a requested env /// The type that can send the response to a requested header
type EnvResponseSender = oneshot::Sender<ProviderResult<(CfgEnvWithHandlerCfg, BlockEnv)>>; type HeaderResponseSender = oneshot::Sender<ProviderResult<Header>>;
type BlockLruCache<L> = MultiConsumerLruCache< type BlockLruCache<L> = MultiConsumerLruCache<
B256, B256,
@ -56,8 +53,7 @@ type BlockLruCache<L> = MultiConsumerLruCache<
type ReceiptsLruCache<L> = type ReceiptsLruCache<L> =
MultiConsumerLruCache<B256, Arc<Vec<Receipt>>, L, ReceiptsResponseSender>; MultiConsumerLruCache<B256, Arc<Vec<Receipt>>, L, ReceiptsResponseSender>;
type EnvLruCache<L> = type HeaderLruCache<L> = MultiConsumerLruCache<B256, Header, L, HeaderResponseSender>;
MultiConsumerLruCache<B256, (CfgEnvWithHandlerCfg, BlockEnv), L, EnvResponseSender>;
/// Provides async access to cached eth data /// Provides async access to cached eth data
/// ///
@ -70,26 +66,24 @@ pub struct EthStateCache {
impl EthStateCache { impl EthStateCache {
/// Creates and returns both [`EthStateCache`] frontend and the memory bound service. /// Creates and returns both [`EthStateCache`] frontend and the memory bound service.
fn create<Provider, Tasks, EvmConfig>( fn create<Provider, Tasks>(
provider: Provider, provider: Provider,
action_task_spawner: Tasks, action_task_spawner: Tasks,
evm_config: EvmConfig,
max_blocks: u32, max_blocks: u32,
max_receipts: u32, max_receipts: u32,
max_envs: u32, max_headers: u32,
max_concurrent_db_operations: usize, max_concurrent_db_operations: usize,
) -> (Self, EthStateCacheService<Provider, Tasks, EvmConfig>) { ) -> (Self, EthStateCacheService<Provider, Tasks>) {
let (to_service, rx) = unbounded_channel(); let (to_service, rx) = unbounded_channel();
let service = EthStateCacheService { let service = EthStateCacheService {
provider, provider,
full_block_cache: BlockLruCache::new(max_blocks, "blocks"), full_block_cache: BlockLruCache::new(max_blocks, "blocks"),
receipts_cache: ReceiptsLruCache::new(max_receipts, "receipts"), receipts_cache: ReceiptsLruCache::new(max_receipts, "receipts"),
evm_env_cache: EnvLruCache::new(max_envs, "evm_env"), headers_cache: HeaderLruCache::new(max_headers, "headers"),
action_tx: to_service.clone(), action_tx: to_service.clone(),
action_rx: UnboundedReceiverStream::new(rx), action_rx: UnboundedReceiverStream::new(rx),
action_task_spawner, action_task_spawner,
rate_limiter: Arc::new(Semaphore::new(max_concurrent_db_operations)), rate_limiter: Arc::new(Semaphore::new(max_concurrent_db_operations)),
evm_config,
}; };
let cache = Self { to_service }; let cache = Self { to_service };
(cache, service) (cache, service)
@ -99,52 +93,46 @@ impl EthStateCache {
/// [`tokio::spawn`]. /// [`tokio::spawn`].
/// ///
/// See also [`Self::spawn_with`] /// See also [`Self::spawn_with`]
pub fn spawn<Provider, EvmConfig>( pub fn spawn<Provider>(provider: Provider, config: EthStateCacheConfig) -> Self
provider: Provider,
config: EthStateCacheConfig,
evm_config: EvmConfig,
) -> Self
where where
Provider: StateProviderFactory Provider: StateProviderFactory
+ BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt> + BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt>
+ EvmEnvProvider
+ Clone + Clone
+ Unpin + Unpin
+ 'static, + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
{ {
Self::spawn_with(provider, config, TokioTaskExecutor::default(), evm_config) Self::spawn_with(provider, config, TokioTaskExecutor::default())
} }
/// Creates a new async LRU backed cache service task and spawns it to a new task via the given /// Creates a new async LRU backed cache service task and spawns it to a new task via the given
/// spawner. /// spawner.
/// ///
/// The cache is memory limited by the given max bytes values. /// The cache is memory limited by the given max bytes values.
pub fn spawn_with<Provider, Tasks, EvmConfig>( pub fn spawn_with<Provider, Tasks>(
provider: Provider, provider: Provider,
config: EthStateCacheConfig, config: EthStateCacheConfig,
executor: Tasks, executor: Tasks,
evm_config: EvmConfig,
) -> Self ) -> Self
where where
Provider: StateProviderFactory Provider: StateProviderFactory
+ BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt> + BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt>
+ EvmEnvProvider
+ Clone + Clone
+ Unpin + Unpin
+ 'static, + 'static,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
{ {
let EthStateCacheConfig { max_blocks, max_receipts, max_envs, max_concurrent_db_requests } = let EthStateCacheConfig {
config; max_blocks,
max_receipts,
max_headers,
max_concurrent_db_requests,
} = config;
let (this, service) = Self::create( let (this, service) = Self::create(
provider, provider,
executor.clone(), executor.clone(),
evm_config,
max_blocks, max_blocks,
max_receipts, max_receipts,
max_envs, max_headers,
max_concurrent_db_requests, max_concurrent_db_requests,
); );
executor.spawn_critical("eth state cache", Box::pin(service)); executor.spawn_critical("eth state cache", Box::pin(service));
@ -188,16 +176,12 @@ impl EthStateCache {
Ok(block.zip(receipts)) Ok(block.zip(receipts))
} }
/// Requests the evm env config for the block hash. /// Requests the header for the given hash.
/// ///
/// Returns an error if the corresponding header (required for populating the envs) was not /// Returns an error if the header is not found.
/// found. pub async fn get_header(&self, block_hash: B256) -> ProviderResult<Header> {
pub async fn get_evm_env(
&self,
block_hash: B256,
) -> ProviderResult<(CfgEnvWithHandlerCfg, BlockEnv)> {
let (response_tx, rx) = oneshot::channel(); let (response_tx, rx) = oneshot::channel();
let _ = self.to_service.send(CacheAction::GetEnv { block_hash, response_tx }); let _ = self.to_service.send(CacheAction::GetHeader { block_hash, response_tx });
rx.await.map_err(|_| ProviderError::CacheServiceUnavailable)? rx.await.map_err(|_| ProviderError::CacheServiceUnavailable)?
} }
} }
@ -222,14 +206,13 @@ impl EthStateCache {
pub(crate) struct EthStateCacheService< pub(crate) struct EthStateCacheService<
Provider, Provider,
Tasks, Tasks,
EvmConfig,
LimitBlocks = ByLength, LimitBlocks = ByLength,
LimitReceipts = ByLength, LimitReceipts = ByLength,
LimitEnvs = ByLength, LimitHeaders = ByLength,
> where > where
LimitBlocks: Limiter<B256, Arc<SealedBlockWithSenders>>, LimitBlocks: Limiter<B256, Arc<SealedBlockWithSenders>>,
LimitReceipts: Limiter<B256, Arc<Vec<Receipt>>>, LimitReceipts: Limiter<B256, Arc<Vec<Receipt>>>,
LimitEnvs: Limiter<B256, (CfgEnvWithHandlerCfg, BlockEnv)>, LimitHeaders: Limiter<B256, Header>,
{ {
/// The type used to lookup data from disk /// The type used to lookup data from disk
provider: Provider, provider: Provider,
@ -237,8 +220,11 @@ pub(crate) struct EthStateCacheService<
full_block_cache: BlockLruCache<LimitBlocks>, full_block_cache: BlockLruCache<LimitBlocks>,
/// The LRU cache for full blocks grouped by their hash. /// The LRU cache for full blocks grouped by their hash.
receipts_cache: ReceiptsLruCache<LimitReceipts>, receipts_cache: ReceiptsLruCache<LimitReceipts>,
/// The LRU cache for revm environments /// The LRU cache for headers.
evm_env_cache: EnvLruCache<LimitEnvs>, ///
/// Headers are cached because they are required to populate the environment for execution
/// (evm).
headers_cache: HeaderLruCache<LimitHeaders>,
/// Sender half of the action channel. /// Sender half of the action channel.
action_tx: UnboundedSender<CacheAction>, action_tx: UnboundedSender<CacheAction>,
/// Receiver half of the action channel. /// Receiver half of the action channel.
@ -247,15 +233,12 @@ pub(crate) struct EthStateCacheService<
action_task_spawner: Tasks, action_task_spawner: Tasks,
/// Rate limiter /// Rate limiter
rate_limiter: Arc<Semaphore>, rate_limiter: Arc<Semaphore>,
/// The type that determines how to configure the EVM.
evm_config: EvmConfig,
} }
impl<Provider, Tasks, EvmConfig> EthStateCacheService<Provider, Tasks, EvmConfig> impl<Provider, Tasks> EthStateCacheService<Provider, Tasks>
where where
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Provider: StateProviderFactory + BlockReader + Clone + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
{ {
fn on_new_block( fn on_new_block(
&mut self, &mut self,
@ -341,20 +324,18 @@ where
fn update_cached_metrics(&self) { fn update_cached_metrics(&self) {
self.full_block_cache.update_cached_metrics(); self.full_block_cache.update_cached_metrics();
self.receipts_cache.update_cached_metrics(); self.receipts_cache.update_cached_metrics();
self.evm_env_cache.update_cached_metrics(); self.headers_cache.update_cached_metrics();
} }
} }
impl<Provider, Tasks, EvmConfig> Future for EthStateCacheService<Provider, Tasks, EvmConfig> impl<Provider, Tasks> Future for EthStateCacheService<Provider, Tasks>
where where
Provider: StateProviderFactory Provider: StateProviderFactory
+ BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt> + BlockReader<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt>
+ EvmEnvProvider
+ Clone + Clone
+ Unpin + Unpin
+ 'static, + 'static,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
{ {
type Output = (); type Output = ();
@ -421,39 +402,30 @@ where
})); }));
} }
} }
CacheAction::GetEnv { block_hash, response_tx } => { CacheAction::GetHeader { block_hash, response_tx } => {
// check if env data is cached // check if the header is cached
if let Some(env) = this.evm_env_cache.get(&block_hash).cloned() { if let Some(header) = this.headers_cache.get(&block_hash).cloned() {
let _ = response_tx.send(Ok(env)); let _ = response_tx.send(Ok(header));
continue continue
} }
// env data is not in the cache, request it if this is the first // header is not in the cache, request it if this is the first
// consumer // consumer
if this.evm_env_cache.queue(block_hash, response_tx) { if this.headers_cache.queue(block_hash, response_tx) {
let provider = this.provider.clone(); let provider = this.provider.clone();
let action_tx = this.action_tx.clone(); let action_tx = this.action_tx.clone();
let rate_limiter = this.rate_limiter.clone(); let rate_limiter = this.rate_limiter.clone();
let evm_config = this.evm_config.clone();
this.action_task_spawner.spawn_blocking(Box::pin(async move { this.action_task_spawner.spawn_blocking(Box::pin(async move {
// Acquire permit // Acquire permit
let _permit = rate_limiter.acquire().await; let _permit = rate_limiter.acquire().await;
let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id( let header = provider.header(&block_hash).and_then(|header| {
CfgEnv::default(), header.ok_or_else(|| {
SpecId::LATEST, ProviderError::HeaderNotFound(block_hash.into())
); })
let mut block_env = BlockEnv::default(); });
let res = provider let _ = action_tx.send(CacheAction::HeaderResult {
.fill_env_at(
&mut cfg,
&mut block_env,
block_hash.into(),
evm_config,
)
.map(|_| (cfg, block_env));
let _ = action_tx.send(CacheAction::EnvResult {
block_hash, block_hash,
res: Box::new(res), res: Box::new(header),
}); });
})); }));
} }
@ -472,18 +444,18 @@ where
this.on_new_block(block_hash, Err(e)); this.on_new_block(block_hash, Err(e));
} }
}, },
CacheAction::EnvResult { block_hash, res } => { CacheAction::HeaderResult { block_hash, res } => {
let res = *res; let res = *res;
if let Some(queued) = this.evm_env_cache.remove(&block_hash) { if let Some(queued) = this.headers_cache.remove(&block_hash) {
// send the response to queued senders // send the response to queued senders
for tx in queued { for tx in queued {
let _ = tx.send(res.clone()); let _ = tx.send(res.clone());
} }
} }
// cache good env data // cache good header
if let Ok(data) = res { if let Ok(data) = res {
this.evm_env_cache.insert(block_hash, data); this.headers_cache.insert(block_hash, data);
} }
} }
CacheAction::CacheNewCanonicalChain { chain_change } => { CacheAction::CacheNewCanonicalChain { chain_change } => {
@ -528,9 +500,9 @@ enum CacheAction {
block_hash: B256, block_hash: B256,
response_tx: BlockWithSendersResponseSender, response_tx: BlockWithSendersResponseSender,
}, },
GetEnv { GetHeader {
block_hash: B256, block_hash: B256,
response_tx: EnvResponseSender, response_tx: HeaderResponseSender,
}, },
GetReceipts { GetReceipts {
block_hash: B256, block_hash: B256,
@ -544,9 +516,9 @@ enum CacheAction {
block_hash: B256, block_hash: B256,
res: ProviderResult<Option<Arc<Vec<Receipt>>>>, res: ProviderResult<Option<Arc<Vec<Receipt>>>>,
}, },
EnvResult { HeaderResult {
block_hash: B256, block_hash: B256,
res: Box<ProviderResult<(CfgEnvWithHandlerCfg, BlockEnv)>>, res: Box<ProviderResult<Header>>,
}, },
CacheNewCanonicalChain { CacheNewCanonicalChain {
chain_change: ChainChange, chain_change: ChainChange,

View File

@ -113,8 +113,8 @@ pub mod cache {
/// Default cache size for the receipts cache: 2000 receipts. /// Default cache size for the receipts cache: 2000 receipts.
pub const DEFAULT_RECEIPT_CACHE_MAX_LEN: u32 = 2000; pub const DEFAULT_RECEIPT_CACHE_MAX_LEN: u32 = 2000;
/// Default cache size for the env cache: 1000 envs. /// Default cache size for the header cache: 1000 headers.
pub const DEFAULT_ENV_CACHE_MAX_LEN: u32 = 1000; pub const DEFAULT_HEADER_CACHE_MAX_LEN: u32 = 1000;
/// Default number of concurrent database requests. /// Default number of concurrent database requests.
pub const DEFAULT_CONCURRENT_DB_REQUESTS: usize = 512; pub const DEFAULT_CONCURRENT_DB_REQUESTS: usize = 512;

View File

@ -450,7 +450,7 @@ mod tests {
provider: P, provider: P,
) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> { ) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> {
let evm_config = EthEvmConfig::new(provider.chain_spec()); let evm_config = EthEvmConfig::new(provider.chain_spec());
let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config.clone()); let cache = EthStateCache::spawn(provider.clone(), Default::default());
let fee_history_cache = let fee_history_cache =
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());

View File

@ -52,8 +52,7 @@ mod tests {
let pool = testing_pool(); let pool = testing_pool();
let evm_config = EthEvmConfig::new(MAINNET.clone()); let evm_config = EthEvmConfig::new(MAINNET.clone());
let cache = let cache = EthStateCache::spawn(NoopProvider::default(), Default::default());
EthStateCache::spawn(NoopProvider::default(), Default::default(), evm_config.clone());
EthApi::new( EthApi::new(
NoopProvider::default(), NoopProvider::default(),
pool, pool,
@ -79,8 +78,7 @@ mod tests {
let evm_config = EthEvmConfig::new(mock_provider.chain_spec()); let evm_config = EthEvmConfig::new(mock_provider.chain_spec());
mock_provider.extend_accounts(accounts); mock_provider.extend_accounts(accounts);
let cache = let cache = EthStateCache::spawn(mock_provider.clone(), Default::default());
EthStateCache::spawn(mock_provider.clone(), Default::default(), evm_config.clone());
EthApi::new( EthApi::new(
mock_provider.clone(), mock_provider.clone(),
pool, pool,

View File

@ -57,7 +57,7 @@ mod tests {
let pool = testing_pool(); let pool = testing_pool();
let evm_config = EthEvmConfig::new(noop_provider.chain_spec()); let evm_config = EthEvmConfig::new(noop_provider.chain_spec());
let cache = EthStateCache::spawn(noop_provider, Default::default(), evm_config.clone()); let cache = EthStateCache::spawn(noop_provider, Default::default());
let fee_history_cache = let fee_history_cache =
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());
let eth_api = EthApi::new( let eth_api = EthApi::new(