example_database_ref/
main.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Optimism-specific constants, types, and helpers.
#![cfg_attr(not(test), warn(unused_crate_dependencies))]

use core::error::Error;
use core::fmt::Debug;
use database::CacheDB;
use inspector::{
    inspector_handle_register,
    inspectors::{NoOpInspector, TracerEip3155},
};
use revm::{
    database_interface::{EmptyDB, WrapDatabaseRef},
    handler::register::HandleRegister,
    wiring::{
        result::{HaltReason, ResultAndState},
        EthereumWiring,
    },
    DatabaseCommit, DatabaseRef, Evm,
};

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: Debug, DB: DatabaseRefDebugError>(
    db: DB,
    ext: EXT,
    register_handles_fn: HandleRegister<EthereumWiring<WrapDatabaseRef<DB>, EXT>>,
) -> anyhow::Result<(ResultAndState<HaltReason>, DB)> {
    let mut evm = Evm::<EthereumWiring<_, _>>::builder()
        .with_db(WrapDatabaseRef(db))
        .with_external_context(ext)
        .append_handler_register(register_handles_fn)
        .build();

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

fn run_transaction_and_commit_with_ext<EXT: Debug, DB: DatabaseRefDebugError + DatabaseCommit>(
    db: DB,
    ext: EXT,
    register_handles_fn: HandleRegister<EthereumWiring<WrapDatabaseRef<DB>, EXT>>,
) -> 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::<EthereumWiring<_, _>>::builder()
            .with_db(WrapDatabaseRef(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()));

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

    Ok(())
}