-
Notifications
You must be signed in to change notification settings - Fork 0
breaking up simulator code #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
prestwich
wants to merge
7
commits into
03-16-adds_simulation_factory_to_builder
from
prestwich/sim-breakup
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
0980523
refactor: start breaking up simulator code
prestwich adae713
wip
prestwich e1417c9
fix: timelime
prestwich b398437
feat: sim_round
prestwich 013e2b3
chore: delete sim
prestwich 979c35e
wip
prestwich 660264f
wip
prestwich File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
use crate::tasks::sim::SimOutcome; | ||
use signet_bundle::{SignetEthBundle, SignetEthBundleDriver, SignetEthBundleError}; | ||
use signet_evm::SignetLayered; | ||
use signet_types::config::SignetSystemConstants; | ||
use std::{convert::Infallible, marker::PhantomData}; | ||
use trevm::{ | ||
Block, BundleDriver, Cfg, DbConnect, EvmFactory, Tx, | ||
db::{TryCachingDb, cow::CacheOnWrite}, | ||
helpers::Ctx, | ||
inspectors::{Layered, TimeLimit}, | ||
revm::{ | ||
DatabaseRef, Inspector, context::result::EVMError, database::Cache, | ||
inspector::NoOpInspector, | ||
}, | ||
}; | ||
|
||
use super::BundleOrTx; | ||
|
||
/// Factory for creating simulation tasks. | ||
#[derive(Debug, Clone)] | ||
pub struct SimEnv<Db, C, B, Insp = NoOpInspector> { | ||
/// The database to use for the simulation. | ||
db: Db, | ||
|
||
/// The system constants for the Signet network. | ||
constants: SignetSystemConstants, | ||
|
||
/// Chain cfg to use for the simulation. | ||
cfg: C, | ||
|
||
/// Block to use for the simulation. | ||
block: B, | ||
|
||
/// The max time to spend on any simulation. | ||
execution_timeout: std::time::Duration, | ||
|
||
_pd: PhantomData<fn() -> Insp>, | ||
} | ||
|
||
impl<Db, C, B, Insp> SimEnv<Db, C, B, Insp> { | ||
/// Creates a new `SimFactory` instance. | ||
pub fn new( | ||
db: Db, | ||
constants: SignetSystemConstants, | ||
cfg: C, | ||
block: B, | ||
execution_timeout: std::time::Duration, | ||
) -> Self { | ||
Self { db, constants, cfg, block, execution_timeout, _pd: PhantomData } | ||
} | ||
|
||
/// Get a reference to the database. | ||
pub fn db_mut(&mut self) -> &mut Db { | ||
&mut self.db | ||
} | ||
|
||
/// Get a reference to the system constants. | ||
pub fn constants(&self) -> &SignetSystemConstants { | ||
&self.constants | ||
} | ||
|
||
/// Get a reference to the chain cfg. | ||
pub fn cfg(&self) -> &C { | ||
&self.cfg | ||
} | ||
|
||
/// Get a mutable reference to the chain cfg. | ||
pub fn cfg_mut(&mut self) -> &mut C { | ||
&mut self.cfg | ||
} | ||
|
||
/// Get a reference to the block. | ||
pub fn block(&self) -> &B { | ||
&self.block | ||
} | ||
|
||
/// Get a mutable reference to the block. | ||
pub fn block_mut(&mut self) -> &mut B { | ||
&mut self.block | ||
} | ||
|
||
/// Get the exectuion timeout. | ||
pub fn execution_timeout(&self) -> std::time::Duration { | ||
self.execution_timeout | ||
} | ||
|
||
/// Set the execution timeout. | ||
pub fn set_execution_timeout(&mut self, timeout: std::time::Duration) { | ||
self.execution_timeout = timeout; | ||
} | ||
} | ||
|
||
impl<Db, C, B, Insp> DbConnect for SimEnv<Db, C, B, Insp> | ||
where | ||
Db: DatabaseRef + Clone + Sync, | ||
C: Sync, | ||
B: Sync, | ||
Insp: Sync, | ||
{ | ||
type Database = CacheOnWrite<Db>; | ||
|
||
type Error = Infallible; | ||
|
||
fn connect(&self) -> Result<Self::Database, Self::Error> { | ||
Ok(CacheOnWrite::new(self.db.clone())) | ||
} | ||
} | ||
|
||
impl<Db, C, B, Insp> EvmFactory for SimEnv<Db, C, B, Insp> | ||
where | ||
Db: DatabaseRef + Clone + Sync, | ||
C: Sync, | ||
B: Sync, | ||
Insp: Inspector<Ctx<CacheOnWrite<Db>>> + Default + Sync, | ||
{ | ||
type Insp = SignetLayered<Layered<TimeLimit, Insp>>; | ||
|
||
fn create(&self) -> Result<trevm::EvmNeedsCfg<Self::Database, Self::Insp>, Self::Error> { | ||
let db = self.connect().unwrap(); | ||
|
||
let inspector = Layered::new(TimeLimit::new(self.execution_timeout), Insp::default()); | ||
|
||
Ok(signet_evm::signet_evm_with_inspector(db, inspector, self.constants.clone())) | ||
} | ||
} | ||
|
||
impl<Db, C, B, Insp> SimEnv<Db, C, B, Insp> | ||
where | ||
Db: DatabaseRef + Clone + Sync, | ||
C: Cfg + Sync, | ||
B: Block + Sync, | ||
Insp: Inspector<Ctx<CacheOnWrite<Db>>> + Default + Sync, | ||
{ | ||
/// Simulates a transaction in the context of a block. | ||
/// | ||
/// This function runs the simulation in a separate thread and waits for | ||
/// the result or the deadline to expire. | ||
fn simulate_tx<'a, T>( | ||
&self, | ||
transaction: &'a T, | ||
) -> Result<SimOutcome<&'a T, Cache>, SignetEthBundleError<CacheOnWrite<Db>>> | ||
where | ||
T: Tx, | ||
{ | ||
let trevm = self.create_with_block(&self.cfg, &self.block).unwrap(); | ||
|
||
// Get the initial beneficiary balance | ||
let beneificiary = trevm.beneficiary(); | ||
let initial_beneficiary_balance = | ||
trevm.try_read_balance_ref(beneificiary).map_err(EVMError::Database)?; | ||
|
||
// If succesful, take the cache. If failed, return the error. | ||
match trevm.run_tx(transaction) { | ||
Ok(trevm) => { | ||
// Get the beneficiary balance after the transaction and calculate the | ||
// increase | ||
let beneficiary_balance = | ||
trevm.try_read_balance_ref(beneificiary).map_err(EVMError::Database)?; | ||
let increase = beneficiary_balance.saturating_sub(initial_beneficiary_balance); | ||
|
||
let cache = trevm.accept_state().into_db().into_cache(); | ||
|
||
// Create the outcome | ||
Ok(SimOutcome::new_unchecked(transaction, cache, increase)) | ||
} | ||
Err(e) => Err(SignetEthBundleError::from(e.into_error())), | ||
} | ||
} | ||
|
||
/// Simulates a bundle in the context of a block. | ||
fn simulate_bundle<'a>( | ||
&self, | ||
bundle: &'a SignetEthBundle, | ||
) -> Result<SimOutcome<&'a SignetEthBundle, Cache>, SignetEthBundleError<CacheOnWrite<Db>>> | ||
where | ||
Insp: Inspector<Ctx<CacheOnWrite<Db>>> + Default + Sync, | ||
{ | ||
let mut driver = | ||
SignetEthBundleDriver::new(&bundle, std::time::Instant::now() + self.execution_timeout); | ||
let trevm = self.create_with_block(&self.cfg, &self.block).unwrap(); | ||
|
||
// run the bundle | ||
let trevm = match driver.run_bundle(trevm) { | ||
Ok(result) => result, | ||
Err(e) => return Err(e.into_error()), | ||
}; | ||
|
||
// evaluate the result | ||
let score = driver.beneficiary_balance_increase(); | ||
|
||
let db = trevm.into_db(); | ||
let cache = db.into_cache(); | ||
|
||
Ok(SimOutcome::new_unchecked(bundle, cache, score)) | ||
} | ||
|
||
/// Simulate a [`BundleOrTx`], containing either a [`SignetEthBundle`] or a | ||
/// [`TxEnvelope`] | ||
pub fn simulate<'a, 'b: 'a>( | ||
&self, | ||
item: &'a BundleOrTx<'b>, | ||
) -> Result<SimOutcome<&'a BundleOrTx<'b>>, SignetEthBundleError<CacheOnWrite<Db>>> { | ||
match item { | ||
BundleOrTx::Bundle(bundle) => { | ||
Ok(self.simulate_bundle(bundle.as_ref())?.map_in(|_| item)) | ||
} | ||
BundleOrTx::Tx(tx) => Ok(self.simulate_tx(tx.as_ref())?.map_in(|_| item)), | ||
} | ||
} | ||
} | ||
|
||
impl<Db, C, B, Insp> SimEnv<Db, C, B, Insp> | ||
where | ||
Db: TryCachingDb + DatabaseRef + Clone + Sync, | ||
C: Cfg + Sync, | ||
B: Block + Sync, | ||
Insp: Inspector<Ctx<CacheOnWrite<Db>>> + Default + Sync, | ||
{ | ||
/// Accepts a cache from the simulation and extends the database with it. | ||
pub fn accept_cache(&mut self, cache: Cache) -> Result<(), <Db as TryCachingDb>::Error> { | ||
self.db_mut().try_extend(cache) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
mod outcome; | ||
pub use outcome::SimOutcome; | ||
|
||
mod env; | ||
pub use env::SimEnv; | ||
|
||
mod task; | ||
pub use task::SimTask; | ||
|
||
mod item; | ||
pub use item::BundleOrTx; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
use alloy::primitives::U256; | ||
use trevm::revm::database::Cache; | ||
|
||
/// An evaluated EVM transaction with a particular score. | ||
#[derive(Debug, Clone)] | ||
pub struct SimOutcome<In, Out = Cache, S = U256> { | ||
/// The transaction or bundle being executed. | ||
input: In, | ||
/// The result of the tx/bundle execution. | ||
output: Out, | ||
/// The score calculated by the evaluation function. | ||
score: S, | ||
} | ||
|
||
impl<In, Out, S> SimOutcome<In, Out, S> { | ||
/// Creates a new `Best` instance. | ||
pub fn new(input: In, output: Out, evaluator: impl FnOnce(&Out) -> S) -> Self { | ||
let score = evaluator(&output); | ||
Self::new_unchecked(input, output, score) | ||
} | ||
|
||
/// Transform the input type to a new type, while keeping the output and | ||
/// score the same. | ||
pub fn map_in_into<In2>(self) -> SimOutcome<In2, Out, S> | ||
where | ||
In2: From<In>, | ||
{ | ||
self.map_in(Into::into) | ||
} | ||
|
||
/// Transform the input type to a new type using a closure. | ||
pub fn map_in<In2, F>(self, f: F) -> SimOutcome<In2, Out, S> | ||
where | ||
F: FnOnce(In) -> In2, | ||
{ | ||
let input = f(self.input); | ||
SimOutcome { input, output: self.output, score: self.score } | ||
} | ||
|
||
/// Creates a new `Best` instance without evaluating the score. | ||
pub fn new_unchecked(input: In, output: Out, score: S) -> Self { | ||
Self { input, output, score } | ||
} | ||
|
||
/// Get a reference to the input, usually a transaction or bundle. | ||
pub fn input(&self) -> &In { | ||
&self.input | ||
} | ||
|
||
/// Get a reference to the output. | ||
pub fn output(&self) -> &Out { | ||
&self.output | ||
} | ||
|
||
/// Get a reference to the score. | ||
pub fn score(&self) -> &S { | ||
&self.score | ||
} | ||
|
||
/// Deconstruct the `SimOutcome` into its parts. | ||
pub fn into_parts(self) -> (In, Out, S) { | ||
(self.input, self.output, self.score) | ||
} | ||
|
||
/// Deconstruct the `SimOutcome` into its output. | ||
pub fn into_output(self) -> Out { | ||
self.output | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: update comments which still call this
Best