use alloc::{rc::Rc, vec::Vec};
use evm_interpreter::uint::H160;
use evm_interpreter::{
EtableInterpreter, ExitError, ExitResult, Interpreter, Machine,
etable::Etable,
runtime::{RuntimeBackend, RuntimeState},
trap::CallScheme,
};
use crate::{
invoker::{InvokerControl, InvokerExit},
standard::Config,
};
#[derive(Clone, Debug, Copy, Eq, PartialEq)]
pub enum ResolverOrigin {
Substack,
Transaction,
}
pub trait Resolver<H> {
type State;
type Interpreter: Interpreter<H, State = Self::State>;
fn resolve_call(
&self,
origin: ResolverOrigin,
scheme: CallScheme,
code_address: H160,
input: Vec<u8>,
state: Self::State,
handler: &mut H,
) -> Result<InvokerControl<Self::Interpreter, Self::State>, ExitError>;
fn resolve_create(
&self,
origin: ResolverOrigin,
init_code: Vec<u8>,
state: Self::State,
handler: &mut H,
) -> Result<InvokerControl<Self::Interpreter, Self::State>, ExitError>;
}
pub trait PrecompileSet<S, H> {
fn execute(
&self,
code_address: H160,
input: &[u8],
state: &mut S,
handler: &mut H,
) -> Option<(ExitResult, Vec<u8>)>;
fn on_transaction(&self, _state: &mut S, _handler: &mut H) {}
}
impl<S, H> PrecompileSet<S, H> for () {
fn execute(
&self,
_code_address: H160,
_input: &[u8],
_state: &mut S,
_handler: &mut H,
) -> Option<(ExitResult, Vec<u8>)> {
None
}
}
pub struct EtableResolver<'precompile, 'etable, Pre, ES> {
etable: &'etable ES,
precompiles: &'precompile Pre,
}
impl<'precompile, 'etable, Pre, ES> EtableResolver<'precompile, 'etable, Pre, ES> {
pub const fn new(precompiles: &'precompile Pre, etable: &'etable ES) -> Self {
Self {
precompiles,
etable,
}
}
}
impl<'precompile, 'etable, H, Pre, ES> Resolver<H> for EtableResolver<'precompile, 'etable, Pre, ES>
where
ES::State: AsRef<RuntimeState> + AsMut<RuntimeState> + AsRef<Config>,
H: RuntimeBackend,
Pre: PrecompileSet<ES::State, H>,
ES: Etable<H>,
{
type State = ES::State;
type Interpreter = EtableInterpreter<'etable, ES::State, ES>;
fn resolve_call(
&self,
origin: ResolverOrigin,
_scheme: CallScheme,
code_address: H160,
input: Vec<u8>,
mut state: ES::State,
handler: &mut H,
) -> Result<InvokerControl<Self::Interpreter, Self::State>, ExitError> {
if origin == ResolverOrigin::Transaction {
self.precompiles.on_transaction(&mut state, handler);
}
if let Some((r, retval)) =
self.precompiles
.execute(code_address, &input, &mut state, handler)
{
return Ok(InvokerControl::DirectExit(InvokerExit {
result: r,
substate: Some(state),
retval,
}));
}
let code = handler.code(code_address);
let config: &Config = state.as_ref();
let machine = Machine::<ES::State>::new(
Rc::new(code),
Rc::new(input),
config.stack_limit(),
config.memory_limit(),
state,
);
let ret = InvokerControl::Enter(EtableInterpreter::new(machine, self.etable));
Ok(ret)
}
fn resolve_create(
&self,
origin: ResolverOrigin,
init_code: Vec<u8>,
mut state: ES::State,
handler: &mut H,
) -> Result<InvokerControl<Self::Interpreter, Self::State>, ExitError> {
if origin == ResolverOrigin::Transaction {
self.precompiles.on_transaction(&mut state, handler);
}
let config: &Config = state.as_ref();
let machine = Machine::new(
Rc::new(init_code),
Rc::new(Vec::new()),
config.stack_limit(),
config.memory_limit(),
state,
);
let ret = InvokerControl::Enter(EtableInterpreter::new(machine, self.etable));
Ok(ret)
}
}