Skip to content

Commit

Permalink
Merge branch 'master' into fs-remove-cargo-deny.yml
Browse files Browse the repository at this point in the history
  • Loading branch information
montekki authored May 21, 2024
2 parents 038bd49 + 493fcec commit 9802d66
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 89 deletions.
35 changes: 26 additions & 9 deletions src/callframe.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use crate::{modified_world::Snapshot, program::Program, stack::Stack, Instruction};
use crate::{
address_into_u256, decommit::is_kernel, heap::HeapId, modified_world::Snapshot,
program::Program, stack::Stack, Instruction,
};
use u256::H160;
use zkevm_opcode_defs::system_params::{NEW_FRAME_MEMORY_STIPEND, NEW_KERNEL_FRAME_MEMORY_STIPEND};

#[derive(Clone, PartialEq, Debug)]
pub struct Callframe {
Expand All @@ -12,9 +16,6 @@ pub struct Callframe {
pub is_static: bool,

pub stack: Box<Stack>,

pub heap: u32,
pub aux_heap: u32,
pub sp: u16,

pub gas: u32,
Expand All @@ -26,16 +27,24 @@ pub struct Callframe {

pub(crate) program: Program,

pub heap: HeapId,
pub aux_heap: HeapId,

/// The amount of heap that has been paid for. This should always be greater
/// or equal to the actual size of the heap in memory.
pub heap_size: u32,
pub aux_heap_size: u32,

/// Returning a pointer to the calldata is illegal because it could result in
/// the caller's heap being accessible both directly and via the fat pointer.
/// The problem only occurs if the calldata originates from the caller's heap
/// but this rule is easy to implement.
pub(crate) calldata_heap: u32,
pub(crate) calldata_heap: HeapId,

/// Because of the above rule we know that heaps returned to this frame only
/// exist to allow this frame to read from them. Therefore we can deallocate
/// all of them upon return, except possibly one that we pass on.
pub(crate) heaps_i_am_keeping_alive: Vec<u32>,
pub(crate) heaps_i_am_keeping_alive: Vec<HeapId>,

pub(crate) world_before_this_frame: Snapshot,
}
Expand All @@ -57,16 +66,22 @@ impl Callframe {
caller: H160,
program: Program,
stack: Box<Stack>,
heap: u32,
aux_heap: u32,
calldata_heap: u32,
heap: HeapId,
aux_heap: HeapId,
calldata_heap: HeapId,
gas: u32,
stipend: u32,
exception_handler: u16,
context_u128: u128,
is_static: bool,
world_before_this_frame: Snapshot,
) -> Self {
let heap_size = if is_kernel(address_into_u256(code_address)) {
NEW_KERNEL_FRAME_MEMORY_STIPEND
} else {
NEW_FRAME_MEMORY_STIPEND
};

Self {
address,
code_address,
Expand All @@ -77,6 +92,8 @@ impl Callframe {
stack,
heap,
aux_heap,
heap_size,
aux_heap_size: heap_size,
calldata_heap,
heaps_i_am_keeping_alive: vec![],
sp: 1024,
Expand Down
5 changes: 3 additions & 2 deletions src/fat_pointer.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::heap::HeapId;
use u256::U256;

#[repr(C)]
pub(crate) struct FatPointer {
pub struct FatPointer {
pub offset: u32,
pub memory_page: u32,
pub memory_page: HeapId,
pub start: u32,
pub length: u32,
}
Expand Down
67 changes: 67 additions & 0 deletions src/heap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::ops::{Index, IndexMut};

use zkevm_opcode_defs::system_params::NEW_FRAME_MEMORY_STIPEND;

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct HeapId(u32);

impl HeapId {
/// Only for dealing with external data structures, never use internally.
pub fn from_u32_unchecked(value: u32) -> Self {
Self(value)
}

pub fn to_u32(self) -> u32 {
self.0
}
}

#[derive(Debug, Clone)]
pub struct Heaps(Vec<Vec<u8>>);

pub(crate) const CALLDATA_HEAP: HeapId = HeapId(1);
pub const FIRST_HEAP: HeapId = HeapId(2);
pub(crate) const FIRST_AUX_HEAP: HeapId = HeapId(3);

impl Heaps {
pub(crate) fn new(calldata: Vec<u8>) -> Self {
// The first heap can never be used because heap zero
// means the current heap in precompile calls
Self(vec![vec![], calldata, vec![], vec![]])
}

pub(crate) fn allocate(&mut self) -> HeapId {
let id = HeapId(self.0.len() as u32);
self.0.push(vec![0; NEW_FRAME_MEMORY_STIPEND as usize]);
id
}

pub(crate) fn deallocate(&mut self, heap: HeapId) {
self.0[heap.0 as usize] = vec![];
}
}

impl Index<HeapId> for Heaps {
type Output = Vec<u8>;

fn index(&self, index: HeapId) -> &Self::Output {
&self.0[index.0 as usize]
}
}

impl IndexMut<HeapId> for Heaps {
fn index_mut(&mut self, index: HeapId) -> &mut Self::Output {
&mut self.0[index.0 as usize]
}
}

impl PartialEq for Heaps {
fn eq(&self, other: &Self) -> bool {
for i in 0..self.0.len().max(other.0.len()) {
if self.0.get(i).unwrap_or(&vec![]) != other.0.get(i).unwrap_or(&vec![]) {
return false;
}
}
true
}
}
4 changes: 2 additions & 2 deletions src/instruction_handlers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ struct Meta;
impl ContextOp for Meta {
fn get(state: &State) -> U256 {
VmMetaParameters {
heap_size: state.heaps[state.current_frame.heap].len() as u32,
aux_heap_size: state.heaps[state.current_frame.aux_heap].len() as u32,
heap_size: state.current_frame.heap_size,
aux_heap_size: state.current_frame.aux_heap_size,
this_shard_id: 0, // TODO properly implement shards
caller_shard_id: 0,
code_shard_id: 0,
Expand Down
31 changes: 18 additions & 13 deletions src/instruction_handlers/heap_access.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
use super::{common::instruction_boilerplate_with_panic, PANIC};
use crate::{
address_into_u256,
addressing_modes::{
Arguments, Destination, DestinationWriter, Immediate1, Register1, Register2,
RegisterOrImmediate, Source,
},
decommit::is_kernel,
fat_pointer::FatPointer,
instruction::InstructionResult,
state::State,
ExecutionEnd, Instruction, VirtualMachine, World,
};
use u256::U256;
use zkevm_opcode_defs::system_params::NEW_KERNEL_FRAME_MEMORY_STIPEND;

pub trait HeapFromState {
fn get_heap(state: &mut State) -> &mut Vec<u8>;
fn get_heap_size(state: &mut State) -> &mut u32;
}

pub struct Heap;
impl HeapFromState for Heap {
fn get_heap(state: &mut State) -> &mut Vec<u8> {
&mut state.heaps[state.current_frame.heap]
}
fn get_heap_size(state: &mut State) -> &mut u32 {
&mut state.current_frame.heap_size
}
}

pub struct AuxHeap;
impl HeapFromState for AuxHeap {
fn get_heap(state: &mut State) -> &mut Vec<u8> {
&mut state.heaps[state.current_frame.aux_heap]
}
fn get_heap_size(state: &mut State) -> &mut u32 {
&mut state.current_frame.aux_heap_size
}
}

/// The last address to which 32 can be added without overflow.
Expand Down Expand Up @@ -119,17 +123,18 @@ fn store<H: HeapFromState, In: Source, const INCREMENT: bool, const HOOKING_ENAB
}

pub fn grow_heap<H: HeapFromState>(state: &mut State, new_bound: u32) -> Result<(), ()> {
let heap_length = H::get_heap(state).len() as u32;
let already_paid = if is_kernel(address_into_u256(state.current_frame.code_address)) {
heap_length.max(NEW_KERNEL_FRAME_MEMORY_STIPEND)
} else {
heap_length
};

state.use_gas(new_bound.saturating_sub(already_paid))?;
if heap_length < new_bound {
H::get_heap(state).resize(new_bound as usize, 0);
let already_paid = H::get_heap_size(state);
if *already_paid < new_bound {
let to_pay = new_bound - *already_paid;
*already_paid = new_bound;
state.use_gas(to_pay)?;
}

let heap = H::get_heap(state);
if (heap.len() as u32) < new_bound {
heap.resize(new_bound as usize, 0);
}

Ok(())
}

Expand Down
9 changes: 5 additions & 4 deletions src/instruction_handlers/precompiles.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::{common::instruction_boilerplate_with_panic, PANIC};
use crate::{
addressing_modes::{Arguments, Destination, Register1, Register2, Source},
heap::{HeapId, Heaps},
instruction::InstructionResult,
state::Heaps,
Instruction, VirtualMachine, World,
};
use u256::U256;
Expand Down Expand Up @@ -42,10 +42,10 @@ fn precompile_call(

let mut abi = PrecompileCallABI::from_u256(Register1::get(args, &mut vm.state));
if abi.memory_page_to_read == 0 {
abi.memory_page_to_read = vm.state.current_frame.heap;
abi.memory_page_to_read = vm.state.current_frame.heap.to_u32();
}
if abi.memory_page_to_write == 0 {
abi.memory_page_to_write = vm.state.current_frame.heap;
abi.memory_page_to_write = vm.state.current_frame.heap.to_u32();
}

let query = LogQuery {
Expand Down Expand Up @@ -95,7 +95,8 @@ impl Memory for Heaps {
_monotonic_cycle_counter: u32,
mut query: zk_evm_abstractions::queries::MemoryQuery,
) -> zk_evm_abstractions::queries::MemoryQuery {
let page = query.location.page.0;
let page = HeapId::from_u32_unchecked(query.location.page.0);

let start = query.location.index.0 as usize * 32;
let range = start..start + 32;
if query.rw_flag {
Expand Down
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ mod bitset;
mod callframe;
pub mod decode;
mod decommit;
mod fat_pointer;
pub mod fat_pointer;
mod heap;
mod instruction;
pub mod instruction_handlers;
mod modified_world;
Expand All @@ -21,11 +22,12 @@ use u256::{H160, U256};

pub use decommit::address_into_u256;
pub use decommit::initial_decommit;
pub use heap::{HeapId, FIRST_HEAP};
pub use instruction::{jump_to_beginning, ExecutionEnd, Instruction};
pub use modified_world::{Event, L2ToL1Log, WorldDiff};
pub use predication::Predicate;
pub use program::Program;
pub use state::{State, FIRST_HEAP};
pub use state::State;
pub use vm::{Settings, VirtualMachine, VmSnapshot as Snapshot};

pub trait World {
Expand Down
58 changes: 13 additions & 45 deletions src/state.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use crate::{
addressing_modes::Addressable, bitset::Bitset, callframe::Callframe, fat_pointer::FatPointer,
modified_world::Snapshot, predication::Flags, program::Program, stack::Stack,
addressing_modes::Addressable,
bitset::Bitset,
callframe::Callframe,
fat_pointer::FatPointer,
heap::{Heaps, CALLDATA_HEAP, FIRST_AUX_HEAP, FIRST_HEAP},
modified_world::Snapshot,
predication::Flags,
program::Program,
stack::Stack,
};
use std::ops::{Index, IndexMut};
use u256::{H160, U256};

#[derive(Clone, PartialEq, Debug)]
Expand All @@ -25,8 +31,6 @@ pub struct State {
pub(crate) context_u128: u128,
}

pub const FIRST_HEAP: u32 = 2;

impl State {
pub(crate) fn new(
address: H160,
Expand All @@ -39,7 +43,7 @@ impl State {
) -> Self {
let mut registers: [U256; 16] = Default::default();
registers[1] = FatPointer {
memory_page: 1,
memory_page: CALLDATA_HEAP,
offset: 0,
start: 0,
length: calldata.len() as u32,
Expand All @@ -57,8 +61,8 @@ impl State {
program,
stack,
FIRST_HEAP,
3,
1,
FIRST_AUX_HEAP,
CALLDATA_HEAP,
gas,
0,
0,
Expand All @@ -68,9 +72,7 @@ impl State {
),
previous_frames: vec![],

// The first heap can never be used because heap zero
// means the current heap in precompile calls
heaps: Heaps(vec![vec![], calldata, vec![], vec![]]),
heaps: Heaps::new(calldata),

transaction_number: 0,
context_u128: 0,
Expand Down Expand Up @@ -131,37 +133,3 @@ impl Addressable for State {
self.current_frame.program.code_page()
}
}

#[derive(Debug, Clone)]
pub struct Heaps(pub(crate) Vec<Vec<u8>>);

impl Heaps {
pub(crate) fn deallocate(&mut self, heap: u32) {
self.0[heap as usize] = vec![];
}
}

impl Index<u32> for Heaps {
type Output = Vec<u8>;

fn index(&self, index: u32) -> &Self::Output {
&self.0[index as usize]
}
}

impl IndexMut<u32> for Heaps {
fn index_mut(&mut self, index: u32) -> &mut Self::Output {
&mut self.0[index as usize]
}
}

impl PartialEq for Heaps {
fn eq(&self, other: &Self) -> bool {
for i in 0..self.0.len().max(other.0.len()) {
if self.0.get(i).unwrap_or(&vec![]) != other.0.get(i).unwrap_or(&vec![]) {
return false;
}
}
true
}
}
Loading

0 comments on commit 9802d66

Please sign in to comment.