use core::convert::Infallible;
use revm::{
primitives::{EVMError, ResultAndState},
Database, DatabaseCommit,
};
use std::format;
use crate::{
Block, Cfg, EvmErrored, EvmNeedsBlock, EvmNeedsCfg, EvmNeedsTx, EvmReady, EvmTransacted, Tx,
};
pub trait DbConnect<'a>: Sync {
type Database: Database + DatabaseCommit;
type Error: core::error::Error;
fn connect(&'a self) -> Result<Self::Database, Self::Error>;
}
impl<Db> DbConnect<'_> for Db
where
Db: Database + DatabaseCommit + Clone + Sync,
{
type Database = Self;
type Error = Infallible;
fn connect(&self) -> Result<Self::Database, Self::Error> {
Ok(self.clone())
}
}
pub trait EvmFactory<'a>: DbConnect<'a> {
type Ext: Sync;
fn create(&'a self) -> Result<EvmNeedsCfg<'a, Self::Ext, Self::Database>, Self::Error>;
fn create_with_cfg<C>(
&'a self,
cfg: &C,
) -> Result<EvmNeedsBlock<'a, Self::Ext, Self::Database>, Self::Error>
where
C: Cfg,
{
self.create().map(|evm| evm.fill_cfg(cfg))
}
fn create_with_block<C, B>(
&'a self,
cfg: &C,
block: &B,
) -> Result<EvmNeedsTx<'a, Self::Ext, Self::Database>, Self::Error>
where
C: Cfg,
B: Block,
{
self.create_with_cfg(cfg).map(|evm| evm.fill_block(block))
}
fn create_with_tx<C, B, T>(
&'a self,
cfg: &C,
block: &B,
tx: &T,
) -> Result<EvmReady<'a, Self::Ext, Self::Database>, Self::Error>
where
C: Cfg,
B: Block,
T: Tx,
{
self.create_with_block(cfg, block).map(|evm| evm.fill_tx(tx))
}
#[allow(clippy::type_complexity)]
fn transact<C, B, T>(
&'a self,
cfg: &C,
block: &B,
tx: &T,
) -> Result<
Result<
EvmTransacted<'a, Self::Ext, Self::Database>,
EvmErrored<'a, Self::Ext, Self::Database>,
>,
Self::Error,
>
where
C: Cfg,
B: Block,
T: Tx,
{
let evm = self.create_with_tx(cfg, block, tx)?;
Ok(evm.run())
}
fn run<C, B, T>(
&'a self,
cfg: &C,
block: &B,
tx: &T,
) -> Result<ResultAndState, EVMError<<Self::Database as Database>::Error>>
where
C: Cfg,
B: Block,
T: Tx,
{
let trevm = self.transact(cfg, block, tx).map_err(|e| EVMError::Custom(format!("{e}")))?;
match trevm {
Ok(t) => Ok(t.into_result_and_state()),
Err(t) => Err(t.into_error()),
}
}
}