Skip to content

Commit

Permalink
refactor: decouple EvmContext and Database lifetimes
Browse files Browse the repository at this point in the history
Once dynamic trait object upcasting is supported in Rust, this should
be updated to pass the Database trait object directly to the EvmImpl
  • Loading branch information
Wodann committed Dec 28, 2023
1 parent 23cbac4 commit c0209bf
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 119 deletions.
13 changes: 8 additions & 5 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl<DB: Database + DatabaseCommit> EVM<DB> {
}

/// Inspect transaction and commit changes to database.
pub fn inspect_commit<INSP: Inspector<DB>>(
pub fn inspect_commit<INSP: Inspector<DB::Error>>(
&mut self,
inspector: INSP,
) -> Result<ExecutionResult, EVMError<DB::Error>> {
Expand Down Expand Up @@ -103,7 +103,10 @@ impl<DB: Database> EVM<DB> {
}

/// Execute transaction with given inspector, without wring to DB. Return change state.
pub fn inspect<INSP: Inspector<DB>>(&mut self, mut inspector: INSP) -> EVMResult<DB::Error> {
pub fn inspect<INSP: Inspector<DB::Error>>(
&mut self,
mut inspector: INSP,
) -> EVMResult<DB::Error> {
if let Some(db) = self.db.as_mut() {
evm_inner::<DB, true>(&mut self.env, db, &mut inspector).transact()
} else {
Expand Down Expand Up @@ -157,7 +160,7 @@ impl<'a, DB: DatabaseRef> EVM<DB> {
}

/// Execute transaction with given inspector, without wring to DB. Return change state.
pub fn inspect_ref<I: Inspector<WrapDatabaseRef<&'a DB>>>(
pub fn inspect_ref<I: Inspector<DB::Error>>(
&'a self,
mut inspector: I,
) -> EVMResult<DB::Error> {
Expand Down Expand Up @@ -201,11 +204,11 @@ impl<DB> EVM<DB> {
pub fn evm_inner<'a, DB: Database, const INSPECT: bool>(
env: &'a mut Env,
db: &'a mut DB,
insp: &'a mut dyn Inspector<DB>,
insp: &'a mut dyn Inspector<DB::Error>,
) -> Box<dyn Transact<DB::Error> + 'a> {
macro_rules! create_evm {
($spec:ident) => {
Box::new(EVMImpl::<'a, $spec, DB, INSPECT>::new(
Box::new(EVMImpl::<'a, $spec, DB::Error, INSPECT>::new(
db,
env,
insp,
Expand Down
66 changes: 36 additions & 30 deletions crates/revm/src/evm_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ use revm_precompile::{Precompile, Precompiles};
#[cfg(feature = "optimism")]
use crate::optimism;

pub struct EVMData<'a, DB: Database> {
pub struct EVMData<'a, DatabaseErrorT> {
pub env: &'a mut Env,
pub journaled_state: JournaledState,
pub db: &'a mut DB,
pub error: Option<DB::Error>,
pub db: &'a mut dyn Database<Error = DatabaseErrorT>,
pub error: Option<DatabaseErrorT>,
pub precompiles: Precompiles,
/// Used as temporary value holder to store L1 block info.
#[cfg(feature = "optimism")]
pub l1_block_info: Option<optimism::L1BlockInfo>,
}

pub struct EVMImpl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> {
data: EVMData<'a, DB>,
inspector: &'a mut dyn Inspector<DB>,
handler: Handler<DB>,
pub struct EVMImpl<'a, GSPEC: Spec, DatabaseErrorT, const INSPECT: bool> {
data: EVMData<'a, DatabaseErrorT>,
inspector: &'a mut dyn Inspector<DatabaseErrorT>,
handler: Handler<DatabaseErrorT>,
_phantomdata: PhantomData<GSPEC>,
}

Expand Down Expand Up @@ -80,12 +80,12 @@ pub trait Transact<DBError> {
}
}

impl<'a, DB: Database> EVMData<'a, DB> {
impl<'a, DatabaseErrorT> EVMData<'a, DatabaseErrorT> {
/// Load access list for berlin hardfork.
///
/// Loading of accounts/storages is needed to make them warm.
#[inline]
fn load_access_list(&mut self) -> Result<(), EVMError<DB::Error>> {
fn load_access_list(&mut self) -> Result<(), EVMError<DatabaseErrorT>> {
for (address, slots) in self.env.tx.access_list.iter() {
self.journaled_state
.initial_account_load(*address, slots, self.db)
Expand All @@ -96,16 +96,18 @@ impl<'a, DB: Database> EVMData<'a, DB> {
}

#[cfg(feature = "optimism")]
impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> {
impl<'a, GSPEC: Spec, DatabaseErrorT, const INSPECT: bool>
EVMImpl<'a, GSPEC, DatabaseErrorT, INSPECT>
{
/// If the transaction is not a deposit transaction, subtract the L1 data fee from the
/// caller's balance directly after minting the requested amount of ETH.
fn remove_l1_cost(
fn remove_l1_cost<DB: Database<Error = DatabaseErrorT> + ?Sized>(
is_deposit: bool,
tx_caller: Address,
l1_cost: U256,
db: &mut DB,
journal: &mut JournaledState,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
if is_deposit {
return Ok(());
}
Expand Down Expand Up @@ -133,12 +135,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
/// If the transaction is a deposit with a `mint` value, add the mint value
/// in wei to the caller's balance. This should be persisted to the database
/// prior to the rest of execution.
fn commit_mint_value(
fn commit_mint_value<DB: Database<Error = DatabaseErrorT> + ?Sized>(
tx_caller: Address,
tx_mint: Option<u128>,
db: &mut DB,
journal: &mut JournaledState,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
if let Some(mint) = tx_mint {
journal
.load_account(tx_caller, db)
Expand All @@ -152,10 +154,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
}
}

impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
for EVMImpl<'a, GSPEC, DB, INSPECT>
impl<'a, GSPEC: Spec, DatabaseErrorT, const INSPECT: bool> Transact<DatabaseErrorT>
for EVMImpl<'a, GSPEC, DatabaseErrorT, INSPECT>
{
fn preverify_transaction(&mut self) -> Result<(), EVMError<DB::Error>> {
fn preverify_transaction(&mut self) -> Result<(), EVMError<DatabaseErrorT>> {
let env = self.env();

// Important: validate block before tx.
Expand Down Expand Up @@ -187,7 +189,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
.map_err(Into::into)
}

fn transact_preverified(&mut self) -> EVMResult<DB::Error> {
fn transact_preverified(&mut self) -> EVMResult<DatabaseErrorT> {
let env = &self.data.env;
let tx_caller = env.tx.caller;
let tx_value = env.tx.value;
Expand Down Expand Up @@ -246,15 +248,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>

#[cfg(feature = "optimism")]
if self.data.env.cfg.optimism {
EVMImpl::<GSPEC, DB, INSPECT>::commit_mint_value(
EVMImpl::<GSPEC, DatabaseErrorT, INSPECT>::commit_mint_value(
tx_caller,
self.data.env.tx.optimism.mint,
self.data.db,
journal,
)?;

let is_deposit = self.data.env.tx.optimism.source_hash.is_some();
EVMImpl::<GSPEC, DB, INSPECT>::remove_l1_cost(
EVMImpl::<GSPEC, DatabaseErrorT, INSPECT>::remove_l1_cost(
is_deposit,
tx_caller,
tx_l1_cost,
Expand Down Expand Up @@ -394,11 +396,13 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
}
}

impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> {
pub fn new(
impl<'a, GSPEC: Spec, DatabaseErrorT, const INSPECT: bool>
EVMImpl<'a, GSPEC, DatabaseErrorT, INSPECT>
{
pub fn new<DB: Database<Error = DatabaseErrorT>>(
db: &'a mut DB,
env: &'a mut Env,
inspector: &'a mut dyn Inspector<DB>,
inspector: &'a mut dyn Inspector<DatabaseErrorT>,
precompiles: Precompiles,
) -> Self {
let journaled_state = JournaledState::new(precompiles.len(), GSPEC::SPEC_ID);
Expand Down Expand Up @@ -819,8 +823,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
}
}

impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host
for EVMImpl<'a, GSPEC, DB, INSPECT>
impl<'a, GSPEC: Spec, DatabaseErrorT, const INSPECT: bool> Host
for EVMImpl<'a, GSPEC, DatabaseErrorT, INSPECT>
{
fn step(&mut self, interp: &mut Interpreter) -> InstructionResult {
self.inspector.step(interp, &mut self.data)
Expand Down Expand Up @@ -1000,6 +1004,8 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host
#[cfg(feature = "optimism")]
#[cfg(test)]
mod tests {
use core::convert::Infallible;

use super::*;

use crate::db::InMemoryDB;
Expand All @@ -1024,7 +1030,7 @@ mod tests {
.initial_account_load(caller, &[U256::from(100)], &mut db)
.unwrap();
assert!(
EVMImpl::<BedrockSpec, InMemoryDB, false>::commit_mint_value(
EVMImpl::<BedrockSpec, Infallible, false>::commit_mint_value(
caller,
mint_value,
&mut db,
Expand All @@ -1039,7 +1045,7 @@ mod tests {

// No mint value should be a no-op.
assert!(
EVMImpl::<BedrockSpec, InMemoryDB, false>::commit_mint_value(
EVMImpl::<BedrockSpec, Infallible, false>::commit_mint_value(
caller,
None,
&mut db,
Expand All @@ -1060,7 +1066,7 @@ mod tests {
journal
.initial_account_load(caller, slots, &mut db)
.unwrap();
assert!(EVMImpl::<BedrockSpec, InMemoryDB, false>::remove_l1_cost(
assert!(EVMImpl::<BedrockSpec, Infallible, false>::remove_l1_cost(
true,
caller,
U256::ZERO,
Expand All @@ -1087,7 +1093,7 @@ mod tests {
journal
.initial_account_load(caller, &[U256::from(100)], &mut db)
.unwrap();
assert!(EVMImpl::<BedrockSpec, InMemoryDB, false>::remove_l1_cost(
assert!(EVMImpl::<BedrockSpec, Infallible, false>::remove_l1_cost(
false,
caller,
U256::from(1),
Expand Down Expand Up @@ -1119,7 +1125,7 @@ mod tests {
.initial_account_load(caller, &[U256::from(100)], &mut db)
.unwrap();
assert_eq!(
EVMImpl::<BedrockSpec, InMemoryDB, false>::remove_l1_cost(
EVMImpl::<BedrockSpec, Infallible, false>::remove_l1_cost(
false,
caller,
U256::from(101),
Expand Down
31 changes: 15 additions & 16 deletions crates/revm/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ pub mod mainnet;
#[cfg(feature = "optimism")]
pub mod optimism;

use revm_interpreter::primitives::db::Database;
use revm_interpreter::primitives::{EVMError, EVMResultGeneric};

use crate::interpreter::{Gas, InstructionResult};
Expand All @@ -13,35 +12,35 @@ use crate::EVMData;
type CallReturnHandle = fn(&Env, InstructionResult, Gas) -> Gas;

/// Reimburse the caller with ethereum it didn't spent.
type ReimburseCallerHandle<DB> =
fn(&mut EVMData<'_, DB>, &Gas, u64) -> EVMResultGeneric<(), <DB as Database>::Error>;
type ReimburseCallerHandle<DatabaseErrorT> =
fn(&mut EVMData<'_, DatabaseErrorT>, &Gas, u64) -> EVMResultGeneric<(), DatabaseErrorT>;

/// Reward beneficiary with transaction rewards.
type RewardBeneficiaryHandle<DB> = ReimburseCallerHandle<DB>;
type RewardBeneficiaryHandle<DatabaseErrorT> = ReimburseCallerHandle<DatabaseErrorT>;

/// Calculate gas refund for transaction.
type CalculateGasRefundHandle = fn(&Env, &Gas) -> u64;

/// Handler acts as a proxy and allow to define different behavior for different
/// sections of the code. This allows nice integration of different chains or
/// to disable some mainnet behavior.
pub struct Handler<DB: Database> {
pub struct Handler<DatabaseErrorT> {
// Uses env, call resul and returned gas from the call to determine the gas
// that is returned from transaction execution..
pub call_return: CallReturnHandle,
pub reimburse_caller: ReimburseCallerHandle<DB>,
pub reward_beneficiary: RewardBeneficiaryHandle<DB>,
pub reimburse_caller: ReimburseCallerHandle<DatabaseErrorT>,
pub reward_beneficiary: RewardBeneficiaryHandle<DatabaseErrorT>,
pub calculate_gas_refund: CalculateGasRefundHandle,
}

impl<DB: Database> Handler<DB> {
impl<DatabaseErrorT> Handler<DatabaseErrorT> {
/// Handler for the mainnet
pub fn mainnet<SPEC: Spec>() -> Self {
Self {
call_return: mainnet::handle_call_return::<SPEC>,
calculate_gas_refund: mainnet::calculate_gas_refund::<SPEC>,
reimburse_caller: mainnet::handle_reimburse_caller::<SPEC, DB>,
reward_beneficiary: mainnet::reward_beneficiary::<SPEC, DB>,
reimburse_caller: mainnet::handle_reimburse_caller::<SPEC, DatabaseErrorT>,
reward_beneficiary: mainnet::reward_beneficiary::<SPEC, DatabaseErrorT>,
}
}

Expand All @@ -52,9 +51,9 @@ impl<DB: Database> Handler<DB> {
call_return: optimism::handle_call_return::<SPEC>,
// we reinburse caller the same was as in mainnet.
// Refund is calculated differently then mainnet.
reimburse_caller: mainnet::handle_reimburse_caller::<SPEC, DB>,
reimburse_caller: mainnet::handle_reimburse_caller::<SPEC, DatabaseErrorT>,
calculate_gas_refund: optimism::calculate_gas_refund::<SPEC>,
reward_beneficiary: optimism::reward_beneficiary::<SPEC, DB>,
reward_beneficiary: optimism::reward_beneficiary::<SPEC, DatabaseErrorT>,
}
}

Expand All @@ -66,10 +65,10 @@ impl<DB: Database> Handler<DB> {
/// Reimburse the caller with gas that were not spend.
pub fn reimburse_caller(
&self,
data: &mut EVMData<'_, DB>,
data: &mut EVMData<'_, DatabaseErrorT>,
gas: &Gas,
gas_refund: u64,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
(self.reimburse_caller)(data, gas, gas_refund)
}

Expand All @@ -81,10 +80,10 @@ impl<DB: Database> Handler<DB> {
/// Reward beneficiary
pub fn reward_beneficiary(
&self,
data: &mut EVMData<'_, DB>,
data: &mut EVMData<'_, DatabaseErrorT>,
gas: &Gas,
gas_refund: u64,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
(self.reward_beneficiary)(data, gas, gas_refund)
}
}
14 changes: 7 additions & 7 deletions crates/revm/src/handler/mainnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use revm_interpreter::primitives::EVMError;

use crate::{
interpreter::{return_ok, return_revert, Gas, InstructionResult},
primitives::{db::Database, Env, Spec, SpecId::LONDON, U256},
primitives::{Env, Spec, SpecId::LONDON, U256},
EVMData,
};

Expand Down Expand Up @@ -32,11 +32,11 @@ pub fn handle_call_return<SPEC: Spec>(
}

#[inline]
pub fn handle_reimburse_caller<SPEC: Spec, DB: Database>(
data: &mut EVMData<'_, DB>,
pub fn handle_reimburse_caller<SPEC: Spec, DatabaseErrorT>(
data: &mut EVMData<'_, DatabaseErrorT>,
gas: &Gas,
gas_refund: u64,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
let _ = data;
let caller = data.env.tx.caller;
let effective_gas_price = data.env.effective_gas_price();
Expand All @@ -57,11 +57,11 @@ pub fn handle_reimburse_caller<SPEC: Spec, DB: Database>(

/// Reward beneficiary with gas fee.
#[inline]
pub fn reward_beneficiary<SPEC: Spec, DB: Database>(
data: &mut EVMData<'_, DB>,
pub fn reward_beneficiary<SPEC: Spec, DatabaseErrorT>(
data: &mut EVMData<'_, DatabaseErrorT>,
gas: &Gas,
gas_refund: u64,
) -> Result<(), EVMError<DB::Error>> {
) -> Result<(), EVMError<DatabaseErrorT>> {
let beneficiary = data.env.block.coinbase;
let effective_gas_price = data.env.effective_gas_price();

Expand Down
Loading

0 comments on commit c0209bf

Please sign in to comment.