use crate::{CallInput, InstructionResult, InterpreterAction};
use core::{
cell::Ref,
ops::{Deref, Range},
};
use primitives::{hardfork::SpecId, Address, Bytes, B256, U256};
pub trait Immediates {
#[inline]
fn read_i16(&self) -> i16 {
self.read_u16() as i16
}
fn read_u16(&self) -> u16;
#[inline]
fn read_i8(&self) -> i8 {
self.read_u8() as i8
}
fn read_u8(&self) -> u8;
#[inline]
fn read_offset_i16(&self, offset: isize) -> i16 {
self.read_offset_u16(offset) as i16
}
fn read_offset_u16(&self, offset: isize) -> u16;
fn read_slice(&self, len: usize) -> &[u8];
}
pub trait InputsTr {
fn target_address(&self) -> Address;
fn bytecode_address(&self) -> Option<&Address>;
fn caller_address(&self) -> Address;
fn input(&self) -> &CallInput;
fn call_value(&self) -> U256;
}
pub trait LegacyBytecode {
fn bytecode_len(&self) -> usize;
fn bytecode_slice(&self) -> &[u8];
}
pub trait Jumps {
fn relative_jump(&mut self, offset: isize);
fn absolute_jump(&mut self, offset: usize);
fn is_valid_legacy_jump(&mut self, offset: usize) -> bool;
fn pc(&self) -> usize;
fn opcode(&self) -> u8;
}
pub trait MemoryTr {
fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]);
fn set_data_from_global(
&mut self,
memory_offset: usize,
data_offset: usize,
len: usize,
data_range: Range<usize>,
);
fn global_slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
fn local_memory_offset(&self) -> usize;
fn set(&mut self, memory_offset: usize, data: &[u8]);
fn size(&self) -> usize;
fn copy(&mut self, destination: usize, source: usize, len: usize);
fn slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
fn slice_len(&self, offset: usize, len: usize) -> impl Deref<Target = [u8]> + '_ {
self.slice(offset..offset + len)
}
fn resize(&mut self, new_size: usize) -> bool;
#[cfg(feature = "memory_limit")]
fn limit_reached(&self, offset: usize, len: usize) -> bool;
}
pub trait StackTr {
fn len(&self) -> usize;
fn data(&self) -> &[U256];
fn is_empty(&self) -> bool {
self.len() == 0
}
fn clear(&mut self);
#[must_use]
fn push(&mut self, value: U256) -> bool;
fn push_slice(&mut self, slice: &[u8]) -> bool;
#[must_use]
fn push_b256(&mut self, value: B256) -> bool {
self.push(value.into())
}
#[must_use]
fn popn<const N: usize>(&mut self) -> Option<[U256; N]>;
#[must_use]
fn popn_top<const POPN: usize>(&mut self) -> Option<([U256; POPN], &mut U256)>;
#[must_use]
fn top(&mut self) -> Option<&mut U256> {
self.popn_top().map(|([], top)| top)
}
#[must_use]
fn pop(&mut self) -> Option<U256> {
self.popn::<1>().map(|[value]| value)
}
#[must_use]
fn pop_address(&mut self) -> Option<Address> {
self.pop().map(|value| Address::from(value.to_be_bytes()))
}
#[must_use]
fn exchange(&mut self, n: usize, m: usize) -> bool;
#[must_use]
fn dup(&mut self, n: usize) -> bool;
}
pub trait ReturnData {
fn buffer(&self) -> &Bytes;
fn set_buffer(&mut self, bytes: Bytes);
fn clear(&mut self) {
self.set_buffer(Bytes::new());
}
}
pub trait LoopControl {
fn is_not_end(&self) -> bool;
#[inline]
fn is_end(&self) -> bool {
!self.is_not_end()
}
fn reset_action(&mut self);
fn set_action(&mut self, action: InterpreterAction);
fn action(&mut self) -> &mut Option<InterpreterAction>;
#[inline]
fn instruction_result(&mut self) -> Option<InstructionResult> {
self.action()
.as_ref()
.and_then(|action| action.instruction_result())
}
}
pub trait RuntimeFlag {
fn is_static(&self) -> bool;
fn spec_id(&self) -> SpecId;
}
pub trait Interp {
type Instruction;
type Action;
fn run(&mut self, instructions: &[Self::Instruction; 256]) -> Self::Action;
}
pub trait InterpreterTypes {
type Stack: StackTr;
type Memory: MemoryTr;
type Bytecode: Jumps + Immediates + LoopControl + LegacyBytecode;
type ReturnData: ReturnData;
type Input: InputsTr;
type RuntimeFlag: RuntimeFlag;
type Extend;
type Output;
}