From e1b771c2923adf4d870b3bc0f85cfaa61c963296 Mon Sep 17 00:00:00 2001 From: Fedor Sakharov Date: Fri, 14 Jun 2024 18:02:40 +0200 Subject: [PATCH] initial commit: test_code_oracle works --- ..._to_msg_value_far_call_forward_fat_pointer | Bin 834 -> 0 bytes afl-fuzz/in/return_calldata | Bin 799 -> 0 bytes src/decode.rs | 7 +- src/decommit.rs | 32 ++++- src/fat_pointer.rs | 1 + src/instruction_handlers/decommit.rs | 117 ++++++++++++++++++ src/instruction_handlers/mod.rs | 1 + src/program.rs | 4 + src/single_instruction_test/heap.rs | 2 + src/single_instruction_test/vm.rs | 5 - src/state.rs | 16 ++- src/vm.rs | 1 + 12 files changed, 173 insertions(+), 13 deletions(-) delete mode 100644 afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer delete mode 100644 afl-fuzz/in/return_calldata create mode 100644 src/instruction_handlers/decommit.rs diff --git a/afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer b/afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer deleted file mode 100644 index b9842250bcf515c86b0dc6c4f7185e8b5ce0abad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 834 zcmZQzKnL3{{`c;eHu|T;U#nf3v!iErB8$`U97cZzMn=Xx9h^YrjJ385rK@eTzBfOw zjL-=-+U#ck-v2km!;n|-jz?X zG>t3%9W(L|JM`({0tLOPN_F!lIc{9KWc{2@>p50@)4aC4Rc*Z$wrq3R^Gz3aTgEQ= zU(diWJJ;<%41dnTt&6V}{#sxnb!iufS<-snh;{AJTbI3zb<>f(jQ(69b$DTU%o2h(t=|*;!y-#nQ@V2u5pLqmSn%f5+nPWd9UJkdJI^kvbG)}}TXlRT*ZmC!d~qB0 z?YL*ja3tbE6_?gOaS11ZrIO~;BQy3Yl-}F3;W88)#O>YeV)j`Kj0~TZmv?dKmoqfZap5)cE zv%vY#tfgo9PgZ5F>^i$v(`lcA(fRKOYqSo;^XKL1XN2&F`lc`*LDmXkBPU*DOBEUa za)B_q<)t~7P!jmw?+UI!ni$)Z%_6H@Z)POCNx1WZ{o>R7w`I#F Kq^1NvfHDC0rCp~0 diff --git a/afl-fuzz/in/return_calldata b/afl-fuzz/in/return_calldata deleted file mode 100644 index 501238b834ce82a391aeebf4e267357bc77edbb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 799 zcmZQzKnL3{{`c;eHu|T;U#nf3v!iErB8$`U97cZzMn=ZH-xYu)LyZ+<{uPI!jz2SM zVr)}3i>z|JnUU}&;m!;8i%)|elqkk=eiw;;m=vPb@8>rUkgm6F6{y_OIq(6v93LO>#~=z&RGfHTH#FIbB&d*4%$0c zb~bU&{k^!2(d^zEj_x3@HuOM2gB6{RO){!cDvx3*MZ1TN7xbV4fA=1a$ziz~82R$KC% zKd^eCNaBaQWDy zrPD2r!fUrqezJqx0Vn*5C(P2SR;Q7>~R#6*gb#w{elG(t$YstRnp~fBuRx o{ro`wc>bJ%+<+^l!sme@@34ba=QwJ-0(p&dTzHMHU4w-y03f7NV*mgE diff --git a/src/decode.rs b/src/decode.rs index afc14635..b952904f 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -283,7 +283,12 @@ pub(crate) fn decode(raw: u64, is_bootloader: bool) -> Instruction { out.try_into().unwrap(), arguments, ), - x => unimplemented_instruction(zkevm_opcode_defs::Opcode::Log(x)), + zkevm_opcode_defs::LogOpcode::Decommit => Instruction::from_decommit( + src1.try_into().unwrap(), + src2, + out.try_into().unwrap(), + arguments, + ), }, zkevm_opcode_defs::Opcode::UMA(x) => { let increment = parsed.variant.flags[UMA_INCREMENT_FLAG_IDX]; diff --git a/src/decommit.rs b/src/decommit.rs index a3806c6b..0401a544 100644 --- a/src/decommit.rs +++ b/src/decommit.rs @@ -1,9 +1,15 @@ use crate::{program::Program, world_diff::WorldDiff, World}; -use u256::{H160, U256}; +use u256::{H160, H256, U256}; use zkevm_opcode_defs::{ ethereum_types::Address, system_params::DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW, }; +pub fn u256_to_h256(num: U256) -> H256 { + let mut bytes = [0u8; 32]; + num.to_big_endian(&mut bytes); + H256::from_slice(&bytes) +} + impl WorldDiff { pub(crate) fn decommit( &mut self, @@ -67,14 +73,23 @@ impl WorldDiff { code_info[1] = 0; let code_key: U256 = U256::from_big_endian(&code_info); - let cost = if self.decommitted_hashes.as_ref().contains_key(&code_key) { + println!("code key {:?}", H256::from(code_info)); + let is_initial = self.decommitted_hashes.as_ref().contains_key(&code_key); + let cost = if is_initial { 0 } else { let code_length_in_words = u16::from_be_bytes([code_info[2], code_info[3]]); code_length_in_words as u32 * zkevm_opcode_defs::ERGS_PER_CODE_WORD_DECOMMITTMENT }; - Some((UnpaidDecommit { cost, code_key }, is_evm)) + Some(( + UnpaidDecommit { + cost, + code_key, + is_initial, + }, + is_evm, + )) } pub(crate) fn pay_for_decommit( @@ -94,8 +109,15 @@ impl WorldDiff { } pub(crate) struct UnpaidDecommit { - cost: u32, - code_key: U256, + pub cost: u32, + pub code_key: U256, + pub is_initial: bool, +} + +impl UnpaidDecommit { + pub fn is_initial(&self) -> bool { + self.is_initial + } } /// May be used to load code when the VM first starts up. diff --git a/src/fat_pointer.rs b/src/fat_pointer.rs index fc0aa9b9..88c15df3 100644 --- a/src/fat_pointer.rs +++ b/src/fat_pointer.rs @@ -1,6 +1,7 @@ use crate::heap::HeapId; use u256::U256; +#[derive(Debug)] #[repr(C)] pub struct FatPointer { pub offset: u32, diff --git a/src/instruction_handlers/decommit.rs b/src/instruction_handlers/decommit.rs new file mode 100644 index 00000000..48dd0383 --- /dev/null +++ b/src/instruction_handlers/decommit.rs @@ -0,0 +1,117 @@ +use u256::{H256, U256}; +use zkevm_opcode_defs::{ + BlobSha256Format, ContractCodeSha256Format, VersionedHashHeader, VersionedHashLen32, + VersionedHashNormalizedPreimage, +}; + +use crate::{ + addressing_modes::{Addressable, Arguments, Destination, Register1, Register2, Source}, + decommit::UnpaidDecommit, + fat_pointer::FatPointer, + instruction::InstructionResult, + Instruction, VirtualMachine, World, +}; + +use super::{common::instruction_boilerplate_with_panic, HeapInterface}; + +pub fn u256_to_h256(num: U256) -> H256 { + let mut bytes = [0u8; 32]; + num.to_big_endian(&mut bytes); + H256::from_slice(&bytes) +} + +fn decommit( + vm: &mut VirtualMachine, + instruction: *const Instruction, + world: &mut dyn World, +) -> InstructionResult { + instruction_boilerplate_with_panic( + vm, + instruction, + world, + |vm, args, world, continue_normally| { + let extra_cost = Register2::get(args, &mut vm.state).low_u32(); + let code_hash = Register1::get(args, &mut vm.state); + + /* + let unpaid_decommit = vm.world_diff.decommit( + world, + CodeInfo::CodeHash(code_hash), + vm.settings.default_aa_code_hash, + vm.settings.evm_interpreter_code_hash, + vm.state.in_kernel_mode(), + ); + + if unpaid_decommit.as_ref().unwrap().0.is_initial() { + vm.state.current_frame.gas.saturating_sub(extra_cost); + } + */ + + let unpaid_decommit = UnpaidDecommit { + cost: 1000, + code_key: code_hash, + is_initial: true, + }; + + let decommit_result = vm.world_diff.pay_for_decommit( + world, + unpaid_decommit, + &mut vm.state.current_frame.gas, + ); + + let heap = vm.state.heaps.allocate(); + let mut length = decommit_result + .as_ref() + .unwrap() + .code_page() + .as_ref() + .len() + .try_into() + .unwrap(); + + length *= 32; + + for (i, word) in decommit_result + .unwrap() + .code_page() + .as_ref() + .iter() + .enumerate() + { + let mut bytes = [0; 32]; + word.to_big_endian(&mut bytes); + let h: H256 = H256::from(bytes); + + vm.state.heaps[heap].write_u256((i * 32) as u32, *word); + } + + let value = FatPointer { + offset: 0, + memory_page: heap, + start: 0, + length, + }; + dbg!(&value); + let value = value.into_u256(); + Register1::set_fat_ptr(args, &mut vm.state, value); + + continue_normally + }, + ) +} +impl Instruction { + pub fn from_decommit( + abi: Register1, + burn: Register2, + out: Register1, + arguments: Arguments, + ) -> Self { + Self { + arguments: arguments + .write_source(&abi) + .write_source(&burn) + .write_destination(&out), + handler: decommit, + } + } +} diff --git a/src/instruction_handlers/mod.rs b/src/instruction_handlers/mod.rs index a8dc7e08..220566d7 100644 --- a/src/instruction_handlers/mod.rs +++ b/src/instruction_handlers/mod.rs @@ -7,6 +7,7 @@ pub(crate) use ret::{free_panic, PANIC}; mod binop; mod common; mod context; +mod decommit; mod event; mod far_call; mod heap_access; diff --git a/src/program.rs b/src/program.rs index ac6d6b80..4f961956 100644 --- a/src/program.rs +++ b/src/program.rs @@ -25,6 +25,10 @@ impl Program { self.instructions.get::(n.into()) } + pub fn instructions(&self) -> &[Instruction] { + &self.instructions + } + pub fn code_page(&self) -> &Arc<[U256]> { &self.code_page } diff --git a/src/single_instruction_test/heap.rs b/src/single_instruction_test/heap.rs index c33548bf..da76841d 100644 --- a/src/single_instruction_test/heap.rs +++ b/src/single_instruction_test/heap.rs @@ -30,6 +30,8 @@ impl HeapInterface for Heap { self.write = Some((start_address, value)); } + fn memset(&mut self, mem: &[U256]) {} + fn read_range_big_endian(&self, _: std::ops::Range) -> Vec { // This is wrong, but this method is only used to get the final return value. vec![] diff --git a/src/single_instruction_test/vm.rs b/src/single_instruction_test/vm.rs index 503d8981..28b6819e 100644 --- a/src/single_instruction_test/vm.rs +++ b/src/single_instruction_test/vm.rs @@ -40,11 +40,6 @@ impl VirtualMachine { } pub fn instruction_is_not_precompile_call(&self) -> bool { - // TODO PLA-934 implement Decommit - if self.current_opcode() == 1093 { - return false; - } - // TODO PLA-972 implement StaticMemoryRead/Write if (1096..=1103).contains(&self.current_opcode()) { return false; diff --git a/src/state.rs b/src/state.rs index 3d8681d0..e46e6535 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,7 @@ use crate::{ addressing_modes::Addressable, callframe::Callframe, + decommit::u256_into_address, fat_pointer::FatPointer, heap::{Heaps, CALLDATA_HEAP, FIRST_AUX_HEAP, FIRST_HEAP}, predication::Flags, @@ -10,7 +11,7 @@ use crate::{ }; use u256::{H160, U256}; -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq)] pub struct State { pub registers: [U256; 16], pub(crate) register_pointer_flags: u16, @@ -30,6 +31,17 @@ pub struct State { pub(crate) context_u128: u128, } +impl std::fmt::Debug for State { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("State") + .field("registers", &self.registers) + .field("register_pointer_flags", &self.register_pointer_flags) + .field("flags", &self.flags) + .field("callframe", &self.current_frame) + .finish() + } +} + impl State { pub(crate) fn new( address: H160, @@ -40,7 +52,7 @@ impl State { world_before_this_frame: Snapshot, stack: Box, ) -> Self { - let mut registers: [U256; 16] = Default::default(); + let mut registers = [0.into(); 16]; registers[1] = FatPointer { memory_page: CALLDATA_HEAP, offset: 0, diff --git a/src/vm.rs b/src/vm.rs index 8243d016..b697ede7 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -281,6 +281,7 @@ impl VirtualMachine { #[cfg(feature = "trace")] fn print_instruction(&self, instruction: *const Instruction) { + return; print!("{:?}: ", unsafe { instruction.offset_from(self.state.current_frame.program.instruction(0).unwrap()) });