use super::utility::as_usize_saturated;
use crate::{
address::AddressMapper,
vm::{
evm::{interpreter::Halt, util::as_usize_or_halt, EVMGas, Interpreter},
Ext, RuntimeCosts,
},
Config, Error, U256,
};
use core::ops::ControlFlow;
use revm::interpreter::gas::{BASE, VERYLOW};
use sp_core::H256;
use sp_io::hashing::keccak_256;
pub const KECCAK_EMPTY: [u8; 32] =
alloy_core::hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
pub fn keccak256<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
let ([offset], top) = interpreter.stack.popn_top()?;
let len = as_usize_or_halt::<E::T>(*top)?;
interpreter
.ext
.frame_meter_mut()
.charge_or_halt(RuntimeCosts::HashKeccak256(len as u32))?;
let hash = if len == 0 {
H256::from(KECCAK_EMPTY)
} else {
let from = as_usize_or_halt::<E::T>(offset)?;
interpreter.memory.resize(from, len)?;
H256::from(keccak_256(interpreter.memory.slice_len(from, len)))
};
*top = U256::from_big_endian(hash.as_ref());
ControlFlow::Continue(())
}
pub fn address<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(RuntimeCosts::Address)?;
let address = interpreter.ext.address();
interpreter.stack.push(address)
}
pub fn caller<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(RuntimeCosts::Caller)?;
match interpreter.ext.caller().account_id() {
Ok(account_id) => {
let address = <E::T as Config>::AddressMapper::to_address(account_id);
interpreter.stack.push(address)
},
Err(_) => ControlFlow::Break(Error::<E::T>::ContractTrapped.into()),
}
}
pub fn codesize<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(BASE))?;
interpreter.stack.push(U256::from(interpreter.bytecode.len()))
}
pub fn codecopy<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
let [memory_offset, code_offset, len] = interpreter.stack.popn()?;
let len = as_usize_or_halt::<E::T>(len)?;
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len)? else {
return ControlFlow::Continue(())
};
let code_offset = as_usize_saturated(code_offset);
interpreter.memory.set_data(
memory_offset,
code_offset,
len,
interpreter.bytecode.bytecode_slice(),
);
ControlFlow::Continue(())
}
pub fn calldataload<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(VERYLOW))?;
let ([], offset_ptr) = interpreter.stack.popn_top()?;
let mut word = [0u8; 32];
let offset = as_usize_saturated(*offset_ptr);
let input = &interpreter.input;
let input_len = input.len();
if offset < input_len {
let count = 32.min(input_len - offset);
word[..count].copy_from_slice(&input[offset..offset + count]);
}
*offset_ptr = U256::from_big_endian(&word);
ControlFlow::Continue(())
}
pub fn calldatasize<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(BASE))?;
interpreter.stack.push(U256::from(interpreter.input.len()))
}
pub fn callvalue<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(RuntimeCosts::ValueTransferred)?;
let value = interpreter.ext.value_transferred();
interpreter.stack.push(value)
}
pub fn calldatacopy<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
let [memory_offset, data_offset, len] = interpreter.stack.popn()?;
let len = as_usize_or_halt::<E::T>(len)?;
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len)? else {
return ControlFlow::Continue(());
};
let data_offset = as_usize_saturated(data_offset);
interpreter.memory.set_data(memory_offset, data_offset, len, &interpreter.input);
ControlFlow::Continue(())
}
pub fn returndatasize<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(BASE))?;
let return_data_len = interpreter.ext.last_frame_output().data.len();
interpreter.stack.push(U256::from(return_data_len))
}
pub fn returndatacopy<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
let [memory_offset, offset, len] = interpreter.stack.popn()?;
let len = as_usize_or_halt::<E::T>(len)?;
let data_offset = as_usize_saturated(offset);
let data_end = data_offset.saturating_add(len);
if data_end > interpreter.ext.last_frame_output().data.len() {
return ControlFlow::Break(Error::<E::T>::OutOfBounds.into());
}
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len)? else {
return ControlFlow::Continue(())
};
interpreter.memory.set_data(
memory_offset,
data_offset,
len,
&interpreter.ext.last_frame_output().data,
);
ControlFlow::Continue(())
}
pub fn gas<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(RuntimeCosts::RefTimeLeft)?;
let gas = interpreter.ext.gas_left();
interpreter.stack.push(U256::from(gas))
}
pub fn memory_resize<'a, E: Ext>(
interpreter: &mut Interpreter<'a, E>,
memory_offset: U256,
len: usize,
) -> ControlFlow<Halt, Option<usize>> {
if len == 0 {
return ControlFlow::Continue(None)
}
interpreter.ext.charge_or_halt(RuntimeCosts::CopyToContract(len as u32))?;
let memory_offset = as_usize_or_halt::<E::T>(memory_offset)?;
interpreter.memory.resize(memory_offset, len)?;
ControlFlow::Continue(Some(memory_offset))
}