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}