reth_evm/system_calls/
eip7002.rs

1//! [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) system call implementation.
2use crate::ConfigureEvm;
3use alloc::{boxed::Box, format};
4use alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS;
5use alloy_primitives::Bytes;
6use reth_execution_errors::{BlockExecutionError, BlockValidationError};
7use revm::{interpreter::Host, Database, Evm};
8use revm_primitives::{ExecutionResult, ResultAndState};
9
10/// Applies the post-block call to the EIP-7002 withdrawal requests contract.
11///
12/// If Prague is not active at the given timestamp, then this is a no-op.
13///
14/// Note: this does not commit the state changes to the database, it only transact the call.
15#[inline]
16pub(crate) fn transact_withdrawal_requests_contract_call<EvmConfig, EXT, DB>(
17    evm_config: &EvmConfig,
18    evm: &mut Evm<'_, EXT, DB>,
19) -> Result<ResultAndState, BlockExecutionError>
20where
21    DB: Database,
22    DB::Error: core::fmt::Display,
23    EvmConfig: ConfigureEvm,
24{
25    // get previous env
26    let previous_env = Box::new(evm.context.env().clone());
27
28    // Fill transaction environment with the EIP-7002 withdrawal requests contract message data.
29    //
30    // This requirement for the withdrawal requests contract call defined by
31    // [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) is:
32    //
33    // At the end of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e.
34    // after processing all transactions and after performing the block body withdrawal requests
35    // validations), call the contract as `SYSTEM_ADDRESS`.
36    evm_config.fill_tx_env_system_contract_call(
37        &mut evm.context.evm.env,
38        alloy_eips::eip7002::SYSTEM_ADDRESS,
39        WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
40        Bytes::new(),
41    );
42
43    let mut res = match evm.transact() {
44        Ok(res) => res,
45        Err(e) => {
46            evm.context.evm.env = previous_env;
47            return Err(BlockValidationError::WithdrawalRequestsContractCall {
48                message: format!("execution failed: {e}"),
49            }
50            .into())
51        }
52    };
53
54    // cleanup the state
55    res.state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS);
56    res.state.remove(&evm.block().coinbase);
57
58    // re-set the previous env
59    evm.context.evm.env = previous_env;
60
61    Ok(res)
62}
63
64/// Calls the withdrawals requests system contract, and returns the requests from the execution
65/// output.
66#[inline]
67pub(crate) fn post_commit(result: ExecutionResult) -> Result<Bytes, BlockExecutionError> {
68    match result {
69        ExecutionResult::Success { output, .. } => Ok(output.into_data()),
70        ExecutionResult::Revert { output, .. } => {
71            Err(BlockValidationError::WithdrawalRequestsContractCall {
72                message: format!("execution reverted: {output}"),
73            }
74            .into())
75        }
76        ExecutionResult::Halt { reason, .. } => {
77            Err(BlockValidationError::WithdrawalRequestsContractCall {
78                message: format!("execution halted: {reason:?}"),
79            }
80            .into())
81        }
82    }
83}