Skip to content

Commit e35d1c7

Browse files
authored
feat: start host env breakout (#125)
1 parent 777380c commit e35d1c7

File tree

7 files changed

+307
-196
lines changed

7 files changed

+307
-196
lines changed

crates/sim/src/env/host.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use crate::{InnerDb, SimDb, TimeLimited};
2+
use std::{marker::PhantomData, sync::Arc, time::Instant};
3+
use trevm::{
4+
helpers::Ctx,
5+
inspectors::{Layered, TimeLimit},
6+
revm::{
7+
database::CacheDB,
8+
inspector::{Inspector, NoOpInspector},
9+
DatabaseRef,
10+
},
11+
TrevmBuilder,
12+
};
13+
14+
/// A host simulation environment.
15+
#[derive(Debug)]
16+
pub struct HostEnv<Db, Insp = NoOpInspector> {
17+
db: InnerDb<Db>,
18+
_pd: PhantomData<fn() -> Insp>,
19+
}
20+
21+
impl<Db, Insp> Clone for HostEnv<Db, Insp> {
22+
fn clone(&self) -> Self {
23+
Self { db: self.db.clone(), _pd: PhantomData }
24+
}
25+
}
26+
27+
impl<Db> From<Db> for HostEnv<Db, NoOpInspector>
28+
where
29+
Db: DatabaseRef + Send + Sync,
30+
{
31+
fn from(db: Db) -> Self {
32+
Self::new(db)
33+
}
34+
}
35+
36+
impl<Db, Insp> HostEnv<Db, Insp> {
37+
/// Create a new host environment.
38+
pub fn new(db: Db) -> Self {
39+
Self { db: Arc::new(CacheDB::new(db)), _pd: PhantomData }
40+
}
41+
42+
/// Get a mutable reference to the inner database.
43+
pub const fn db_mut(&mut self) -> &mut InnerDb<Db> {
44+
&mut self.db
45+
}
46+
}
47+
48+
impl<Db, Insp> HostEnv<Db, Insp>
49+
where
50+
Db: DatabaseRef + Send + Sync,
51+
Insp: Inspector<Ctx<SimDb<Db>>> + Default + Sync,
52+
{
53+
/// Connect a fresh database for the simulation.
54+
pub fn sim_db(&self) -> crate::SimDb<Db> {
55+
crate::SimDb::new(self.db.clone())
56+
}
57+
58+
/// Create a new EVM for the host environment that will finish by the
59+
/// given instant.
60+
pub fn create_evm(
61+
&self,
62+
finish_by: Instant,
63+
) -> trevm::EvmNeedsCfg<crate::SimDb<Db>, TimeLimited<Insp>> {
64+
let db = self.sim_db();
65+
let inspector = Layered::new(TimeLimit::new(finish_by - Instant::now()), Insp::default());
66+
67+
TrevmBuilder::new().with_insp(inspector).with_db(db).build_trevm().unwrap()
68+
}
69+
}

crates/sim/src/env/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mod host;
2+
pub use host::HostEnv;
3+
4+
mod rollup;
5+
pub use rollup::RollupEnv;
6+
7+
mod shared;
8+
pub use shared::SharedSimEnv;
9+
10+
mod sim_env;
11+
pub use sim_env::SimEnv;

crates/sim/src/env/rollup.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use crate::{InnerDb, SimDb, TimeLimited};
2+
use signet_evm::EvmNeedsCfg;
3+
use signet_types::constants::SignetSystemConstants;
4+
use std::{marker::PhantomData, sync::Arc, time::Instant};
5+
use trevm::{
6+
db::{cow::CacheOnWrite, TryCachingDb},
7+
helpers::Ctx,
8+
inspectors::{Layered, TimeLimit},
9+
revm::{
10+
database::{Cache, CacheDB},
11+
inspector::NoOpInspector,
12+
DatabaseRef, Inspector,
13+
},
14+
};
15+
16+
/// A rollup simulation environment.
17+
#[derive(Debug)]
18+
pub struct RollupEnv<Db, Insp = NoOpInspector> {
19+
db: InnerDb<Db>,
20+
constants: SignetSystemConstants,
21+
_pd: PhantomData<fn() -> Insp>,
22+
}
23+
24+
impl<Db, Insp> Clone for RollupEnv<Db, Insp> {
25+
fn clone(&self) -> Self {
26+
Self { db: self.db.clone(), constants: self.constants.clone(), _pd: PhantomData }
27+
}
28+
}
29+
30+
impl<Db, Insp> RollupEnv<Db, Insp> {
31+
/// Create a new rollup environment.
32+
pub fn new(db: Db, constants: SignetSystemConstants) -> Self {
33+
Self { db: Arc::new(CacheDB::new(db)), constants, _pd: PhantomData }
34+
}
35+
36+
/// Get a mutable reference to the inner database.
37+
pub const fn db_mut(&mut self) -> &mut InnerDb<Db> {
38+
&mut self.db
39+
}
40+
41+
/// Get the constants for this environment.
42+
pub const fn constants(&self) -> &SignetSystemConstants {
43+
&self.constants
44+
}
45+
}
46+
47+
impl<Db, Insp> RollupEnv<Db, Insp>
48+
where
49+
Db: DatabaseRef + Send + Sync,
50+
Insp: Inspector<Ctx<SimDb<Db>>> + Default + Sync,
51+
{
52+
/// Connect a fresh database for the simulation.
53+
pub fn sim_db(&self) -> SimDb<Db> {
54+
CacheOnWrite::new(self.db.clone())
55+
}
56+
57+
/// Create a new EVM for the rollup environment that will finish by the
58+
/// given instant.
59+
pub fn create_evm(&self, finish_by: Instant) -> EvmNeedsCfg<SimDb<Db>, TimeLimited<Insp>> {
60+
let db = self.sim_db();
61+
62+
let inspector = Layered::new(TimeLimit::new(finish_by - Instant::now()), Insp::default());
63+
64+
signet_evm::signet_evm_with_inspector(db, inspector, self.constants.clone())
65+
}
66+
}
67+
68+
impl<Db, Insp> RollupEnv<Db, Insp>
69+
where
70+
Db: DatabaseRef,
71+
Insp: Inspector<Ctx<SimDb<Db>>> + Default + Sync,
72+
{
73+
/// Accepts a cache from the simulation and extends the database with it.
74+
pub fn accept_cache(
75+
&mut self,
76+
cache: Cache,
77+
) -> Result<(), <InnerDb<Db> as TryCachingDb>::Error> {
78+
self.db_mut().try_extend(cache)
79+
}
80+
81+
/// Accepts a cache from the simulation and extends the database with it.
82+
pub fn accept_cache_ref(
83+
&mut self,
84+
cache: &Cache,
85+
) -> Result<(), <InnerDb<Db> as TryCachingDb>::Error> {
86+
self.db_mut().try_extend_ref(cache)
87+
}
88+
}

crates/sim/src/env/shared.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use crate::{env::RollupEnv, outcome::SimulatedItem, SimCache, SimDb, SimEnv};
2+
use core::fmt;
3+
use std::{ops::Deref, sync::Arc};
4+
use tokio::{select, sync::watch};
5+
use tracing::{instrument, trace};
6+
use trevm::{
7+
helpers::Ctx,
8+
revm::{inspector::NoOpInspector, DatabaseRef, Inspector},
9+
Block, Cfg,
10+
};
11+
12+
/// A simulation environment.
13+
///
14+
/// Contains enough information to run a simulation.
15+
pub struct SharedSimEnv<Db, Insp = NoOpInspector> {
16+
inner: Arc<SimEnv<Db, Insp>>,
17+
}
18+
19+
impl<Db, Insp> fmt::Debug for SharedSimEnv<Db, Insp> {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
f.debug_struct("SharedSimEnv")
22+
.field("finish_by", &self.inner.finish_by())
23+
.field("concurrency_limit", &self.inner.concurrency_limit())
24+
.finish_non_exhaustive()
25+
}
26+
}
27+
28+
impl<Db, Insp> Deref for SharedSimEnv<Db, Insp> {
29+
type Target = SimEnv<Db, Insp>;
30+
31+
fn deref(&self) -> &Self::Target {
32+
&self.inner
33+
}
34+
}
35+
36+
impl<Db, Insp> From<SimEnv<Db, Insp>> for SharedSimEnv<Db, Insp>
37+
where
38+
Db: DatabaseRef + Send + Sync + 'static,
39+
Insp: Inspector<Ctx<SimDb<Db>>> + Default + Sync + 'static,
40+
{
41+
fn from(inner: SimEnv<Db, Insp>) -> Self {
42+
Self { inner: Arc::new(inner) }
43+
}
44+
}
45+
46+
impl<Db, Insp> SharedSimEnv<Db, Insp>
47+
where
48+
Db: DatabaseRef + Send + Sync + 'static,
49+
Insp: Inspector<Ctx<SimDb<Db>>> + Default + Sync + 'static,
50+
{
51+
/// Creates a new `SimEnv` instance.
52+
pub fn new<C, B>(
53+
rollup: RollupEnv<Db, Insp>,
54+
cfg: C,
55+
block: B,
56+
finish_by: std::time::Instant,
57+
concurrency_limit: usize,
58+
sim_items: SimCache,
59+
) -> Self
60+
where
61+
C: Cfg,
62+
B: Block,
63+
{
64+
SimEnv::new(rollup, cfg, block, finish_by, concurrency_limit, sim_items).into()
65+
}
66+
67+
/// Run a simulation round, returning the best item.
68+
#[instrument(skip(self))]
69+
pub async fn sim_round(&mut self, max_gas: u64) -> Option<SimulatedItem> {
70+
let (best_tx, mut best_watcher) = watch::channel(None);
71+
72+
let this = self.inner.clone();
73+
74+
// Spawn a blocking task to run the simulations.
75+
let sim_task = tokio::task::spawn_blocking(move || this.sim_round(max_gas, best_tx));
76+
77+
// Either simulation is done, or we time out
78+
select! {
79+
_ = tokio::time::sleep_until(self.finish_by().into()) => {
80+
trace!("Sim round timed out");
81+
},
82+
_ = sim_task => {
83+
trace!("Sim round done");
84+
},
85+
}
86+
87+
// Check what the current best outcome is.
88+
let best = best_watcher.borrow_and_update();
89+
trace!(score = %best.as_ref().map(|candidate| candidate.score).unwrap_or_default(), "Read outcome from channel");
90+
let outcome = best.as_ref()?;
91+
92+
// Remove the item from the cache.
93+
let item = self.sim_items().remove(outcome.cache_rank)?;
94+
// Accept the cache from the simulation.
95+
Arc::get_mut(&mut self.inner)
96+
.expect("sims dropped already")
97+
.rollup_mut()
98+
.accept_cache_ref(&outcome.cache)
99+
.ok()?;
100+
101+
Some(SimulatedItem { gas_used: outcome.gas_used, score: outcome.score, item })
102+
}
103+
}

0 commit comments

Comments
 (0)