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

Zk server compatibility #221

Merged
merged 60 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
5de8afb
Derive partial-eq for VmState
MarcosNicolau Aug 13, 2024
59470a7
Add initial gas param for VmState new
MarcosNicolau Aug 13, 2024
26c2b18
Update era-compiler-tester branch
MarcosNicolau Aug 13, 2024
e5cb98b
fix test bytecode_publishing
juan518munoz Aug 14, 2024
f0dce41
Store changes for get_used_contracts tests
MarcosNicolau Aug 14, 2024
c862649
adapt to zksync-era tests
juan518munoz Aug 16, 2024
bbac76d
Remove hash_map from Storage trait
MarcosNicolau Aug 16, 2024
5ca9edf
Fix increment_tx_number not cleaning transient_storage
MarcosNicolau Aug 20, 2024
01c6eb6
Fix decommit opcode
MarcosNicolau Aug 20, 2024
be5024f
Various far_call fixes
MarcosNicolau Aug 20, 2024
cdfcd92
Add stipend param to frame and decrease it in panics and reverts
MarcosNicolau Aug 20, 2024
5be7e35
Add no refund storage_read for far_call decommit_code_hash
MarcosNicolau Aug 20, 2024
29c184a
Remove rollbacks from main context
MarcosNicolau Aug 20, 2024
679d38d
Reimplement vec snapshots
MarcosNicolau Aug 20, 2024
1c9a4b2
Add external snapshot(whole vm)
MarcosNicolau Aug 20, 2024
f6f2829
Add storage cache and util functio to get storage changes from initial
MarcosNicolau Aug 20, 2024
8747004
Refactor state pub fields
MarcosNicolau Aug 20, 2024
2a28162
Add new function to get storage changes from snapshot or initial
MarcosNicolau Aug 20, 2024
6509f4a
Merge branch 'main' into zksync-era-integration-tests
MarcosNicolau Aug 20, 2024
41db1b5
Update zksync-era submodule
MarcosNicolau Aug 20, 2024
fe7a666
Update era-compiler-tester submodule
MarcosNicolau Aug 20, 2024
18c5199
Address clippy warnings
MarcosNicolau Aug 20, 2024
897eb16
More clippy warnings
MarcosNicolau Aug 20, 2024
4efc066
Update zksync-era submodule
MarcosNicolau Aug 20, 2024
b512b31
ci: add submodule step for era
fkrause98 Aug 20, 2024
a5700ea
Address review comments
MarcosNicolau Aug 20, 2024
c30ea73
Add cache to storage_read
MarcosNicolau Aug 21, 2024
cd451dd
Update zksync-era submodule
MarcosNicolau Aug 22, 2024
d0c59af
Add full tracers implementation
MarcosNicolau Aug 22, 2024
855d043
Refactor how the vm handles tracers
MarcosNicolau Aug 22, 2024
439f68e
Update era-compiler-tester submodule
MarcosNicolau Aug 22, 2024
e5ab604
Update zksync-era submodule
MarcosNicolau Aug 22, 2024
6d1682e
Address clippy warnings
MarcosNicolau Aug 22, 2024
0cc8684
Add default function in Tracer trait
MarcosNicolau Aug 23, 2024
081d615
Address clippy warnings
MarcosNicolau Aug 23, 2024
ee97d09
Address review comments
MarcosNicolau Aug 26, 2024
5baf370
Add docs to state
MarcosNicolau Aug 26, 2024
75434eb
Address review comments
MarcosNicolau Aug 26, 2024
66d412c
Remove optional from run with tracers
MarcosNicolau Aug 26, 2024
291e4c1
Update era-compiler-tester submodule
MarcosNicolau Aug 26, 2024
02e8a90
Update era-compiler-tester submodule
MarcosNicolau Aug 26, 2024
ed3784c
Address clippy warnings
MarcosNicolau Aug 26, 2024
aea62fe
Fix storage_read
MarcosNicolau Aug 26, 2024
e6b1c19
Merge remote-tracking branch 'origin' into zksync-era-integration-tests
MarcosNicolau Aug 26, 2024
0385534
Merge branch 'zksync-era-tests' into implement-tracers
MarcosNicolau Aug 26, 2024
caad06d
Merge branch 'zksync-era-integration-tests' into implement-tracers
MarcosNicolau Aug 26, 2024
c06ce65
Merge branch 'main' into implement-tracers
MarcosNicolau Aug 28, 2024
fc2855a
Implement statistics (#213)
MarcosNicolau Aug 29, 2024
c36cf47
Merge branch 'main' into implement-tracers
MarcosNicolau Aug 29, 2024
5de6b4d
Update zksync-era submodule
MarcosNicolau Aug 29, 2024
adc3c0e
Move storage param to vm run
MarcosNicolau Aug 30, 2024
c1ab599
Merge branch 'main' into zk_server_compatibility
gianbelinche Sep 3, 2024
05c6bb9
Update zksync era submodule
gianbelinche Sep 3, 2024
beb8ef0
Update compiler tester submodule
gianbelinche Sep 3, 2024
264c0d0
Lint
gianbelinche Sep 3, 2024
d9f581f
Remove print
gianbelinche Sep 3, 2024
1e6167a
Update zksync era submodule
gianbelinche Sep 3, 2024
2a213dc
Add heap size optimization
gianbelinche Sep 4, 2024
a44f3b8
Update submodules
gianbelinche Sep 4, 2024
c4dab0e
Address comments
gianbelinche Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion era-compiler-tester
42 changes: 31 additions & 11 deletions src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Stack {
#[derive(Debug, Clone, PartialEq)]
pub struct Heap {
heap: Vec<u8>,
size: u32,
}

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -448,34 +449,47 @@ impl Stack {

impl Default for Heap {
fn default() -> Self {
Self::new(vec![])
Self::new(vec![], 0)
}
}

impl Heap {
pub fn new(values: Vec<u8>) -> Self {
Self { heap: values }
pub fn new(values: Vec<u8>, size: u32) -> Self {
Self { heap: values, size }
}
// Returns how many ergs the expand costs
pub fn expand_memory(&mut self, address: u32) -> u32 {
fn expand_memory_inner(&mut self, address: u32) {
if address >= self.heap.len() as u32 {
let old_size = self.heap.len() as u32;
self.heap.resize(address as usize, 0);
return MEMORY_GROWTH_ERGS_PER_BYTE * (address - old_size);
}
}

// Returns how many ergs the expand costs
pub fn expand_memory(&mut self, address: u32) -> u32 {
if address >= self.size {
let old_size = self.size;
self.size = address;
return MEMORY_GROWTH_ERGS_PER_BYTE * (self.size - old_size);
}
0
}

pub fn store(&mut self, address: u32, value: U256) {
let start = address as usize;
let end = start + 32;
self.expand_memory_inner(end as u32);
value.to_big_endian(&mut self.heap[start..end]);
}

pub fn read(&self, address: u32) -> U256 {
let start = address as usize;
let end = start + 32;
U256::from_big_endian(&self.heap[start..end])
let mut end = start + 32;
if start >= self.heap.len() {
return U256::zero();
}
end = end.min(self.heap.len());
let mut result = self.heap[start..end].to_vec();
result.resize(32, 0);
U256::from_big_endian(&result)
}

pub fn expanded_read(&mut self, address: u32) -> (U256, u32) {
Expand All @@ -485,13 +499,19 @@ impl Heap {
}

pub fn read_byte(&self, address: u32) -> u8 {
if address >= self.heap.len() as u32 {
return 0;
}
self.heap[address as usize]
}

pub fn read_from_pointer(&self, pointer: &FatPointer) -> U256 {
let mut result = U256::zero();
for i in 0..32 {
let addr = pointer.start + pointer.offset + (31 - i);
if addr >= self.heap.len() as u32 {
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done out of the loop, like this:

let start = pointer.start + offset;
let end = self.heap.len().min(start + 32);
for i in start..end {
    result |= U256::from(self.heap[addr as usize]) << (1 * 8);
}
result

Or quite possibly as a slice copy, if the U256 provides a byte representation.

result |= U256::from(self.heap[addr as usize]) << (i * 8);
}
result
Expand All @@ -504,10 +524,10 @@ impl Heap {
}

pub fn len(&self) -> usize {
self.heap.len()
self.size as usize
}

pub fn is_empty(&self) -> bool {
self.heap.is_empty()
self.size == 0
}
}
11 changes: 5 additions & 6 deletions src/heaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ impl Heaps {
pub fn new(calldata: Vec<u8>) -> Self {
// The first heap can never be used because heap zero
// means the current heap in precompile calls
let size = calldata.len() as u32;
let heaps = vec![
Heap::default(),
Heap::new(calldata),
Heap::new(calldata, size),
Heap::default(),
Heap::default(),
];
Expand All @@ -23,15 +24,13 @@ impl Heaps {

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

pub fn allocate_copy(&mut self) -> u32 {
let id = self.heaps.len() as u32;
self.heaps
.push(Heap::new(vec![0; NEW_FRAME_MEMORY_STIPEND as usize]));
let id: u32 = self.heaps.len() as u32;
self.heaps.push(Heap::new(vec![], NEW_FRAME_MEMORY_STIPEND));
id
}

Expand Down
56 changes: 36 additions & 20 deletions src/op_handlers/far_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ use crate::{
rollbacks::Rollbackable,
state::VMState,
statistics::{VmStatistics, STORAGE_READ_STORAGE_APPLICATION_CYCLES},
store::{StorageError, StorageKey},
store::{Storage, StorageError, StorageKey},
utils::{address_into_u256, is_kernel},
value::{FatPointer, TaggedValue},
Opcode,
};

use super::ret::panic_from_far_call;
#[allow(dead_code)]
struct FarCallParams {
forward_memory: FatPointer,
Expand Down Expand Up @@ -134,14 +136,15 @@ fn decommit_code_hash(
default_aa_code_hash: [u8; 32],
evm_interpreter_code_hash: [u8; 32],
is_constructor_call: bool,
storage: &mut dyn Storage,
) -> Result<(U256, bool, u32), EraVmError> {
let mut is_evm = false;
let deployer_system_contract_address =
Address::from_low_u64_be(DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW as u64);
let storage_key = StorageKey::new(deployer_system_contract_address, address_into_u256(address));

// reading when decommiting doesn't refund
let code_info = state.storage_read_with_no_refund(storage_key);
let code_info = state.storage_read_with_no_refund(storage_key, storage);
let mut code_info_bytes = [0; 32];
code_info.to_big_endian(&mut code_info_bytes);

Expand Down Expand Up @@ -216,6 +219,7 @@ pub fn far_call(
far_call: &FarCallOpcode,
state: &mut VMState,
statistics: &mut VmStatistics,
storage: &mut dyn Storage,
) -> Result<(), EraVmError> {
let (src0, src1) = address_operands_read(vm, opcode)?;
let contract_address = address_from_u256(&src1.value);
Expand All @@ -227,45 +231,57 @@ pub fn far_call(
abi.is_constructor_call = abi.is_constructor_call && vm.current_context()?.is_kernel();
abi.is_system_call = abi.is_system_call && is_kernel(&contract_address);

let FarCallParams {
ergs_passed,
forward_memory,
..
} = far_call_params_from_register(src0, vm)?;

let mut mandated_gas = if abi.is_system_call && src1.value == ADDRESS_MSG_VALUE.into() {
MSG_VALUE_SIMULATOR_ADDITIVE_COST
} else {
0
};

let (code_key, is_evm, decommit_cost) = decommit_code_hash(
state,
contract_address,
vm.default_aa_code_hash,
vm.evm_interpreter_code_hash,
abi.is_constructor_call,
storage,
)?;

// Unlike all other gas costs, this one is not paid if low on gas.
if decommit_cost <= vm.gas_left()? {
vm.decrease_gas(decommit_cost)?;
if vm.decrease_gas(mandated_gas).is_err() {
vm.set_gas_left(0)?;
mandated_gas = 0;
panic_from_far_call(vm, opcode)?;
} else {
return Err(EraVmError::DecommitFailed);
// Pay for decommit
// Unlike all other gas costs, this one is not paid if low on gas.
if decommit_cost <= vm.gas_left()? {
vm.decrease_gas(decommit_cost)?;
} else {
return Err(EraVmError::DecommitFailed);
}
}

let FarCallParams {
ergs_passed,
forward_memory,
..
} = far_call_params_from_register(src0, vm)?;

let mandated_gas = if abi.is_system_call && src1.value == ADDRESS_MSG_VALUE.into() {
MSG_VALUE_SIMULATOR_ADDITIVE_COST
} else {
0
};
let gas_left = vm.gas_left()?;
let maximum_gas =
gas_left / FAR_CALL_GAS_SCALAR_MODIFIER_DIVISOR * FAR_CALL_GAS_SCALAR_MODIFIER_DIVIDEND;
let ergs_passed = ergs_passed.min(maximum_gas);
vm.decrease_gas(ergs_passed)?;

// mandated gas can surprass the 63/64 limit
let ergs_passed = ergs_passed + mandated_gas;

vm.decrease_gas(ergs_passed)?;

let stipend = if is_evm { EVM_SIMULATOR_STIPEND } else { 0 };

let ergs_passed = (ergs_passed)
.checked_add(stipend)
.expect("stipend must not cause overflow");

let (program_code, was_decommited) = state.decommit(code_key);
let (program_code, was_decommited) = state.decommit(code_key, storage);

let program_code = program_code.ok_or(StorageError::KeyNotPresent)?;
if !was_decommited {
Expand Down
8 changes: 5 additions & 3 deletions src/op_handlers/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
VmStatistics, STORAGE_READ_STORAGE_APPLICATION_CYCLES,
STORAGE_WRITE_STORAGE_APPLICATION_CYCLES,
},
store::StorageKey,
store::{Storage, StorageKey},
value::TaggedValue,
Opcode,
};
Expand All @@ -16,6 +16,7 @@ pub fn storage_write(
opcode: &Opcode,
state: &mut VMState,
statistics: &mut VmStatistics,
storage: &mut dyn Storage,
) -> Result<(), EraVmError> {
let key_for_contract_storage = vm.get_register(opcode.src0_index).value;
let address = vm.current_context()?.contract_address;
Expand All @@ -24,7 +25,7 @@ pub fn storage_write(
statistics.storage_application_cycles += STORAGE_WRITE_STORAGE_APPLICATION_CYCLES;
}
let value = vm.get_register(opcode.src1_index).value;
let refund = state.storage_write(key, value);
let refund = state.storage_write(key, value, storage);
vm.increase_gas(refund)?;
Ok(())
}
Expand All @@ -34,6 +35,7 @@ pub fn storage_read(
opcode: &Opcode,
state: &mut VMState,
statistics: &mut VmStatistics,
storage: &mut dyn Storage,
) -> Result<(), EraVmError> {
let key_for_contract_storage = vm.get_register(opcode.src0_index).value;
let address = vm.current_context()?.contract_address;
Expand All @@ -43,7 +45,7 @@ pub fn storage_read(
if !state.read_storage_slots().contains(&key) && !state.written_storage_slots().contains(&key) {
statistics.storage_application_cycles += STORAGE_READ_STORAGE_APPLICATION_CYCLES;
}
let (value, refund) = state.storage_read(key);
let (value, refund) = state.storage_read(key, storage);
vm.increase_gas(refund)?;
vm.set_register(opcode.dst0_index, TaggedValue::new_raw_integer(value));
Ok(())
Expand Down
4 changes: 3 additions & 1 deletion src/op_handlers/opcode_decommit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
execution::Execution,
state::VMState,
statistics::{VmStatistics, STORAGE_READ_STORAGE_APPLICATION_CYCLES},
store::Storage,
value::{FatPointer, TaggedValue},
Opcode,
};
Expand All @@ -15,6 +16,7 @@ pub fn opcode_decommit(
opcode: &Opcode,
state: &mut VMState,
statistics: &mut VmStatistics,
storage: &mut dyn Storage,
) -> Result<(), EraVmError> {
let (src0, src1) = address_operands_read(vm, opcode)?;

Expand All @@ -34,7 +36,7 @@ pub fn opcode_decommit(
return Ok(());
}

let (code, was_decommited) = state.decommit(code_hash);
let (code, was_decommited) = state.decommit(code_hash, storage);
if was_decommited {
// refund it
vm.increase_gas(extra_cost)?;
Expand Down
Loading
Loading