use super::resize_memory_mip3;
use alloc::boxed::Box;
use core::cmp::{max, min};
use revm::interpreter::{
instructions::contract::get_memory_input_and_out_ranges,
interpreter::Interpreter,
interpreter_types::{
InputsTr, InterpreterTypes, LegacyBytecode, LoopControl, MemoryTr, ReturnData, RuntimeFlag,
StackTr,
},
CallInput, CallInputs, CallScheme, CallValue, CreateInputs, InstructionContext,
InstructionExecResult as Result, InstructionResult, InterpreterAction,
};
use revm::{
context_interface::{cfg::GasParams, host::LoadError, CreateScheme, Host},
interpreter::interpreter_action::FrameInput,
primitives::{self, hardfork::SpecId, Address, Bytes, B256, KECCAK_EMPTY, U256},
state::Bytecode,
};
use revm_interpreter::instructions::utility::IntoAddress;
fn monad_copy_cost_and_memory_resize(
interpreter: &mut Interpreter<impl InterpreterTypes>,
gas_params: &GasParams,
memory_offset: U256,
len: usize,
) -> Result<Option<usize>, InstructionResult> {
revm_interpreter::gas!(interpreter, gas_params.copy_cost(len));
if len == 0 {
return Ok(None);
}
let memory_offset = revm_interpreter::as_usize_or_fail!(interpreter, memory_offset);
resize_memory_mip3!(interpreter, memory_offset, len);
Ok(Some(memory_offset))
}
#[inline]
fn monad_return_inner(
interpreter: &mut Interpreter<impl InterpreterTypes>,
instruction_result: InstructionResult,
) -> Result {
revm_interpreter::popn!([offset, len], interpreter);
let len = revm_interpreter::as_usize_or_fail!(interpreter, len);
let mut output = Bytes::default();
if len != 0 {
let offset = revm_interpreter::as_usize_or_fail!(interpreter, offset);
crate::memory::monad_resize_memory(
&mut interpreter.gas,
&mut interpreter.memory,
offset,
len,
)?;
output = interpreter.memory.slice_len(offset, len).to_vec().into();
}
interpreter.bytecode.set_action(InterpreterAction::new_return(
instruction_result,
output,
interpreter.gas,
));
Err(instruction_result)
}
#[inline]
fn monad_get_memory_input_and_out_ranges(
interpreter: &mut Interpreter<impl InterpreterTypes>,
_gas_params: &GasParams,
) -> Result<(core::ops::Range<usize>, core::ops::Range<usize>), InstructionResult> {
revm_interpreter::popn!([in_offset, in_len, out_offset, out_len], interpreter);
let mut in_range = monad_call_resize_memory(interpreter, in_offset, in_len)?;
if !in_range.is_empty() {
let offset = interpreter.memory.local_memory_offset();
in_range = in_range.start.saturating_add(offset)..in_range.end.saturating_add(offset);
}
let ret_range = monad_call_resize_memory(interpreter, out_offset, out_len)?;
Ok((in_range, ret_range))
}
#[inline]
fn call_memory_input_and_out_ranges(
interpreter: &mut Interpreter<impl InterpreterTypes>,
gas_params: &GasParams,
) -> Result<(core::ops::Range<usize>, core::ops::Range<usize>), InstructionResult> {
if interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::OSAKA) {
monad_get_memory_input_and_out_ranges(interpreter, gas_params)
} else {
get_memory_input_and_out_ranges(interpreter, gas_params)
}
}
#[inline]
fn monad_call_resize_memory(
interpreter: &mut Interpreter<impl InterpreterTypes>,
offset: U256,
len: U256,
) -> Result<core::ops::Range<usize>, InstructionResult> {
let len = revm_interpreter::as_usize_or_fail!(interpreter, len);
let offset = if len != 0 {
let offset = revm_interpreter::as_usize_or_fail!(interpreter, offset);
resize_memory_mip3!(interpreter, offset, len);
offset
} else {
usize::MAX
};
Ok(offset..offset + len)
}
#[inline]
fn load_acc_and_calc_gas_with_bytecode_address<H: Host + ?Sized>(
context: &mut InstructionContext<'_, H, impl InterpreterTypes>,
to: Address,
transfers_value: bool,
create_empty_account: bool,
stack_gas_limit: u64,
) -> Result<(u64, Bytecode, B256, Address, bool), InstructionResult> {
if transfers_value {
revm_interpreter::gas!(
context.interpreter,
context.host.gas_params().transfer_value_cost()
);
}
let remaining_gas = context.interpreter.gas.remaining();
let spec = context.interpreter.runtime_flag.spec_id();
let (gas, state_gas_cost, bytecode, code_hash, bytecode_address) = load_account_delegated(
context.host,
spec,
remaining_gas,
to,
transfers_value,
create_empty_account,
)?;
let charged_new_account_state_gas = state_gas_cost > 0;
revm_interpreter::gas!(context.interpreter, gas);
revm_interpreter::state_gas!(context.interpreter, state_gas_cost);
let mut gas_limit =
if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::TANGERINE) {
let reduced_gas_limit = context
.host
.gas_params()
.call_stipend_reduction(context.interpreter.gas.remaining());
min(reduced_gas_limit, stack_gas_limit)
} else {
stack_gas_limit
};
revm_interpreter::gas!(context.interpreter, gas_limit);
if transfers_value {
gas_limit = gas_limit.saturating_add(context.host.gas_params().call_stipend());
}
Ok((gas_limit, bytecode, code_hash, bytecode_address, charged_new_account_state_gas))
}
#[inline]
fn load_account_delegated<H: Host + ?Sized>(
host: &mut H,
spec: SpecId,
remaining_gas: u64,
address: Address,
transfers_value: bool,
create_empty_account: bool,
) -> Result<(u64, u64, Bytecode, B256, Address), LoadError> {
let mut cost = 0;
let mut state_gas_cost = 0;
let is_berlin = spec.is_enabled_in(SpecId::BERLIN);
let is_spurious_dragon = spec.is_enabled_in(SpecId::SPURIOUS_DRAGON);
let additional_cold_cost = host.gas_params().cold_account_additional_cost();
let warm_storage_read_cost = host.gas_params().warm_storage_read_cost();
let skip_cold_load = is_berlin && remaining_gas < additional_cold_cost;
let account = host.load_account_info_skip_cold_load(address, true, skip_cold_load)?;
if is_berlin && account.is_cold {
cost += additional_cold_cost;
}
let mut bytecode = account.code.clone().unwrap_or_default();
let mut code_hash = account.code_hash();
let mut bytecode_address = address;
if create_empty_account && account.is_empty {
cost += host.gas_params().new_account_cost(is_spurious_dragon, transfers_value);
if host.is_amsterdam_eip8037_enabled() && transfers_value {
state_gas_cost += host.gas_params().new_account_state_gas();
}
return Ok((cost, state_gas_cost, bytecode, code_hash, bytecode_address));
}
if let Some(delegated_address) = account.code.as_ref().and_then(Bytecode::eip7702_address) {
cost += warm_storage_read_cost;
if cost > remaining_gas {
return Err(LoadError::ColdLoadSkipped);
}
let skip_cold_load = remaining_gas < cost + additional_cold_cost;
let delegated_account =
host.load_account_info_skip_cold_load(delegated_address, true, skip_cold_load)?;
if delegated_account.is_cold {
cost += additional_cold_cost;
}
bytecode = delegated_account.code.clone().unwrap_or_default();
code_hash = delegated_account.code_hash();
bytecode_address = delegated_address;
}
Ok((cost, state_gas_cost, bytecode, code_hash, bytecode_address))
}
pub fn mload<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn_top!([], top, context.interpreter);
let offset = revm_interpreter::as_usize_or_fail!(context.interpreter, top);
resize_memory_mip3!(context.interpreter, offset, 32);
*top =
U256::try_from_be_slice(context.interpreter.memory.slice_len(offset, 32).as_ref()).unwrap();
Ok(())
}
pub fn mstore<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([offset, value], context.interpreter);
let offset = revm_interpreter::as_usize_or_fail!(context.interpreter, offset);
resize_memory_mip3!(context.interpreter, offset, 32);
context.interpreter.memory.set(offset, &value.to_be_bytes::<32>());
Ok(())
}
pub fn mstore8<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([offset, value], context.interpreter);
let offset = revm_interpreter::as_usize_or_fail!(context.interpreter, offset);
resize_memory_mip3!(context.interpreter, offset, 1);
context.interpreter.memory.set(offset, &[value.byte(0)]);
Ok(())
}
pub fn mcopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::check!(context.interpreter, CANCUN);
revm_interpreter::popn!([dst, src, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
revm_interpreter::gas!(context.interpreter, context.host.gas_params().mcopy_cost(len));
if len == 0 {
return Ok(());
}
let dst = revm_interpreter::as_usize_or_fail!(context.interpreter, dst);
let src = revm_interpreter::as_usize_or_fail!(context.interpreter, src);
resize_memory_mip3!(context.interpreter, max(dst, src), len);
context.interpreter.memory.copy(dst, src, len);
Ok(())
}
pub fn keccak256<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn_top!([offset], top, context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, top);
revm_interpreter::gas!(context.interpreter, context.host.gas_params().keccak256_cost(len));
let hash = if len == 0 {
KECCAK_EMPTY
} else {
let from = revm_interpreter::as_usize_or_fail!(context.interpreter, offset);
resize_memory_mip3!(context.interpreter, from, len);
revm::primitives::keccak256(
context.interpreter.memory.slice_len(from, len).as_ref() as &[u8]
)
};
*top = hash.into();
Ok(())
}
pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([memory_offset, data_offset, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
let Some(memory_offset) = monad_copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
)?
else {
return Ok(());
};
let data_offset = revm_interpreter::as_usize_saturated!(data_offset);
match context.interpreter.input.input() {
CallInput::Bytes(bytes) => {
context.interpreter.memory.set_data(memory_offset, data_offset, len, bytes.as_ref());
}
CallInput::SharedBuffer(range) => {
context.interpreter.memory.set_data_from_global(
memory_offset,
data_offset,
len,
range.clone(),
);
}
}
Ok(())
}
pub fn codecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([memory_offset, code_offset, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
let Some(memory_offset) = monad_copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
)?
else {
return Ok(());
};
let code_offset = revm_interpreter::as_usize_saturated!(code_offset);
context.interpreter.memory.set_data(
memory_offset,
code_offset,
len,
context.interpreter.bytecode.bytecode_slice(),
);
Ok(())
}
pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::check!(context.interpreter, BYZANTIUM);
revm_interpreter::popn!([memory_offset, offset, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
let data_offset = revm_interpreter::as_usize_saturated!(offset);
let data_end = data_offset.saturating_add(len);
if data_end > context.interpreter.return_data.buffer().len() {
return Err(InstructionResult::OutOfOffset);
}
let Some(memory_offset) = monad_copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
)?
else {
return Ok(());
};
context.interpreter.memory.set_data(
memory_offset,
data_offset,
len,
context.interpreter.return_data.buffer(),
);
Ok(())
}
pub fn extcodecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([address, memory_offset, code_offset, len_u256], context.interpreter);
let address = address.into_address();
let spec_id = context.interpreter.runtime_flag.spec_id();
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len_u256);
revm_interpreter::gas!(context.interpreter, context.host.gas_params().extcodecopy(len));
let mut memory_offset_usize = 0;
if len != 0 {
memory_offset_usize =
revm_interpreter::as_usize_or_fail!(context.interpreter, memory_offset);
resize_memory_mip3!(context.interpreter, memory_offset_usize, len);
}
let code = if spec_id.is_enabled_in(SpecId::BERLIN) {
let cold_load_gas = context.host.gas_params().cold_account_additional_cost();
let skip_cold_load = context.interpreter.gas.remaining() < cold_load_gas;
let account =
context.host.load_account_info_skip_cold_load(address, true, skip_cold_load)?;
if account.is_cold {
revm_interpreter::gas!(context.interpreter, cold_load_gas);
}
account.code.as_ref().unwrap().original_bytes()
} else {
context.host.load_account_code(address).ok_or(InstructionResult::FatalExternalError)?.data
};
let code_offset_usize =
core::cmp::min(revm_interpreter::as_usize_saturated!(code_offset), code.len());
context.interpreter.memory.set_data(memory_offset_usize, code_offset_usize, len, &code);
Ok(())
}
pub fn log<const N: usize, H: Host + ?Sized>(
context: InstructionContext<'_, H, impl InterpreterTypes>,
) -> Result {
revm_interpreter::require_non_staticcall!(context.interpreter);
revm_interpreter::popn!([offset, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
revm_interpreter::gas!(
context.interpreter,
context.host.gas_params().log_cost(N as u8, len as u64)
);
let data = if len == 0 {
Bytes::new()
} else {
let offset = revm_interpreter::as_usize_or_fail!(context.interpreter, offset);
resize_memory_mip3!(context.interpreter, offset, len);
Bytes::copy_from_slice(context.interpreter.memory.slice_len(offset, len).as_ref())
};
let Some(topics) = context.interpreter.stack.popn::<N>() else {
return Err(InstructionResult::StackUnderflow);
};
let log = revm::primitives::Log {
address: context.interpreter.input.target_address(),
data: revm::primitives::LogData::new(topics.into_iter().map(B256::from).collect(), data)
.expect("LogData should have <=4 topics"),
};
context.host.log(log);
Ok(())
}
fn target_is_delegated_account<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: &mut InstructionContext<'_, H, WIRE>,
) -> Result<bool, LoadError> {
let target = context.interpreter.input.target_address();
context
.host
.load_account_info_skip_cold_load(target, true, false)
.map(|account| account.code.as_ref().map(Bytecode::is_eip7702).unwrap_or(false))
}
pub fn create<WIRE: InterpreterTypes, const IS_CREATE2: bool, H: Host + ?Sized>(
mut context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::require_non_staticcall!(context.interpreter);
if IS_CREATE2 {
revm_interpreter::check!(context.interpreter, PETERSBURG);
}
match target_is_delegated_account(&mut context) {
Ok(true) => {
return Err(InstructionResult::NotActivated);
}
Ok(false) => {}
Err(LoadError::ColdLoadSkipped) => {
return Err(InstructionResult::OutOfGas);
}
Err(LoadError::DBError) => {
return Err(InstructionResult::FatalExternalError);
}
}
revm_interpreter::popn!([value, code_offset, len], context.interpreter);
let len = revm_interpreter::as_usize_or_fail!(context.interpreter, len);
let mut code = Bytes::new();
if len != 0 {
if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::SHANGHAI) {
if len > context.host.max_initcode_size() {
return Err(InstructionResult::CreateInitCodeSizeLimit);
}
revm_interpreter::gas!(
context.interpreter,
context.host.gas_params().initcode_cost(len)
);
}
let code_offset = revm_interpreter::as_usize_or_fail!(context.interpreter, code_offset);
if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::OSAKA) {
resize_memory_mip3!(context.interpreter, code_offset, len);
} else {
context.interpreter.resize_memory(context.host.gas_params(), code_offset, len)?;
}
code =
Bytes::copy_from_slice(context.interpreter.memory.slice_len(code_offset, len).as_ref());
}
let scheme = if IS_CREATE2 {
revm_interpreter::popn!([salt], context.interpreter);
revm_interpreter::gas!(context.interpreter, context.host.gas_params().create2_cost(len));
CreateScheme::Create2 { salt }
} else {
revm_interpreter::gas!(context.interpreter, context.host.gas_params().create_cost());
CreateScheme::Create
};
let mut gas_limit = context.interpreter.gas.remaining();
if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::TANGERINE) {
gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
}
revm_interpreter::gas!(context.interpreter, gas_limit);
context.interpreter.bytecode.set_action(InterpreterAction::NewFrame(FrameInput::Create(
Box::new(CreateInputs::new(
context.interpreter.input.target_address(),
scheme,
value,
code,
gas_limit,
context.interpreter.gas.reservoir(),
)),
)));
Err(InstructionResult::Suspend)
}
pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
mut context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([local_gas_limit, to, value], context.interpreter);
let to = to.into_address();
let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
let has_transfer = !value.is_zero();
if context.interpreter.runtime_flag.is_static() && has_transfer {
return Err(InstructionResult::CallNotAllowedInsideStatic);
}
let (input, return_memory_offset) =
call_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
let (gas_limit, bytecode, bytecode_hash, bytecode_address, charged_new_account_state_gas) =
load_acc_and_calc_gas_with_bytecode_address(
&mut context,
to,
has_transfer,
true,
local_gas_limit,
)?;
context.interpreter.bytecode.set_action(InterpreterAction::NewFrame(FrameInput::Call(
Box::new(CallInputs {
input: CallInput::SharedBuffer(input),
gas_limit,
target_address: to,
caller: context.interpreter.input.target_address(),
bytecode_address,
known_bytecode: (bytecode_hash, bytecode),
value: CallValue::Transfer(value),
scheme: CallScheme::Call,
is_static: context.interpreter.runtime_flag.is_static(),
return_memory_offset,
reservoir: context.interpreter.gas.reservoir(),
charged_new_account_state_gas,
}),
)));
Err(InstructionResult::Suspend)
}
pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
mut context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::popn!([local_gas_limit, to, value], context.interpreter);
let to = Address::from_word(B256::from(to));
let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
let has_transfer = !value.is_zero();
let (input, return_memory_offset) =
call_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
let (gas_limit, bytecode, bytecode_hash, bytecode_address, charged_new_account_state_gas) =
load_acc_and_calc_gas_with_bytecode_address(
&mut context,
to,
has_transfer,
false,
local_gas_limit,
)?;
context.interpreter.bytecode.set_action(InterpreterAction::NewFrame(FrameInput::Call(
Box::new(CallInputs {
input: CallInput::SharedBuffer(input),
gas_limit,
target_address: context.interpreter.input.target_address(),
caller: context.interpreter.input.target_address(),
bytecode_address,
known_bytecode: (bytecode_hash, bytecode),
value: CallValue::Transfer(value),
scheme: CallScheme::CallCode,
is_static: context.interpreter.runtime_flag.is_static(),
return_memory_offset,
reservoir: context.interpreter.gas.reservoir(),
charged_new_account_state_gas,
}),
)));
Err(InstructionResult::Suspend)
}
pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
mut context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::check!(context.interpreter, HOMESTEAD);
revm_interpreter::popn!([local_gas_limit, to], context.interpreter);
let to = Address::from_word(B256::from(to));
let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
let (input, return_memory_offset) =
call_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
let (gas_limit, bytecode, bytecode_hash, bytecode_address, charged_new_account_state_gas) =
load_acc_and_calc_gas_with_bytecode_address(
&mut context,
to,
false,
false,
local_gas_limit,
)?;
context.interpreter.bytecode.set_action(InterpreterAction::NewFrame(FrameInput::Call(
Box::new(CallInputs {
input: CallInput::SharedBuffer(input),
gas_limit,
target_address: context.interpreter.input.target_address(),
caller: context.interpreter.input.caller_address(),
bytecode_address,
known_bytecode: (bytecode_hash, bytecode),
value: CallValue::Apparent(context.interpreter.input.call_value()),
scheme: CallScheme::DelegateCall,
is_static: context.interpreter.runtime_flag.is_static(),
return_memory_offset,
reservoir: context.interpreter.gas.reservoir(),
charged_new_account_state_gas,
}),
)));
Err(InstructionResult::Suspend)
}
pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
mut context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::check!(context.interpreter, BYZANTIUM);
revm_interpreter::popn!([local_gas_limit, to], context.interpreter);
let to = Address::from_word(B256::from(to));
let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
let (input, return_memory_offset) =
call_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
let (gas_limit, bytecode, bytecode_hash, bytecode_address, charged_new_account_state_gas) =
load_acc_and_calc_gas_with_bytecode_address(
&mut context,
to,
false,
false,
local_gas_limit,
)?;
context.interpreter.bytecode.set_action(InterpreterAction::NewFrame(FrameInput::Call(
Box::new(CallInputs {
input: CallInput::SharedBuffer(input),
gas_limit,
target_address: to,
caller: context.interpreter.input.target_address(),
bytecode_address,
known_bytecode: (bytecode_hash, bytecode),
value: CallValue::Transfer(U256::ZERO),
scheme: CallScheme::StaticCall,
is_static: true,
return_memory_offset,
reservoir: context.interpreter.gas.reservoir(),
charged_new_account_state_gas,
}),
)));
Err(InstructionResult::Suspend)
}
pub fn ret<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
monad_return_inner(context.interpreter, InstructionResult::Return)
}
pub fn revert<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) -> Result {
revm_interpreter::check!(context.interpreter, BYZANTIUM);
monad_return_inner(context.interpreter, InstructionResult::Revert)
}