Skip to content
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

feat: add example for using a database by reference #1150

Merged
merged 5 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/revm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ name = "generate_block_traces"
path = "../../examples/generate_block_traces.rs"
required-features = ["std", "serde-json", "ethersdb"]

[[example]]
name = "db_by_ref"
path = "../../examples/db_by_ref.rs"
required-features = ["std", "serde-json"]

[[bench]]
name = "bench"
path = "benches/bench.rs"
Expand Down
8 changes: 4 additions & 4 deletions crates/revm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB>
/// When called, EvmBuilder will transition from SetGenericStage to HandlerStage.
pub fn append_handler_register(
mut self,
handle_register: register::HandleRegister<'a, EXT, DB>,
) -> EvmBuilder<'_, HandlerStage, EXT, DB> {
handle_register: register::HandleRegister<EXT, DB>,
) -> EvmBuilder<'a, HandlerStage, EXT, DB> {
self.handler
.append_handler_register(register::HandleRegisters::Plain(handle_register));
EvmBuilder {
Expand All @@ -302,8 +302,8 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB>
/// When called, EvmBuilder will transition from SetGenericStage to HandlerStage.
pub fn append_handler_register_box(
mut self,
handle_register: register::HandleRegisterBox<'a, EXT, DB>,
) -> EvmBuilder<'_, HandlerStage, EXT, DB> {
handle_register: register::HandleRegisterBox<EXT, DB>,
) -> EvmBuilder<'a, HandlerStage, EXT, DB> {
self.handler
.append_handler_register(register::HandleRegisters::Box(handle_register));
EvmBuilder {
Expand Down
12 changes: 6 additions & 6 deletions crates/revm/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> {
/// Instruction table type.
pub instruction_table: Option<InstructionTables<'a, H>>,
/// Registers that will be called on initialization.
pub registers: Vec<HandleRegisters<'a, EXT, DB>>,
pub registers: Vec<HandleRegisters<EXT, DB>>,
/// Validity handles.
pub validation: ValidationHandler<'a, EXT, DB>,
/// Pre execution handle
Expand Down Expand Up @@ -138,25 +138,25 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
}

/// Append handle register.
pub fn append_handler_register(&mut self, register: HandleRegisters<'a, EXT, DB>) {
pub fn append_handler_register(&mut self, register: HandleRegisters<EXT, DB>) {
register.register(self);
self.registers.push(register);
}

/// Append plain handle register.
pub fn append_handler_register_plain(&mut self, register: HandleRegister<'a, EXT, DB>) {
pub fn append_handler_register_plain(&mut self, register: HandleRegister<EXT, DB>) {
register(self);
self.registers.push(HandleRegisters::Plain(register));
}

/// Append boxed handle register.
pub fn append_handler_register_box(&mut self, register: HandleRegisterBox<'a, EXT, DB>) {
pub fn append_handler_register_box(&mut self, register: HandleRegisterBox<EXT, DB>) {
register(self);
self.registers.push(HandleRegisters::Box(register));
}

/// Pop last handle register and reapply all registers that are left.
pub fn pop_handle_register(&mut self) -> Option<HandleRegisters<'a, EXT, DB>> {
pub fn pop_handle_register(&mut self) -> Option<HandleRegisters<EXT, DB>> {
let out = self.registers.pop();
if out.is_some() {
let registers = core::mem::take(&mut self.registers);
Expand Down Expand Up @@ -211,7 +211,7 @@ mod test {

#[test]
fn test_handler_register_pop() {
let register = |inner: &Rc<RefCell<i32>>| -> HandleRegisterBox<'_, (), EmptyDB> {
let register = |inner: &Rc<RefCell<i32>>| -> HandleRegisterBox<(), EmptyDB> {
let inner = inner.clone();
Box::new(move |h| {
*inner.borrow_mut() += 1;
Expand Down
14 changes: 7 additions & 7 deletions crates/revm/src/handler/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ pub type EvmHandler<'a, EXT, DB> = Handler<'a, Evm<'a, EXT, DB>, EXT, DB>;
pub type EvmInstructionTables<'a, EXT, DB> = InstructionTables<'a, Evm<'a, EXT, DB>>;

// Handle register
pub type HandleRegister<'a, EXT, DB> = fn(&mut EvmHandler<'a, EXT, DB>);
pub type HandleRegister<EXT, DB> = for<'a> fn(&mut EvmHandler<'a, EXT, DB>);

// Boxed handle register
pub type HandleRegisterBox<'a, EXT, DB> = Box<dyn Fn(&mut EvmHandler<'a, EXT, DB>)>;
pub type HandleRegisterBox<EXT, DB> = Box<dyn for<'a> Fn(&mut EvmHandler<'a, EXT, DB>)>;

pub enum HandleRegisters<'a, EXT, DB: Database> {
pub enum HandleRegisters<EXT, DB: Database> {
/// Plain function register
Plain(HandleRegister<'a, EXT, DB>),
Plain(HandleRegister<EXT, DB>),
/// Boxed function register.
Box(HandleRegisterBox<'a, EXT, DB>),
Box(HandleRegisterBox<EXT, DB>),
}

impl<'a, EXT, DB: Database> HandleRegisters<'a, EXT, DB> {
impl<EXT, DB: Database> HandleRegisters<EXT, DB> {
/// Call register function to modify EvmHandler.
pub fn register(&self, handler: &mut EvmHandler<'a, EXT, DB>) {
pub fn register(&self, handler: &mut EvmHandler<'_, EXT, DB>) {
match self {
HandleRegisters::Plain(f) => f(handler),
HandleRegisters::Box(f) => f(handler),
Expand Down
81 changes: 81 additions & 0 deletions examples/db_by_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use revm::{
db::{CacheDB, EmptyDB, WrapDatabaseRef},
handler::register::HandleRegister,
inspector_handle_register,
inspectors::{NoOpInspector, TracerEip3155},
primitives::ResultAndState,
DatabaseCommit, DatabaseRef, Evm,
};
use std::error::Error;

trait DatabaseRefDebugError: DatabaseRef<Error = Self::DBError> {
type DBError: std::fmt::Debug + Error + Send + Sync + 'static;
}

impl<DBError, DB> DatabaseRefDebugError for DB
where
DB: DatabaseRef<Error = DBError>,
DBError: std::fmt::Debug + Error + Send + Sync + 'static,
{
type DBError = DBError;
}

fn run_transaction<EXT, DB: DatabaseRefDebugError>(
db: DB,
ext: EXT,
register_handles_fn: HandleRegister<EXT, WrapDatabaseRef<DB>>,
) -> anyhow::Result<(ResultAndState, DB)> {
let mut evm = Evm::builder()
.with_ref_db(db)
.with_external_context(ext)
.append_handler_register(register_handles_fn)
.build();

let result = evm.transact()?;
Ok((result, evm.into_context().evm.db.0))
}

fn run_transaction_and_commit_with_ext<EXT, DB: DatabaseRefDebugError + DatabaseCommit>(
db: DB,
ext: EXT,
register_handles_fn: HandleRegister<EXT, WrapDatabaseRef<DB>>,
) -> anyhow::Result<()> {
// To circumvent borrow checker issues, we need to move the database into the
// transaction and return it after the transaction is done.
let (ResultAndState { state: changes, .. }, mut db) =
{ run_transaction(db, ext, register_handles_fn)? };

db.commit(changes);

Ok(())
}

fn run_transaction_and_commit(db: &mut CacheDB<EmptyDB>) -> anyhow::Result<()> {
let ResultAndState { state: changes, .. } = {
let rdb = &*db;

let mut evm = Evm::builder()
.with_ref_db(rdb)
.with_external_context(NoOpInspector)
.append_handler_register(inspector_handle_register)
.build();

evm.transact()?
};

// No compiler error because there is no lifetime parameter for the `HandleRegister` function
db.commit(changes);

Ok(())
}

fn main() -> anyhow::Result<()> {
let mut cache_db = CacheDB::new(EmptyDB::default());

let mut tracer = TracerEip3155::new(Box::new(std::io::stdout()), true, true);

run_transaction_and_commit_with_ext(&mut cache_db, &mut tracer, inspector_handle_register)?;
run_transaction_and_commit(&mut cache_db)?;

Ok(())
}
Loading