ckb_debugger/
misc.rs

1use ckb_chain_spec::consensus::TYPE_ID_CODE_HASH;
2use ckb_hash::blake2b_256;
3use ckb_mock_tx_types::{MockResourceLoader, MockTransaction};
4use ckb_script::ScriptGroupType;
5use ckb_types::H256;
6use ckb_types::core::{HeaderView, ScriptHashType};
7use ckb_types::packed::{Byte32, CellOutput, OutPoint, Script};
8use ckb_types::prelude::{Builder, Entity, Pack};
9use ckb_vm::Bytes;
10use regex::{Captures, Regex};
11use std::collections::HashMap;
12use std::path::{Path, PathBuf};
13
14pub struct DummyResourceLoader {}
15
16impl MockResourceLoader for DummyResourceLoader {
17    fn get_header(&mut self, hash: H256) -> Result<Option<HeaderView>, String> {
18        return Err(format!("Header {:x} is missing!", hash));
19    }
20
21    fn get_live_cell(&mut self, out_point: OutPoint) -> Result<Option<(CellOutput, Bytes, Option<Byte32>)>, String> {
22        return Err(format!("Cell: {:?} is missing!", out_point));
23    }
24}
25
26pub struct Embed {
27    pub data: String,
28    pub path: PathBuf,
29    pub type_id_dict: HashMap<String, String>,
30}
31
32impl Embed {
33    pub fn new(path: PathBuf, data: String) -> Self {
34        Self { data, path, type_id_dict: HashMap::new() }
35    }
36
37    pub fn replace_data(&mut self) -> &mut Self {
38        let regex = Regex::new(r"\{\{ ?data (.+?) ?\}\}").unwrap();
39        self.data = regex
40            .replace_all(&self.data, |caps: &Captures| -> String {
41                let cap1 = &caps[1];
42                let path = if !Path::new(cap1).is_absolute() {
43                    let root = self.path.parent().unwrap();
44                    root.join(cap1)
45                } else {
46                    Path::new(cap1).to_path_buf()
47                };
48                let data = std::fs::read(&path);
49                if data.is_err() {
50                    panic!("Read {:?} failed : {:?}", path, data);
51                }
52                let data = data.unwrap();
53                hex::encode(data)
54            })
55            .to_string();
56        self
57    }
58
59    pub fn replace_hash(&mut self) -> &mut Self {
60        let regex = Regex::new(r"\{\{ ?hash (.+?) ?\}\}").unwrap();
61        self.data = regex
62            .replace_all(&self.data, |caps: &Captures| -> String {
63                let cap1 = &caps[1];
64                let path = if !Path::new(cap1).is_absolute() {
65                    let root = self.path.parent().unwrap();
66                    root.join(cap1)
67                } else {
68                    Path::new(cap1).to_path_buf()
69                };
70                let data = std::fs::read(path).unwrap();
71                hex::encode(blake2b_256(data))
72            })
73            .to_string();
74        self
75    }
76
77    pub fn prelude_type_id(&mut self) -> &mut Self {
78        let rule = Regex::new(r"\{\{ ?def_type (.+?) ?\}\}").unwrap();
79        for caps in rule.captures_iter(&self.data) {
80            let type_id_name = &caps[1];
81            assert!(!self.type_id_dict.contains_key(type_id_name));
82            let type_id_script = Script::new_builder()
83                .args(Bytes::from(type_id_name.to_string()).pack())
84                .code_hash(TYPE_ID_CODE_HASH.pack())
85                .hash_type(ScriptHashType::Type.into())
86                .build();
87            let type_id_script_hash = type_id_script.calc_script_hash();
88            let type_id_script_hash = format!("{:x}", type_id_script_hash);
89            self.type_id_dict.insert(type_id_name.to_string(), type_id_script_hash);
90        }
91        self
92    }
93
94    pub fn replace_def_type(&mut self) -> &mut Self {
95        let regex = Regex::new(r#""?\{\{ ?def_type (.+?) ?\}\}"?"#).unwrap();
96        self.data = regex
97            .replace_all(&self.data, |caps: &Captures| -> String {
98                let cap1 = &caps[1];
99                let type_id_script_json = ckb_jsonrpc_types::Script {
100                    code_hash: TYPE_ID_CODE_HASH,
101                    hash_type: ckb_jsonrpc_types::ScriptHashType::Type,
102                    args: ckb_jsonrpc_types::JsonBytes::from_vec(cap1.as_bytes().to_vec()),
103                };
104                return serde_json::to_string_pretty(&type_id_script_json).unwrap();
105            })
106            .to_string();
107        self
108    }
109
110    pub fn replace_ref_type(&mut self) -> &mut Self {
111        let regex = Regex::new(r"\{\{ ?ref_type (.+?) ?\}\}").unwrap();
112        self.data = regex
113            .replace_all(&self.data, |caps: &Captures| -> String {
114                let cap1 = &caps[1];
115                return self.type_id_dict[&cap1.to_string()].clone();
116            })
117            .to_string();
118        self
119    }
120
121    pub fn replace_all(&mut self) -> String {
122        self.replace_data().replace_hash().prelude_type_id().replace_def_type().replace_ref_type();
123        self.data.clone()
124    }
125}
126
127pub struct HumanReadableCycles(pub u64);
128
129impl std::fmt::Display for HumanReadableCycles {
130    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131        write!(f, "{}", self.0)?;
132        if self.0 >= 1024 * 1024 {
133            write!(f, "({:.1}M)", self.0 as f64 / 1024. / 1024.)?;
134        } else if self.0 >= 1024 {
135            write!(f, "({:.1}K)", self.0 as f64 / 1024.)?;
136        } else {
137        }
138        Ok(())
139    }
140}
141
142// Get script hash by give group type, cell type and cell index.
143// Note cell_type should be a string, in the range ["input", "output"].
144pub fn get_script_hash_by_index(
145    mock_tx: &MockTransaction,
146    script_group_type: &ScriptGroupType,
147    cell_type: &str,
148    cell_index: usize,
149) -> Byte32 {
150    match (&script_group_type, cell_type) {
151        (ScriptGroupType::Lock, "input") => mock_tx.mock_info.inputs[cell_index].output.calc_lock_hash(),
152        (ScriptGroupType::Type, "input") => mock_tx.mock_info.inputs[cell_index]
153            .output
154            .type_()
155            .to_opt()
156            .expect("cell should have type script")
157            .calc_script_hash(),
158        (ScriptGroupType::Type, "output") => mock_tx
159            .tx
160            .raw()
161            .outputs()
162            .get(cell_index)
163            .expect("index out of bound")
164            .type_()
165            .to_opt()
166            .expect("cell should have type script")
167            .calc_script_hash(),
168        _ => panic!("Invalid specified script: {:?} {} {}", script_group_type, cell_type, cell_index),
169    }
170}