Skip to content

Commit

Permalink
stopped by tracer is distinguishable from other ends
Browse files Browse the repository at this point in the history
  • Loading branch information
joonazan committed Oct 31, 2024
1 parent 1df8bee commit edb7c45
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 63 deletions.
46 changes: 7 additions & 39 deletions crates/vm2-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
//! # use zksync_vm2_interface as zksync_vm2_interface_v1;
//! use zksync_vm2_interface_v1::{
//! StateInterface as StateInterfaceV1, GlobalStateInterface as GlobalStateInterfaceV1, Tracer as TracerV1, opcodes::NearCall,
//! ShouldStop,
//! };
//!
//! trait StateInterface: StateInterfaceV1 {
Expand Down Expand Up @@ -60,7 +61,9 @@
//!
//! trait Tracer {
//! fn before_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) {}
//! fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) {}
//! fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) -> ShouldStop {
//! ShouldStop::Continue
//! }
//! }
//!
//! impl<T: TracerV1> Tracer for T {
Expand All @@ -73,7 +76,9 @@
//! }
//! }
//! }
//! fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) {}
//! fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) -> ShouldStop {
//! todo!()
//! }
//! }
//!
//! // Now you can use the new features by implementing TracerV2
Expand All @@ -91,40 +96,3 @@ pub use self::{state_interface::*, tracer_interface::*};

mod state_interface;
mod tracer_interface;

/// Returned from [`Tracer::after_instruction`] to indicate whether the VM should continue execution.
#[derive(Debug)]
pub enum ExecutionStatus {
/// Continue execution.
Running,
/// Stop or suspend execution.
Stopped(ExecutionEnd),
}

impl ExecutionStatus {
/// Combines [`ExecutionStatus`] values from two sources, choosing the most severe one.
/// So if one tracer wants to suspend but the other wants to panic, the VM will panic.
#[must_use]
#[inline(always)]
pub fn merge(self, other: Self) -> Self {
use ExecutionStatus::{Running, Stopped};
match (self, other) {
(Running | Stopped(ExecutionEnd::SuspendedOnHook(_)), other @ Stopped(_)) => other,
(me @ Stopped(_), _) => me,
_ => Running,
}
}
}

/// VM stop reason and return value.
#[derive(Debug, PartialEq)]
pub enum ExecutionEnd {
/// The executed program has finished and returned the specified data.
ProgramFinished(Vec<u8>),
/// The executed program has reverted returning the specified data.
Reverted(Vec<u8>),
/// The executed program has panicked.
Panicked,
/// Returned when the bootloader writes to the heap location specified by [`hook_address`](crate::Settings.hook_address).
SuspendedOnHook(u32),
}
28 changes: 24 additions & 4 deletions crates/vm2-interface/src/tracer_interface.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ExecutionStatus, GlobalStateInterface};
use crate::GlobalStateInterface;

macro_rules! forall_simple_opcodes {
($m:ident) => {
Expand Down Expand Up @@ -271,9 +271,9 @@ pub trait Tracer {
fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(
&mut self,
state: &mut S,
) -> ExecutionStatus {
) -> ShouldStop {
let _ = state;
ExecutionStatus::Running
ShouldStop::Continue
}

/// Provides cycle statistics for "complex" instructions from the prover perspective (mostly precompile calls).
Expand All @@ -282,6 +282,26 @@ pub trait Tracer {
fn on_extra_prover_cycles(&mut self, _stats: CycleStats) {}
}

/// Returned from [`Tracer::after_instruction`] to indicate if the VM should stop.
#[derive(Debug)]
pub enum ShouldStop {
/// The VM should stop.
Stop,
/// The VM should continue.
Continue,
}

impl ShouldStop {
#[must_use]
#[inline(always)]
fn merge(self, other: ShouldStop) -> ShouldStop {
match (self, other) {
(ShouldStop::Continue, ShouldStop::Continue) => ShouldStop::Continue,
_ => ShouldStop::Stop,
}
}
}

/// Cycle statistics emitted by the VM and supplied to [`Tracer::on_extra_prover_cycles()`].
#[derive(Debug, Clone, Copy)]
pub enum CycleStats {
Expand Down Expand Up @@ -314,7 +334,7 @@ impl<A: Tracer, B: Tracer> Tracer for (A, B) {
fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(
&mut self,
state: &mut S,
) -> ExecutionStatus {
) -> ShouldStop {
self.0
.after_instruction::<OP, S>(state)
.merge(self.1.after_instruction::<OP, S>(state))
Expand Down
3 changes: 2 additions & 1 deletion crates/vm2/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use zksync_vm2_interface::{
self, Add, And, Div, Mul, Or, PointerAdd, PointerPack, PointerShrink, PointerSub,
RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor,
},
ExecutionEnd, ExecutionStatus, Tracer,
Tracer,
};

use crate::{
Expand All @@ -20,6 +20,7 @@ use crate::{
Immediate1, Immediate2, Register, Register1, Register2, RegisterAndImmediate,
RelativeStack, SourceWriter,
},
instruction::{ExecutionEnd, ExecutionStatus},
mode_requirements::ModeRequirements,
Instruction, Predicate, VirtualMachine, World,
};
Expand Down
43 changes: 42 additions & 1 deletion crates/vm2/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

pub(crate) use zksync_vm2_interface::ExecutionStatus;
use zksync_vm2_interface::ShouldStop;

use crate::{addressing_modes::Arguments, vm::VirtualMachine};

Expand All @@ -23,3 +23,44 @@ impl<T, W> fmt::Debug for Instruction<T, W> {
}

pub(crate) type Handler<T, W> = fn(&mut VirtualMachine<T, W>, &mut W, &mut T) -> ExecutionStatus;

#[derive(Debug)]
pub(crate) enum ExecutionStatus {
Running,
Stopped(ExecutionEnd),
}

impl ExecutionStatus {
#[must_use]
#[inline(always)]
pub(crate) fn merge_tracer(self, should_stop: ShouldStop) -> Self {
match (&self, should_stop) {
(Self::Running, ShouldStop::Stop) => Self::Stopped(ExecutionEnd::StoppedByTracer),
_ => self,
}
}
}

impl From<ShouldStop> for ExecutionStatus {
fn from(should_stop: ShouldStop) -> Self {
match should_stop {
ShouldStop::Stop => Self::Stopped(ExecutionEnd::StoppedByTracer),
ShouldStop::Continue => Self::Running,
}
}
}

/// VM stop reason returned from [`VirtualMachine::run()`].
#[derive(Debug, PartialEq)]
pub enum ExecutionEnd {
/// The executed program has finished and returned the specified data.
ProgramFinished(Vec<u8>),
/// The executed program has reverted returning the specified data.
Reverted(Vec<u8>),
/// The executed program has panicked.
Panicked,
/// Returned when the bootloader writes to the heap location specified by [`hook_address`](crate::Settings.hook_address).
SuspendedOnHook(u32),
/// One of the tracers decided it is time to stop the VM.
StoppedByTracer,
}
10 changes: 5 additions & 5 deletions crates/vm2/src/instruction_handlers/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ pub(crate) fn full_boilerplate<Opcode: OpcodeType, T: Tracer, W: World<T>>(
if args.predicate().satisfied(&vm.state.flags) {
tracer.before_instruction::<Opcode, _>(&mut VmAndWorld { vm, world });
vm.state.current_frame.pc = unsafe { vm.state.current_frame.pc.add(1) };
let result = business_logic(vm, args, world, tracer);
tracer
.after_instruction::<Opcode, _>(&mut VmAndWorld { vm, world })
.merge(result)
business_logic(vm, args, world, tracer)
.merge_tracer(tracer.after_instruction::<Opcode, _>(&mut VmAndWorld { vm, world }))
} else {
tracer.before_instruction::<opcodes::Nop, _>(&mut VmAndWorld { vm, world });
vm.state.current_frame.pc = unsafe { vm.state.current_frame.pc.add(1) };
tracer.after_instruction::<opcodes::Nop, _>(&mut VmAndWorld { vm, world })
tracer
.after_instruction::<opcodes::Nop, _>(&mut VmAndWorld { vm, world })
.into()
}
}
16 changes: 8 additions & 8 deletions crates/vm2/src/instruction_handlers/ret.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use primitive_types::U256;
use zksync_vm2_interface::{
opcodes::{self, Normal, Panic, Revert, TypeLevelReturnType},
ExecutionEnd, ReturnType, Tracer,
ReturnType, Tracer,
};

use super::{
Expand All @@ -12,7 +12,7 @@ use super::{
use crate::{
addressing_modes::{Arguments, Immediate1, Register1, Source, INVALID_INSTRUCTION_COST},
callframe::FrameRemnant,
instruction::ExecutionStatus,
instruction::{ExecutionEnd, ExecutionStatus},
mode_requirements::ModeRequirements,
predication::Flags,
tracing::VmAndWorld,
Expand Down Expand Up @@ -146,13 +146,11 @@ pub(crate) fn free_panic<T: Tracer, W: World<T>>(
) -> ExecutionStatus {
tracer.before_instruction::<opcodes::Ret<Panic>, _>(&mut VmAndWorld { vm, world });
// args aren't used for panics unless TO_LABEL
let result = naked_ret::<T, W, Panic, false>(
naked_ret::<T, W, Panic, false>(
vm,
&Arguments::new(Predicate::Always, 0, ModeRequirements::none()),
);
tracer
.after_instruction::<opcodes::Ret<Panic>, _>(&mut VmAndWorld { vm, world })
.merge(result)
)
.merge_tracer(tracer.after_instruction::<opcodes::Ret<Panic>, _>(&mut VmAndWorld { vm, world }))
}

/// Formally, a far call pushes a new frame and returns from it immediately if it panics.
Expand All @@ -173,7 +171,9 @@ pub(crate) fn panic_from_failed_far_call<T: Tracer, W: World<T>>(
vm.state.flags = Flags::new(true, false, false);
vm.state.current_frame.set_pc_from_u16(exception_handler);

tracer.after_instruction::<opcodes::Ret<Panic>, _>(&mut VmAndWorld { vm, world })
tracer
.after_instruction::<opcodes::Ret<Panic>, _>(&mut VmAndWorld { vm, world })
.into()
}

fn invalid<T: Tracer, W: World<T>>(
Expand Down
3 changes: 1 addition & 2 deletions crates/vm2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ use std::hash::{DefaultHasher, Hash, Hasher};

use primitive_types::{H160, U256};
pub use zksync_vm2_interface as interface;
pub use zksync_vm2_interface::ExecutionEnd;
use zksync_vm2_interface::Tracer;

// Re-export missing modules if single instruction testing is enabled
#[cfg(feature = "single_instruction_test")]
pub(crate) use self::single_instruction_test::{heap, program, stack};
pub use self::{
fat_pointer::FatPointer,
instruction::Instruction,
instruction::{ExecutionEnd, Instruction},
mode_requirements::ModeRequirements,
predication::Predicate,
program::Program,
Expand Down
5 changes: 2 additions & 3 deletions crates/vm2/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::fmt;

use primitive_types::H160;
use zksync_vm2_interface::{
opcodes::TypeLevelCallingMode, CallingMode, ExecutionStatus, HeapId, Tracer,
};
use zksync_vm2_interface::{opcodes::TypeLevelCallingMode, CallingMode, HeapId, Tracer};

use crate::{
callframe::{Callframe, FrameRemnant},
decommit::u256_into_address,
instruction::ExecutionStatus,
stack::StackPool,
state::{State, StateSnapshot},
world_diff::{ExternalSnapshot, Snapshot, WorldDiff},
Expand Down

0 comments on commit edb7c45

Please sign in to comment.