simplicityhl_core/trackers/
debug_tracker.rs1use std::collections::HashMap;
4
5use simplicityhl::debug::DebugSymbols;
6use simplicityhl::either::Either;
7use simplicityhl::simplicity::Cmr;
8use simplicityhl::simplicity::bit_machine::ExecTracker;
9use simplicityhl::simplicity::ffi::ffi::UWORD;
10use simplicityhl::simplicity::jet::Elements;
11use simplicityhl::value::StructuralValue;
12
13#[derive(Debug)]
15pub struct DebugTracker<'a> {
16 pub debug_symbols: &'a DebugSymbols,
17 pub debug_logs: HashMap<String, String>,
18}
19
20impl<'a> DebugTracker<'a> {
21 pub fn new(debug_symbols: &'a DebugSymbols) -> Self {
22 Self {
23 debug_symbols,
24 debug_logs: HashMap::new(),
25 }
26 }
27}
28
29impl<'a> ExecTracker<Elements> for DebugTracker<'a> {
30 fn track_left(&mut self, _: simplicityhl::simplicity::Ihr) {}
31
32 fn track_right(&mut self, _: simplicityhl::simplicity::Ihr) {}
33
34 fn track_jet_call(&mut self, _: &Elements, _: &[UWORD], _: &[UWORD], _: bool) {}
35
36 fn track_dbg_call(&mut self, cmr: &Cmr, value: simplicityhl::simplicity::Value) {
37 if let Some(tracked_call) = self.debug_symbols.get(cmr)
38 && let Some(Either::Right(debug_value)) =
39 tracked_call.map_value(&StructuralValue::from(value))
40 {
41 self.debug_logs.insert(
42 debug_value.text().to_string(),
43 debug_value.value().to_string(),
44 );
45 }
46 }
47
48 fn is_track_debug_enabled(&self) -> bool {
49 true
50 }
51}
52
53#[cfg(test)]
54mod test {
55 use super::*;
56
57 use anyhow::anyhow;
58
59 use std::sync::Arc;
60
61 use simplicityhl::simplicity::elements;
62 use simplicityhl::simplicity::elements::pset::PartiallySignedTransaction;
63 use simplicityhl::simplicity::elements::taproot::ControlBlock;
64 use simplicityhl::simplicity::hashes::Hash;
65
66 use simplicityhl::simplicity::jet::elements::ElementsEnv;
67 use simplicityhl::{Arguments, TemplateProgram, WitnessValues};
68
69 pub const MOCKED_PROGRAM_SOURCE: &str = r#"
70 fn main() {
71 let a: u64 = 1;
72 let b: u64 = dbg!(a);
73 assert!(true);
74 }
75 "#;
76
77 #[test]
78 fn test_debug_tracker() -> anyhow::Result<()> {
79 let program = TemplateProgram::new(MOCKED_PROGRAM_SOURCE).map_err(|e| anyhow!("{}", e))?;
80 let program = program
81 .instantiate(Arguments::default(), true)
82 .map_err(|e| anyhow!("{}", e))?;
83
84 let tx = PartiallySignedTransaction::new_v2();
85
86 let env = ElementsEnv::new(
87 Arc::new(tx.extract_tx()?),
88 vec![],
89 0,
90 Cmr::from_byte_array([0; 32]),
91 ControlBlock::from_slice(&[0xc0; 33])?,
92 None,
93 elements::BlockHash::all_zeros(),
94 );
95
96 let satisfied = program
97 .satisfy(WitnessValues::default())
98 .map_err(|e| anyhow!("{}", e))?;
99
100 let pruned = match satisfied.redeem().prune(&env) {
101 Ok(pruned) => pruned,
102 Err(e) => return Err(e.into()),
103 };
104 let mut mac = match simplicityhl::simplicity::BitMachine::for_program(&pruned) {
105 Ok(mac) => mac,
106 Err(e) => return Err(e.into()),
107 };
108
109 let mut tracker = DebugTracker::new(satisfied.debug_symbols());
110 match mac.exec_with_tracker(&pruned, &env, &mut tracker) {
111 Ok(_) => {}
112 Err(e) => return Err(e.into()),
113 };
114
115 let logs = tracker.debug_logs.iter().collect::<Vec<_>>();
116 assert_eq!(logs.len(), 1);
117 assert_eq!(logs[0].0, "a");
118 assert_eq!(logs[0].1, "1");
119
120 Ok(())
121 }
122}