use crate::{
interpreter::Interpreter,
interpreter_types::{
InputsTr, InterpreterTypes, LegacyBytecode, MemoryTr, ReturnData, RuntimeFlag, StackTr,
},
CallInput, InstructionResult,
};
use context_interface::{cfg::GasParams, Host};
use core::ptr;
use primitives::{B256, KECCAK_EMPTY, U256};
use crate::InstructionContext;
pub fn keccak256<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
popn_top!([offset], top, context.interpreter);
let len = as_usize_or_fail!(context.interpreter, top);
gas!(
context.interpreter,
context.host.gas_params().keccak256_cost(len)
);
let hash = if len == 0 {
KECCAK_EMPTY
} else {
let from = as_usize_or_fail!(context.interpreter, offset);
resize_memory!(context.interpreter, context.host.gas_params(), from, len);
primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref())
};
*top = hash.into();
}
pub fn address<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
push!(
context.interpreter,
context
.interpreter
.input
.target_address()
.into_word()
.into()
);
}
pub fn caller<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
push!(
context.interpreter,
context
.interpreter
.input
.caller_address()
.into_word()
.into()
);
}
pub fn codesize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
push!(
context.interpreter,
U256::from(context.interpreter.bytecode.bytecode_len())
);
}
pub fn codecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
popn!([memory_offset, code_offset, len], context.interpreter);
let len = as_usize_or_fail!(context.interpreter, len);
let Some(memory_offset) = copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
) else {
return;
};
let code_offset = as_usize_saturated!(code_offset);
context.interpreter.memory.set_data(
memory_offset,
code_offset,
len,
context.interpreter.bytecode.bytecode_slice(),
);
}
pub fn calldataload<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([], offset_ptr, context.interpreter);
let mut word = B256::ZERO;
let offset = as_usize_saturated!(*offset_ptr);
let input = context.interpreter.input.input();
let input_len = input.len();
if offset < input_len {
let count = 32.min(input_len - offset);
let input = &*input.as_bytes_memory(&context.interpreter.memory);
unsafe { ptr::copy_nonoverlapping(input.as_ptr().add(offset), word.as_mut_ptr(), count) };
}
*offset_ptr = word.into();
}
pub fn calldatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
push!(
context.interpreter,
U256::from(context.interpreter.input.input().len())
);
}
pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
push!(context.interpreter, context.interpreter.input.call_value());
}
pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
popn!([memory_offset, data_offset, len], context.interpreter);
let len = as_usize_or_fail!(context.interpreter, len);
let Some(memory_offset) = copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
) else {
return;
};
let data_offset = 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(),
);
}
}
}
pub fn returndatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
check!(context.interpreter, BYZANTIUM);
push!(
context.interpreter,
U256::from(context.interpreter.return_data.buffer().len())
);
}
pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
check!(context.interpreter, BYZANTIUM);
popn!([memory_offset, offset, len], context.interpreter);
let len = as_usize_or_fail!(context.interpreter, len);
let data_offset = as_usize_saturated!(offset);
let data_end = data_offset.saturating_add(len);
if data_end > context.interpreter.return_data.buffer().len() {
context.interpreter.halt(InstructionResult::OutOfOffset);
return;
}
let Some(memory_offset) = copy_cost_and_memory_resize(
context.interpreter,
context.host.gas_params(),
memory_offset,
len,
) else {
return;
};
context.interpreter.memory.set_data(
memory_offset,
data_offset,
len,
context.interpreter.return_data.buffer(),
);
}
pub fn gas<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
let gas = &context.interpreter.gas;
push!(context.interpreter, U256::from(gas.remaining()));
}
pub fn copy_cost_and_memory_resize(
interpreter: &mut Interpreter<impl InterpreterTypes>,
gas_params: &GasParams,
memory_offset: U256,
len: usize,
) -> Option<usize> {
gas!(interpreter, gas_params.copy_cost(len), None);
if len == 0 {
return None;
}
let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
resize_memory!(interpreter, gas_params, memory_offset, len, None);
Some(memory_offset)
}