mod handle_types;
pub mod mainnet;
pub mod register;
pub use handle_types::*;
use crate::{
interpreter::{opcode::InstructionTables, Host, InterpreterAction, SharedMemory},
primitives::{db::Database, spec_to_generic, EVMError, HandlerCfg, Spec, SpecId},
Context, Frame,
};
use core::mem;
use register::{EvmHandler, HandleRegisters};
use std::vec::Vec;
use self::register::{HandleRegister, HandleRegisterBox};
pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> {
pub cfg: HandlerCfg,
pub instruction_table: InstructionTables<'a, H>,
pub registers: Vec<HandleRegisters<'a, EXT, DB>>,
pub validation: ValidationHandler<'a, EXT, DB>,
pub pre_execution: PreExecutionHandler<'a, EXT, DB>,
pub post_execution: PostExecutionHandler<'a, EXT, DB>,
pub execution: ExecutionHandler<'a, EXT, DB>,
}
impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
pub fn new(cfg: HandlerCfg) -> Self {
cfg_if::cfg_if! {
if #[cfg(feature = "optimism")] {
if cfg.is_optimism {
Handler::optimism_with_spec(cfg.spec_id)
} else {
Handler::mainnet_with_spec(cfg.spec_id)
}
} else {
Handler::mainnet_with_spec(cfg.spec_id)
}
}
}
pub fn mainnet<SPEC: Spec>() -> Self {
Self {
cfg: HandlerCfg::new(SPEC::SPEC_ID),
instruction_table: InstructionTables::new_plain::<SPEC>(),
registers: Vec::new(),
validation: ValidationHandler::new::<SPEC>(),
pre_execution: PreExecutionHandler::new::<SPEC>(),
post_execution: PostExecutionHandler::new::<SPEC>(),
execution: ExecutionHandler::new::<SPEC>(),
}
}
pub fn is_optimism(&self) -> bool {
self.cfg.is_optimism()
}
#[cfg(feature = "optimism")]
pub fn optimism<SPEC: Spec>() -> Self {
let mut handler = Self::mainnet::<SPEC>();
handler.cfg.is_optimism = true;
handler.append_handler_register(HandleRegisters::Plain(
crate::optimism::optimism_handle_register::<DB, EXT>,
));
handler
}
#[cfg(feature = "optimism")]
pub fn optimism_with_spec(spec_id: SpecId) -> Self {
spec_to_generic!(spec_id, Self::optimism::<SPEC>())
}
pub fn mainnet_with_spec(spec_id: SpecId) -> Self {
spec_to_generic!(spec_id, Self::mainnet::<SPEC>())
}
pub fn cfg(&self) -> HandlerCfg {
self.cfg
}
pub fn spec_id(&self) -> SpecId {
self.cfg.spec_id
}
pub fn execute_frame(
&self,
frame: &mut Frame,
shared_memory: &mut SharedMemory,
context: &mut Context<EXT, DB>,
) -> Result<InterpreterAction, EVMError<DB::Error>> {
self.execution
.execute_frame(frame, shared_memory, &self.instruction_table, context)
}
pub fn take_instruction_table(&mut self) -> InstructionTables<'a, Context<EXT, DB>> {
let spec_id = self.spec_id();
mem::replace(
&mut self.instruction_table,
spec_to_generic!(spec_id, InstructionTables::new_plain::<SPEC>()),
)
}
pub fn set_instruction_table(&mut self, table: InstructionTables<'a, Context<EXT, DB>>) {
self.instruction_table = table;
}
pub fn pre_execution(&self) -> &PreExecutionHandler<'a, EXT, DB> {
&self.pre_execution
}
pub fn post_execution(&self) -> &PostExecutionHandler<'a, EXT, DB> {
&self.post_execution
}
pub fn execution(&self) -> &ExecutionHandler<'a, EXT, DB> {
&self.execution
}
pub fn validation(&self) -> &ValidationHandler<'a, EXT, DB> {
&self.validation
}
pub fn append_handler_register(&mut self, register: HandleRegisters<'a, EXT, DB>) {
register.register(self);
self.registers.push(register);
}
pub fn append_handler_register_plain(&mut self, register: HandleRegister<EXT, DB>) {
register(self);
self.registers.push(HandleRegisters::Plain(register));
}
pub fn append_handler_register_box(&mut self, register: HandleRegisterBox<'a, EXT, DB>) {
register(self);
self.registers.push(HandleRegisters::Box(register));
}
pub fn pop_handle_register(&mut self) -> Option<HandleRegisters<'a, EXT, DB>> {
let out = self.registers.pop();
if out.is_some() {
let registers = core::mem::take(&mut self.registers);
let mut base_handler = Handler::mainnet_with_spec(self.cfg.spec_id);
for register in registers {
base_handler.append_handler_register(register)
}
*self = base_handler;
}
out
}
pub fn create_handle_generic<SPEC: Spec>(&mut self) -> EvmHandler<'a, EXT, DB> {
let registers = core::mem::take(&mut self.registers);
let mut base_handler = Handler::mainnet::<SPEC>();
for register in registers {
base_handler.append_handler_register(register)
}
base_handler
}
pub fn modify_spec_id(&mut self, spec_id: SpecId) {
if self.cfg.spec_id == spec_id {
return;
}
let registers = core::mem::take(&mut self.registers);
let mut handler = Handler::mainnet_with_spec(spec_id);
for register in registers {
handler.append_handler_register(register)
}
handler.cfg = self.cfg();
handler.cfg.spec_id = spec_id;
*self = handler;
}
}
#[cfg(test)]
mod test {
use core::cell::RefCell;
use crate::{db::EmptyDB, primitives::EVMError};
use std::{rc::Rc, sync::Arc};
use super::*;
#[test]
fn test_handler_register_pop() {
let register = |inner: &Rc<RefCell<i32>>| -> HandleRegisterBox<'_, (), EmptyDB> {
let inner = inner.clone();
Box::new(move |h| {
*inner.borrow_mut() += 1;
h.post_execution.output = Arc::new(|_, _| Err(EVMError::Custom("test".to_string())))
})
};
let mut handler = EvmHandler::<(), EmptyDB>::new(HandlerCfg::new(SpecId::LATEST));
let test = Rc::new(RefCell::new(0));
handler.append_handler_register_box(register(&test));
assert_eq!(*test.borrow(), 1);
handler.append_handler_register_box(register(&test));
assert_eq!(*test.borrow(), 2);
assert!(handler.pop_handle_register().is_some());
assert_eq!(*test.borrow(), 3);
}
}