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;
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    /// Called by [`Handler::run`] to execute the core handler logic.
89    ///
90    /// Executes the four phases in sequence: [Handler::validate],
91    /// [Handler::pre_execution], [Handler::execution], [Handler::post_execution].
92    ///
93    /// Returns any errors without catching them or calling [`Handler::catch_error`].
94    #[inline]
95    fn run_without_catch_error(
96        &mut self,
97        evm: &mut Self::Evm,
98    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
99        let init_and_floor_gas = self.validate(evm)?;
100        let eip7702_refund = self.pre_execution(evm)? as i64;
101        let exec_result = self.execution(evm, &init_and_floor_gas)?;
102        self.post_execution(evm, exec_result, init_and_floor_gas, eip7702_refund)
103    }
104
105    /// Validates the execution environment and transaction parameters.
106    ///
107    /// Calculates initial and floor gas requirements and verifies they are covered by the gas limit.
108    ///
109    /// Loads the caller account and validates transaction fields against state,
110    /// including nonce checks and balance verification for maximum gas costs.
111    #[inline]
112    fn validate(&self, evm: &mut Self::Evm) -> Result<InitialAndFloorGas, Self::Error> {
113        self.validate_env(evm)?;
114        let initial_and_floor_gas = self.validate_initial_tx_gas(evm)?;
115        self.validate_tx_against_state(evm)?;
116        Ok(initial_and_floor_gas)
117    }
118
119    /// Prepares the EVM state for execution.
120    ///
121    /// Loads the beneficiary account (EIP-3651: Warm COINBASE) and all accounts/storage from the access list (EIP-2929).
122    ///
123    /// Deducts the maximum possible fee from the caller's balance.
124    ///
125    /// For EIP-7702 transactions, applies the authorization list and delegates successful authorizations.
126    /// Returns the gas refund amount from EIP-7702. Authorizations are applied before execution begins.
127    #[inline]
128    fn pre_execution(&self, evm: &mut Self::Evm) -> Result<u64, Self::Error> {
129        self.load_accounts(evm)?;
130        self.deduct_caller(evm)?;
131        let gas = self.apply_eip7702_auth_list(evm)?;
132        Ok(gas)
133    }
134
135    /// Creates and executes the initial frame, then processes the execution loop.
136    ///
137    /// Always calls [Handler::last_frame_result] to handle returned gas from the call.
138    #[inline]
139    fn execution(
140        &mut self,
141        evm: &mut Self::Evm,
142        init_and_floor_gas: &InitialAndFloorGas,
143    ) -> Result<FrameResult, Self::Error> {
144        let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
145
146        // Create first frame action
147        let first_frame_input = self.first_frame_input(evm, gas_limit)?;
148        let first_frame = self.first_frame_init(evm, first_frame_input)?;
149        let mut frame_result = match first_frame {
150            ItemOrResult::Item(frame) => self.run_exec_loop(evm, frame)?,
151            ItemOrResult::Result(result) => result,
152        };
153
154        self.last_frame_result(evm, &mut frame_result)?;
155        Ok(frame_result)
156    }
157
158    /// Handles the final steps of transaction execution.
159    ///
160    /// Calculates final refunds and validates the gas floor (EIP-7623) to ensure minimum gas is spent.
161    /// After EIP-7623, at least floor gas must be consumed.
162    ///
163    /// Reimburses unused gas to the caller and rewards the beneficiary with transaction fees.
164    /// The effective gas price determines rewards, with the base fee being burned.
165    ///
166    /// Finally, finalizes output by returning the journal state and clearing internal state
167    /// for the next execution.
168    #[inline]
169    fn post_execution(
170        &self,
171        evm: &mut Self::Evm,
172        mut exec_result: FrameResult,
173        init_and_floor_gas: InitialAndFloorGas,
174        eip7702_gas_refund: i64,
175    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
176        // Calculate final refund and add EIP-7702 refund to gas.
177        self.refund(evm, &mut exec_result, eip7702_gas_refund);
178        // Ensure gas floor is met and minimum floor gas is spent.
179        self.eip7623_check_gas_floor(evm, &mut exec_result, init_and_floor_gas);
180        // Return unused gas to caller
181        self.reimburse_caller(evm, &mut exec_result)?;
182        // Pay transaction fees to beneficiary
183        self.reward_beneficiary(evm, &mut exec_result)?;
184        // Prepare transaction output
185        self.output(evm, exec_result)
186    }
187
188    /* VALIDATION */
189
190    /// Validates block, transaction and configuration fields.
191    ///
192    /// Performs all validation checks that can be done without loading state.
193    /// For example, verifies transaction gas limit is below block gas limit.
194    #[inline]
195    fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
196        validation::validate_env(evm.ctx())
197    }
198
199    /// Calculates initial gas costs based on transaction type and input data.
200    ///
201    /// Includes additional costs for access list and authorization list.
202    ///
203    /// Verifies the initial cost does not exceed the transaction gas limit.
204    #[inline]
205    fn validate_initial_tx_gas(&self, evm: &Self::Evm) -> Result<InitialAndFloorGas, Self::Error> {
206        let ctx = evm.ctx_ref();
207        validation::validate_initial_tx_gas(ctx.tx(), ctx.cfg().spec().into()).map_err(From::from)
208    }
209
210    /// Loads caller account to access nonce and balance.
211    ///
212    /// Calculates maximum possible transaction fee and verifies caller has sufficient balance.
213    #[inline]
214    fn validate_tx_against_state(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
215        validation::validate_tx_against_state(evm.ctx())
216    }
217
218    /* PRE EXECUTION */
219
220    /// Loads access list and beneficiary account, marking them as warm in the [`context::Journal`].
221    #[inline]
222    fn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
223        pre_execution::load_accounts(evm)
224    }
225
226    /// Processes the authorization list, validating authority signatures, nonces and chain IDs.
227    /// Applies valid authorizations to accounts.
228    ///
229    /// Returns the gas refund amount specified by EIP-7702.
230    #[inline]
231    fn apply_eip7702_auth_list(&self, evm: &mut Self::Evm) -> Result<u64, Self::Error> {
232        pre_execution::apply_eip7702_auth_list(evm.ctx())
233    }
234
235    /// Deducts maximum possible fee and transfer value from caller's balance.
236    ///
237    /// Unused fees are returned to caller after execution completes.
238    #[inline]
239    fn deduct_caller(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
240        pre_execution::deduct_caller(evm.ctx()).map_err(From::from)
241    }
242
243    /* EXECUTION */
244
245    /// Creates initial frame input using transaction parameters, gas limit and configuration.
246    #[inline]
247    fn first_frame_input(
248        &mut self,
249        evm: &mut Self::Evm,
250        gas_limit: u64,
251    ) -> Result<FrameInput, Self::Error> {
252        let ctx: &<<Self as Handler>::Evm as EvmTr>::Context = evm.ctx_ref();
253        Ok(execution::create_init_frame(
254            ctx.tx(),
255            ctx.cfg().spec().into(),
256            gas_limit,
257        ))
258    }
259
260    /// Processes the result of the initial call and handles returned gas.
261    #[inline]
262    fn last_frame_result(
263        &self,
264        evm: &mut Self::Evm,
265        frame_result: &mut <Self::Frame as Frame>::FrameResult,
266    ) -> Result<(), Self::Error> {
267        let instruction_result = frame_result.interpreter_result().result;
268        let gas = frame_result.gas_mut();
269        let remaining = gas.remaining();
270        let refunded = gas.refunded();
271
272        // Spend the gas limit. Gas is reimbursed when the tx returns successfully.
273        *gas = Gas::new_spent(evm.ctx().tx().gas_limit());
274
275        if instruction_result.is_ok_or_revert() {
276            gas.erase_cost(remaining);
277        }
278
279        if instruction_result.is_ok() {
280            gas.record_refund(refunded);
281        }
282        Ok(())
283    }
284
285    /* FRAMES */
286
287    /// Initializes the first frame from the provided frame input.
288    #[inline]
289    fn first_frame_init(
290        &mut self,
291        evm: &mut Self::Evm,
292        frame_input: <Self::Frame as Frame>::FrameInit,
293    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
294        Self::Frame::init_first(evm, frame_input)
295    }
296
297    /// Initializes a new frame from the provided frame input and previous frame.
298    ///
299    /// The previous frame contains shared memory that is passed to the new frame.
300    #[inline]
301    fn frame_init(
302        &mut self,
303        frame: &Self::Frame,
304        evm: &mut Self::Evm,
305        frame_input: <Self::Frame as Frame>::FrameInit,
306    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
307        Frame::init(frame, evm, frame_input)
308    }
309
310    /// Executes a frame and returns either input for a new frame or the frame's result.
311    ///
312    /// When a result is returned, the frame is removed from the call stack. When frame input
313    /// is returned, a new frame is created and pushed onto the call stack.
314    #[inline]
315    fn frame_call(
316        &mut self,
317        frame: &mut Self::Frame,
318        evm: &mut Self::Evm,
319    ) -> Result<FrameInitOrResult<Self::Frame>, Self::Error> {
320        Frame::run(frame, evm)
321    }
322
323    /// Processes a frame's result by inserting it into the parent frame.
324    #[inline]
325    fn frame_return_result(
326        &mut self,
327        frame: &mut Self::Frame,
328        evm: &mut Self::Evm,
329        result: <Self::Frame as Frame>::FrameResult,
330    ) -> Result<(), Self::Error> {
331        Self::Frame::return_result(frame, evm, result)
332    }
333
334    /// Executes the main frame processing loop.
335    ///
336    /// This loop manages the frame stack, processing each frame until execution completes.
337    /// For each iteration:
338    /// 1. Calls the current frame
339    /// 2. Handles the returned frame input or result
340    /// 3. Creates new frames or propagates results as needed
341    #[inline]
342    fn run_exec_loop(
343        &mut self,
344        evm: &mut Self::Evm,
345        frame: Self::Frame,
346    ) -> Result<FrameResult, Self::Error> {
347        let mut frame_stack: Vec<Self::Frame> = vec![frame];
348        loop {
349            let frame = frame_stack.last_mut().unwrap();
350            let call_or_result = self.frame_call(frame, evm)?;
351
352            let result = match call_or_result {
353                ItemOrResult::Item(init) => {
354                    match self.frame_init(frame, evm, init)? {
355                        ItemOrResult::Item(new_frame) => {
356                            frame_stack.push(new_frame);
357                            continue;
358                        }
359                        // Do not pop the frame since no new frame was created
360                        ItemOrResult::Result(result) => result,
361                    }
362                }
363                ItemOrResult::Result(result) => {
364                    // Remove the frame that returned the result
365                    frame_stack.pop();
366                    result
367                }
368            };
369
370            let Some(frame) = frame_stack.last_mut() else {
371                return Ok(result);
372            };
373            self.frame_return_result(frame, evm, result)?;
374        }
375    }
376
377    /* POST EXECUTION */
378
379    /// Validates that the minimum gas floor requirements are satisfied.
380    ///
381    /// Ensures that at least the floor gas amount has been consumed during execution.
382    #[inline]
383    fn eip7623_check_gas_floor(
384        &self,
385        _evm: &mut Self::Evm,
386        exec_result: &mut <Self::Frame as Frame>::FrameResult,
387        init_and_floor_gas: InitialAndFloorGas,
388    ) {
389        post_execution::eip7623_check_gas_floor(exec_result.gas_mut(), init_and_floor_gas)
390    }
391
392    /// Calculates the final gas refund amount, including any EIP-7702 refunds.
393    #[inline]
394    fn refund(
395        &self,
396        evm: &mut Self::Evm,
397        exec_result: &mut <Self::Frame as Frame>::FrameResult,
398        eip7702_refund: i64,
399    ) {
400        let spec = evm.ctx().cfg().spec().into();
401        post_execution::refund(spec, exec_result.gas_mut(), eip7702_refund)
402    }
403
404    /// Returns unused gas costs to the transaction sender's account.
405    #[inline]
406    fn reimburse_caller(
407        &self,
408        evm: &mut Self::Evm,
409        exec_result: &mut <Self::Frame as Frame>::FrameResult,
410    ) -> Result<(), Self::Error> {
411        post_execution::reimburse_caller(evm.ctx(), exec_result.gas_mut()).map_err(From::from)
412    }
413
414    /// Transfers transaction fees to the block beneficiary's account.
415    #[inline]
416    fn reward_beneficiary(
417        &self,
418        evm: &mut Self::Evm,
419        exec_result: &mut <Self::Frame as Frame>::FrameResult,
420    ) -> Result<(), Self::Error> {
421        post_execution::reward_beneficiary(evm.ctx(), exec_result.gas_mut()).map_err(From::from)
422    }
423
424    /// Processes the final execution output.
425    ///
426    /// This method, retrieves the final state from the journal, converts internal results to the external output format.
427    /// Internal state is cleared and EVM is prepared for the next transaction.
428    #[inline]
429    fn output(
430        &self,
431        evm: &mut Self::Evm,
432        result: <Self::Frame as Frame>::FrameResult,
433    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
434        match core::mem::replace(evm.ctx().error(), Ok(())) {
435            Err(ContextError::Db(e)) => return Err(e.into()),
436            Err(ContextError::Custom(e)) => return Err(Self::Error::from_string(e)),
437            Ok(_) => (),
438        }
439
440        let output = post_execution::output(evm.ctx(), result);
441
442        // Clear journal
443        evm.ctx().journal().clear();
444        Ok(output)
445    }
446
447    /// Handles cleanup when an error occurs during execution.
448    ///
449    /// Ensures the journal state is properly cleared before propagating the error.
450    /// On happy path journal is cleared in [`Handler::output`] method.
451    #[inline]
452    fn catch_error(
453        &self,
454        evm: &mut Self::Evm,
455        error: Self::Error,
456    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
457        // Clean up journal state if error occurs
458        evm.ctx().journal().clear();
459        Err(error)
460    }
461}