Skip to main content

Module freshness

Module freshness 

Source
Expand description

Freshness control plane and the optimistic verify-and-rerun execution loop.

This module is the generic core of the engine’s “honest freshness” model: it knows which cached state it can trust, for how long, and how to keep the rest correct without blocking simulations on RPC. It is built from four layers:

  1. ClassificationValidity (Pinned / Volatile / ValidThrough) and the FreshnessRegistry that resolves a validity per (address, slot) with the precedence slot ▸ account ▸ default.
  2. ObservationSlotObservationTracker records per-slot change frequency (clock-agnostic) to drive adaptive re-verification, tuned by FreshnessParams.
  3. Policy — the FreshnessPolicy trait decides which volatile slots to verify this cycle; built-ins are AlwaysVerify, NeverVerify and ObservationDriven.
  4. MechanismEvmCache::verify_slots / EvmCache::purge_account, and the freshness controller that runs the optimistic loop.

The clock is configurable via FreshnessClock: BlockClock (the default, block-number based) or WallClock (unix seconds). The controller threads clock.now() as now: u64 through the tracker, the policy, and FreshnessRegistry::is_volatile.

§Reconciliation scope

The optimistic loop verifies only volatile storage slots in each sim’s read set. Account-level state — native balance, nonce, and bytecode — is not re-fetched or diffed today, so Validation::ConfirmedStorage means “no volatile storage slot the sims read had changed”, not “no account state changed”. A sim whose result depends on a BALANCE/SELFBALANCE (or nonce/code) that moved on-chain without a co-changing storage slot in its read set can still be reported ConfirmedStorage. If account-level state matters to a sim, mark the account Validity::Pinned and keep it fresh via event-driven writes, or reconcile it out of band.

The verdict taxonomy is deliberately split so this over-promise is visible in the type: ConfirmedStorage (storage only, account fields unverified) is distinct from ConfirmedFull (storage and verified account-level fields both unchanged). ConfirmedFull is defined but not yet emitted — a follow-up wave wires validator-side account verification that will populate it and the Corrected verdict’s changed_accounts. See Validation for the per-verdict note.

§Example

Classification + policy selection, no network required:

use alloy_primitives::{Address, U256};
use evm_fork_cache::freshness::{
    AlwaysVerify, FreshnessPolicy, FreshnessRegistry, NeverVerify,
};
use evm_fork_cache::cache::SlotObservationTracker;

let contract = Address::repeat_byte(0x01);
let volatile_slot = U256::from(0);
let immutable_slot = U256::from(6); // e.g. a constructor-set config value

let mut registry = FreshnessRegistry::new(); // default: Volatile
registry.pin_slot(contract, immutable_slot); // never re-verified

// `now` is in clock units (block number for the default BlockClock).
let now = 100;
assert!(registry.is_volatile(contract, volatile_slot, now));
assert!(!registry.is_volatile(contract, immutable_slot, now));

// Policies pick which volatile candidates to verify this cycle.
let obs = SlotObservationTracker::new();
let candidates = [(contract, volatile_slot)];
assert_eq!(
    AlwaysVerify.select(&candidates, &obs, now),
    vec![(contract, volatile_slot)]
);
assert!(NeverVerify.select(&candidates, &obs, now).is_empty());

Structs§

AlwaysVerify
Verifies every volatile candidate (safe / eager). Always correct, most RPC.
BlockClock
Block-number clock (the default). Cloning shares the underlying counter, so a clone observed by a background task sees set_block updates made on the main thread.
FreshnessController
Drives the optimistic verify-and-rerun loop over an EvmCache.
FreshnessParams
Tunable thresholds for the adaptive freshness model.
FreshnessRegistry
Per-address / per-slot validity classification.
NeverVerify
Verifies nothing (trust-all). Selects no slots from the predicted set, though the actual-read-set reconcile in the background validator can still surface changes.
ObservationDriven
Adaptive policy: verifies candidates the observation tracker flags via SlotObservationTracker::should_refetch, driven by the thresholds in FreshnessParams.
SimRequest
A single non-committing simulation request for the optimistic loop.
SlotChange
A storage slot whose value changed: old is the prior cached/snapshot value (ZERO if previously uncached), new is the resulting value.
SlotOutcome
The classified outcome of fetching a single storage slot.
SpeculativeSim
Optimistic simulation results plus a handle to their deferred validation.
WallClock
Wall-clock clock: now returns unix seconds.

Enums§

SlotFetch
The classified result of an individual slot fetch.
Validation
The deferred verdict on a SpeculativeSim’s optimistic results.
Validity
How long a cached account or storage slot can be trusted.

Constants§

DEFAULT_ALWAYS_REFETCH_RATE
Default change-rate above which a slot is always refetched.
DEFAULT_CYCLE_INTERVAL
Default clock units per “cycle” used by the probabilistic model.
DEFAULT_MAX_REUSE
Default maximum reuse window, in clock units, before a slot is rechecked.
DEFAULT_MIN_OBSERVATIONS
Default minimum observations before the change-frequency data is trusted.
DEFAULT_STALENESS_THRESHOLD
Default refetch threshold on expected probability of change.

Traits§

FreshnessClock
Source of the current clock value used throughout the freshness model.
FreshnessPolicy
Decides which volatile candidate slots must be verified this cycle.