88//!
99//! It is a private module but all types and traits are re-exported above.
1010
11- use simplicity_sys:: ffi:: UWORD ;
1211use std:: collections:: HashSet ;
1312
1413use crate :: jet:: Jet ;
15- use crate :: { Cmr , Ihr , Value } ;
14+ use crate :: node:: Inner ;
15+ use crate :: { Ihr , RedeemNode , Value } ;
1616
17- /// A type that keeps track of Bit Machine execution .
17+ /// Write frame of a terminal (childless) Simplicity program node .
1818///
19- /// The trait is implemented for [`SetTracker`], that tracks which case branches were executed,
20- /// and it is implemented for [`NoTracker`], which is a dummy tracker that is
21- /// optimized out by the compiler.
19+ /// When a terminal node of a program is encountered in the Bit Machine, it
20+ /// has a well-defined "output": the contents of the topmost write frame in
21+ /// the machine. In particular, for `witness` nodes this will be the witness
22+ /// data, for jets it will be the result of the jet, and so on.
2223///
23- /// The trait enables us to turn tracking on or off depending on a generic parameter.
24- pub trait ExecTracker < J : Jet > {
25- /// Track the execution of the left branch of the case node with the given `ihr`.
26- fn track_left ( & mut self , ihr : Ihr ) ;
27-
28- /// Track the execution of the right branch of the case node with the given `ihr`.
29- fn track_right ( & mut self , ihr : Ihr ) ;
30-
31- /// Track the execution of a `jet` call with the given `input_buffer`, `output_buffer`, and call result `success`.
32- fn track_jet_call (
33- & mut self ,
34- jet : & J ,
35- input_buffer : & [ UWORD ] ,
36- output_buffer : & [ UWORD ] ,
37- success : bool ,
38- ) ;
39-
40- /// Track the potential execution of a `dbg!` call with the given `cmr` and `value`.
41- fn track_dbg_call ( & mut self , cmr : & Cmr , value : Value ) ;
24+ /// For non-terminal nodes, the Bit Machine typically does some setup, then
25+ /// executes the nodes' children, then does some teardown. So at no point is
26+ /// there a well-defined "output" we can provide.
27+ #[ derive( Debug , Clone ) ]
28+ pub enum NodeOutput < ' m > {
29+ /// Non-terminal node, which has no output.
30+ NonTerminal ,
31+ /// Node was a jet which failed, i.e. aborted the program, and therefore
32+ /// has no output.
33+ JetFailed ,
34+ /// Node succeeded. This is its output frame.
35+ Success ( super :: FrameIter < ' m > ) ,
36+ }
4237
43- /// Check if tracking debug calls is enabled.
44- fn is_track_debug_enabled ( & self ) -> bool ;
38+ /// An object which can be used to introspect the execution of the Bit Machine.
39+ ///
40+ /// If this tracker records accesses to the left and right children of `Case` nodes, you
41+ /// may want to also implement [`PruneTracker`] so that this data can be used by
42+ /// [`RedeemNode::prune_with_tracker`] to prune the program. The most straightforward
43+ /// way to do this is to embed a [`SetTracker`] in your tracker and forward all the trait
44+ /// methods to that.
45+ pub trait ExecTracker < J : Jet > {
46+ /// Called immediately after a specific node of the program is executed, but before
47+ /// its children are executed.
48+ ///
49+ /// More precisely, this iterates through the through the Simplicity program tree in
50+ /// *pre* ordering. That is, for the program `comp iden unit` the nodes will be visited
51+ /// in the order `comp`, `iden`, `unit`.
52+ ///
53+ /// This method can be used for logging, to track left or right accesses of the children of a
54+ /// `Case` node (to do this, call `input.peek_bit()`; false means left and true means right),
55+ /// to extract debug information (which may be embedded in the hidden CMR in `AssertL`
56+ /// and `AssertR` nodes, depending how the program was constructed), and so on.
57+ ///
58+ /// The provided arguments are:
59+ /// * `node` is the node which was just visited.
60+ /// * `input` is an iterator over the read frame when the node's execution began
61+ /// * for terminal nodes (`witness`, `unit`, `iden` and jets), `output` is an iterator
62+ /// the write frame after the node has executed. See [`NodeOutput`] for more information.
63+ fn visit_node ( & mut self , _node : & RedeemNode < J > , _input : super :: FrameIter , _output : NodeOutput ) {
64+ }
4565}
4666
4767pub trait PruneTracker < J : Jet > : ExecTracker < J > {
@@ -60,20 +80,21 @@ pub struct SetTracker {
6080}
6181
6282impl < J : Jet > ExecTracker < J > for SetTracker {
63- fn track_left ( & mut self , ihr : Ihr ) {
64- self . left . insert ( ihr) ;
65- }
66-
67- fn track_right ( & mut self , ihr : Ihr ) {
68- self . right . insert ( ihr) ;
69- }
70-
71- fn track_jet_call ( & mut self , _: & J , _: & [ UWORD ] , _: & [ UWORD ] , _: bool ) { }
72-
73- fn track_dbg_call ( & mut self , _: & Cmr , _: Value ) { }
74-
75- fn is_track_debug_enabled ( & self ) -> bool {
76- false
83+ fn visit_node < ' d > (
84+ & mut self ,
85+ node : & RedeemNode < J > ,
86+ mut input : super :: FrameIter ,
87+ _output : NodeOutput ,
88+ ) {
89+ match ( node. inner ( ) , input. next ( ) ) {
90+ ( Inner :: AssertL ( ..) | Inner :: Case ( ..) , Some ( false ) ) => {
91+ self . left . insert ( node. ihr ( ) ) ;
92+ }
93+ ( Inner :: AssertR ( ..) | Inner :: Case ( ..) , Some ( true ) ) => {
94+ self . right . insert ( node. ihr ( ) ) ;
95+ }
96+ _ => { }
97+ }
7798 }
7899}
79100
@@ -92,16 +113,21 @@ impl<J: Jet> PruneTracker<J> for SetTracker {
92113pub struct NoTracker ;
93114
94115impl < J : Jet > ExecTracker < J > for NoTracker {
95- fn track_left ( & mut self , _: Ihr ) { }
96-
97- fn track_right ( & mut self , _: Ihr ) { }
98-
99- fn track_jet_call ( & mut self , _: & J , _: & [ UWORD ] , _: & [ UWORD ] , _: bool ) { }
100-
101- fn track_dbg_call ( & mut self , _: & Cmr , _: Value ) { }
102-
103- fn is_track_debug_enabled ( & self ) -> bool {
104- // Set flag to test frame decoding in unit tests
105- cfg ! ( test)
116+ fn visit_node < ' d > (
117+ & mut self ,
118+ node : & RedeemNode < J > ,
119+ mut input : super :: FrameIter ,
120+ output : NodeOutput ,
121+ ) {
122+ if cfg ! ( test) {
123+ // In unit tests, attempt to decode values from the frames, confirming that
124+ // decoding works.
125+ Value :: from_padded_bits ( & mut input, & node. arrow ( ) . source )
126+ . expect ( "decoding input should work" ) ;
127+ if let NodeOutput :: Success ( mut output) = output {
128+ Value :: from_padded_bits ( & mut output, & node. arrow ( ) . target )
129+ . expect ( "decoding output should work" ) ;
130+ }
131+ }
106132 }
107133}
0 commit comments