Skip to content

Commit

Permalink
Merge pull request #1198 from 0xPolygonMiden/andrew-add-tracing-to-host
Browse files Browse the repository at this point in the history
Add tracing to the `Host` interface
  • Loading branch information
bobbinth authored Jan 17, 2024
2 parents 2662639 + a24f896 commit a9a1c6a
Show file tree
Hide file tree
Showing 21 changed files with 262 additions and 90 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Added methods `StackOutputs::get_stack_item()` and `StackOutputs::get_stack_word()` (#1155).
- Added [Tracing](https://crates.io/crates/tracing) logger to the VM (#1139).
- Added `on_assert_failed()` method to the Host trait (#1197).
- Added support for handling `trace` instruction in the `Host` interface (#1198).

#### CLI
- Introduced the `!use` command for the Miden REPL (#1162).
Expand Down
18 changes: 18 additions & 0 deletions air/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,15 @@ impl From<ProvingOptions> for WinterProofOptions {
pub struct ExecutionOptions {
max_cycles: u32,
expected_cycles: u32,
enable_tracing: bool,
}

impl Default for ExecutionOptions {
fn default() -> Self {
ExecutionOptions {
max_cycles: u32::MAX,
expected_cycles: MIN_TRACE_LEN as u32,
enable_tracing: false,
}
}
}
Expand All @@ -171,6 +173,7 @@ impl ExecutionOptions {
pub fn new(
max_cycles: Option<u32>,
expected_cycles: u32,
enable_tracing: bool,
) -> Result<Self, ExecutionOptionsError> {
let max_cycles = max_cycles.unwrap_or(u32::MAX);
if max_cycles < MIN_TRACE_LEN as u32 {
Expand All @@ -187,9 +190,19 @@ impl ExecutionOptions {
Ok(ExecutionOptions {
max_cycles,
expected_cycles,
enable_tracing,
})
}

/// Enables Host to handle the `tracing` instructions.
pub fn with_tracing(mut self) -> Self {
self.enable_tracing = true;
self
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

/// Returns maximum number of cycles
pub fn max_cycles(&self) -> u32 {
self.max_cycles
Expand All @@ -199,4 +212,9 @@ impl ExecutionOptions {
pub fn expected_cycles(&self) -> u32 {
self.expected_cycles
}

/// Returns a flag indicating whether the Host should handle `trace` instructions
pub fn enable_tracing(&self) -> bool {
self.enable_tracing
}
}
6 changes: 6 additions & 0 deletions assembly/src/assembler/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,12 @@ impl Assembler {
span.push_decorator(Decorator::Event(*event_id));
Ok(None)
}

// ----- trace instruction ------------------------------------------------------------
Instruction::Trace(trace_id) => {
span.push_decorator(Decorator::Trace(*trace_id));
Ok(None)
}
};

// compute and update the cycle count of the instruction which just finished executing
Expand Down
6 changes: 4 additions & 2 deletions assembly/src/ast/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,9 @@ pub enum Instruction {
Breakpoint,
Debug(DebugOptions),

// ----- emit instruction ---------------------------------------------------------------------
// ----- event decorators ---------------------------------------------------------------------
Emit(u32),
Trace(u32),
}

impl Instruction {
Expand Down Expand Up @@ -545,8 +546,9 @@ impl fmt::Display for Instruction {
Self::Breakpoint => write!(f, "breakpoint"),
Self::Debug(options) => write!(f, "debug.{options}"),

// ----- emit instruction -------------------------------------------------------------
// ----- event decorators -------------------------------------------------------------
Self::Emit(value) => write!(f, "emit.{value}"),
Self::Trace(value) => write!(f, "trace.{value}"),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion assembly/src/ast/nodes/serde/deserialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,9 @@ impl Deserializable for Instruction {
Ok(Instruction::Debug(options))
}

// ----- emit ------------------------------------------------------------------------
// ----- event decorators -------------------------------------------------------------
OpCode::Emit => Ok(Instruction::Emit(source.read_u32()?)),
OpCode::Trace => Ok(Instruction::Trace(source.read_u32()?)),

// ----- control flow -----------------------------------------------------------------
// control flow instructions should be parsed as a part of Node::read_from() and we
Expand Down
3 changes: 2 additions & 1 deletion assembly/src/ast/nodes/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,9 @@ pub enum OpCode {
// ----- debugging ----------------------------------------------------------------------------
Debug = 220,

// ----- emit --------------------------------------------------------------------------------
// ----- event decorators ---------------------------------------------------------------------
Emit = 221,
Trace = 222,

// ----- control flow -------------------------------------------------------------------------
IfElse = 253,
Expand Down
7 changes: 6 additions & 1 deletion assembly/src/ast/nodes/serde/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,11 +473,16 @@ impl Serializable for Instruction {
debug::write_options_into(target, options);
}

// ----- emit instruction -------------------------------------------------------------
// ----- event decorators -------------------------------------------------------------
Self::Emit(event_id) => {
OpCode::Emit.write_into(target);
target.write_u32(*event_id);
}

Self::Trace(trace_id) => {
OpCode::Trace.write_into(target);
target.write_u32(*trace_id);
}
}
}
}
7 changes: 4 additions & 3 deletions assembly/src/ast/parsers/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
super::ProcReExport, adv_ops, debug, emit, field_ops, io_ops, stack_ops, sys_ops, u32_ops,
super::ProcReExport, adv_ops, debug, events, field_ops, io_ops, stack_ops, sys_ops, u32_ops,
CodeBody, Instruction, InvocationTarget, LibraryPath, LocalConstMap, LocalProcMap,
ModuleImports, Node, ParsingError, ProcedureAst, ProcedureId, ProcedureName, ReExportedProcMap,
Token, TokenStream, MAX_BODY_LEN, MAX_DOCS_LEN,
Expand Down Expand Up @@ -626,8 +626,9 @@ impl ParserContext<'_> {
"breakpoint" => simple_instruction(op, Breakpoint),
"debug" => debug::parse_debug(op, self.num_proc_locals),

// ----- emit instruction -------------------------------------------------------------
"emit" => emit::parse_emit(op, &self.local_constants),
// ----- event decorators -------------------------------------------------------------
"emit" => events::parse_emit(op, &self.local_constants),
"trace" => events::parse_trace(op, &self.local_constants),

// ----- catch all --------------------------------------------------------------------
_ => Err(ParsingError::invalid_op(op)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,25 @@ pub fn parse_emit(op: &Token, constants: &LocalConstMap) -> Result<Node, Parsing
_ => Err(ParsingError::extra_param(op)),
}
}

// TRACE PARSER
// ================================================================================================

/// Returns `Trace` instruction node with the parsed `trace_id`.
///
/// The `trace_id` can be provided as a constant label or as a u32 value.
///
/// # Errors
/// Returns an error if the constant does not exist or if the value is not a u32.
pub fn parse_trace(op: &Token, constants: &LocalConstMap) -> Result<Node, ParsingError> {
debug_assert_eq!(op.parts()[0], "trace");
match op.num_parts() {
0 => unreachable!(),
1 => Err(ParsingError::missing_param(op, "trace.<tace_id>")),
2 => {
let trace_id = parse_param_with_constant_lookup(op, 1, constants)?;
Ok(Instruction(Trace(trace_id)))
}
_ => Err(ParsingError::extra_param(op)),
}
}
2 changes: 1 addition & 1 deletion assembly/src/ast/parsers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::{fmt::Display, ops::RangeBounds};

mod adv_ops;
mod debug;
mod emit;
mod events;
mod field_ops;
mod io_ops;
mod stack_ops;
Expand Down
3 changes: 3 additions & 0 deletions core/src/operations/decorators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub enum Decorator {
Debug(DebugOptions),
/// Emits an event to the host.
Event(u32),
/// Emmits a trace to the host.
Trace(u32),
}

impl fmt::Display for Decorator {
Expand All @@ -43,6 +45,7 @@ impl fmt::Display for Decorator {
}
Self::Debug(options) => write!(f, "debug({options})"),
Self::Event(event_id) => write!(f, "event({})", event_id),
Self::Trace(trace_id) => write!(f, "trace({})", trace_id),
}
}
}
Expand Down
15 changes: 14 additions & 1 deletion docs/src/user_docs/assembly/events.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
## Events

Miden assembly supports the concept of events. Events are a simple data structure with a single `event_id` field. When an event is emitted by a program, it is communicated to the host. Events can be emitted at specific points of program execution with the intent of triggering some action on the host. This is useful as the program has contextual information that would be challenging for the host to infer. The emission of events allows the program to communicate this contextual information to the host. The host contains an event handler that is responsible for handling events and taking appropriate actions. The emission of events does not change the state of the VM but it can change the state of the host.
Miden assembly supports the concept of events. Events are a simple data structure with a single `event_id` field. When an event is emitted by a program, it is communicated to the host. Events can be emitted at specific points of program execution with the intent of triggering some action on the host. This is useful as the program has contextual information that would be challenging for the host to infer. The emission of events allows the program to communicate this contextual information to the host. The host contains an event handler that is responsible for handling events and taking appropriate actions. The emission of events does not change the state of the VM but it can change the state of the host.

An event can be emitted via the `emit.<event_id>` assembly instruction where `<event_id>` can be any 32-bit value specified either directly or via a [named constant](./code_organization.md#constants). For example:

```
emit.EVENT_ID_1
emit.2
```

## Tracing

Miden assembly also supports code tracing, which works similar to the event emitting.

A trace can be emitted via the `trace.<trace_id>` assembly instruction where `<trace_id>` can be any 32-bit value specified either directly or via a [named constant](./code_organization.md#constants). For example:

```
trace.EVENT_ID_1
trace.2
```

To make use of the `trace` instruction, programs should be ran with tracing flag (`-t` or `--tracing`), otherwise these instructions will be ignored.
7 changes: 6 additions & 1 deletion miden/src/cli/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@ pub struct ProveCmd {
/// Security level for execution proofs generated by the VM
#[clap(short = 's', long = "security", default_value = "96bits")]
security: String,

/// Enable tracing to monitor execution of the VM
#[clap(short = 't', long = "tracing")]
tracing: bool,
}

impl ProveCmd {
pub fn get_proof_options(&self) -> Result<ProvingOptions, ExecutionOptionsError> {
let exec_options = ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles)?;
let exec_options =
ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles, self.tracing)?;
Ok(match self.security.as_str() {
"96bits" => ProvingOptions::with_96_bit_security(self.recursive),
"128bits" => ProvingOptions::with_128_bit_security(self.recursive),
Expand Down
9 changes: 7 additions & 2 deletions miden/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ pub struct RunCmd {
/// Path to output file
#[clap(short = 'o', long = "output", value_parser)]
output_file: Option<PathBuf>,

/// Enable tracing to monitor execution of the VM
#[clap(short = 't', long = "tracing")]
tracing: bool,
}

impl RunCmd {
Expand Down Expand Up @@ -106,8 +110,9 @@ fn run_program(params: &RunCmd) -> Result<(ExecutionTrace, [u8; 32]), String> {
let input_data = InputFile::read(&params.input_file, &params.assembly_file)?;

// get execution options
let execution_options = ExecutionOptions::new(Some(params.max_cycles), params.expected_cycles)
.map_err(|err| format!("{err}"))?;
let execution_options =
ExecutionOptions::new(Some(params.max_cycles), params.expected_cycles, params.tracing)
.map_err(|err| format!("{err}"))?;

// fetch the stack and program inputs from the arguments
let stack_inputs = input_data.parse_stack_inputs()?;
Expand Down
7 changes: 6 additions & 1 deletion miden/src/examples/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub struct ExampleOptions {
/// Security level for execution proofs generated by the VM
#[clap(short = 's', long = "security", default_value = "96bits")]
security: String,

/// Enable tracing to monitor execution of the VM
#[clap(short = 't', long = "tracing")]
tracing: bool,
}

#[derive(Debug, Clone, Parser)]
Expand All @@ -67,7 +71,8 @@ pub enum ExampleType {

impl ExampleOptions {
pub fn get_proof_options(&self) -> Result<ProvingOptions, ExecutionOptionsError> {
let exec_options = ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles)?;
let exec_options =
ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles, self.tracing)?;
Ok(match self.security.as_str() {
"96bits" => ProvingOptions::with_96_bit_security(self.recursive),
"128bits" => ProvingOptions::with_128_bit_security(self.recursive),
Expand Down
72 changes: 0 additions & 72 deletions miden/tests/integration/operations/decorators/event.rs

This file was deleted.

Loading

0 comments on commit a9a1c6a

Please sign in to comment.