Skip to main content

miden_core/operations/decorators/
mod.rs

1use alloc::{string::ToString, vec::Vec};
2use core::fmt;
3
4use miden_crypto::hash::blake::Blake3_256;
5use num_traits::ToBytes;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9mod assembly_op;
10pub use assembly_op::AssemblyOp;
11
12mod debug;
13pub use debug::DebugOptions;
14
15use crate::mast::{DecoratedOpLink, DecoratorFingerprint};
16
17// DECORATORS
18// ================================================================================================
19
20/// A set of decorators which can be executed by the VM.
21///
22/// Executing a decorator does not affect the state of the main VM components such as operand stack
23/// and memory.
24///
25/// Executing decorators does not advance the VM clock. As such, many decorators can be executed in
26/// a single VM cycle.
27#[derive(Clone, Debug, Eq, PartialEq)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
30pub enum Decorator {
31    /// Adds information about the assembly instruction at a particular index (only applicable in
32    /// debug mode).
33    AsmOp(AssemblyOp),
34    /// Prints out information about the state of the VM based on the specified options. This
35    /// decorator is executed only in debug mode.
36    Debug(DebugOptions),
37    /// Emits a trace to the host.
38    Trace(u32),
39}
40
41impl Decorator {
42    pub fn fingerprint(&self) -> DecoratorFingerprint {
43        match self {
44            Self::AsmOp(asm_op) => {
45                let bytes_to_hash_suffix = [
46                    asm_op.context_name().as_bytes(),
47                    asm_op.op().as_bytes(),
48                    &[asm_op.num_cycles()],
49                    &[asm_op.should_break() as u8],
50                ];
51                if let Some(location) = asm_op.location() {
52                    let bytes_to_hash = [
53                        location.uri.as_str().as_bytes(),
54                        &location.start.to_u32().to_le_bytes()[..],
55                        &location.end.to_u32().to_le_bytes()[..],
56                    ];
57                    Blake3_256::hash_iter(bytes_to_hash.into_iter().chain(bytes_to_hash_suffix))
58                } else {
59                    Blake3_256::hash_iter(bytes_to_hash_suffix.into_iter())
60                }
61            },
62            Self::Debug(debug) => Blake3_256::hash(debug.to_string().as_bytes()),
63            Self::Trace(trace) => Blake3_256::hash(&trace.to_le_bytes()),
64        }
65    }
66}
67
68impl crate::prettier::PrettyPrint for Decorator {
69    fn render(&self) -> crate::prettier::Document {
70        crate::prettier::display(self)
71    }
72}
73
74impl fmt::Display for Decorator {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self {
77            Self::AsmOp(assembly_op) => {
78                write!(f, "asmOp({}, {})", assembly_op.op(), assembly_op.num_cycles())
79            },
80            Self::Debug(options) => write!(f, "debug({options})"),
81            Self::Trace(trace_id) => write!(f, "trace({trace_id})"),
82        }
83    }
84}
85
86/// Vector consisting of a tuple of operation index (within a span block) and decorator at that
87/// index.
88///
89/// Note: for `AssemblyOp` decorators, when an instruction compiles down to multiple operations,
90/// only the first operation is associated with the assembly op.
91pub type DecoratorList = Vec<DecoratedOpLink>;