pub struct CachingDatabase { /* private fields */ }Expand description
A database wrapper that caches state lookups for parallel pre-warming.
This enables parallel warming workers to share cached data, and allows the sequential execution phase to reuse warmed state. Reduces redundant database/trie lookups when multiple transactions touch the same accounts.
Thread-safe via RwLock - optimized for read-heavy concurrent access.
This caching database is inspired by reth’s overlay/proof worker cache.
Besides the per-block warmer/executor sharing above, the mempool
prewarmer builds one instance per slot and publishes it across the block
boundary: execute_block_pipeline seeds the next block’s execution
with it when the parent state and fork match (see
ethrex-blockchain::prewarm).
§Invariant
Because one instance is shared across the block boundary (and the
prewarmer may still be filling it while the next block executes), every
cached entry must be a pure function of the parent state root. A cache
layer whose entries also depend on the executing block (fork, number,
timestamp, …) needs a matching handoff guard in
execute_block_pipeline — see precompile_cache, whose fork-dependent
entries are covered by the fork-equality check there.
Implementations§
Source§impl CachingDatabase
impl CachingDatabase
pub fn new(inner: Arc<dyn Database>, precompile_cache_enabled: bool) -> Self
Sourcepub fn code_bytes(&self) -> u64
pub fn code_bytes(&self) -> u64
Total Code::size of the bytecode this cache holds.
Sourcepub fn touched_keys_where(
&self,
account_filter: &dyn Fn(&Address) -> bool,
slot_filter: &dyn Fn(&(Address, H256)) -> bool,
) -> TouchedKeys
pub fn touched_keys_where( &self, account_filter: &dyn Fn(&Address) -> bool, slot_filter: &dyn Fn(&(Address, H256)) -> bool, ) -> TouchedKeys
Snapshot of the touched key sets matching the given filters: cached accounts (with their storage roots) and cached storage slot keys. The filters let a caller that tracks already-processed keys collect only the delta, keeping the per-call allocation O(new) while the scan stays O(cache).
Trait Implementations§
Source§impl Database for CachingDatabase
impl Database for CachingDatabase
Source§fn get_account_states_batch(
&self,
addresses: &[Address],
) -> Result<Vec<AccountState>, DatabaseError>
fn get_account_states_batch( &self, addresses: &[Address], ) -> Result<Vec<AccountState>, DatabaseError>
Warms every address through Self::prefetch_accounts, then answers from the
cache under one read lock. Repeated addresses cost a single database read, and a
caller that wants the states pays one map lookup each rather than a full
get_account_state round trip per address.
The read lock spans the whole assembly, so callers should keep addresses to a
bounded slice: a writer (an executor filling the same cache) waits on it.
Source§fn prefetch_codes(&self, code_hashes: &[H256]) -> Result<u64, DatabaseError>
fn prefetch_codes(&self, code_hashes: &[H256]) -> Result<u64, DatabaseError>
Fetches the uncached bytecodes in one batch and inserts them, reading each distinct hash once however many entries share it.
Returns only the warmed byte count, not the bytecodes: the executor reads code
through Self::get_account_code, which this turns into a cache hit. Assembling
a result vector here would hold the write lock that guards every executor code
read for the length of the batch, to build something a warming caller discards.
fn get_account_state( &self, address: Address, ) -> Result<AccountState, DatabaseError>
fn get_storage_value( &self, address: Address, key: H256, ) -> Result<U256, DatabaseError>
fn get_block_hash(&self, block_number: u64) -> Result<H256, DatabaseError>
fn get_chain_config(&self) -> Result<ChainConfig, DatabaseError>
fn get_account_code(&self, code_hash: H256) -> Result<Code, DatabaseError>
fn get_code_metadata( &self, code_hash: H256, ) -> Result<CodeMetadata, DatabaseError>
Source§fn precompile_cache(&self) -> Option<&PrecompileCache>
fn precompile_cache(&self) -> Option<&PrecompileCache>
Source§fn code_cache_budget_bytes(&self) -> u64
fn code_cache_budget_bytes(&self) -> u64
Code::size. Read moreSource§fn prefetch_accounts(&self, addresses: &[Address]) -> Result<(), DatabaseError>
fn prefetch_accounts(&self, addresses: &[Address]) -> Result<(), DatabaseError>
Source§fn prefetch_storage(
&self,
keys: &[(Address, H256)],
) -> Result<(), DatabaseError>
fn prefetch_storage( &self, keys: &[(Address, H256)], ) -> Result<(), DatabaseError>
Source§fn get_account_codes_batch(
&self,
code_hashes: &[H256],
) -> Result<Vec<Option<Code>>, DatabaseError>
fn get_account_codes_batch( &self, code_hashes: &[H256], ) -> Result<Vec<Option<Code>>, DatabaseError>
code_hashes. None means the hash is absent
from the database. Default: loop. Backends with a batched read path (e.g. rocksdb
multi_get_cf on the account-codes table) should override this; the caching layer
above dispatches to it from Self::prefetch_codes.Source§fn get_storage_values_batch(
&self,
keys: &[(Address, H256)],
) -> Result<Vec<U256>, DatabaseError>
fn get_storage_values_batch( &self, keys: &[(Address, H256)], ) -> Result<Vec<U256>, DatabaseError>
multi_get_cf on the storage flat key-value table)
should override this and the caching layer above will dispatch to it.Auto Trait Implementations§
impl !Freeze for CachingDatabase
impl !RefUnwindSafe for CachingDatabase
impl !UnwindSafe for CachingDatabase
impl Send for CachingDatabase
impl Sync for CachingDatabase
impl Unpin for CachingDatabase
impl UnsafeUnpin for CachingDatabase
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.