Skip to main content

miden_processor/host/
handlers.rs

1use alloc::{
2    boxed::Box,
3    collections::{BTreeMap, btree_map::Entry},
4    sync::Arc,
5    vec::Vec,
6};
7use core::{error::Error, fmt, fmt::Debug};
8
9use miden_core::events::{EventId, EventName, SystemEvent};
10
11use crate::{ExecutionError, ProcessorState, advice::AdviceMutation};
12
13// EVENT HANDLER TRAIT
14// ================================================================================================
15
16/// An [`EventHandler`] defines a function that that can be called from the processor which can
17/// read the VM state and modify the state of the advice provider.
18///
19/// A struct implementing this trait can access its own state, but any output it produces must
20/// be stored in the process's advice provider.
21pub trait EventHandler: Send + Sync + 'static {
22    /// Handles the event when triggered.
23    fn on_event(&self, process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError>;
24}
25
26/// Default implementation for both free functions and closures with signature
27/// `fn(&ProcessorState) -> Result<Vec<AdviceMutation>, EventError>`
28impl<F> EventHandler for F
29where
30    F: for<'a> Fn(&'a ProcessorState) -> Result<Vec<AdviceMutation>, EventError>
31        + Send
32        + Sync
33        + 'static,
34{
35    fn on_event(&self, process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError> {
36        self(process)
37    }
38}
39
40/// A handler which ignores the process state and leaves the `AdviceProvider` unchanged.
41pub struct NoopEventHandler;
42
43impl EventHandler for NoopEventHandler {
44    fn on_event(&self, _process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError> {
45        Ok(Vec::new())
46    }
47}
48
49// EVENT ERROR
50// ================================================================================================
51
52/// A generic [`Error`] wrapper allowing handlers to return errors to the Host caller.
53///
54/// Error handlers can define their own [`Error`] type which can be seamlessly converted
55/// into this type since it is a [`Box`].
56///
57/// # Example
58///
59/// ```rust, ignore
60/// pub struct MyError{ /* ... */ };
61///
62/// fn try_something() -> Result<(), MyError> { /* ... */ }
63///
64/// fn my_handler(process: &mut ProcessorState) -> Result<(), HandlerError> {
65///     // ...
66///     try_something()?;
67///     // ...
68///     Ok(())
69/// }
70/// ```
71pub type EventError = Box<dyn Error + Send + Sync + 'static>;
72
73// EVENT HANDLER REGISTRY
74// ================================================================================================
75
76/// Registry for maintaining event handlers.
77///
78/// # Example
79///
80/// ```rust, ignore
81/// impl Host for MyHost {
82///     fn on_event(
83///         &mut self,
84///         process: &mut ProcessorState,
85///         event_id: u32,
86///     ) -> Result<(), EventError> {
87///         if self
88///             .event_handlers
89///             .handle_event(event_id, process)
90///             .map_err(|err| EventError::HandlerError { id: event_id, err })?
91///         {
92///             // the event was handled by the registered event handlers; just return
93///             return Ok(());
94///         }
95///
96///         // implement custom event handling
97///
98///         Err(EventError::UnhandledEvent { id: event_id })
99///     }
100/// }
101/// ```
102#[derive(Default)]
103pub struct EventHandlerRegistry {
104    handlers: BTreeMap<EventId, (EventName, Arc<dyn EventHandler>)>,
105}
106
107impl EventHandlerRegistry {
108    pub fn new() -> Self {
109        Self { handlers: BTreeMap::new() }
110    }
111
112    /// Registers an [`EventHandler`] with a given event name.
113    ///
114    /// The [`EventId`] is computed from the event name during registration.
115    ///
116    /// # Errors
117    /// Returns an error if:
118    /// - The event is a reserved system event
119    /// - A handler with the same event ID is already registered
120    pub fn register(
121        &mut self,
122        event: EventName,
123        handler: Arc<dyn EventHandler>,
124    ) -> Result<(), ExecutionError> {
125        // Check if the event is a reserved system event
126        if SystemEvent::from_name(event.as_str()).is_some() {
127            return Err(crate::errors::HostError::ReservedEventNamespace { event }.into());
128        }
129
130        // Compute EventId from the event name
131        let id = event.to_event_id();
132        match self.handlers.entry(id) {
133            Entry::Vacant(e) => e.insert((event, handler)),
134            Entry::Occupied(_) => {
135                return Err(crate::errors::HostError::DuplicateEventHandler { event }.into());
136            },
137        };
138        Ok(())
139    }
140
141    /// Unregisters a handler with the given identifier, returning a flag whether a handler with
142    /// that identifier was previously registered.
143    pub fn unregister(&mut self, id: EventId) -> bool {
144        self.handlers.remove(&id).is_some()
145    }
146
147    /// Returns the [`EventName`] registered for `id`, if any.
148    pub fn resolve_event(&self, id: EventId) -> Option<&EventName> {
149        self.handlers.get(&id).map(|(event, _)| event)
150    }
151
152    /// Handles the event if the registry contains a handler with the same identifier.
153    ///
154    /// Returns an `Option<_>` indicating whether the event was handled. Returns `None` if the
155    /// event was not handled, `Some(mutations)` if it was handled successfully, and propagates
156    /// handler errors to the caller.
157    pub fn handle_event(
158        &self,
159        id: EventId,
160        process: &ProcessorState,
161    ) -> Result<Option<Vec<AdviceMutation>>, EventError> {
162        if let Some((_event_name, handler)) = self.handlers.get(&id) {
163            let mutations = handler.on_event(process)?;
164            return Ok(Some(mutations));
165        }
166
167        Ok(None)
168    }
169}
170
171impl Debug for EventHandlerRegistry {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        let events: Vec<_> = self.handlers.values().map(|(event, _)| event).collect();
174        f.debug_struct("EventHandlerRegistry").field("handlers", &events).finish()
175    }
176}
177
178// TRACE HANDLER TRAIT
179// ================================================================================================
180
181/// Handles an optional, read-only trace event emitted by the VM.
182///
183/// Assembly programs emit trace events with `trace`, `trace.CONST`, or `trace.event("...")`. When
184/// the handler runs, [`SystemEvent::TraceEvent`] is at stack position 0 and the user trace event ID
185/// is at position 1. The handler receives a read-only [`ProcessorState`] and cannot return advice
186/// mutations.
187///
188/// The instruction expansions are:
189///
190/// - `trace` expands to `push.<sys::trace_event> emit drop`.
191/// - `trace.CONST` and `trace.event("...")` expand to `push.<trace_id> push.<sys::trace_event> emit
192///   drop drop`.
193pub trait TraceHandler: Send + Sync + 'static {
194    /// Handles the trace event when triggered.
195    fn on_trace(&self, process: &ProcessorState) -> Result<(), TraceError>;
196}
197
198/// Default implementation for both free functions and closures with signature
199/// `fn(&ProcessorState) -> Result<(), TraceError>`
200impl<F> TraceHandler for F
201where
202    F: for<'a> Fn(&'a ProcessorState) -> Result<(), TraceError> + Send + Sync + 'static,
203{
204    fn on_trace(&self, process: &ProcessorState) -> Result<(), TraceError> {
205        self(process)
206    }
207}
208
209// TRACE ERROR
210// ================================================================================================
211
212/// Error type returned by trace handlers.
213///
214/// Handlers should return errors without event names or IDs; the processor enriches them with the
215/// trace event ID and any name registered in the host's trace handler registry.
216pub type TraceError = Box<dyn Error + Send + Sync + 'static>;
217
218// TRACE HANDLER REGISTRY
219// ================================================================================================
220
221/// Registry for maintaining trace handlers.
222#[derive(Default)]
223pub struct TraceHandlerRegistry {
224    handlers: BTreeMap<EventId, (EventName, Arc<dyn TraceHandler>)>,
225}
226
227impl TraceHandlerRegistry {
228    pub fn new() -> Self {
229        Self { handlers: BTreeMap::new() }
230    }
231
232    /// Registers a [`TraceHandler`] with the given event name.
233    ///
234    /// The [`EventId`] is computed from the event name during registration.
235    ///
236    /// # Errors
237    /// Returns an error if:
238    /// - The event is a reserved system event
239    /// - A handler with the same event ID is already registered
240    pub fn register(
241        &mut self,
242        event: EventName,
243        handler: Arc<dyn TraceHandler>,
244    ) -> Result<(), ExecutionError> {
245        // Check if the event is a reserved system event
246        if SystemEvent::from_name(event.as_str()).is_some() {
247            return Err(crate::errors::HostError::ReservedEventNamespace { event }.into());
248        }
249
250        let id = event.to_event_id();
251        match self.handlers.entry(id) {
252            Entry::Vacant(e) => e.insert((event, handler)),
253            Entry::Occupied(_) => {
254                return Err(crate::errors::HostError::DuplicateEventHandler { event }.into());
255            },
256        };
257        Ok(())
258    }
259
260    /// Unregisters a handler with the given identifier, returning whether a handler with that
261    /// identifier was previously registered.
262    pub fn unregister(&mut self, id: EventId) -> bool {
263        self.handlers.remove(&id).is_some()
264    }
265
266    /// Returns the [`EventName`] registered for `id`, if any.
267    pub fn resolve_trace(&self, id: EventId) -> Option<&EventName> {
268        self.handlers.get(&id).map(|(event, _)| event)
269    }
270
271    /// Handles the trace event if the registry contains a handler with the same identifier.
272    ///
273    /// Returns `Ok(None)` if no handler is registered for `id`, `Ok(Some(()))` if the trace was
274    /// handled, and propagates handler errors to the caller.
275    pub fn handle_trace(
276        &self,
277        id: EventId,
278        process: &ProcessorState,
279    ) -> Result<Option<()>, TraceError> {
280        if let Some((_event_name, handler)) = self.handlers.get(&id) {
281            handler.on_trace(process)?;
282            return Ok(Some(()));
283        }
284
285        Ok(None)
286    }
287}
288
289impl Debug for TraceHandlerRegistry {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        let traces: Vec<_> = self.handlers.values().map(|(event, _)| event).collect();
292        f.debug_struct("TraceHandlerRegistry").field("handlers", &traces).finish()
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use alloc::{sync::Arc, vec::Vec};
299
300    use miden_core::events::{EventId, EventName, SystemEvent};
301
302    use super::{
303        EventError, EventHandler, EventHandlerRegistry, NoopEventHandler, TraceError, TraceHandler,
304        TraceHandlerRegistry,
305    };
306    use crate::{
307        BaseHost, DefaultHost, ExecutionError, FastProcessor, HostError, ProcessorState,
308        StackInputs, advice::AdviceMutation,
309    };
310
311    #[derive(Debug, thiserror::Error)]
312    #[error("handler intentionally failed")]
313    struct HandlerFailed;
314
315    /// An event handler that always errors.
316    struct FailingEventHandler;
317    impl EventHandler for FailingEventHandler {
318        fn on_event(&self, _process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError> {
319            Err(HandlerFailed.into())
320        }
321    }
322
323    /// A trace handler that always errors.
324    struct FailingTraceHandler;
325    impl TraceHandler for FailingTraceHandler {
326        fn on_trace(&self, _process: &ProcessorState) -> Result<(), TraceError> {
327            Err(HandlerFailed.into())
328        }
329    }
330
331    struct NoopTraceHandler;
332    impl TraceHandler for NoopTraceHandler {
333        fn on_trace(&self, _process: &ProcessorState) -> Result<(), TraceError> {
334            Ok(())
335        }
336    }
337
338    /// Builds a default processor and runs `f` against its [`ProcessorState`].
339    ///
340    /// Allows exercising the handlers defined above without spinning up a full execution. This is
341    /// fine since these handlers ignore processor state.
342    fn with_fresh_processor_state(f: impl FnOnce(&ProcessorState)) {
343        let processor = FastProcessor::new(StackInputs::default());
344        let state = processor.state();
345        f(&state);
346    }
347
348    #[test]
349    fn event_registry_resolve() {
350        const NAME: EventName = EventName::new("test::event::register_resolve");
351        let id = NAME.to_event_id();
352
353        let mut registry = EventHandlerRegistry::new();
354        assert!(registry.resolve_event(id).is_none());
355
356        registry.register(NAME, Arc::new(NoopEventHandler)).unwrap();
357        assert_eq!(registry.resolve_event(id), Some(&NAME));
358    }
359
360    #[test]
361    fn event_registry_handle_hit_and_miss() {
362        const NAME: EventName = EventName::new("test::event::handle");
363        let id = NAME.to_event_id();
364
365        let mut registry = EventHandlerRegistry::new();
366        registry.register(NAME, Arc::new(NoopEventHandler)).unwrap();
367
368        with_fresh_processor_state(|state| {
369            let handled =
370                registry.handle_event(id, state).expect("registered handler should not error");
371            assert!(handled.is_some(), "registered id should be handled");
372
373            let missed = registry
374                .handle_event(EventId::from_u64(999), state)
375                .expect("unregistered id should not error");
376            assert!(missed.is_none(), "unknown id should not be handled");
377        });
378    }
379
380    #[test]
381    fn event_registry_handle_propagates_handler_error() {
382        const NAME: EventName = EventName::new("test::event::handle_error");
383        let id = NAME.to_event_id();
384
385        let mut registry = EventHandlerRegistry::new();
386        registry.register(NAME, Arc::new(FailingEventHandler)).unwrap();
387
388        with_fresh_processor_state(|state| {
389            let err = registry.handle_event(id, state).unwrap_err();
390            assert!(
391                err.downcast_ref::<HandlerFailed>().is_some(),
392                "expected the handler's HandlerFailed to propagate, got {err}"
393            );
394        });
395    }
396
397    #[test]
398    fn event_registry_unregister() {
399        const NAME: EventName = EventName::new("test::event::unregister");
400        let id = NAME.to_event_id();
401
402        let mut registry = EventHandlerRegistry::new();
403        registry.register(NAME, Arc::new(NoopEventHandler)).unwrap();
404
405        assert!(registry.unregister(id), "unregistering a known id should return true");
406        assert!(registry.resolve_event(id).is_none());
407        assert!(!registry.unregister(id), "unregistering again should return false");
408    }
409
410    #[test]
411    fn event_register_rejects_reserved_namespace() {
412        let reserved = SystemEvent::MerkleNodeMerge.event_name();
413        let mut registry = EventHandlerRegistry::new();
414        let err = registry.register(reserved.clone(), Arc::new(NoopEventHandler)).unwrap_err();
415        match err {
416            ExecutionError::HostError(HostError::ReservedEventNamespace { event }) => {
417                assert_eq!(event, reserved);
418            },
419            other => panic!("expected ReservedEventNamespace, got {other:?}"),
420        }
421    }
422
423    #[test]
424    fn event_register_rejects_duplicate() {
425        const NAME: EventName = EventName::new("test::event::duplicate");
426        let mut registry = EventHandlerRegistry::new();
427        registry.register(NAME, Arc::new(NoopEventHandler)).unwrap();
428
429        let err = registry.register(NAME, Arc::new(NoopEventHandler)).unwrap_err();
430        match err {
431            ExecutionError::HostError(HostError::DuplicateEventHandler { event }) => {
432                assert_eq!(event, NAME);
433            },
434            other => panic!("expected DuplicateEventHandler, got {other:?}"),
435        }
436    }
437
438    #[test]
439    fn trace_registry_register_then_resolve() {
440        const NAME: EventName = EventName::new("test::trace::register_resolve");
441        let id = NAME.to_event_id();
442
443        let mut registry = TraceHandlerRegistry::new();
444        assert!(registry.resolve_trace(id).is_none());
445
446        registry.register(NAME, Arc::new(NoopTraceHandler)).unwrap();
447        assert_eq!(registry.resolve_trace(id), Some(&NAME));
448    }
449
450    #[test]
451    fn trace_registry_handle_hit_and_miss() {
452        const NAME: EventName = EventName::new("test::trace::handle");
453        let id = NAME.to_event_id();
454
455        let mut registry = TraceHandlerRegistry::new();
456        registry.register(NAME, Arc::new(NoopTraceHandler)).unwrap();
457
458        with_fresh_processor_state(|state| {
459            let handled =
460                registry.handle_trace(id, state).expect("registered handler should not error");
461            assert_eq!(handled, Some(()), "registered id should be handled");
462
463            let missed = registry
464                .handle_trace(EventId::from_u64(999), state)
465                .expect("unregistered id should not error");
466            assert_eq!(missed, None, "unknown id should not be handled");
467        });
468    }
469
470    #[test]
471    fn trace_registry_handle_propagates_handler_error() {
472        const NAME: EventName = EventName::new("test::trace::handle_error");
473        let id = NAME.to_event_id();
474
475        let mut registry = TraceHandlerRegistry::new();
476        registry.register(NAME, Arc::new(FailingTraceHandler)).unwrap();
477
478        with_fresh_processor_state(|state| {
479            let err = registry.handle_trace(id, state).unwrap_err();
480            assert!(
481                err.downcast_ref::<HandlerFailed>().is_some(),
482                "expected the handler's HandlerFailed to propagate, got {err}"
483            );
484        });
485    }
486
487    #[test]
488    fn trace_registry_unregister() {
489        const NAME: EventName = EventName::new("test::trace::unregister");
490        let id = NAME.to_event_id();
491
492        let mut registry = TraceHandlerRegistry::new();
493        registry.register(NAME, Arc::new(NoopTraceHandler)).unwrap();
494
495        assert!(registry.unregister(id), "unregistering a known id should return true");
496        assert!(registry.resolve_trace(id).is_none());
497        assert!(!registry.unregister(id), "unregistering again should return false");
498    }
499
500    #[test]
501    fn trace_register_rejects_reserved_namespace() {
502        // The trace-event system name is reserved, so it cannot be used for a user handler.
503        let reserved = SystemEvent::TraceEvent.event_name();
504        let mut registry = TraceHandlerRegistry::new();
505        let err = registry.register(reserved.clone(), Arc::new(NoopTraceHandler)).unwrap_err();
506        match err {
507            ExecutionError::HostError(HostError::ReservedEventNamespace { event }) => {
508                assert_eq!(event, reserved);
509            },
510            other => panic!("expected ReservedEventNamespace, got {other:?}"),
511        }
512    }
513
514    #[test]
515    fn trace_register_rejects_duplicate() {
516        const NAME: EventName = EventName::new("test::trace::duplicate");
517        let mut registry = TraceHandlerRegistry::new();
518        registry.register(NAME, Arc::new(NoopTraceHandler)).unwrap();
519
520        let err = registry.register(NAME, Arc::new(NoopTraceHandler)).unwrap_err();
521        match err {
522            ExecutionError::HostError(HostError::DuplicateEventHandler { event }) => {
523                assert_eq!(event, NAME);
524            },
525            other => panic!("expected DuplicateEventHandler, got {other:?}"),
526        }
527    }
528
529    #[test]
530    fn default_host_event_handler_lifecycle() {
531        const NAME: EventName = EventName::new("test::host::event_lifecycle");
532        let id = NAME.to_event_id();
533        let mut host = DefaultHost::default();
534
535        // `replace_handler` reports whether a prior handler existed; before any registration it
536        // returns false but registers the handler.
537        let existed = host.replace_handler(NAME, Arc::new(NoopEventHandler));
538        assert!(!existed, "replace before register should report no prior handler");
539        assert_eq!(host.resolve_event(id), Some(&NAME));
540
541        // A second replace now observes the prior handler.
542        assert!(host.replace_handler(NAME, Arc::new(NoopEventHandler)));
543
544        // Re-registering the same event directly is rejected.
545        assert!(matches!(
546            host.register_handler(NAME, Arc::new(NoopEventHandler)),
547            Err(ExecutionError::HostError(HostError::DuplicateEventHandler { .. }))
548        ));
549
550        assert!(host.unregister_handler(id));
551        assert!(host.resolve_event(id).is_none());
552        assert!(!host.unregister_handler(id));
553    }
554
555    #[test]
556    fn default_host_trace_handler_lifecycle() {
557        const NAME: EventName = EventName::new("test::host::trace_lifecycle");
558        let id = NAME.to_event_id();
559        let mut host = DefaultHost::default();
560
561        let existed = host.replace_trace_handler(NAME, Arc::new(NoopTraceHandler));
562        assert!(!existed, "replace before register should report no prior handler");
563        assert_eq!(host.resolve_trace(id), Some(&NAME));
564
565        assert!(host.replace_trace_handler(NAME, Arc::new(NoopTraceHandler)));
566
567        assert!(matches!(
568            host.register_trace_handler(NAME, Arc::new(NoopTraceHandler)),
569            Err(ExecutionError::HostError(HostError::DuplicateEventHandler { .. }))
570        ));
571
572        assert!(host.unregister_trace_handler(id));
573        assert!(host.resolve_trace(id).is_none());
574        assert!(!host.unregister_trace_handler(id));
575    }
576}