ckb_debugger/
misc.rs

1use ckb_mock_tx_types::{MockResourceLoader, MockTransaction};
2use ckb_script::ScriptGroupType;
3use ckb_types::H256;
4use ckb_types::core::HeaderView;
5use ckb_types::packed::{Byte32, CellOutput, OutPoint};
6use ckb_vm::Bytes;
7use ckb_vm_syscall_tracer::CollectorKey;
8use ckb_vm_syscall_tracer::generated::traces::VmCreation;
9use std::collections::HashMap;
10
11pub struct DummyResourceLoader {}
12
13impl MockResourceLoader for DummyResourceLoader {
14    fn get_header(&mut self, hash: H256) -> Result<Option<HeaderView>, String> {
15        return Err(format!("Header {:x} is missing!", hash));
16    }
17
18    fn get_live_cell(&mut self, out_point: OutPoint) -> Result<Option<(CellOutput, Bytes, Option<Byte32>)>, String> {
19        return Err(format!("Cell: {:?} is missing!", out_point));
20    }
21}
22
23pub struct HumanReadableCycles(pub u64);
24
25impl std::fmt::Display for HumanReadableCycles {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        write!(f, "{}", self.0)?;
28        if self.0 >= 1024 * 1024 {
29            write!(f, "({:.1}M)", self.0 as f64 / 1024. / 1024.)?;
30        } else if self.0 >= 1024 {
31            write!(f, "({:.1}K)", self.0 as f64 / 1024.)?;
32        } else {
33        }
34        Ok(())
35    }
36}
37
38// Get script hash by give group type, cell type and cell index.
39// Note cell_type should be a string, in the range ["input", "output"].
40pub fn get_script_hash_by_index(
41    mock_tx: &MockTransaction,
42    script_group_type: &ScriptGroupType,
43    cell_type: &str,
44    cell_index: usize,
45) -> Byte32 {
46    match (&script_group_type, cell_type) {
47        (ScriptGroupType::Lock, "input") => mock_tx.mock_info.inputs[cell_index].output.calc_lock_hash(),
48        (ScriptGroupType::Type, "input") => mock_tx.mock_info.inputs[cell_index]
49            .output
50            .type_()
51            .to_opt()
52            .expect("cell should have type script")
53            .calc_script_hash(),
54        (ScriptGroupType::Type, "output") => mock_tx
55            .tx
56            .raw()
57            .outputs()
58            .get(cell_index)
59            .expect("index out of bound")
60            .type_()
61            .to_opt()
62            .expect("cell should have type script")
63            .calc_script_hash(),
64        _ => panic!("Invalid specified script: {:?} {} {}", script_group_type, cell_type, cell_index),
65    }
66}
67
68pub fn collector_key_str(collector_key: &CollectorKey) -> String {
69    if collector_key.generation_id != 0 {
70        format!("{}/{}", collector_key.vm_id, collector_key.generation_id)
71    } else {
72        format!("{}", collector_key.vm_id)
73    }
74}
75
76// Recursive helper function to print the tree.
77pub fn print_vm_tree_recursive(
78    tree: &HashMap<CollectorKey, Vec<VmCreation>>,
79    hint: &HashMap<CollectorKey, String>,
80    ckey: CollectorKey,
81    prefix: &str,
82    is_last: bool,
83) {
84    let mut line = format!("Spawn tree: {}{}", prefix, collector_key_str(&ckey));
85    if line.chars().count() < 32 {
86        line.push_str(String::from(" ").repeat(32 - line.chars().count()).as_str());
87    }
88    line.push_str(" ");
89    line.push_str(&hint.get(&ckey).unwrap());
90    println!("{}", line);
91
92    // Get children, if any
93    if let Some(children) = tree.get(&ckey) {
94        // Update prefix for children
95        let new_prefix = if prefix.is_empty() {
96            "".to_string()
97        } else if is_last {
98            format!("{}    ", prefix.trim_end_matches("├── ").trim_end_matches("└── "))
99        } else {
100            format!("{}│   ", prefix.trim_end_matches("├── ").trim_end_matches("└── "))
101        };
102        // Print each child
103        for (i, child) in children.iter().enumerate() {
104            let is_last_child = i == children.len() - 1;
105            let child_prefix =
106                if is_last_child { format!("{}└── ", new_prefix) } else { format!("{}├── ", new_prefix) };
107            print_vm_tree_recursive(
108                tree,
109                hint,
110                CollectorKey { vm_id: child.vm_id, generation_id: child.generation_id },
111                &child_prefix,
112                is_last_child,
113            );
114        }
115    }
116}