mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
Compare commits
1 Commits
devnet4
...
klkvr/fixe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a119da5f8 |
17
Cargo.lock
generated
17
Cargo.lock
generated
@@ -3986,6 +3986,16 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-cache"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba59b6c98ba422a13f17ee1305c995cb5742bba7997f5b4d9af61b2ff0ffb213"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-hash"
|
||||
version = "0.8.0"
|
||||
@@ -8243,6 +8253,7 @@ dependencies = [
|
||||
"dashmap 6.1.0",
|
||||
"derive_more",
|
||||
"eyre",
|
||||
"fixed-cache",
|
||||
"futures",
|
||||
"metrics",
|
||||
"metrics-util",
|
||||
@@ -13202,6 +13213,12 @@ dependencies = [
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
|
||||
@@ -588,6 +588,7 @@ zstd = "0.13"
|
||||
byteorder = "1"
|
||||
mini-moka = "0.10"
|
||||
moka = "0.12"
|
||||
fixed-cache = "0.1.3"
|
||||
tar-no-std = { version = "0.3.2", default-features = false }
|
||||
miniz_oxide = { version = "0.8.4", default-features = false }
|
||||
chrono = "0.4.41"
|
||||
|
||||
@@ -54,6 +54,7 @@ thiserror.workspace = true
|
||||
tokio = { workspace = true, features = ["rt", "rt-multi-thread", "sync", "macros"] }
|
||||
mini-moka = { workspace = true, features = ["sync"] }
|
||||
moka = { workspace = true, features = ["sync"] }
|
||||
fixed-cache = { workspace = true, features = ["stats"] }
|
||||
smallvec.workspace = true
|
||||
|
||||
# metrics
|
||||
|
||||
@@ -438,7 +438,7 @@ where
|
||||
precompile,
|
||||
precompile_cache_map.cache_for_address(*address),
|
||||
spec_id,
|
||||
None, // No metrics for prewarm
|
||||
false, // No metrics for prewarm
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::tree::{
|
||||
error::{InsertBlockError, InsertBlockErrorKind, InsertPayloadError},
|
||||
instrumented_state::InstrumentedStateProvider,
|
||||
payload_processor::{executor::WorkloadExecutor, PayloadProcessor},
|
||||
precompile_cache::{CachedPrecompile, CachedPrecompileMetrics, PrecompileCacheMap},
|
||||
precompile_cache::{CachedPrecompile, PrecompileCacheMap},
|
||||
sparse_trie::StateRootComputeOutcome,
|
||||
EngineApiMetrics, EngineApiTreeState, ExecutionEnv, PayloadHandle, StateProviderBuilder,
|
||||
StateProviderDatabase, TreeConfig,
|
||||
@@ -45,7 +45,6 @@ use reth_trie::{updates::TrieUpdates, HashedPostState, StateRoot, TrieInputSorte
|
||||
use reth_trie_parallel::root::{ParallelStateRoot, ParallelStateRootError};
|
||||
use revm_primitives::Address;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
panic::{self, AssertUnwindSafe},
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
@@ -121,8 +120,6 @@ where
|
||||
payload_processor: PayloadProcessor<Evm>,
|
||||
/// Precompile cache map.
|
||||
precompile_cache_map: PrecompileCacheMap<SpecFor<Evm>>,
|
||||
/// Precompile cache metrics.
|
||||
precompile_cache_metrics: HashMap<alloy_primitives::Address, CachedPrecompileMetrics>,
|
||||
/// Hook to call when invalid blocks are encountered.
|
||||
#[debug(skip)]
|
||||
invalid_block_hook: Box<dyn InvalidBlockHook<Evm::Primitives>>,
|
||||
@@ -168,7 +165,6 @@ where
|
||||
evm_config,
|
||||
payload_processor,
|
||||
precompile_cache_map,
|
||||
precompile_cache_metrics: HashMap::new(),
|
||||
config,
|
||||
invalid_block_hook,
|
||||
metrics: EngineApiMetrics::default(),
|
||||
@@ -596,7 +592,7 @@ where
|
||||
/// Executes a block with the given state provider
|
||||
#[instrument(level = "debug", target = "engine::tree::payload_validator", skip_all)]
|
||||
fn execute_block<S, Err, T>(
|
||||
&mut self,
|
||||
&self,
|
||||
state_provider: S,
|
||||
env: ExecutionEnv<Evm>,
|
||||
input: &BlockOrPayload<T>,
|
||||
@@ -625,16 +621,11 @@ where
|
||||
if !self.config.precompile_cache_disabled() {
|
||||
// Only cache pure precompiles to avoid issues with stateful precompiles
|
||||
executor.evm_mut().precompiles_mut().map_pure_precompiles(|address, precompile| {
|
||||
let metrics = self
|
||||
.precompile_cache_metrics
|
||||
.entry(*address)
|
||||
.or_insert_with(|| CachedPrecompileMetrics::new_with_address(*address))
|
||||
.clone();
|
||||
CachedPrecompile::wrap(
|
||||
precompile,
|
||||
self.precompile_cache_map.cache_for_address(*address),
|
||||
*env.evm_env.spec_id(),
|
||||
Some(metrics),
|
||||
true,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use revm_primitives::Address;
|
||||
use std::{hash::Hash, sync::Arc};
|
||||
|
||||
/// Default max cache size for [`PrecompileCache`]
|
||||
const MAX_CACHE_SIZE: u32 = 10_000;
|
||||
const MAX_CACHE_SIZE: u32 = 131_072;
|
||||
|
||||
/// Stores caches for each precompile.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@@ -29,28 +29,33 @@ where
|
||||
//
|
||||
// This should be very rare as caches for all precompiles will be initialized as soon as
|
||||
// first EVM is created.
|
||||
self.0.entry(address).or_default().clone()
|
||||
self.0.entry(address).or_insert_with(|| PrecompileCache::new(address)).clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Cache for precompiles, for each input stores the result.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrecompileCache<S>(
|
||||
moka::sync::Cache<Bytes, CacheEntry<S>, alloy_primitives::map::DefaultHashBuilder>,
|
||||
)
|
||||
where
|
||||
S: Eq + Hash + std::fmt::Debug + Send + Sync + Clone + 'static;
|
||||
|
||||
impl<S> Default for PrecompileCache<S>
|
||||
pub struct PrecompileCache<S>
|
||||
where
|
||||
S: Eq + Hash + std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self(
|
||||
moka::sync::CacheBuilder::new(MAX_CACHE_SIZE as u64)
|
||||
.initial_capacity(MAX_CACHE_SIZE as usize)
|
||||
.build_with_hasher(Default::default()),
|
||||
)
|
||||
cache: Arc<fixed_cache::Cache<Bytes, CacheEntry<S>, alloy_primitives::map::DefaultHashBuilder>>,
|
||||
metrics: CachedPrecompileMetrics,
|
||||
}
|
||||
|
||||
impl<S> PrecompileCache<S>
|
||||
where
|
||||
S: Eq + Hash + std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||
{
|
||||
fn new(address: Address) -> Self {
|
||||
let metrics = CachedPrecompileMetrics::new_with_address(address);
|
||||
Self {
|
||||
cache: Arc::new(
|
||||
fixed_cache::Cache::new(MAX_CACHE_SIZE as usize, Default::default())
|
||||
.with_stats(Some(fixed_cache::Stats::new(metrics.clone()))),
|
||||
),
|
||||
metrics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,13 +64,16 @@ where
|
||||
S: Eq + Hash + std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||
{
|
||||
fn get(&self, input: &[u8], spec: S) -> Option<CacheEntry<S>> {
|
||||
self.0.get(input).filter(|e| e.spec == spec)
|
||||
self.cache
|
||||
.get(input)
|
||||
.filter(|e| e.spec == spec)
|
||||
.inspect(|_| self.metrics.precompile_cache_hits.increment(1))
|
||||
}
|
||||
|
||||
/// Inserts the given key and value into the cache, returning the new cache size.
|
||||
fn insert(&self, input: Bytes, value: CacheEntry<S>) -> usize {
|
||||
self.0.insert(input, value);
|
||||
self.0.entry_count() as usize
|
||||
self.cache.insert(input, value);
|
||||
MAX_CACHE_SIZE as usize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,12 +115,13 @@ where
|
||||
S: Eq + Hash + std::fmt::Debug + Send + Sync + Clone + 'static,
|
||||
{
|
||||
/// `CachedPrecompile` constructor.
|
||||
pub(crate) const fn new(
|
||||
pub(crate) fn new(
|
||||
precompile: DynPrecompile,
|
||||
cache: PrecompileCache<S>,
|
||||
spec_id: S,
|
||||
metrics: Option<CachedPrecompileMetrics>,
|
||||
track_hits_and_misses: bool,
|
||||
) -> Self {
|
||||
let metrics = track_hits_and_misses.then(|| cache.metrics.clone());
|
||||
Self { precompile, cache, spec_id, metrics }
|
||||
}
|
||||
|
||||
@@ -120,10 +129,10 @@ where
|
||||
precompile: DynPrecompile,
|
||||
cache: PrecompileCache<S>,
|
||||
spec_id: S,
|
||||
metrics: Option<CachedPrecompileMetrics>,
|
||||
track_hits_and_misses: bool,
|
||||
) -> DynPrecompile {
|
||||
let precompile_id = precompile.precompile_id().clone();
|
||||
let wrapped = Self::new(precompile, cache, spec_id, metrics);
|
||||
let wrapped = Self::new(precompile, cache, spec_id, track_hits_and_misses);
|
||||
(precompile_id, move |input: PrecompileInput<'_>| -> PrecompileResult {
|
||||
wrapped.call(input)
|
||||
})
|
||||
@@ -204,6 +213,9 @@ pub(crate) struct CachedPrecompileMetrics {
|
||||
/// Precompile cache size. Uses the LRU cache length as the size metric.
|
||||
precompile_cache_size: metrics::Gauge,
|
||||
|
||||
/// Precompile cache collisions.
|
||||
precompile_cache_collisions: metrics::Counter,
|
||||
|
||||
/// Precompile execution errors.
|
||||
precompile_errors: metrics::Counter,
|
||||
}
|
||||
@@ -218,6 +230,17 @@ impl CachedPrecompileMetrics {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> fixed_cache::StatsHandler<Bytes, CacheEntry<S>> for CachedPrecompileMetrics {
|
||||
fn on_collision(
|
||||
&self,
|
||||
_new_key: fixed_cache::AnyRef<'_>,
|
||||
_existing_key: &Bytes,
|
||||
_existing_value: &CacheEntry<S>,
|
||||
) {
|
||||
self.precompile_cache_collisions.increment(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user