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
38pub 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
76pub 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 if let Some(children) = tree.get(&ckey) {
94 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 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}