Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: decommit opcode #44

Merged
merged 12 commits into from
Jun 18, 2024
Merged
7 changes: 6 additions & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
7 changes: 7 additions & 0 deletions src/decommit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ impl WorldDiff {
Some((UnpaidDecommit { cost, code_key }, is_evm))
}

pub(crate) fn decommit_opcode(&mut self, world: &mut dyn World, code_hash: U256) -> Vec<u8> {
let mut code_info_bytes = [0; 32];
code_hash.to_big_endian(&mut code_info_bytes);
self.decommitted_hashes.insert(code_hash, ());
world.decommit_code(code_hash)
}

pub(crate) fn pay_for_decommit(
&mut self,
world: &mut dyn World,
Expand Down
3 changes: 3 additions & 0 deletions src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ impl HeapInterface for Heap {
}
result
}
fn memset(&mut self, src: &[u8]) {
self.0 = src.to_vec();
}
}

#[derive(Debug, Clone)]
Expand Down
67 changes: 67 additions & 0 deletions src/instruction_handlers/decommit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use u256::U256;
use zkevm_opcode_defs::{BlobSha256Format, ContractCodeSha256Format, VersionedHashLen32};

use crate::{
addressing_modes::{Arguments, Destination, Register1, Register2, Source},
fat_pointer::FatPointer,
instruction::InstructionResult,
Instruction, VirtualMachine, World,
};

use super::{common::instruction_boilerplate, HeapInterface};

fn decommit(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate(vm, instruction, world, |vm, args, world| {
let code_hash = Register1::get(args, &mut vm.state);
let extra_cost = Register2::get(args, &mut vm.state).low_u32();

let mut buffer = [0u8; 32];
code_hash.to_big_endian(&mut buffer);

let preimage_len_in_bytes =
zkevm_opcode_defs::system_params::NEW_KERNEL_FRAME_MEMORY_STIPEND;

if vm.state.use_gas(extra_cost).is_err()
|| (!ContractCodeSha256Format::is_valid(&buffer)
&& !BlobSha256Format::is_valid(&buffer))
{
Register1::set(args, &mut vm.state, U256::zero());
return;
}

let program = vm.world_diff.decommit_opcode(world, code_hash);

let heap = vm.state.heaps.allocate();
vm.state.current_frame.heaps_i_am_keeping_alive.push(heap);
vm.state.heaps[heap].memset(program.as_ref());

let value = FatPointer {
offset: 0,
memory_page: heap,
start: 0,
length: preimage_len_in_bytes,
};
let value = value.into_u256();
Register1::set_fat_ptr(args, &mut vm.state, value);
})
}
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,
}
}
}
1 change: 1 addition & 0 deletions src/instruction_handlers/heap_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub trait HeapInterface {
fn read_u256_partially(&self, range: Range<u32>) -> U256;
fn write_u256(&mut self, start_address: u32, value: U256);
fn read_range_big_endian(&self, range: Range<u32>) -> Vec<u8>;
fn memset(&mut self, memory: &[u8]);
}

pub trait HeapFromState {
Expand Down
1 change: 1 addition & 0 deletions src/instruction_handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub trait World {
/// the world implementor's job.
fn decommit(&mut self, hash: U256) -> Program;

fn decommit_code(&mut self, hash: U256) -> Vec<u8>;

/// There is no write_storage; [WorldDiff::get_storage_changes] gives a list of all storage changes.
fn read_storage(&mut self, contract: H160, key: U256) -> Option<U256>;

Expand Down
20 changes: 18 additions & 2 deletions src/single_instruction_test/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ impl HeapInterface for Heap {
// This is wrong, but this method is only used to get the final return value.
vec![]
}

fn memset(&mut self, src: &[u8]) {
let u = U256::from_big_endian(src);
self.write_u256(0, u);
}
}

impl<'a> Arbitrary<'a> for Heap {
Expand All @@ -45,8 +50,9 @@ impl<'a> Arbitrary<'a> for Heap {
}
}

#[derive(Debug, Clone, Arbitrary)]
#[derive(Debug, Clone)]
pub struct Heaps {
heap_id: HeapId,
pub(crate) read: MockRead<HeapId, Heap>,
}

Expand All @@ -60,10 +66,20 @@ impl Heaps {
}

pub(crate) fn allocate(&mut self) -> HeapId {
HeapId(3)
self.heap_id
}

pub(crate) fn deallocate(&mut self, _: HeapId) {}

pub(crate) fn from_id(
heap_id: HeapId,
u: &mut arbitrary::Unstructured<'_>,
) -> arbitrary::Result<Heaps> {
Ok(Heaps {
heap_id,
read: u.arbitrary()?,
})
}
}

impl Index<HeapId> for Heaps {
Expand Down
11 changes: 4 additions & 7 deletions src/single_instruction_test/vm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::stack::StackPool;
use super::{heap::Heaps, stack::StackPool};
use crate::{
callframe::Callframe, fat_pointer::FatPointer, instruction::InstructionResult,
instruction_handlers::free_panic, HeapId, Instruction, Settings, State, VirtualMachine, World,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -81,6 +76,8 @@ impl<'a> Arbitrary<'a> for VirtualMachine {
register_pointer_flags |= (is_pointer as u16) << i;
}

let heaps = Heaps::from_id(current_frame.heap, u)?;

joonazan marked this conversation as resolved.
Show resolved Hide resolved
Ok(Self {
state: State {
registers,
Expand All @@ -90,7 +87,7 @@ impl<'a> Arbitrary<'a> for VirtualMachine {
// Exiting the final frame is different in vm2 on purpose,
// so always generate two frames to avoid that.
previous_frames: vec![(0, Callframe::dummy())],
heaps: u.arbitrary()?,
heaps,
transaction_number: u.arbitrary()?,
joonazan marked this conversation as resolved.
Show resolved Hide resolved
context_u128: u.arbitrary()?,
},
Expand Down
4 changes: 4 additions & 0 deletions src/single_instruction_test/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ impl World for MockWorld {
Program::for_decommit()
}

fn decommit_code(&mut self, _hash: U256) -> Vec<u8> {
vec![0; 32]
}

fn read_storage(&mut self, contract: H160, key: U256) -> Option<U256> {
*self.storage_slot.get((contract, key))
}
Expand Down
12 changes: 12 additions & 0 deletions src/testworld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ impl World for TestWorld {
}
}

fn decommit_code(&mut self, hash: U256) -> Vec<u8> {
self.decommit(hash)
.code_page()
.iter()
.flat_map(|u256| {
let mut buffer = [0u8; 32];
u256.to_big_endian(&mut buffer);
buffer
})
.collect()
}

fn read_storage(&mut self, contract: u256::H160, key: u256::U256) -> Option<U256> {
let deployer_system_contract_address =
Address::from_low_u64_be(DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW as u64);
Expand Down
6 changes: 5 additions & 1 deletion src/world_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ mod tests {
.map(|(key, value)| (
*key,
StorageChange {
before: first_changes.get(key).or(initial_values.get(&key)).copied(),
before: first_changes.get(key).or(initial_values.get(key)).copied(),
after: *value,
is_initial: initial_values.get(key).is_none(),
tx_number: 1,
Expand Down Expand Up @@ -432,5 +432,9 @@ mod tests {
fn is_free_storage_slot(&self, _: &H160, _: &U256) -> bool {
false
}

fn decommit_code(&mut self, _: U256) -> Vec<u8> {
unimplemented!()
}
}
}
Loading