revm_handler/
handler.rs

1use crate::EvmTr;
2use crate::{
3    execution, post_execution, pre_execution, validation, Frame, FrameInitOrResult, FrameOrResult,
4    FrameResult, ItemOrResult,
5};
6use context::result::FromStringError;
7use context::{JournalOutput, LocalContextTr, TransactionType};
8use context_interface::context::ContextError;
9use context_interface::ContextTr;
10use context_interface::{
11    result::{HaltReasonTr, InvalidHeader, InvalidTransaction, ResultAndState},
12    Cfg, Database, JournalTr, Transaction,
13};
14use interpreter::{FrameInput, Gas, InitialAndFloorGas};
15use std::{vec, vec::Vec};
16
17pub trait EvmTrError<EVM: EvmTr>:
18    From<InvalidTransaction>
19    + From<InvalidHeader>
20    + From<<<EVM::Context as ContextTr>::Db as Database>::Error>
21    + FromStringError
22{
23}
24
25impl<
26        EVM: EvmTr,
27        T: From<InvalidTransaction>
28            + From<InvalidHeader>
29            + From<<<EVM::Context as ContextTr>::Db as Database>::Error>
30            + FromStringError,
31    > EvmTrError<EVM> for T
32{
33}
34
35/// The main implementation of Ethereum Mainnet transaction execution.
36///
37/// The [`Handler::run`] method serves as the entry point for execution and provides
38/// out-of-the-box support for executing Ethereum mainnet transactions.
39///
40/// This trait allows EVM variants to customize execution logic by implementing
41/// their own method implementations.
42///
43/// The handler logic consists of four phases:
44///   * Validation - Validates tx/block/config fields and loads caller account and validates initial gas requirements and
45///     balance checks.
46///   * Pre-execution - Loads and warms accounts, deducts initial gas
47///   * Execution - Executes the main frame loop, delegating to [`Frame`] for sub-calls
48///   * Post-execution - Calculates final refunds, validates gas floor, reimburses caller,
49///     and rewards beneficiary
50///
51/// The [`Handler::catch_error`] method handles cleanup of intermediate state if an error
52/// occurs during execution.
53pub trait Handler {
54    /// The EVM type containing Context, Instruction, and Precompiles implementations.
55    type Evm: EvmTr<Context: ContextTr<Journal: JournalTr<FinalOutput = JournalOutput>>>;
56    /// The error type returned by this handler.
57    type Error: EvmTrError<Self::Evm>;
58    /// The Frame type containing data for frame execution. Supports Call, Create and EofCreate frames.
59    // TODO `FrameResult` should be a generic trait.
60    // TODO `FrameInit` should be a generic.
61    type Frame: Frame<
62        Evm = Self::Evm,
63        Error = Self::Error,
64        FrameResult = FrameResult,
65        FrameInit = FrameInput,
66    >;
67    /// The halt reason type included in the output
68    type HaltReason: HaltReasonTr;
69
70    /// The main entry point for transaction execution.
71    ///
72    /// This method calls [`Handler::run_without_catch_error`] and if it returns an error,
73    /// calls [`Handler::catch_error`] to handle the error and cleanup.
74    ///
75    /// The [`Handler::catch_error`] method ensures intermediate state is properly cleared.
76    #[inline]
77    fn run(
78        &mut self,
79        evm: &mut Self::Evm,
80    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
81        // Run inner handler and catch all errors to handle cleanup.
82        match self.run_without_catch_error(evm) {
83            Ok(output) => Ok(output),
84            Err(e) => self.catch_error(evm, e),
85        }
86    }
87
88    /// Runs the system call.
89    ///
90    /// System call is a special transaction where caller is a [`crate::SYSTEM_ADDRESS`]
91    ///
92    /// It is used to call a system contracts and it skips all the `validation` and `pre-execution` and most of `post-execution` phases.
93    /// For example it will not deduct the caller or reward the beneficiary.
94    #[inline]
95    fn run_system_call(
96        &mut self,
97        evm: &mut Self::Evm,
98    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
99        // dummy values that are not used.
100        let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
101        // call execution and than output.
102        match self
103            .execution(evm, &init_and_floor_gas)
104            .and_then(|exec_result| self.output(evm, exec_result))
105        {
106            Ok(output) => Ok(output),
107            Err(e) => self.catch_error(evm, e),
108        }
109    }
110
111    /// Called by [`Handler::run`] to execute the core handler logic.
112    ///
113    /// Executes the four phases in sequence: [Handler::validate],
114    /// [Handler::pre_execution], [Handler::execution], [Handler::post_execution].
115    ///
116    /// Returns any errors without catching them or calling [`Handler::catch_error`].
117    #[inline]
118    fn run_without_catch_error(
119        &mut self,
120        evm: &mut Self::Evm,
121    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
122        let init_and_floor_gas = self.validate(evm)?;
123        let eip7702_refund = self.pre_execution(evm)? as i64;
124        let exec_result = self.execution(evm, &init_and_floor_gas)?;
125        self.post_execution(evm, exec_result, init_and_floor_gas, eip7702_refund)
126    }
127
128    /// Validates the execution environment and transaction parameters.
129    ///
130    /// Calculates initial and floor gas requirements and verifies they are covered by the gas limit.
131    ///
132    /// Validation against state is done later in pre-execution phase in deduct_caller function.
133    #[inline]
134    fn validate(&self, evm: &mut Self::Evm) -> Result<InitialAndFloorGas, Self::Error> {
135        self.validate_env(evm)?;
136        self.validate_initial_tx_gas(evm)
137    }
138
139    /// Prepares the EVM state for execution.
140    ///
141    /// Loads the beneficiary account (EIP-3651: Warm COINBASE) and all accounts/storage from the access list (EIP-2929).
142    ///
143    /// Deducts the maximum possible fee from the caller's balance.
144    ///
145    /// For EIP-7702 transactions, applies the authorization list and delegates successful authorizations.
146    /// Returns the gas refund amount from EIP-7702. Authorizations are applied before execution begins.
147    #[inline]
148    fn pre_execution(&self, evm: &mut Self::Evm) -> Result<u64, Self::Error> {
149        self.validate_against_state_and_deduct_caller(evm)?;
150        self.load_accounts(evm)?;
151        // Cache EIP-7873 EOF initcodes and calculate its hash. Does nothing if not Initcode Transaction.
152        self.apply_eip7873_eof_initcodes(evm)?;
153        let gas = self.apply_eip7702_auth_list(evm)?;
154        Ok(gas)
155    }
156
157    /// Creates and executes the initial frame, then processes the execution loop.
158    ///
159    /// Always calls [Handler::last_frame_result] to handle returned gas from the call.
160    #[inline]
161    fn execution(
162        &mut self,
163        evm: &mut Self::Evm,
164        init_and_floor_gas: &InitialAndFloorGas,
165    ) -> Result<FrameResult, Self::Error> {
166        let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
167
168        // Create first frame action
169        let first_frame_input = self.first_frame_input(evm, gas_limit)?;
170        let first_frame = self.first_frame_init(evm, first_frame_input)?;
171        let mut frame_result = match first_frame {
172            ItemOrResult::Item(frame) => self.run_exec_loop(evm, frame)?,
173            ItemOrResult::Result(result) => result,
174        };
175
176        self.last_frame_result(evm, &mut frame_result)?;
177        Ok(frame_result)
178    }
179
180    /// Handles the final steps of transaction execution.
181    ///
182    /// Calculates final refunds and validates the gas floor (EIP-7623) to ensure minimum gas is spent.
183    /// After EIP-7623, at least floor gas must be consumed.
184    ///
185    /// Reimburses unused gas to the caller and rewards the beneficiary with transaction fees.
186    /// The effective gas price determines rewards, with the base fee being burned.
187    ///
188    /// Finally, finalizes output by returning the journal state and clearing internal state
189    /// for the next execution.
190    #[inline]
191    fn post_execution(
192        &self,
193        evm: &mut Self::Evm,
194        mut exec_result: FrameResult,
195        init_and_floor_gas: InitialAndFloorGas,
196        eip7702_gas_refund: i64,
197    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
198        // Calculate final refund and add EIP-7702 refund to gas.
199        self.refund(evm, &mut exec_result, eip7702_gas_refund);
200        // Ensure gas floor is met and minimum floor gas is spent.
201        self.eip7623_check_gas_floor(evm, &mut exec_result, init_and_floor_gas);
202        // Return unused gas to caller
203        self.reimburse_caller(evm, &mut exec_result)?;
204        // Pay transaction fees to beneficiary
205        self.reward_beneficiary(evm, &mut exec_result)?;
206        // Prepare transaction output
207        self.output(evm, exec_result)
208    }
209
210    /* VALIDATION */
211
212    /// Validates block, transaction and configuration fields.
213    ///
214    /// Performs all validation checks that can be done without loading state.
215    /// For example, verifies transaction gas limit is below block gas limit.
216    #[inline]
217    fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
218        validation::validate_env(evm.ctx())
219    }
220
221    /// Calculates initial gas costs based on transaction type and input data.
222    ///
223    /// Includes additional costs for access list and authorization list.
224    ///
225    /// Verifies the initial cost does not exceed the transaction gas limit.
226    #[inline]
227    fn validate_initial_tx_gas(&self, evm: &Self::Evm) -> Result<InitialAndFloorGas, Self::Error> {
228        let ctx = evm.ctx_ref();
229        validation::validate_initial_tx_gas(ctx.tx(), ctx.cfg().spec().into()).map_err(From::from)
230    }
231
232    /* PRE EXECUTION */
233
234    /// Loads access list and beneficiary account, marking them as warm in the [`context::Journal`].
235    #[inline]
236    fn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
237        pre_execution::load_accounts(evm)
238    }
239
240    /// Processes the authorization list, validating authority signatures, nonces and chain IDs.
241    /// Applies valid authorizations to accounts.
242    ///
243    /// Returns the gas refund amount specified by EIP-7702.
244    #[inline]
245    fn apply_eip7702_auth_list(&self, evm: &mut Self::Evm) -> Result<u64, Self::Error> {
246        pre_execution::apply_eip7702_auth_list(evm.ctx())
247    }
248
249    /// Processes the authorization list, validating authority signatures, nonces and chain IDs.
250    /// Applies valid authorizations to accounts.
251    ///
252    /// Returns the gas refund amount specified by EIP-7702.
253    #[inline]
254    fn apply_eip7873_eof_initcodes(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
255        if evm.ctx().tx().tx_type() != TransactionType::Eip7873 {
256            return Ok(());
257        }
258        Ok(())
259        /* TODO(EOF)
260        let (tx, local) = evm.ctx().tx_local();
261        local.insert_initcodes(&[]);
262        tx.initcodes());
263        Ok(())
264        */
265    }
266
267    /// Deducts maximum possible fee and transfer value from caller's balance.
268    ///
269    /// Unused fees are returned to caller after execution completes.
270    #[inline]
271    fn validate_against_state_and_deduct_caller(
272        &self,
273        evm: &mut Self::Evm,
274    ) -> Result<(), Self::Error> {
275        pre_execution::validate_against_state_and_deduct_caller(evm.ctx())
276    }
277
278    /* EXECUTION */
279
280    /// Creates initial frame input using transaction parameters, gas limit and configuration.
281    #[inline]
282    fn first_frame_input(
283        &mut self,
284        evm: &mut Self::Evm,
285        gas_limit: u64,
286    ) -> Result<FrameInput, Self::Error> {
287        let ctx: &<<Self as Handler>::Evm as EvmTr>::Context = evm.ctx_ref();
288        Ok(execution::create_init_frame(
289            ctx.tx(),
290            ctx.cfg().spec().into(),
291            gas_limit,
292        ))
293    }
294
295    /// Processes the result of the initial call and handles returned gas.
296    #[inline]
297    fn last_frame_result(
298        &mut self,
299        evm: &mut Self::Evm,
300        frame_result: &mut <Self::Frame as Frame>::FrameResult,
301    ) -> Result<(), Self::Error> {
302        let instruction_result = frame_result.interpreter_result().result;
303        let gas = frame_result.gas_mut();
304        let remaining = gas.remaining();
305        let refunded = gas.refunded();
306
307        // Spend the gas limit. Gas is reimbursed when the tx returns successfully.
308        *gas = Gas::new_spent(evm.ctx().tx().gas_limit());
309
310        if instruction_result.is_ok_or_revert() {
311            gas.erase_cost(remaining);
312        }
313
314        if instruction_result.is_ok() {
315            gas.record_refund(refunded);
316        }
317        Ok(())
318    }
319
320    /* FRAMES */
321
322    /// Initializes the first frame from the provided frame input.
323    #[inline]
324    fn first_frame_init(
325        &mut self,
326        evm: &mut Self::Evm,
327        frame_input: <Self::Frame as Frame>::FrameInit,
328    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
329        Self::Frame::init_first(evm, frame_input)
330    }
331
332    /// Initializes a new frame from the provided frame input and previous frame.
333    ///
334    /// The previous frame contains shared memory that is passed to the new frame.
335    #[inline]
336    fn frame_init(
337        &mut self,
338        frame: &mut Self::Frame,
339        evm: &mut Self::Evm,
340        frame_input: <Self::Frame as Frame>::FrameInit,
341    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
342        Frame::init(frame, evm, frame_input)
343    }
344
345    /// Executes a frame and returns either input for a new frame or the frame's result.
346    ///
347    /// When a result is returned, the frame is removed from the call stack. When frame input
348    /// is returned, a new frame is created and pushed onto the call stack.
349    #[inline]
350    fn frame_call(
351        &mut self,
352        frame: &mut Self::Frame,
353        evm: &mut Self::Evm,
354    ) -> Result<FrameInitOrResult<Self::Frame>, Self::Error> {
355        Frame::run(frame, evm)
356    }
357
358    /// Processes a frame's result by inserting it into the parent frame.
359    #[inline]
360    fn frame_return_result(
361        &mut self,
362        frame: &mut Self::Frame,
363        evm: &mut Self::Evm,
364        result: <Self::Frame as Frame>::FrameResult,
365    ) -> Result<(), Self::Error> {
366        Self::Frame::return_result(frame, evm, result)
367    }
368
369    /// Executes the main frame processing loop.
370    ///
371    /// This loop manages the frame stack, processing each frame until execution completes.
372    /// For each iteration:
373    /// 1. Calls the current frame
374    /// 2. Handles the returned frame input or result
375    /// 3. Creates new frames or propagates results as needed
376    #[inline]
377    fn run_exec_loop(
378        &mut self,
379        evm: &mut Self::Evm,
380        frame: Self::Frame,
381    ) -> Result<FrameResult, Self::Error> {
382        let mut frame_stack: Vec<Self::Frame> = vec![frame];
383        loop {
384            let frame = frame_stack.last_mut().unwrap();
385            let call_or_result = self.frame_call(frame, evm)?;
386
387            let result = match call_or_result {
388                ItemOrResult::Item(init) => {
389                    match self.frame_init(frame, evm, init)? {
390                        ItemOrResult::Item(new_frame) => {
391                            frame_stack.push(new_frame);
392                            continue;
393                        }
394                        // Do not pop the frame since no new frame was created
395                        ItemOrResult::Result(result) => result,
396                    }
397                }
398                ItemOrResult::Result(result) => {
399                    // Remove the frame that returned the result
400                    frame_stack.pop();
401                    result
402                }
403            };
404
405            let Some(frame) = frame_stack.last_mut() else {
406                return Ok(result);
407            };
408            self.frame_return_result(frame, evm, result)?;
409        }
410    }
411
412    /* POST EXECUTION */
413
414    /// Validates that the minimum gas floor requirements are satisfied.
415    ///
416    /// Ensures that at least the floor gas amount has been consumed during execution.
417    #[inline]
418    fn eip7623_check_gas_floor(
419        &self,
420        _evm: &mut Self::Evm,
421        exec_result: &mut <Self::Frame as Frame>::FrameResult,
422        init_and_floor_gas: InitialAndFloorGas,
423    ) {
424        post_execution::eip7623_check_gas_floor(exec_result.gas_mut(), init_and_floor_gas)
425    }
426
427    /// Calculates the final gas refund amount, including any EIP-7702 refunds.
428    #[inline]
429    fn refund(
430        &self,
431        evm: &mut Self::Evm,
432        exec_result: &mut <Self::Frame as Frame>::FrameResult,
433        eip7702_refund: i64,
434    ) {
435        let spec = evm.ctx().cfg().spec().into();
436        post_execution::refund(spec, exec_result.gas_mut(), eip7702_refund)
437    }
438
439    /// Returns unused gas costs to the transaction sender's account.
440    #[inline]
441    fn reimburse_caller(
442        &self,
443        evm: &mut Self::Evm,
444        exec_result: &mut <Self::Frame as Frame>::FrameResult,
445    ) -> Result<(), Self::Error> {
446        post_execution::reimburse_caller(evm.ctx(), exec_result.gas_mut()).map_err(From::from)
447    }
448
449    /// Transfers transaction fees to the block beneficiary's account.
450    #[inline]
451    fn reward_beneficiary(
452        &self,
453        evm: &mut Self::Evm,
454        exec_result: &mut <Self::Frame as Frame>::FrameResult,
455    ) -> Result<(), Self::Error> {
456        post_execution::reward_beneficiary(evm.ctx(), exec_result.gas_mut()).map_err(From::from)
457    }
458
459    /// Processes the final execution output.
460    ///
461    /// This method, retrieves the final state from the journal, converts internal results to the external output format.
462    /// Internal state is cleared and EVM is prepared for the next transaction.
463    #[inline]
464    fn output(
465        &self,
466        evm: &mut Self::Evm,
467        result: <Self::Frame as Frame>::FrameResult,
468    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
469        match core::mem::replace(evm.ctx().error(), Ok(())) {
470            Err(ContextError::Db(e)) => return Err(e.into()),
471            Err(ContextError::Custom(e)) => return Err(Self::Error::from_string(e)),
472            Ok(_) => (),
473        }
474
475        let output = post_execution::output(evm.ctx(), result);
476
477        // Clear local context
478        evm.ctx().local().clear();
479        // Clear journal
480        evm.ctx().journal().clear();
481        Ok(output)
482    }
483
484    /// Handles cleanup when an error occurs during execution.
485    ///
486    /// Ensures the journal state is properly cleared before propagating the error.
487    /// On happy path journal is cleared in [`Handler::output`] method.
488    #[inline]
489    fn catch_error(
490        &self,
491        evm: &mut Self::Evm,
492        error: Self::Error,
493    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
494        // clean up local context. Initcode cache needs to be discarded.
495        evm.ctx().local().clear();
496        // Clean up journal state if error occurs
497        evm.ctx().journal().clear();
498        Err(error)
499    }
500}