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: Remove EVM stipend #73

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 0 additions & 5 deletions crates/zk_evm/src/opcodes/execution/far_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@
0
};

let (mut callee_stipend, mut extra_ergs_from_caller_to_callee) =

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo build

variable does not need to be mutable

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo build

variable does not need to be mutable

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo test

variable does not need to be mutable

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo test

variable does not need to be mutable

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo test

variable does not need to be mutable

Check warning on line 442 in crates/zk_evm/src/opcodes/execution/far_call.rs

View workflow job for this annotation

GitHub Actions / cargo test

variable does not need to be mutable
get_stipend_and_extra_cost(&called_address, far_call_abi.to_system);

let remaining_ergs_of_caller_frame =
Expand All @@ -456,11 +456,6 @@
0
};

if can_call_evm_simulator {
assert_eq!(callee_stipend, 0);
callee_stipend = zkevm_opcode_defs::system_params::EVM_SIMULATOR_STIPEND;
}

let (code_memory_page, remaining_ergs_after_decommittment) = if exceptions.is_empty()
== false
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -885,15 +885,6 @@ where
unsafe { UInt32::from_variable_unchecked(extra_ergs_from_caller_to_callee) };
let callee_stipend = unsafe { UInt32::from_variable_unchecked(callee_stipend) };

let evm_simulator_stipend =
UInt32::allocated_constant(cs, zkevm_opcode_defs::system_params::EVM_SIMULATOR_STIPEND);
let callee_stipend = UInt32::conditionally_select(
cs,
can_call_evm_simulator_without_masking,
&evm_simulator_stipend,
&callee_stipend,
);

if crate::config::CIRCUIT_VERSOBE {
if execute.witness_hook(&*cs)().unwrap() {
dbg!(address_low.witness_hook(&*cs)().unwrap());
Expand Down Expand Up @@ -1170,6 +1161,9 @@ where
let boolean_false = Boolean::allocated_constant(cs, false);
new_callstack_entry.is_local_call = boolean_false;

// stipend
new_callstack_entry.stipend = callee_stipend;

let oracle = witness_oracle.clone();
// we should assemble all the dependencies here, and we will use AllocateExt here
let mut dependencies = Vec::with_capacity(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ where

// -----------------------------------------

// we should subtract stipend, but only if we exit local frame
// we should subtract stipend, but only if we exit non-local frame
let stipend_to_subtract = current_callstack_entry
.stipend
.mask_negated(cs, is_local_frame);
Expand Down
2 changes: 0 additions & 2 deletions crates/zkevm_opcode_defs/src/system_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ pub const MAX_TX_ERGS_LIMIT: u32 = 80_000_000;

pub const VM_INITIAL_FRAME_ERGS: u32 = u32::MAX;

pub const EVM_SIMULATOR_STIPEND: u32 = 1u32 << 30;

/// How much a single circuit should cost in terms of ergs.
pub const ERGS_PER_CIRCUIT: u32 = 80000;

Expand Down
58 changes: 57 additions & 1 deletion crates/zkevm_test_harness/src/helper/artifact_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::zk_evm::aux_structures::LogQuery;
use crate::zk_evm::ethereum_types::Address;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use zkevm_assembly::zkevm_opcode_defs::{BlobSha256, VersionedHashGeneric};

use crate::blake2::Blake2s256;
use crate::ethereum_types::{H160, U256};
Expand Down Expand Up @@ -34,7 +35,6 @@ pub fn save_predeployed_contracts(
}

let storage_logs: Vec<(u8, Address, U256, U256)> = sorted_contracts
.clone()
.into_iter()
.map(|(address, bytecode)| {
let hash = bytecode_to_code_hash(&bytecode).unwrap();
Expand Down Expand Up @@ -63,6 +63,62 @@ pub fn save_predeployed_contracts(
.flatten()
.collect();

populate_storage(storage, tree, storage_logs);
}

pub fn save_predeployed_evm_contract_stubs(
storage: &mut InMemoryStorage,
tree: &mut impl BinarySparseStorageTree<256, 32, 32, 8, 32, Blake2s256, ZkSyncStorageLeaf>,
contracts: &Vec<Address>,
) {
let mut sorted_contracts = contracts.clone();
sorted_contracts.sort();

let empty_code_hash = U256::from_big_endian(&bytecode_to_code_hash(&[[0; 32]]).unwrap());
let versioned_hash = VersionedHashGeneric::<BlobSha256>::from_digest_and_preimage_length(
empty_code_hash.into(),
0,
);

let evm_stub_hash = U256::from_big_endian(&versioned_hash.serialize().unwrap());

let storage_logs: Vec<(u8, Address, U256, U256)> = sorted_contracts
.into_iter()
.map(|address| {
let hash = evm_stub_hash.clone();

println!(
"Have address {:?} in EVM mode with code hash {:x}",
address,
U256::from(hash)
);

vec![
(
0,
ACCOUNT_CODE_STORAGE_ADDRESS,
U256::from_big_endian(address.as_bytes()),
U256::from(hash),
),
(
0,
KNOWN_CODE_HASHES_ADDRESS,
U256::from(hash),
U256::from(1u64),
),
]
})
.flatten()
.collect();

populate_storage(storage, tree, storage_logs);
}

fn populate_storage(
storage: &mut InMemoryStorage,
tree: &mut impl BinarySparseStorageTree<256, 32, 32, 8, 32, Blake2s256, ZkSyncStorageLeaf>,
storage_logs: Vec<(u8, Address, U256, U256)>,
) {
storage.populate(storage_logs.clone());

for (shard_id, address, key, value) in storage_logs.into_iter() {
Expand Down
43 changes: 39 additions & 4 deletions crates/zkevm_test_harness/src/tests/run_manually.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ use crate::zkevm_circuits::main_vm::main_vm_entry_point;
use boojum::gadgets::queue::full_state_queue::FullStateCircuitQueueRawWitness;
use circuit_definitions::aux_definitions::witness_oracle::VmWitnessOracle;
use circuit_definitions::zk_evm::vm_state::cycle;
use helper::artifact_utils::save_predeployed_evm_contract_stubs;
use storage::{InMemoryCustomRefundStorage, StorageRefund};
use witness::oracle::WitnessGenerationArtifact;
use zk_evm::zkevm_opcode_defs::{BlobSha256, VersionedHashGeneric};
use zkevm_assembly::Assembly;
use zkevm_circuits::base_structures::vm_state::FULL_SPONGE_QUEUE_STATE_WIDTH;

Expand Down Expand Up @@ -191,6 +193,8 @@ pub struct Options {
pub other_contracts: Vec<(H160, Vec<[u8; 32]>)>,
// How many cycles should a single VM handle (default is DEFAULT_CYCLES_PER_VM_SNAPSHOT = 5)
pub cycles_per_vm_snapshot: u32,
pub evm_interpreter: Option<Vec<[u8; 32]>>,
pub other_evm_contracts: Vec<H160>,
}

impl Default for Options {
Expand All @@ -199,6 +203,8 @@ impl Default for Options {
cycle_limit: DEFAULT_CYCLE_LIMIT,
other_contracts: Default::default(),
cycles_per_vm_snapshot: DEFAULT_CYCLES_PER_VM_SNAPSHOT,
evm_interpreter: None,
other_evm_contracts: Default::default(),
}
}
}
Expand Down Expand Up @@ -245,20 +251,49 @@ pub(crate) fn run_with_options(entry_point_bytecode: Vec<[u8; 32]>, options: Opt
use crate::witness::tree::BinarySparseStorageTree;
use crate::witness::tree::ZKSyncTestingTree;

// We must pass a correct empty code hash (with proper version) into the run method.
let empty_code_hash = U256::from_big_endian(&bytecode_to_code_hash(&[[0; 32]]).unwrap());

let evm_simulator_hash = if options.evm_interpreter.is_some() {
U256::from_big_endian(
&bytecode_to_code_hash(options.evm_interpreter.as_ref().unwrap()).unwrap(),
)
} else {
empty_code_hash
};

let mut used_bytecodes_and_hashes = HashMap::new();
used_bytecodes_and_hashes.extend(options.other_contracts.iter().cloned().map(|(_, code)| {
let code_hash = bytecode_to_code_hash(&code).unwrap();

(U256::from_big_endian(&code_hash), code)
}));

// We must pass a correct empty code hash (with proper version) into the run method.
let empty_code_hash = U256::from_big_endian(&bytecode_to_code_hash(&[[0; 32]]).unwrap());

let mut storage_impl = InMemoryCustomRefundStorage::new();

let mut tree = ZKSyncTestingTree::empty();

if !options.other_evm_contracts.is_empty() {
let mut evm_stub_hash = empty_code_hash;
let versioned_hash = VersionedHashGeneric::<BlobSha256>::from_digest_and_preimage_length(
evm_stub_hash.into(),
0,
);

evm_stub_hash = U256::from_big_endian(&versioned_hash.serialize().unwrap());
used_bytecodes_and_hashes.insert(evm_stub_hash, vec![[0; 32]]);

save_predeployed_evm_contract_stubs(
&mut storage_impl.storage,
&mut tree,
&options.other_evm_contracts,
)
}

if options.evm_interpreter.is_some() {
used_bytecodes_and_hashes.insert(evm_simulator_hash, options.evm_interpreter.unwrap());
}

let mut known_contracts = HashMap::new();
known_contracts.extend(options.other_contracts.iter().cloned());

Expand Down Expand Up @@ -292,7 +327,7 @@ pub(crate) fn run_with_options(entry_point_bytecode: Vec<[u8; 32]>, options: Opt
vec![],
false,
empty_code_hash,
empty_code_hash,
evm_simulator_hash,
used_bytecodes_and_hashes,
vec![],
options.cycle_limit,
Expand Down
27 changes: 27 additions & 0 deletions crates/zkevm_test_harness/src/tests/simple_tests/asm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,33 @@ pub fn run_asm_based_test(
run_asm_based_test_template(test_dir, &additional_contracts, options, None);
}

pub fn run_asm_based_test_with_evm_contracts(
test_dir: &str,
additional_contracts_addresses: &[i32],
additional_evm_contracts_addresses: &[i32],
mut options: Options,
) {
let evm_interpreter =
compile_additional_contracts(test_dir, &vec![("evm_interpreter".to_owned(), 0)], None)[0]
.clone()
.1;

let other_evm_contracts = additional_evm_contracts_addresses
.iter()
.map(|x| Address::from_low_u64_be(*x as u64))
.collect();

options.evm_interpreter = Some(evm_interpreter);
options.other_evm_contracts = other_evm_contracts;

let additional_contracts = additional_contracts_addresses
.iter()
.map(|address| (address.to_string(), *address))
.collect();

run_asm_based_test_template(test_dir, &additional_contracts, options, None);
}

pub fn run_asm_based_test_template(
test_dir: &str,
additional_contracts: &Vec<(String, i32)>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use asm_tests::run_asm_based_test_with_evm_contracts;

use super::*;

#[test_log::test]
fn test_far_call_to_evm_contract() {
run_asm_based_test_with_evm_contracts(
"src/tests/simple_tests/testdata/evm_interpreter/call_zkevm_to_evm",
&[],
&[65536], // evm contracts
Options {
cycles_per_vm_snapshot: 1,
..Default::default()
},
);
}

#[test_log::test]
fn test_far_call_evm_to_zkvm_contract() {
run_asm_based_test_with_evm_contracts(
"src/tests/simple_tests/testdata/evm_interpreter/call_evm_to_zkevm",
&[65537], // zkvm contracts
&[65536], // evm contracts
Options {
cycles_per_vm_snapshot: 1,
..Default::default()
},
);
}

#[test_log::test]
fn test_static_call_to_evm_and_zkvm() {
run_asm_based_test_with_evm_contracts(
"src/tests/simple_tests/testdata/evm_interpreter/static_call_to_evm_and_zkvm",
&[65537], // zkvm contracts
&[65536], // evm contracts
Options {
cycles_per_vm_snapshot: 1,
..Default::default()
},
);
}

#[test_log::test]
fn test_static_call_to_zkevm_and_evm() {
run_asm_based_test_with_evm_contracts(
"src/tests/simple_tests/testdata/evm_interpreter/static_call_to_zkvm_and_evm",
&[65537], // zkvm contracts
&[65536], // evm contracts
Options {
cycles_per_vm_snapshot: 1,
..Default::default()
},
);
}

#[test_log::test]
fn test_delegate_call_to_evm() {
run_asm_based_test_with_evm_contracts(
"src/tests/simple_tests/testdata/evm_interpreter/delegatecall_zkevm_to_evm",
&[], // zkvm contracts
&[65536], // evm contracts
Options {
cycles_per_vm_snapshot: 1,
..Default::default()
},
);
}
1 change: 1 addition & 0 deletions crates/zkevm_test_harness/src/tests/simple_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use zkevm_assembly::Assembly;
mod asm_tests;
mod context;
mod eip4844;
mod evm_interpreter;
mod far_call;
mod kernel_ops;
mod log;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.text
.file "Test_26"
.rodata.cst32
.p2align 5
.text
.globl __entry
__entry:
.main:
ret.ok r0 ; just return
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.text
.file "Test_26"
.rodata.cst32
.p2align 5
CPI0_1:
.cell 65536
.text
.globl __entry
__entry:
.main:
; create ABI for far_call
; give 60k gas
add 60000, r1, r1
shl.s 192, r1, r1

; we are calling address 65536 where we have EVM contract

add @CPI0_1[0], r0, r2
far_call r1, r2, @catch_all

ret.ok r0

catch_all:
ret.panic r0
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.text
.file "Test_26"
.rodata.cst32
.p2align 5
CPI0_1:
.cell 65537
.text
.globl __entry
__entry:
.main:
; create ABI for far_call
; give 40k gas
add 40000, r1, r1
shl.s 192, r1, r1

; we are calling address 65537 which is out of EVM environment

add @CPI0_1[0], r0, r2
far_call r1, r2, @catch_all

ret.ok r0

catch_all:
ret.panic r0
Loading
Loading