Skip to content

Commit 92cc1d6

Browse files
committed
patched with in memory database as workaround for now
1 parent 0b993a7 commit 92cc1d6

File tree

3 files changed

+95
-171
lines changed

3 files changed

+95
-171
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ signet-types = { git = "https://github.com/init4tech/signet-sdk", branch = "main
2929
signet-zenith = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
3030

3131
trevm = { version = "0.20.4", features = [ "concurrent-db", "test-utils" ]}
32+
# trevm = { path = "../trevm", features = [ "concurrent-db", "test-utils" ]}
3233

3334
alloy = { version = "0.12.6", features = [
3435
"full",

src/tasks/simulator.rs

Lines changed: 76 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,21 @@ use eyre::Result;
55
use std::sync::Arc;
66
use tokio::{select, sync::mpsc::UnboundedReceiver, task::JoinSet};
77
use trevm::{
8-
db::{cow::CacheOnWrite, sync::{ConcurrentState, ConcurrentStateInfo}}, helpers::Ctx, revm::{
8+
Cfg, DbConnect, NoopBlock, TrevmBuilder, TrevmBuilderError, Tx,
9+
db::{
10+
cow::CacheOnWrite,
11+
sync::{ConcurrentState, ConcurrentStateInfo},
12+
},
13+
helpers::Ctx,
14+
revm::{
15+
Database, DatabaseCommit, DatabaseRef, Inspector,
916
context::{
10-
result::{EVMError, ExecutionResult, ResultAndState}, CfgEnv
11-
}, primitives::address, state::Account, Database, DatabaseCommit, DatabaseRef, Inspector
12-
}, BlockDriver, Cfg, DbConnect, EvmFactory, NoopBlock, TrevmBuilder, TrevmBuilderError, Tx
17+
CfgEnv,
18+
result::{EVMError, ExecutionResult, ResultAndState},
19+
},
20+
primitives::address,
21+
state::Account,
22+
},
1323
};
1424

1525
/// Tracks the EVM state, score, and result of an EVM execution.
@@ -28,29 +38,33 @@ pub struct Best<T, S: PartialOrd + Ord = U256> {
2838
/// Binds a database and an inspector together for simulation.
2939
#[derive(Debug, Clone)]
3040
pub struct SimulatorFactory<Db, Insp> {
31-
/// The database state the execution is carried out on.
32-
pub db: Db,
3341
/// The inspector
3442
pub inspector: Insp,
43+
/// A CacheOnWrite that is cloneable
44+
pub cow: MakeCow<Db>,
3545
}
3646

3747
/// SimResult is an [`Option`] type that holds a tuple of a transaction and its associated
3848
/// state as a [`Db`] type updates if it was successfully executed.
39-
type SimResult<Db> = Result<Option<(Best<TxEnvelope>, ConcurrentState<Arc<ConcurrentState<Db>>>)>>;
49+
type SimResult<Db> = Result<Option<(Best<TxEnvelope>, CacheOnWrite<Arc<ConcurrentState<Db>>>)>>;
4050

4151
impl<Db, Insp> SimulatorFactory<Db, Insp>
4252
where
43-
Insp: Inspector<Ctx<ConcurrentState<Db>>>
44-
+ Inspector<Ctx<ConcurrentState<Arc<ConcurrentState<Db>>>>>
53+
Insp: Inspector<Ctx<CacheOnWrite<CacheOnWrite<Arc<ConcurrentState<Db>>>>>>
4554
+ Send
4655
+ Sync
4756
+ Clone
4857
+ 'static,
4958
Db: Database + DatabaseRef + DatabaseCommit + Send + Sync + Clone + 'static,
59+
MakeCow<Db>: DbConnect<Database = CacheOnWrite<Arc<ConcurrentState<Db>>>>,
5060
{
5161
/// Creates a new Simulator factory from the provided database and inspector.
52-
pub const fn new(db: Db, inspector: Insp) -> Self {
53-
Self { db, inspector }
62+
pub fn new(db: Db, inspector: Insp) -> Self {
63+
let cdb = ConcurrentState::new(db, ConcurrentStateInfo::default());
64+
let cdb = Arc::new(cdb);
65+
let cow = MakeCow::new(cdb);
66+
67+
Self { inspector, cow }
5468
}
5569

5670
/// Spawns a trevm simulator that runs until `deadline` is hit.
@@ -68,60 +82,62 @@ where
6882
{
6983
tokio::spawn(async move {
7084
let mut join_set = JoinSet::new();
71-
let mut best: Option<Best<TxEnvelope>> = None;
7285
let mut block = InProgressBlock::new();
7386

7487
let sleep = tokio::time::sleep_until(deadline);
7588
tokio::pin!(sleep);
7689

7790
loop {
7891
select! {
79-
_ = &mut sleep => break,
80-
// Handle incoming
92+
_ = &mut sleep => {
93+
tracing::debug!("deadline reached, stopping simulation");
94+
break;
95+
},
8196
tx = inbound_tx.recv() => {
97+
tracing::debug!("#### received transaction");
8298
if let Some(inbound_tx) = tx {
83-
// Setup the simulation environment
84-
let sim = self.clone();
8599
let eval = evaluator.clone();
86-
let db = self.connect().expect("must connect db");
87-
let mut parent_db = Arc::new(db);
100+
let sim = self.clone();
101+
let db = self.cow.connect().unwrap();
88102

89103
join_set.spawn(async move {
90-
let result = sim.simulate_tx(inbound_tx, eval, parent_db.child());
91-
92-
if let Ok(Some((best, db))) = result {
93-
if let Ok(()) = parent_db.merge_child(db) {
94-
tracing::debug!("merging updated simulation state");
95-
return Some(best)
104+
let result = sim.simulate_tx(inbound_tx, eval, db.nest());
105+
match result {
106+
Ok(Some((best, new_db))) => {
107+
tracing::debug!("simulation completed, attempting to update state");
108+
// TODO: call cow.flatten on the nest instead
109+
tracing::debug!("successfully merged simulation state");
110+
return Some(best);
111+
}
112+
Ok(None) => {
113+
tracing::debug!("simulation returned no result");
114+
return None;
115+
}
116+
Err(e) => {
117+
tracing::error!(e = ?e, "failed to simulate transaction");
118+
return None;
96119
}
97-
tracing::error!("failed to update simulation state");
98-
None
99-
} else {
100-
None
101120
}
102121
});
103122
}
104123
}
105124
Some(result) = join_set.join_next() => {
125+
println!("join_set result");
106126
match result {
107-
Ok(Some(candidate)) => {
108-
tracing::info!(tx_hash = ?candidate.tx.tx_hash(), "ingesting transaction");
109-
block.ingest_tx(candidate.tx.as_ref());
110-
111-
if candidate.score > best.as_ref().map(|b| b.score).unwrap_or_default() {
112-
tracing::info!(score = ?candidate.score, "new best candidate found");
113-
best = Some(candidate);
114-
}
115-
}
127+
Ok(Some(best)) => {
128+
println!("simulation completed");
129+
block.ingest_tx(best.tx.as_ref());
130+
},
116131
Ok(None) => {
132+
println!("simulation returned no result");
117133
tracing::debug!("simulation returned no result");
118134
}
119135
Err(e) => {
120-
tracing::error!("simulation task failed: {}", e);
136+
println!("simulation returned an error: {}", e);
137+
tracing::error!(e = ?e, "failed to simulate transaction");
121138
}
122139
}
123140
}
124-
else => break,
125141
}
126142
}
127143

@@ -131,10 +147,10 @@ where
131147

132148
/// Simulates an inbound tx and applies its state if it's successfully simualted
133149
pub fn simulate_tx<F>(
134-
self,
150+
&self,
135151
tx: TxEnvelope,
136152
evaluator: Arc<F>,
137-
db: ConcurrentState<Arc<ConcurrentState<Db>>>,
153+
db: CacheOnWrite<CacheOnWrite<Arc<ConcurrentState<Db>>>>,
138154
) -> SimResult<Db>
139155
where
140156
F: Fn(&ResultAndState) -> U256 + Send + Sync + 'static,
@@ -151,6 +167,9 @@ where
151167
let score = evaluator(&result);
152168
let best = Best { tx: Arc::new(tx), result, score };
153169

170+
// Flatten to save the result to the parent and return it
171+
let db = db.flatten();
172+
154173
Ok(Some((best, db)))
155174
}
156175
Err(terr) => {
@@ -175,106 +194,31 @@ where
175194
}
176195
}
177196

178-
impl<Db, Insp> DbConnect for SimulatorFactory<Db, Insp>
179-
where
180-
Db: Database + DatabaseRef + DatabaseCommit + Sync + Send + Clone + 'static,
181-
Insp: Inspector<Ctx<ConcurrentState<Db>>> + Sync + Send + Clone,
182-
{
183-
type Database = ConcurrentState<Db>;
184-
type Error = TrevmBuilderError;
185-
186-
fn connect(&self) -> Result<Self::Database, Self::Error> {
187-
let inner = ConcurrentState::new(self.db.clone(), ConcurrentStateInfo::default());
188-
Ok(inner)
189-
}
190-
}
197+
/// MakeCow wraps a ConcurrentState database in an Arc to allow for cloning.
198+
#[derive(Debug, Clone)]
199+
pub struct MakeCow<Db>(Arc<ConcurrentState<Db>>);
191200

192-
/// Makes a SimulatorFactory capable of creating and configuring trevm instances
193-
impl<Db, Insp> EvmFactory for SimulatorFactory<Db, Insp>
201+
impl<Db> MakeCow<Db>
194202
where
195-
Db: Database + DatabaseRef + DatabaseCommit + Sync + Send + Clone + 'static,
196-
Insp: Inspector<Ctx<ConcurrentState<Db>>> + Sync + Send + Clone,
203+
Db: Database + DatabaseRef + DatabaseCommit + Send + Sync + 'static,
197204
{
198-
type Insp = Insp;
199-
200-
fn create(
201-
&self,
202-
) -> std::result::Result<trevm::EvmNeedsCfg<Self::Database, Self::Insp>, Self::Error> {
203-
let db = self.connect()?;
204-
let result =
205-
TrevmBuilder::new().with_db(db).with_insp(self.inspector.clone()).build_trevm();
206-
match result {
207-
Ok(t) => Ok(t),
208-
Err(e) => Err(e.into()),
209-
}
205+
/// Returns a new CoW Db that implements Clone for use in DbConnect
206+
pub fn new(db: Arc<ConcurrentState<Db>>) -> Self {
207+
Self(db)
210208
}
211209
}
212210

213-
pub trait BlockExtractor<Insp, Db>
211+
impl<Db> DbConnect for MakeCow<Db>
214212
where
215-
Db: Database + DatabaseCommit,
216-
Insp: Inspector<Ctx<Db>>,
213+
Db: Database + DatabaseRef + DatabaseCommit + Sync + Send + Clone + 'static,
217214
{
218-
/// BlockDriver runs the transactions over the provided trevm instance.
219-
type Driver: BlockDriver<Insp, Error<Db>: core::error::Error>;
220-
221-
/// Instantiate an configure a new [`trevm`] instance.
222-
fn trevm(&self, db: Db) -> trevm::EvmNeedsBlock<Db, Insp>;
223-
224-
/// Extracts transactions from the source.
225-
///
226-
/// Extraction is infallible. Worst case it should return a no-op driver.
227-
fn extract(&mut self, bytes: &[u8]) -> Self::Driver;
228-
}
229-
230-
impl<Insp> BlockDriver<Insp> for InProgressBlock {
231-
type Block = NoopBlock;
232-
233-
type Error<Db: Database + DatabaseCommit> = Error<Db>;
234-
235-
fn block(&self) -> &Self::Block {
236-
&NoopBlock
237-
}
238-
239-
/// Loops through the transactions in the block and runs them, accepting the state at the end
240-
/// if it was successful and returning and erroring out otherwise.
241-
fn run_txns<Db: Database + DatabaseCommit>(
242-
&mut self,
243-
mut trevm: trevm::EvmNeedsTx<Db, Insp>,
244-
) -> trevm::RunTxResult<Db, Insp, Self>
245-
where
246-
Insp: Inspector<Ctx<Db>>,
247-
{
248-
for tx in self.transactions().iter() {
249-
if tx.recover_signer().is_ok() {
250-
let sender = tx.recover_signer().unwrap();
251-
tracing::info!(sender = ?sender, tx_hash = ?tx.tx_hash(), "simulating transaction");
252-
253-
let t = match trevm.run_tx(tx) {
254-
Ok(t) => t,
255-
Err(e) => {
256-
if e.is_transaction_error() {
257-
return Ok(e.discard_error());
258-
} else {
259-
return Err(e.err_into());
260-
}
261-
}
262-
};
263-
264-
(_, trevm) = t.accept();
265-
}
266-
}
267-
Ok(trevm)
268-
}
215+
type Database = CacheOnWrite<Arc<ConcurrentState<Db>>>;
216+
type Error = TrevmBuilderError;
269217

270-
fn post_block<Db: Database + DatabaseCommit>(
271-
&mut self,
272-
_trevm: &trevm::EvmNeedsBlock<Db, Insp>,
273-
) -> Result<(), Self::Error<Db>>
274-
where
275-
Insp: Inspector<Ctx<Db>>,
276-
{
277-
Ok(())
218+
/// Connects to the database and returns a CacheOnWrite instance
219+
fn connect(&self) -> Result<Self::Database, Self::Error> {
220+
let db: CacheOnWrite<Arc<ConcurrentState<Db>>> = CacheOnWrite::new(self.0.clone());
221+
Ok(db)
278222
}
279223
}
280224

0 commit comments

Comments
 (0)