use crate::{
frame::EthFrame, instructions::InstructionProvider, Handler, MainnetHandler, PrecompileProvider,
};
use context::{
result::{
EVMError, ExecResultAndState, ExecutionResult, HaltReason, InvalidTransaction,
ResultAndState, ResultVecAndState, TransactionIndexedError,
},
Block, ContextSetters, ContextTr, Database, Evm, JournalTr, Transaction,
};
#[cfg(feature = "asyncdb")]
use database_interface::async_db::{on_fiber_result_with_stack, AsyncResult};
use database_interface::DatabaseCommit;
use interpreter::{interpreter::EthInterpreter, InterpreterResult};
use state::EvmState;
#[cfg(feature = "asyncdb")]
use std::ptr::NonNull;
use std::vec::Vec;
type TransactManyFinalizeResult<ExecutionResult, State, Error> =
Result<ResultVecAndState<ExecutionResult, State>, TransactionIndexedError<Error>>;
pub trait ExecuteEvm {
type ExecutionResult;
type State;
type Error;
type Tx: Transaction;
type Block: Block;
fn set_block(&mut self, block: Self::Block);
fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error>;
fn finalize(&mut self) -> Self::State;
#[inline]
fn transact(
&mut self,
tx: Self::Tx,
) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
let output_or_error = self.transact_one(tx);
let state = self.finalize();
let output = output_or_error?;
Ok(ExecResultAndState::new(output, state))
}
#[inline]
fn transact_many(
&mut self,
txs: impl Iterator<Item = Self::Tx>,
) -> Result<Vec<Self::ExecutionResult>, TransactionIndexedError<Self::Error>> {
let (lower, _) = txs.size_hint();
let mut outputs = Vec::with_capacity(lower);
for (index, tx) in txs.enumerate() {
outputs.push(
self.transact_one(tx)
.inspect_err(|_| {
let _ = self.finalize();
})
.map_err(|error| TransactionIndexedError::new(error, index))?,
);
}
Ok(outputs)
}
#[inline]
fn transact_many_finalize(
&mut self,
txs: impl Iterator<Item = Self::Tx>,
) -> TransactManyFinalizeResult<Self::ExecutionResult, Self::State, Self::Error> {
let result = self.transact_many(txs)?;
let state = self.finalize();
Ok(ExecResultAndState::new(result, state))
}
fn replay(
&mut self,
) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>;
}
pub trait ExecuteCommitEvm: ExecuteEvm {
fn commit(&mut self, state: Self::State);
#[inline]
fn commit_inner(&mut self) {
let state = self.finalize();
self.commit(state);
}
#[inline]
fn transact_commit(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
let output = self.transact_one(tx).inspect_err(|_| {
let _ = self.finalize();
})?;
self.commit_inner();
Ok(output)
}
#[inline]
fn transact_many_commit(
&mut self,
txs: impl Iterator<Item = Self::Tx>,
) -> Result<Vec<Self::ExecutionResult>, TransactionIndexedError<Self::Error>> {
let outputs = self.transact_many(txs)?;
self.commit_inner();
Ok(outputs)
}
#[inline]
fn replay_commit(&mut self) -> Result<Self::ExecutionResult, Self::Error> {
let result = self.replay()?;
self.commit(result.state);
Ok(result.result)
}
}
#[cfg(feature = "asyncdb")]
pub trait ExecuteEvmAsync: ExecuteEvm {
fn transact_one_async(
&mut self,
tx: Self::Tx,
) -> impl core::future::Future<Output = AsyncResult<Self::ExecutionResult, Self::Error>> + Send + '_;
fn transact_async(
&mut self,
tx: Self::Tx,
) -> impl core::future::Future<
Output = AsyncResult<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>,
> + Send
+ '_;
}
impl<CTX, INSP, INST, PRECOMPILES> ExecuteEvm
for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
where
CTX: ContextTr<Journal: JournalTr<State = EvmState>> + ContextSetters,
INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
{
type ExecutionResult = ExecutionResult<HaltReason>;
type State = EvmState;
type Error = EVMError<<CTX::Db as Database>::Error, InvalidTransaction>;
type Tx = <CTX as ContextTr>::Tx;
type Block = <CTX as ContextTr>::Block;
#[inline]
fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
self.ctx.set_tx(tx);
MainnetHandler::default().run(self)
}
#[inline]
fn finalize(&mut self) -> Self::State {
self.journal_mut().finalize()
}
#[inline]
fn set_block(&mut self, block: Self::Block) {
self.ctx.set_block(block);
}
#[inline]
fn replay(&mut self) -> Result<ResultAndState<HaltReason>, Self::Error> {
MainnetHandler::default()
.run(self)
.inspect_err(|_| {
let _ = self.finalize();
})
.map(|result| {
let state = self.finalize();
ResultAndState::new(result, state)
})
}
}
#[cfg(feature = "asyncdb")]
impl<CTX, INSP, INST, PRECOMPILES> ExecuteEvmAsync
for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
where
CTX: ContextTr<Journal: JournalTr<State = EvmState>> + ContextSetters,
INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
ExecutionResult<HaltReason>: Send,
EvmState: Send,
EVMError<<CTX::Db as Database>::Error, InvalidTransaction>: Send,
<CTX as ContextTr>::Tx: Send,
{
#[inline]
fn transact_one_async(
&mut self,
tx: Self::Tx,
) -> impl core::future::Future<Output = AsyncResult<Self::ExecutionResult, Self::Error>> + Send + '_
{
let stack = NonNull::from(&mut self.async_stack);
unsafe { on_fiber_result_with_stack(stack, move || self.transact_one(tx)) }
}
#[inline]
fn transact_async(
&mut self,
tx: Self::Tx,
) -> impl core::future::Future<
Output = AsyncResult<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>,
> + Send
+ '_ {
let stack = NonNull::from(&mut self.async_stack);
unsafe { on_fiber_result_with_stack(stack, move || self.transact(tx)) }
}
}
impl<CTX, INSP, INST, PRECOMPILES> ExecuteCommitEvm
for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
where
CTX: ContextTr<Journal: JournalTr<State = EvmState>, Db: DatabaseCommit> + ContextSetters,
INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
{
#[inline]
fn commit(&mut self, state: Self::State) {
self.db_mut().commit(state);
}
}