Skip to content

Commit

Permalink
feat(vm): Support tracers for old vm (#926)
Browse files Browse the repository at this point in the history
## What ❔

Support existing tracers for old vms

## Why ❔

First step for making tracing on flight instead of saving it in db 

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [ ] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [ ] Code has been formatted via `zk fmt` and `zk lint`.
- [ ] Spellcheck has been run via `zk spellcheck`.

---------

Signed-off-by: Danil <deniallugo@gmail.com>
  • Loading branch information
Deniallugo committed Jan 25, 2024
1 parent 1c1f131 commit 9fc2d95
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 43 deletions.
18 changes: 16 additions & 2 deletions core/lib/multivm/src/glue/tracers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

use zksync_state::WriteStorage;

use crate::HistoryMode;
use crate::{tracers::old_tracers::OldTracers, HistoryMode};

pub type MultiVmTracerPointer<S, H> = Box<dyn MultiVMTracer<S, H>>;

Expand All @@ -41,6 +41,7 @@ pub trait MultiVMTracer<S: WriteStorage, H: HistoryMode>:
+ IntoVmVirtualBlocksTracer<S, H>
+ IntoVmRefundsEnhancementTracer<S, H>
+ IntoVmBoojumIntegrationTracer<S, H>
+ IntoOldVmTracer
{
fn into_tracer_pointer(self) -> MultiVmTracerPointer<S, H>
where
Expand Down Expand Up @@ -72,6 +73,18 @@ pub trait IntoVmBoojumIntegrationTracer<S: WriteStorage, H: HistoryMode> {
) -> Box<dyn crate::vm_boojum_integration::VmTracer<S, H::VmBoojumIntegration>>;
}

/// Into tracers for old VM versions.
/// Even though number of tracers is limited, we still need to have this trait to be able to convert
/// tracers to old VM tracers.
/// Unfortunately we can't implement this trait for `T`, because specialization is not stable yet.
/// You can follow the conversation here: https://github.com/rust-lang/rust/issues/31844
/// For all new tracers we need to implement this trait manually.
pub trait IntoOldVmTracer {
fn old_tracer(&self) -> OldTracers {
OldTracers::None
}
}

impl<S, T, H> IntoLatestTracer<S, H> for T
where
S: WriteStorage,
Expand Down Expand Up @@ -132,6 +145,7 @@ where
T: IntoLatestTracer<S, H>
+ IntoVmVirtualBlocksTracer<S, H>
+ IntoVmRefundsEnhancementTracer<S, H>
+ IntoVmBoojumIntegrationTracer<S, H>,
+ IntoVmBoojumIntegrationTracer<S, H>
+ IntoOldVmTracer,
{
}
8 changes: 7 additions & 1 deletion core/lib/multivm/src/tracers/call_tracer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use once_cell::sync::OnceCell;
use zksync_types::vm_trace::Call;

use crate::tracers::call_tracer::metrics::CALL_METRICS;
use crate::{glue::tracers::IntoOldVmTracer, tracers::call_tracer::metrics::CALL_METRICS};

mod metrics;
pub mod vm_boojum_integration;
Expand Down Expand Up @@ -88,3 +88,9 @@ impl CallTracer {
}
}
}

impl IntoOldVmTracer for CallTracer {
fn old_tracer(&self) -> crate::tracers::old_tracers::OldTracers {
crate::tracers::old_tracers::OldTracers::CallTracer(self.result.clone())
}
}
1 change: 1 addition & 0 deletions core/lib/multivm/src/tracers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod call_tracer;
mod multivm_dispatcher;
pub mod old_tracers;
pub mod storage_invocation;
pub mod validator;

Expand Down
8 changes: 7 additions & 1 deletion core/lib/multivm/src/tracers/multivm_dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use zksync_state::WriteStorage;

use crate::{HistoryMode, MultiVmTracerPointer};
use crate::{tracers::old_tracers, HistoryMode, MultiVmTracerPointer};

/// Tracer dispatcher is a tracer that can dispatch calls to multiple tracers.
pub struct TracerDispatcher<S, H> {
Expand Down Expand Up @@ -83,3 +83,9 @@ impl<S: WriteStorage, H: HistoryMode> From<TracerDispatcher<S, H>>
impl<S, H> From<TracerDispatcher<S, H>> for () {
fn from(_value: TracerDispatcher<S, H>) -> Self {}
}

impl<S, H> From<TracerDispatcher<S, H>> for old_tracers::TracerDispatcher {
fn from(value: TracerDispatcher<S, H>) -> Self {
Self::new(value.tracers.into_iter().map(|x| x.old_tracer()).collect())
}
}
48 changes: 48 additions & 0 deletions core/lib/multivm/src/tracers/old_tracers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::sync::Arc;

use once_cell::sync::OnceCell;
use zksync_types::vm_trace::Call;

/// For backward compatibility with vm before vm with virtual blocks.
/// These tracers are tightly coupled with the VM implementation and we have to pass only params for them and not tracers by itself.
#[derive(Debug, Clone)]
pub enum OldTracers {
CallTracer(Arc<OnceCell<Vec<Call>>>),
StorageInvocations(usize),
/// Special cases for not supported tracers.
None,
}

impl OldTracers {
pub fn call_tracer(&self) -> Option<Arc<OnceCell<Vec<Call>>>> {
match self {
OldTracers::CallTracer(a) => Some(a.clone()),
_ => None,
}
}
pub fn storage_invocations(&self) -> Option<usize> {
match self {
OldTracers::StorageInvocations(a) => Some(*a),
_ => None,
}
}
}

/// Tracer dispatcher is a tracer that can convert list of tracers to params for old VM.
#[derive(Debug, Default, Clone)]
pub struct TracerDispatcher {
pub(crate) call_tracer: Option<Arc<OnceCell<Vec<Call>>>>,
pub(crate) storage_invocations: Option<usize>,
}

impl TracerDispatcher {
pub fn new(tracers: Vec<OldTracers>) -> Self {
let call_tracer = tracers.iter().find_map(|x| x.call_tracer());
let storage_invocations = tracers.iter().find_map(|x| x.storage_invocations());

Self {
call_tracer,
storage_invocations,
}
}
}
8 changes: 8 additions & 0 deletions core/lib/multivm/src/tracers/storage_invocation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::{glue::tracers::IntoOldVmTracer, tracers::old_tracers::OldTracers};

pub mod vm_boojum_integration;
pub mod vm_latest;
pub mod vm_refunds_enhancement;
Expand All @@ -16,3 +18,9 @@ impl StorageInvocations {
Self { limit, current: 0 }
}
}

impl IntoOldVmTracer for StorageInvocations {
fn old_tracer(&self) -> OldTracers {
OldTracers::StorageInvocations(self.limit)
}
}
7 changes: 6 additions & 1 deletion core/lib/multivm/src/tracers/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ use zksync_types::{
};
use zksync_utils::{be_bytes_to_safe_address, u256_to_account_address, u256_to_h256};

use crate::tracers::validator::types::{NewTrustedValidationItems, ValidationTracerMode};
pub use crate::tracers::validator::types::{ValidationError, ValidationTracerParams};
use crate::{
glue::tracers::IntoOldVmTracer,
tracers::validator::types::{NewTrustedValidationItems, ValidationTracerMode},
};

mod types;
mod vm_boojum_integration;
Expand Down Expand Up @@ -216,3 +219,5 @@ fn valid_eth_token_call(address: Address, msg_sender: Address) -> bool {
|| msg_sender == BOOTLOADER_ADDRESS;
address == L2_ETH_TOKEN_ADDRESS && is_valid_caller
}

impl<H> IntoOldVmTracer for ValidationTracer<H> {}
50 changes: 36 additions & 14 deletions core/lib/multivm/src/versions/vm_1_3_2/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode,
VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmMemoryMetrics,
},
tracers::old_tracers::TracerDispatcher,
vm_1_3_2::{events::merge_events, VmInstance},
};

Expand All @@ -30,8 +31,7 @@ pub struct Vm<S: WriteStorage, H: HistoryMode> {
}

impl<S: WriteStorage, H: HistoryMode> VmInterface<S, H> for Vm<S, H> {
/// Tracers are not supported for vm 1.3.2. So we use `()` as a placeholder
type TracerDispatcher = ();
type TracerDispatcher = TracerDispatcher;

fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr<S>) -> Self {
let oracle_tools = crate::vm_1_3_2::OracleTools::new(storage.clone());
Expand Down Expand Up @@ -69,18 +69,31 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface<S, H> for Vm<S, H> {

fn inspect(
&mut self,
_tracer: Self::TracerDispatcher,
tracer: Self::TracerDispatcher,
execution_mode: VmExecutionMode,
) -> VmExecutionResultAndLogs {
if let Some(storage_invocations) = tracer.storage_invocations {
self.vm
.execution_mode
.set_invocation_limit(storage_invocations);
}

match execution_mode {
VmExecutionMode::OneTx => {
match self.system_env.execution_mode {
TxExecutionMode::VerifyExecute => {
// Even that call tracer is supported here, we don't use it now
self.vm.execute_next_tx(
let enable_call_tracer = tracer
.call_tracer.is_some();
let result = self.vm.execute_next_tx(
self.system_env.default_validation_computational_gas_limit,
false,
).glue_into()
enable_call_tracer,
);
if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) {
call_tracer.set( result.call_traces.clone()).unwrap();

}
result.glue_into()

}
TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self.vm
.execute_till_block_end(
Expand Down Expand Up @@ -172,13 +185,18 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface<S, H> for Vm<S, H> {

fn inspect_transaction_with_bytecode_compression(
&mut self,
_tracer: Self::TracerDispatcher,
tracer: Self::TracerDispatcher,
tx: Transaction,
with_compression: bool,
) -> (
Result<(), BytecodeCompressionError>,
VmExecutionResultAndLogs,
) {
if let Some(storage_invocations) = tracer.storage_invocations {
self.vm
.execution_mode
.set_invocation_limit(storage_invocations);
}
self.last_tx_compressed_bytecodes = vec![];
let bytecodes = if with_compression {
let deps = tx.execute.factory_deps.as_deref().unwrap_or_default();
Expand Down Expand Up @@ -218,13 +236,17 @@ impl<S: WriteStorage, H: HistoryMode> VmInterface<S, H> for Vm<S, H> {

// Even that call tracer is supported here, we don't use it.
let result = match self.system_env.execution_mode {
TxExecutionMode::VerifyExecute => self
.vm
.execute_next_tx(
TxExecutionMode::VerifyExecute => {
let enable_call_tracer = tracer.call_tracer.is_some();
let result = self.vm.execute_next_tx(
self.system_env.default_validation_computational_gas_limit,
false,
)
.glue_into(),
enable_call_tracer,
);
if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) {
call_tracer.set(result.call_traces.clone()).unwrap();
}
result.glue_into()
}
TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self
.vm
.execute_till_block_end(
Expand Down
12 changes: 12 additions & 0 deletions core/lib/multivm/src/versions/vm_1_3_2/vm_with_bootloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,18 @@ impl TxExecutionMode {
} => *missed_storage_invocation_limit,
}
}

pub fn set_invocation_limit(&mut self, limit: usize) {
match self {
Self::VerifyExecute => {}
TxExecutionMode::EstimateFee {
missed_storage_invocation_limit,
} => *missed_storage_invocation_limit = limit,
TxExecutionMode::EthCall {
missed_storage_invocation_limit,
} => *missed_storage_invocation_limit = limit,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down
Loading

0 comments on commit 9fc2d95

Please sign in to comment.