use arbitrary::Arbitrary;
use primitive_types::U256;
use zksync_vm2_interface::{HeapId, Tracer};
use super::{heap::Heaps, stack::StackPool};
use crate::{
callframe::Callframe, fat_pointer::FatPointer, state::State, Settings, VirtualMachine, World,
WorldDiff,
};
impl<T: Tracer, W> VirtualMachine<T, W> {
pub fn run_single_instruction(&mut self, world: &mut W, tracer: &mut T) {
unsafe {
((*self.state.current_frame.pc).handler)(self, world, tracer);
}
}
pub fn is_in_valid_state(&self) -> bool {
self.state.is_valid()
}
pub fn instruction_is_not_precompile_call(&self) -> bool {
if (1096..=1103).contains(&self.current_opcode()) {
return false;
}
self.current_opcode() != 1056u64
}
pub fn instruction_is_far_call(&self) -> bool {
(1057..=1068).contains(&self.current_opcode())
}
fn current_opcode(&self) -> u64 {
self.state.current_frame.program.raw_first_instruction & 0x7FF
}
pub fn raw_first_instruction(&self) -> u64 {
self.state.current_frame.program.raw_first_instruction
}
}
impl<'a, T: Tracer, W: World<T>> Arbitrary<'a> for VirtualMachine<T, W> {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let current_frame: Callframe<T, W> = u.arbitrary()?;
let mut registers = [U256::zero(); 16];
let mut register_pointer_flags = 0;
for (i, register) in registers.iter_mut().enumerate().skip(1) {
let (value, is_pointer) = arbitrary_register_value(
u,
current_frame.calldata_heap,
current_frame.heap.as_u32() - 2,
)?;
*register = value;
register_pointer_flags |= u16::from(is_pointer) << i;
}
let heaps = Heaps::from_id(current_frame.heap, u)?;
Ok(Self {
state: State {
registers,
register_pointer_flags,
flags: u.arbitrary()?,
current_frame,
previous_frames: vec![Callframe::dummy()],
heaps,
transaction_number: u.arbitrary()?,
context_u128: u.arbitrary()?,
},
settings: u.arbitrary()?,
world_diff: WorldDiff::default(),
stack_pool: StackPool {},
snapshot: None,
})
}
}
pub(crate) fn arbitrary_register_value(
u: &mut arbitrary::Unstructured,
calldata_heap: HeapId,
base_page: u32,
) -> arbitrary::Result<(U256, bool)> {
Ok(if u.arbitrary()? {
(
(U256::from(u.arbitrary::<u128>()?) << 128)
| FatPointer {
offset: u.arbitrary()?,
memory_page: if u.arbitrary()? {
calldata_heap
} else {
HeapId::from_u32_unchecked(u.int_in_range(base_page..=u32::MAX)?)
},
start: u.arbitrary()?,
length: u.arbitrary()?,
}
.into_u256(),
true,
)
} else {
(u.arbitrary()?, false)
})
}
impl<'a> Arbitrary<'a> for Settings {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let mut default_aa_code_hash = [0u8; 32];
default_aa_code_hash[0] = 1;
u.fill_buffer(&mut default_aa_code_hash[2..])?;
let mut evm_interpreter_code_hash = [0u8; 32];
evm_interpreter_code_hash[0] = 1;
u.fill_buffer(&mut evm_interpreter_code_hash[2..])?;
Ok(Self {
default_aa_code_hash,
evm_interpreter_code_hash,
hook_address: 0, })
}
}