evm_fork_cache/cold_start/mod.rs
1//! Protocol-neutral cold-start sync for [`EvmCache`](crate::cache::EvmCache).
2//!
3//! Cold start declares rounds of authoritative slot work — verify, probe,
4//! probe_roots, accounts, discover — and drives a bounded multi-round loop via
5//! a pure [`ColdStartPlanner`]. Every verify and probe slot yields a per-slot
6//! [`SlotOutcome`] distinguishing a genuine on-chain zero ([`SlotFetch::Zero`])
7//! from a fetch failure ([`SlotFetch::FetchFailed`]) — closing the "archive-miss"
8//! gap where a transient fetch failure was indistinguishable from absence.
9//!
10//! The module is gated behind the `reactive` feature. The per-slot
11//! [`SlotOutcome`] / [`SlotFetch`] surface lives ungated in
12//! [`crate::freshness`] and is re-exported here for consumer ergonomics.
13//!
14//! # Design
15//!
16//! - The driver performs every fetch and call; planners are pure and IO-free,
17//! handed only a [`StateView`](crate::events::StateView) and a
18//! [`ColdStartResults`].
19//! - Verify-phase changes are injected via the dual-layer
20//! [`inject_storage_batch_fresh`](crate::cache::EvmCache::inject_storage_batch_fresh)
21//! and are visible to the next `on_results` through the state view.
22//! - A run can be pinned to a block hash via [`ColdStartPin::Hash`]; with
23//! `require_canonical: true`, a reorged hash makes the run fail fast. This is
24//! the cold-start reorg defense by design.
25//!
26//! # Runtime requirement
27//!
28//! Like the rest of the crate's RPC seams, cold-start fetching drives async work
29//! synchronously and must run on a **multi-thread** tokio runtime.
30//!
31//! # Example
32//!
33//! A planner that authoritatively warms a fixed working set of slots in one round.
34//! (See `examples/cold_start.rs` for the runnable discover-then-verify version.)
35//!
36//! ```
37//! use alloy_primitives::{Address, U256};
38//! use evm_fork_cache::cache::EvmCache;
39//! use evm_fork_cache::events::StateView;
40//! use evm_fork_cache::{
41//! ColdStartConfig, ColdStartError, ColdStartPlan, ColdStartPlanner, ColdStartResults,
42//! ColdStartStep,
43//! };
44//!
45//! struct WarmSlots {
46//! slots: Vec<(Address, U256)>,
47//! }
48//!
49//! impl ColdStartPlanner for WarmSlots {
50//! fn initial_plan(&mut self, _state: &dyn StateView) -> ColdStartPlan {
51//! // Round 1: re-fetch these slots authoritatively and inject the fresh values.
52//! ColdStartPlan { verify: self.slots.clone(), ..Default::default() }
53//! }
54//! fn on_results(&mut self, _r: &ColdStartResults, _s: &dyn StateView) -> ColdStartStep {
55//! ColdStartStep::Done
56//! }
57//! }
58//!
59//! // `run_cold_start` needs a live cache on a multi-thread runtime; this helper
60//! // shows the call shape (it is never invoked, so the doctest needs no runtime).
61//! # fn warm(cache: &mut EvmCache, slots: Vec<(Address, U256)>) -> Result<(), ColdStartError> {
62//! let mut planner = WarmSlots { slots };
63//! let report = cache.run_cold_start(&mut planner, ColdStartConfig::default())?;
64//! assert_eq!(report.rounds, 1);
65//! # Ok(())
66//! # }
67//! ```
68
69mod config;
70mod driver;
71mod error;
72mod plan;
73mod planner;
74mod results;
75pub mod roots;
76
77pub use config::{ColdStartConfig, ColdStartPin, ColdStartRoundSummary, ColdStartRunReport};
78pub use error::ColdStartError;
79pub use plan::{ColdStartCall, ColdStartPlan};
80pub use planner::{ColdStartPlanner, ColdStartStep};
81pub use results::{ColdStartCallResult, ColdStartResults, RoundOutcome};
82pub use roots::{RootBaseline, RootBaselinePlanner, RootProbeOutcome};
83
84// The per-slot fetch surface is ungated in `freshness`; re-export so
85// `evm_fork_cache::cold_start::SlotFetch` resolves for consumers.
86pub use crate::freshness::{SlotFetch, SlotOutcome};