Files
nanoreth/crates/evm/src/system_calls/eip7002.rs

84 lines
3.0 KiB
Rust

//! [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())
}
};
// cleanup the state
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())
}
}
}