use crate::{
Error, U256,
vm::{
Ext,
evm::{
EVMGas, Interpreter,
interpreter::Halt,
util::{as_usize_or_halt, as_usize_or_halt_with},
},
},
};
use alloc::vec::Vec;
use core::ops::ControlFlow;
use revm::interpreter::gas::{BASE, HIGH, JUMPDEST, MID};
pub fn jump<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(MID))?;
let [target] = interpreter.stack.popn()?;
jump_inner(interpreter, target)?;
ControlFlow::Continue(())
}
pub fn jumpi<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(HIGH))?;
let [target, cond] = interpreter.stack.popn()?;
if !cond.is_zero() {
jump_inner(interpreter, target)?;
}
ControlFlow::Continue(())
}
#[inline(always)]
fn jump_inner<E: Ext>(interpreter: &mut Interpreter<E>, target: U256) -> ControlFlow<Halt> {
let target = as_usize_or_halt_with(target, || Error::<E::T>::InvalidJump.into())?;
if !interpreter.bytecode.is_valid_legacy_jump(target) {
return ControlFlow::Break(Error::<E::T>::InvalidJump.into());
}
interpreter.bytecode.absolute_jump(target);
ControlFlow::Continue(())
}
pub fn jumpdest<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(JUMPDEST))?;
ControlFlow::Continue(())
}
pub fn pc<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(BASE))?;
interpreter.stack.push(U256::from(interpreter.bytecode.pc() - 1))?;
ControlFlow::Continue(())
}
#[inline]
fn return_inner<E: Ext>(
interpreter: &mut Interpreter<E>,
halt: impl Fn(Vec<u8>) -> Halt,
) -> ControlFlow<Halt> {
let [offset, len] = interpreter.stack.popn()?;
let len = as_usize_or_halt::<E::T>(len)?;
let mut output = Default::default();
if len != 0 {
let offset = as_usize_or_halt::<E::T>(offset)?;
interpreter.memory.resize(offset, len)?;
output = interpreter.memory.slice_len(offset, len).to_vec()
}
ControlFlow::Break(halt(output))
}
pub fn ret<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
return_inner(interpreter, Halt::Return)
}
pub fn revert<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
return_inner(interpreter, Halt::Revert)
}
pub fn stop<E: Ext>(_interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
ControlFlow::Break(Halt::Stop)
}
pub fn invalid<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.frame_meter_mut().consume_all_weight();
ControlFlow::Break(Error::<E::T>::InvalidInstruction.into())
}
#[cfg(feature = "runtime-benchmarks")]
pub fn bench_init_code() -> ControlFlow<Halt> {
let runtime_code =
alloc::vec![revm::bytecode::opcode::STOP; revm::primitives::eip170::MAX_CODE_SIZE];
ControlFlow::Break(Halt::Return(runtime_code))
}