Skip to content

Commit

Permalink
feat(vm): Split old and new VM implementations (#2915)
Browse files Browse the repository at this point in the history
## What ❔

Splits old and new VM implementations in the `multivm` crate:

- Old VMs are encapsulated in the `LegacyVmInstance` enum, while new
ones in the `FastVmInstance` enum (which includes plain and shadowed VM
variants).
- Fast VM and `FastVmInstance` now expose a tracer type.
- Usage of the Fast VM in the batch executor are updated
correspondingly.

## Why ❔

It seems infeasible to unify the tracer model for old and new VMs, so
keeping them all in a single enum makes little sense.

## Checklist

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via `zk fmt` and `zk lint`.
  • Loading branch information
slowli committed Sep 23, 2024
1 parent 2224f8f commit 93bc66f
Show file tree
Hide file tree
Showing 56 changed files with 662 additions and 340 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/bin/system-constants-generator/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ pub(super) fn execute_internal_transfer_test() -> u32 {
}
.into_tracer_pointer();
let mut vm: Vm<_, HistoryEnabled> = Vm::new(l1_batch, system_env, storage_view.to_rc_ptr());
let result = vm.inspect(tracer.into(), VmExecutionMode::Bootloader);
let result = vm.inspect(&mut tracer.into(), VmExecutionMode::Bootloader);

assert!(!result.result.is_failed(), "The internal call has reverted");
tracer_result.take()
Expand Down
2 changes: 1 addition & 1 deletion core/lib/multivm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use crate::{
vm_1_3_2, vm_1_4_1, vm_1_4_2, vm_boojum_integration, vm_fast, vm_latest, vm_m5, vm_m6,
vm_refunds_enhancement, vm_virtual_blocks,
},
vm_instance::VmInstance,
vm_instance::{FastVmInstance, LegacyVmInstance},
};

mod glue;
Expand Down
6 changes: 3 additions & 3 deletions core/lib/multivm/src/versions/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
};

type ReferenceVm<S = InMemoryStorage> = vm_latest::Vm<StorageView<S>, HistoryEnabled>;
type ShadowedVmFast<S = InMemoryStorage> = crate::vm_instance::ShadowedVmFast<S, HistoryEnabled>;
type ShadowedFastVm<S = InMemoryStorage> = crate::vm_instance::ShadowedFastVm<S>;

fn hash_block(block_env: L2BlockEnv, tx_hashes: &[H256]) -> H256 {
let mut hasher = L2BlockHasher::new(
Expand Down Expand Up @@ -248,12 +248,12 @@ fn sanity_check_shadow_vm() {

#[test]
fn shadow_vm_basics() {
let (vm, harness) = sanity_check_vm::<ShadowedVmFast>();
let (vm, harness) = sanity_check_vm::<ShadowedFastVm>();
let mut dump = vm.dump_state();
Harness::assert_dump(&mut dump);

// Test standard playback functionality.
let replayed_dump = dump.clone().play_back::<ShadowedVmFast<_>>().dump_state();
let replayed_dump = dump.clone().play_back::<ShadowedFastVm<_>>().dump_state();
pretty_assertions::assert_eq!(replayed_dump, dump);

// Check that the VM executes identically when reading from the original storage and one restored from the dump.
Expand Down
4 changes: 2 additions & 2 deletions core/lib/multivm/src/versions/vm_1_3_2/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {

fn inspect(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
if let Some(storage_invocations) = tracer.storage_invocations {
Expand Down Expand Up @@ -80,7 +80,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {

fn inspect_transaction_with_bytecode_compression(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
tx: Transaction,
with_compression: bool,
) -> (BytecodeCompressionResult<'_>, VmExecutionResultAndLogs) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::mem;

use zk_evm_1_4_1::aux_structures::Timestamp;

use crate::{
Expand All @@ -20,7 +22,7 @@ use crate::{
impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
pub(crate) fn inspect_inner(
&mut self,
dispatcher: TracerDispatcher<S, H::Vm1_4_1>,
dispatcher: &mut TracerDispatcher<S, H::Vm1_4_1>,
execution_mode: VmExecutionMode,
custom_pubdata_tracer: Option<PubdataTracer<S>>,
) -> VmExecutionResultAndLogs {
Expand All @@ -44,7 +46,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
/// Collect the result from the default tracers.
fn inspect_and_collect_results(
&mut self,
dispatcher: TracerDispatcher<S, H::Vm1_4_1>,
dispatcher: &mut TracerDispatcher<S, H::Vm1_4_1>,
execution_mode: VmExecutionMode,
with_refund_tracer: bool,
custom_pubdata_tracer: Option<PubdataTracer<S>>,
Expand All @@ -54,7 +56,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
let mut tx_tracer: DefaultExecutionTracer<S, H::Vm1_4_1> = DefaultExecutionTracer::new(
self.system_env.default_validation_computational_gas_limit,
execution_mode,
dispatcher,
mem::take(dispatcher),
self.storage.clone(),
refund_tracers,
custom_pubdata_tracer
Expand Down Expand Up @@ -90,6 +92,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics),
);
let result = tx_tracer.result_tracer.into_result();
*dispatcher = tx_tracer.dispatcher;

let result = VmExecutionResultAndLogs {
result,
Expand Down
6 changes: 3 additions & 3 deletions core/lib/multivm/src/versions/vm_1_4_1/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
/// Execute VM with custom tracers.
fn inspect(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
self.inspect_inner(tracer, execution_mode, None)
Expand All @@ -102,7 +102,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {

fn inspect_transaction_with_bytecode_compression(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
tx: Transaction,
with_compression: bool,
) -> (BytecodeCompressionResult<'_>, VmExecutionResultAndLogs) {
Expand All @@ -129,7 +129,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
}

fn finish_batch(&mut self) -> FinishedL1Batch {
let result = self.inspect(TracerDispatcher::default(), VmExecutionMode::Batch);
let result = self.inspect(&mut TracerDispatcher::default(), VmExecutionMode::Batch);
let execution_state = self.get_current_execution_state();
let bootloader_memory = self.bootloader_state.bootloader_memory();
FinishedL1Batch {
Expand Down
12 changes: 7 additions & 5 deletions core/lib/multivm/src/versions/vm_1_4_2/vm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::mem;

use circuit_sequencer_api_1_4_2::sort_storage_access::sort_storage_access_queries;
use zksync_types::{
l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log},
Expand Down Expand Up @@ -90,10 +92,10 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
/// Execute VM with custom tracers.
fn inspect(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
self.inspect_inner(tracer, execution_mode, None)
self.inspect_inner(mem::take(tracer), execution_mode, None)
}

fn start_new_l2_block(&mut self, l2_block_env: L2BlockEnv) {
Expand All @@ -102,12 +104,12 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {

fn inspect_transaction_with_bytecode_compression(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
tx: Transaction,
with_compression: bool,
) -> (BytecodeCompressionResult<'_>, VmExecutionResultAndLogs) {
self.push_transaction_with_compression(tx, with_compression);
let result = self.inspect_inner(tracer, VmExecutionMode::OneTx, None);
let result = self.inspect_inner(mem::take(tracer), VmExecutionMode::OneTx, None);
if self.has_unpublished_bytecodes() {
(
Err(BytecodeCompressionError::BytecodeCompressionFailed),
Expand All @@ -129,7 +131,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
}

fn finish_batch(&mut self) -> FinishedL1Batch {
let result = self.inspect(TracerDispatcher::default(), VmExecutionMode::Batch);
let result = self.inspect(&mut TracerDispatcher::default(), VmExecutionMode::Batch);
let execution_state = self.get_current_execution_state();
let bootloader_memory = self.bootloader_state.bootloader_memory();
FinishedL1Batch {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::mem;

use zk_evm_1_4_0::aux_structures::Timestamp;

use crate::{
Expand All @@ -20,7 +22,7 @@ use crate::{
impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
pub(crate) fn inspect_inner(
&mut self,
dispatcher: TracerDispatcher<S, H::VmBoojumIntegration>,
dispatcher: &mut TracerDispatcher<S, H::VmBoojumIntegration>,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
let mut enable_refund_tracer = false;
Expand All @@ -39,7 +41,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
/// Collect the result from the default tracers.
fn inspect_and_collect_results(
&mut self,
dispatcher: TracerDispatcher<S, H::VmBoojumIntegration>,
dispatcher: &mut TracerDispatcher<S, H::VmBoojumIntegration>,
execution_mode: VmExecutionMode,
with_refund_tracer: bool,
) -> (VmExecutionStopReason, VmExecutionResultAndLogs) {
Expand All @@ -49,7 +51,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
DefaultExecutionTracer::new(
self.system_env.default_validation_computational_gas_limit,
execution_mode,
dispatcher,
mem::take(dispatcher),
self.storage.clone(),
refund_tracers,
Some(PubdataTracer::new(self.batch_env.clone(), execution_mode)),
Expand Down Expand Up @@ -84,6 +86,7 @@ impl<S: WriteStorage, H: HistoryMode> Vm<S, H> {
circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics),
);
let result = tx_tracer.result_tracer.into_result();
*dispatcher = tx_tracer.dispatcher; // return the dispatcher back

let result = VmExecutionResultAndLogs {
result,
Expand Down
6 changes: 3 additions & 3 deletions core/lib/multivm/src/versions/vm_boojum_integration/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
/// Execute VM with custom tracers.
fn inspect(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
self.inspect_inner(tracer, execution_mode)
Expand All @@ -103,7 +103,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
/// Inspect transaction with optional bytecode compression.
fn inspect_transaction_with_bytecode_compression(
&mut self,
tracer: Self::TracerDispatcher,
tracer: &mut Self::TracerDispatcher,
tx: Transaction,
with_compression: bool,
) -> (BytecodeCompressionResult<'_>, VmExecutionResultAndLogs) {
Expand All @@ -130,7 +130,7 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface for Vm<S, H> {
}

fn finish_batch(&mut self) -> FinishedL1Batch {
let result = self.inspect(TracerDispatcher::default(), VmExecutionMode::Batch);
let result = self.inspect(&mut TracerDispatcher::default(), VmExecutionMode::Batch);
let execution_state = self.get_current_execution_state();
let bootloader_memory = self.bootloader_state.bootloader_memory();
FinishedL1Batch {
Expand Down
2 changes: 1 addition & 1 deletion core/lib/multivm/src/versions/vm_fast/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
utils::bytecode,
};

impl<S: ReadStorage> Vm<S> {
impl<S: ReadStorage, Tr> Vm<S, Tr> {
/// Checks the last transaction has successfully published compressed bytecodes and returns `true` if there is at least one is still unknown.
pub(crate) fn has_unpublished_bytecodes(&mut self) -> bool {
self.bootloader_state
Expand Down
7 changes: 5 additions & 2 deletions core/lib/multivm/src/versions/vm_fast/circuits_tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ use zksync_vm_interface::CircuitStatistic;

use crate::vm_latest::tracers::circuits_capacity::*;

/// VM tracer tracking [`CircuitStatistic`]s. Statistics generally depend on the number of time some opcodes were invoked,
/// and, for precompiles, invocation complexity (e.g., how many hashing cycles `keccak256` required).
#[derive(Debug, Default, Clone, PartialEq)]
pub(crate) struct CircuitsTracer {
pub struct CircuitsTracer {
main_vm_cycles: u32,
ram_permutation_cycles: u32,
storage_application_cycles: u32,
Expand Down Expand Up @@ -124,7 +126,8 @@ impl Tracer for CircuitsTracer {
}

impl CircuitsTracer {
pub(crate) fn circuit_statistic(&self) -> CircuitStatistic {
/// Obtains the current circuit stats from this tracer.
pub fn circuit_statistic(&self) -> CircuitStatistic {
CircuitStatistic {
main_vm: self.main_vm_cycles as f32 / GEOMETRY_CONFIG.cycles_per_vm_snapshot as f32,
ram_permutation: self.ram_permutation_cycles as f32
Expand Down
4 changes: 3 additions & 1 deletion core/lib/multivm/src/versions/vm_fast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub use self::vm::Vm;
pub use zksync_vm2::interface::Tracer;

pub use self::{circuits_tracer::CircuitsTracer, vm::Vm};

mod bootloader_state;
mod bytecode;
Expand Down
5 changes: 3 additions & 2 deletions core/lib/multivm/src/versions/vm_fast/tests/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use zksync_types::{Address, Execute, U256};

use super::tester::VmTesterBuilder;
use crate::{
interface::{TxExecutionMode, VmExecutionMode, VmInterface},
interface::{TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceExt},
vm_latest::constants::BATCH_COMPUTATIONAL_GAS_LIMIT,
};

Expand All @@ -29,7 +29,8 @@ fn test_circuits() {
None,
);
vm.vm.push_transaction(tx);
let res = vm.vm.inspect((), VmExecutionMode::OneTx);
let res = vm.vm.execute(VmExecutionMode::OneTx);
assert!(!res.result.is_failed(), "{res:#?}");

let s = res.statistics.circuit_statistic;
// Check `circuit_statistic`.
Expand Down
4 changes: 2 additions & 2 deletions core/lib/multivm/src/versions/vm_fast/tests/code_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ use crate::{
interface::{TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceExt},
versions::testonly::ContractToDeploy,
vm_fast::{
circuits_tracer::CircuitsTracer,
tests::{
tester::{get_empty_storage, VmTesterBuilder},
utils::{load_precompiles_contract, read_precompiles_contract, read_test_contract},
},
CircuitsTracer,
},
};

Expand Down Expand Up @@ -210,7 +210,7 @@ fn refunds_in_code_oracle() {
if decommit {
let (_, is_fresh) = vm.vm.inner.world_diff_mut().decommit_opcode(
&mut vm.vm.world,
&mut CircuitsTracer::default(),
&mut ((), CircuitsTracer::default()),
h256_to_u256(normal_zkevm_bytecode_hash),
);
assert!(is_fresh);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct ProxyCounterData {
counter_bytecode_hash: U256,
}

fn execute_proxy_counter(gas: u32) -> (VmTester, ProxyCounterData, VmExecutionResultAndLogs) {
fn execute_proxy_counter(gas: u32) -> (VmTester<()>, ProxyCounterData, VmExecutionResultAndLogs) {
let counter_bytecode = inflated_counter_bytecode();
let counter_bytecode_hash = h256_to_u256(hash_bytecode(&counter_bytecode));
let counter_address = Address::repeat_byte(0x23);
Expand Down
11 changes: 7 additions & 4 deletions core/lib/multivm/src/versions/vm_fast/tests/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use zksync_types::{Address, Execute};

use super::{tester::VmTesterBuilder, utils::read_precompiles_contract};
use crate::{
interface::{TxExecutionMode, VmExecutionMode, VmInterface},
interface::{TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceExt},
versions::testonly::ContractToDeploy,
vm_latest::constants::BATCH_COMPUTATIONAL_GAS_LIMIT,
};
Expand Down Expand Up @@ -37,7 +37,8 @@ fn test_keccak() {
None,
);
vm.vm.push_transaction(tx);
let exec_result = vm.vm.inspect((), VmExecutionMode::OneTx);

let exec_result = vm.vm.execute(VmExecutionMode::OneTx);
assert!(!exec_result.result.is_failed(), "{exec_result:#?}");

let keccak_count = exec_result.statistics.circuit_statistic.keccak256
Expand Down Expand Up @@ -74,7 +75,8 @@ fn test_sha256() {
None,
);
vm.vm.push_transaction(tx);
let exec_result = vm.vm.inspect((), VmExecutionMode::OneTx);

let exec_result = vm.vm.execute(VmExecutionMode::OneTx);
assert!(!exec_result.result.is_failed(), "{exec_result:#?}");

let sha_count = exec_result.statistics.circuit_statistic.sha256
Expand Down Expand Up @@ -104,7 +106,8 @@ fn test_ecrecover() {
None,
);
vm.vm.push_transaction(tx);
let exec_result = vm.vm.inspect((), VmExecutionMode::OneTx);

let exec_result = vm.vm.execute(VmExecutionMode::OneTx);
assert!(!exec_result.result.is_failed(), "{exec_result:#?}");

let ecrecover_count = exec_result.statistics.circuit_statistic.ecrecover
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
},
};

impl VmTester {
impl VmTester<()> {
pub(crate) fn get_eth_balance(&mut self, address: Address) -> U256 {
let key = storage_key_for_standard_token_balance(
AccountTreeId::new(L2_BASE_TOKEN_ADDRESS),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl<S: ReadStorage> Vm<S> {
}
}

impl VmTester {
impl VmTester<()> {
pub(crate) fn execute_and_verify_txs(
&mut self,
txs: &[TransactionTestInfo],
Expand Down
Loading

0 comments on commit 93bc66f

Please sign in to comment.