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