revm/
handler.rs

1// Modules.
2mod handle_types;
3pub mod mainnet;
4pub mod register;
5
6// Exports.
7pub use handle_types::*;
8
9// Includes.
10use crate::{
11    interpreter::{opcode::InstructionTables, Host, InterpreterAction, SharedMemory},
12    primitives::{db::Database, spec_to_generic, EVMError, HandlerCfg, Spec, SpecId},
13    Context, Frame,
14};
15use core::mem;
16use register::{EvmHandler, HandleRegisters};
17use std::vec::Vec;
18
19use self::register::{HandleRegister, HandleRegisterBox};
20
21/// Handler acts as a proxy and allow to define different behavior for different
22/// sections of the code. This allows nice integration of different chains or
23/// to disable some mainnet behavior.
24pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> {
25    /// Handler configuration.
26    pub cfg: HandlerCfg,
27    /// Instruction table type.
28    pub instruction_table: InstructionTables<'a, H>,
29    /// Registers that will be called on initialization.
30    pub registers: Vec<HandleRegisters<'a, EXT, DB>>,
31    /// Validity handles.
32    pub validation: ValidationHandler<'a, EXT, DB>,
33    /// Pre execution handle.
34    pub pre_execution: PreExecutionHandler<'a, EXT, DB>,
35    /// Post Execution handle.
36    pub post_execution: PostExecutionHandler<'a, EXT, DB>,
37    /// Execution loop that handles frames.
38    pub execution: ExecutionHandler<'a, EXT, DB>,
39}
40
41impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
42    /// Created new Handler with given configuration.
43    ///
44    /// Internally it calls `mainnet_with_spec` with the given spec id.
45    /// Or `optimism_with_spec` if the optimism feature is enabled and `cfg.is_optimism` is set.
46    pub fn new(cfg: HandlerCfg) -> Self {
47        cfg_if::cfg_if! {
48            if #[cfg(feature = "optimism")] {
49                if cfg.is_optimism {
50                    Handler::optimism_with_spec(cfg.spec_id)
51                } else {
52                    Handler::mainnet_with_spec(cfg.spec_id)
53                }
54            } else {
55                Handler::mainnet_with_spec(cfg.spec_id)
56            }
57        }
58    }
59
60    /// Default handler for Ethereum mainnet.
61    pub fn mainnet<SPEC: Spec>() -> Self {
62        Self {
63            cfg: HandlerCfg::new(SPEC::SPEC_ID),
64            instruction_table: InstructionTables::new_plain::<SPEC>(),
65            registers: Vec::new(),
66            validation: ValidationHandler::new::<SPEC>(),
67            pre_execution: PreExecutionHandler::new::<SPEC>(),
68            post_execution: PostExecutionHandler::new::<SPEC>(),
69            execution: ExecutionHandler::new::<SPEC>(),
70        }
71    }
72
73    /// Returns `true` if the optimism feature is enabled and flag is set to `true`.
74    pub fn is_optimism(&self) -> bool {
75        self.cfg.is_optimism()
76    }
77
78    /// Handler for optimism
79    #[cfg(feature = "optimism")]
80    pub fn optimism<SPEC: Spec>() -> Self {
81        let mut handler = Self::mainnet::<SPEC>();
82        handler.cfg.is_optimism = true;
83        handler.append_handler_register(HandleRegisters::Plain(
84            crate::optimism::optimism_handle_register::<DB, EXT>,
85        ));
86        handler
87    }
88
89    /// Optimism with spec. Similar to [`Self::mainnet_with_spec`].
90    #[cfg(feature = "optimism")]
91    pub fn optimism_with_spec(spec_id: SpecId) -> Self {
92        spec_to_generic!(spec_id, Self::optimism::<SPEC>())
93    }
94
95    /// Creates handler with variable spec id, inside it will call `mainnet::<SPEC>` for
96    /// appropriate spec.
97    pub fn mainnet_with_spec(spec_id: SpecId) -> Self {
98        spec_to_generic!(spec_id, Self::mainnet::<SPEC>())
99    }
100
101    /// Specification ID.
102    pub fn cfg(&self) -> HandlerCfg {
103        self.cfg
104    }
105
106    /// Returns specification ID.
107    pub fn spec_id(&self) -> SpecId {
108        self.cfg.spec_id
109    }
110
111    /// Executes call frame.
112    pub fn execute_frame(
113        &self,
114        frame: &mut Frame,
115        shared_memory: &mut SharedMemory,
116        context: &mut Context<EXT, DB>,
117    ) -> Result<InterpreterAction, EVMError<DB::Error>> {
118        self.execution
119            .execute_frame(frame, shared_memory, &self.instruction_table, context)
120    }
121
122    /// Take instruction table.
123    pub fn take_instruction_table(&mut self) -> InstructionTables<'a, Context<EXT, DB>> {
124        let spec_id = self.spec_id();
125        mem::replace(
126            &mut self.instruction_table,
127            spec_to_generic!(spec_id, InstructionTables::new_plain::<SPEC>()),
128        )
129    }
130
131    /// Set instruction table.
132    pub fn set_instruction_table(&mut self, table: InstructionTables<'a, Context<EXT, DB>>) {
133        self.instruction_table = table;
134    }
135
136    /// Returns reference to pre execution handler.
137    pub fn pre_execution(&self) -> &PreExecutionHandler<'a, EXT, DB> {
138        &self.pre_execution
139    }
140
141    /// Returns reference to pre execution handler.
142    pub fn post_execution(&self) -> &PostExecutionHandler<'a, EXT, DB> {
143        &self.post_execution
144    }
145
146    /// Returns reference to frame handler.
147    pub fn execution(&self) -> &ExecutionHandler<'a, EXT, DB> {
148        &self.execution
149    }
150
151    /// Returns reference to validation handler.
152    pub fn validation(&self) -> &ValidationHandler<'a, EXT, DB> {
153        &self.validation
154    }
155
156    /// Append handle register.
157    pub fn append_handler_register(&mut self, register: HandleRegisters<'a, EXT, DB>) {
158        register.register(self);
159        self.registers.push(register);
160    }
161
162    /// Append plain handle register.
163    pub fn append_handler_register_plain(&mut self, register: HandleRegister<EXT, DB>) {
164        register(self);
165        self.registers.push(HandleRegisters::Plain(register));
166    }
167
168    /// Append boxed handle register.
169    pub fn append_handler_register_box(&mut self, register: HandleRegisterBox<'a, EXT, DB>) {
170        register(self);
171        self.registers.push(HandleRegisters::Box(register));
172    }
173
174    /// Pop last handle register and reapply all registers that are left.
175    pub fn pop_handle_register(&mut self) -> Option<HandleRegisters<'a, EXT, DB>> {
176        let out = self.registers.pop();
177        if out.is_some() {
178            let registers = core::mem::take(&mut self.registers);
179            let mut base_handler = Handler::mainnet_with_spec(self.cfg.spec_id);
180            // apply all registers to default handler and raw mainnet instruction table.
181            for register in registers {
182                base_handler.append_handler_register(register)
183            }
184            *self = base_handler;
185        }
186        out
187    }
188
189    /// Creates the Handler with Generic Spec.
190    pub fn create_handle_generic<SPEC: Spec>(&mut self) -> EvmHandler<'a, EXT, DB> {
191        let registers = core::mem::take(&mut self.registers);
192        let mut base_handler = Handler::mainnet::<SPEC>();
193        // apply all registers to default handler and raw mainnet instruction table.
194        for register in registers {
195            base_handler.append_handler_register(register)
196        }
197        base_handler
198    }
199
200    /// Creates the Handler with variable SpecId, inside it will call function with Generic Spec.
201    pub fn modify_spec_id(&mut self, spec_id: SpecId) {
202        if self.cfg.spec_id == spec_id {
203            return;
204        }
205
206        let registers = core::mem::take(&mut self.registers);
207        // register for optimism is added as a register, so we need to create mainnet handler here.
208        let mut handler = Handler::mainnet_with_spec(spec_id);
209        // apply all registers to default handler and raw mainnet instruction table.
210        for register in registers {
211            handler.append_handler_register(register)
212        }
213        handler.cfg = self.cfg();
214        handler.cfg.spec_id = spec_id;
215        *self = handler;
216    }
217}
218
219#[cfg(test)]
220mod test {
221    use core::cell::RefCell;
222
223    use crate::{db::EmptyDB, primitives::EVMError};
224    use std::{rc::Rc, sync::Arc};
225
226    use super::*;
227
228    #[test]
229    fn test_handler_register_pop() {
230        let register = |inner: &Rc<RefCell<i32>>| -> HandleRegisterBox<'_, (), EmptyDB> {
231            let inner = inner.clone();
232            Box::new(move |h| {
233                *inner.borrow_mut() += 1;
234                h.post_execution.output = Arc::new(|_, _| Err(EVMError::Custom("test".to_string())))
235            })
236        };
237
238        let mut handler = EvmHandler::<(), EmptyDB>::new(HandlerCfg::new(SpecId::LATEST));
239        let test = Rc::new(RefCell::new(0));
240
241        handler.append_handler_register_box(register(&test));
242        assert_eq!(*test.borrow(), 1);
243
244        handler.append_handler_register_box(register(&test));
245        assert_eq!(*test.borrow(), 2);
246
247        assert!(handler.pop_handle_register().is_some());
248
249        // first handler is reapplied
250        assert_eq!(*test.borrow(), 3);
251    }
252}