Skip to content

Commit

Permalink
Remove ckb-debugger-api dependency for ckb-debugger
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Jun 27, 2024
1 parent 194e554 commit 05669f4
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 10 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ckb-debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ addr2line = "0.17"
byteorder = "1"
clap = "2.33.0"
ckb-chain-spec = { git = "https://github.com/libraries/ckb", branch = "new_spawn" }
ckb-debugger-api = { path = "../ckb-debugger-api", version = "=0.116.1" }
ckb-hash = { git = "https://github.com/libraries/ckb", branch = "new_spawn" }
ckb-jsonrpc-types = { git = "https://github.com/libraries/ckb", branch = "new_spawn" }
ckb-mock-tx-types = { path = "../ckb-mock-tx-types", version = "=0.116.1" }
ckb-script = { git = "https://github.com/libraries/ckb", branch = "new_spawn", default-features = false, features = ["flatmemory"] }
ckb-traits = { git = "https://github.com/libraries/ckb", branch = "new_spawn" }
Expand All @@ -32,5 +32,6 @@ log = "0.4.0"
nix = { version = "0.26.2", optional = true }
probe = "0.5"
rand = "0.8.5"
regex = "1"
serde_json = "1.0"
serde_plain = "1.0"
2 changes: 1 addition & 1 deletion ckb-debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod syscall_stdio;
pub use machine_analyzer::{MachineAnalyzer, MachineOverlap, MachineProfile, MachineStepLog};
pub use machine_assign::MachineAssign;
pub use machine_gdb::{GdbStubHandler, GdbStubHandlerEventLoop};
pub use misc::HumanReadableCycles;
pub use misc::{get_script_hash_by_index, pre_check, DummyResourceLoader, Embed, HumanReadableCycles};
pub use syscall_all::{FileOperation, FileStream, Random, TimeNow};
pub use syscall_elf_dumper::ElfDumper;
#[cfg(feature = "syscall_stdio")]
Expand Down
13 changes: 6 additions & 7 deletions ckb-debugger/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ use ckb_chain_spec::consensus::ConsensusBuilder;
#[cfg(feature = "syscall_stdio")]
use ckb_debugger::Stdio;
use ckb_debugger::{
ElfDumper, FileOperation, FileStream, HumanReadableCycles, MachineAnalyzer, MachineAssign, MachineOverlap,
MachineProfile, MachineStepLog, Random, TimeNow,
get_script_hash_by_index, pre_check, DummyResourceLoader, ElfDumper, FileOperation, FileStream,
HumanReadableCycles, MachineAnalyzer, MachineAssign, MachineOverlap, MachineProfile, MachineStepLog, Random,
TimeNow,
};
use ckb_debugger::{GdbStubHandler, GdbStubHandlerEventLoop};
use ckb_debugger_api::embed::Embed;
use ckb_debugger_api::{check, get_script_hash_by_index, DummyResourceLoader};
use ckb_debugger::{Embed, GdbStubHandler, GdbStubHandlerEventLoop};
use ckb_mock_tx_types::{MockCellDep, MockInfo, MockInput, MockTransaction, ReprMockTransaction, Resource};
use ckb_script::{ScriptGroupType, ScriptVersion, TransactionScriptsVerifier, TxVerifyEnv, ROOT_VM_ID};
use ckb_types::core::cell::{resolve_transaction, CellMetaBuilder};
Expand Down Expand Up @@ -217,7 +216,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buf = String::new();
std::io::stdin().read_to_string(&mut buf)?;
let repr_mock_tx: ReprMockTransaction = serde_json::from_str(&buf)?;
if let Err(msg) = check(&repr_mock_tx) {
if let Err(msg) = pre_check(&repr_mock_tx) {
println!("Potential format error found: {}", msg);
}
repr_mock_tx.into()
Expand All @@ -227,7 +226,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut mock_tx_embed = Embed::new(PathBuf::from(doc.to_string()), buf.clone());
let buf = mock_tx_embed.replace_all();
let repr_mock_tx: ReprMockTransaction = serde_json::from_str(&buf)?;
if let Err(msg) = check(&repr_mock_tx) {
if let Err(msg) = pre_check(&repr_mock_tx) {
println!("Potential format error found: {}", msg);
}
repr_mock_tx.into()
Expand Down
194 changes: 194 additions & 0 deletions ckb-debugger/src/misc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,129 @@
use ckb_chain_spec::consensus::TYPE_ID_CODE_HASH;
use ckb_hash::blake2b_256;
use ckb_mock_tx_types::{MockResourceLoader, MockTransaction, ReprMockTransaction};
use ckb_script::ScriptGroupType;
use ckb_types::core::{HeaderView, ScriptHashType};
use ckb_types::packed::{Byte32, CellOutput, OutPoint, OutPointVec, Script};
use ckb_types::prelude::{Builder, Entity, Pack};
use ckb_types::H256;
use ckb_vm::Bytes;
use regex::{Captures, Regex};
use std::collections::HashMap;
use std::path::{Path, PathBuf};

pub struct DummyResourceLoader {}

impl MockResourceLoader for DummyResourceLoader {
fn get_header(&mut self, hash: H256) -> Result<Option<HeaderView>, String> {
return Err(format!("Header {:x} is missing!", hash));
}

fn get_live_cell(&mut self, out_point: OutPoint) -> Result<Option<(CellOutput, Bytes, Option<Byte32>)>, String> {
return Err(format!("Cell: {:?} is missing!", out_point));
}
}

pub struct Embed {
pub data: String,
pub path: PathBuf,
pub type_id_dict: HashMap<String, String>,
}

impl Embed {
pub fn new(path: PathBuf, data: String) -> Self {
Self { data, path, type_id_dict: HashMap::new() }
}

pub fn replace_data(&mut self) -> &mut Self {
let regex = Regex::new(r"\{\{ ?data (.+?) ?\}\}").unwrap();
self.data = regex
.replace_all(&self.data, |caps: &Captures| -> String {
let cap1 = &caps[1];
let path = if !Path::new(cap1).is_absolute() {
let root = self.path.parent().unwrap();
root.join(cap1)
} else {
Path::new(cap1).to_path_buf()
};
let data = std::fs::read(&path);
if data.is_err() {
panic!("Read {:?} failed : {:?}", path, data);
}
let data = data.unwrap();
hex::encode(data)
})
.to_string();
self
}

pub fn replace_hash(&mut self) -> &mut Self {
let regex = Regex::new(r"\{\{ ?hash (.+?) ?\}\}").unwrap();
self.data = regex
.replace_all(&self.data, |caps: &Captures| -> String {
let cap1 = &caps[1];
let path = if !Path::new(cap1).is_absolute() {
let root = self.path.parent().unwrap();
root.join(cap1)
} else {
Path::new(cap1).to_path_buf()
};
let data = std::fs::read(path).unwrap();
hex::encode(blake2b_256(data))
})
.to_string();
self
}

pub fn prelude_type_id(&mut self) -> &mut Self {
let rule = Regex::new(r"\{\{ ?def_type (.+?) ?\}\}").unwrap();
for caps in rule.captures_iter(&self.data) {
let type_id_name = &caps[1];
assert!(!self.type_id_dict.contains_key(type_id_name));
let type_id_script = Script::new_builder()
.args(Bytes::from(type_id_name.to_string()).pack())
.code_hash(TYPE_ID_CODE_HASH.pack())
.hash_type(ScriptHashType::Type.into())
.build();
let type_id_script_hash = type_id_script.calc_script_hash();
let type_id_script_hash = format!("{:x}", type_id_script_hash);
self.type_id_dict.insert(type_id_name.to_string(), type_id_script_hash);
}
self
}

pub fn replace_def_type(&mut self) -> &mut Self {
let regex = Regex::new(r#""?\{\{ ?def_type (.+?) ?\}\}"?"#).unwrap();
self.data = regex
.replace_all(&self.data, |caps: &Captures| -> String {
let cap1 = &caps[1];
let type_id_script_json = ckb_jsonrpc_types::Script {
code_hash: TYPE_ID_CODE_HASH,
hash_type: ckb_jsonrpc_types::ScriptHashType::Type,
args: ckb_jsonrpc_types::JsonBytes::from_vec(cap1.as_bytes().to_vec()),
};
return serde_json::to_string_pretty(&type_id_script_json).unwrap();
})
.to_string();
self
}

pub fn replace_ref_type(&mut self) -> &mut Self {
let regex = Regex::new(r"\{\{ ?ref_type (.+?) ?\}\}").unwrap();
self.data = regex
.replace_all(&self.data, |caps: &Captures| -> String {
let cap1 = &caps[1];
return self.type_id_dict[&cap1.to_string()].clone();
})
.to_string();
self
}

pub fn replace_all(&mut self) -> String {
self.replace_data().replace_hash().prelude_type_id().replace_def_type().replace_ref_type();
self.data.clone()
}
}

pub struct HumanReadableCycles(pub u64);

impl std::fmt::Display for HumanReadableCycles {
Expand All @@ -12,3 +138,71 @@ impl std::fmt::Display for HumanReadableCycles {
Ok(())
}
}

// Get script hash by give group type, cell type and cell index.
// Note cell_type should be a string, in the range ["input", "output"].
pub fn get_script_hash_by_index(
mock_tx: &MockTransaction,
script_group_type: &ScriptGroupType,
cell_type: &str,
cell_index: usize,
) -> Byte32 {
match (&script_group_type, cell_type) {
(ScriptGroupType::Lock, "input") => mock_tx.mock_info.inputs[cell_index].output.calc_lock_hash(),
(ScriptGroupType::Type, "input") => mock_tx.mock_info.inputs[cell_index]
.output
.type_()
.to_opt()
.expect("cell should have type script")
.calc_script_hash(),
(ScriptGroupType::Type, "output") => mock_tx
.tx
.raw()
.outputs()
.get(cell_index)
.expect("index out of bound")
.type_()
.to_opt()
.expect("cell should have type script")
.calc_script_hash(),
_ => panic!("Invalid specified script: {:?} {} {}", script_group_type, cell_type, cell_index),
}
}

// Check transactions before executing them to avoid obvious mistakes.
pub fn pre_check(tx: &ReprMockTransaction) -> Result<(), String> {
let mut mock_cell_deps: Vec<_> = tx.mock_info.cell_deps.iter().map(|c| c.cell_dep.clone()).collect();
let mut real_cell_deps: Vec<_> = tx.tx.cell_deps.iter().map(|c| c.clone()).collect();
for dep in &tx.mock_info.cell_deps {
if dep.cell_dep.dep_type == ckb_jsonrpc_types::DepType::DepGroup {
let outpoints = OutPointVec::from_slice(dep.data.as_bytes()).unwrap();
let outpoints: Vec<OutPoint> = outpoints.into_iter().collect();
let resolved_cell_deps: Vec<_> = outpoints
.into_iter()
.map(|o| ckb_jsonrpc_types::CellDep { out_point: o.into(), dep_type: ckb_jsonrpc_types::DepType::Code })
.collect();
real_cell_deps.extend(resolved_cell_deps);
}
}
let compare = |a: &ckb_jsonrpc_types::CellDep, b: &ckb_jsonrpc_types::CellDep| {
let l = serde_json::to_string(a).unwrap();
let r = serde_json::to_string(b).unwrap();
l.cmp(&r)
};
mock_cell_deps.sort_by(compare);
real_cell_deps.sort_by(compare);
if mock_cell_deps != real_cell_deps {
return Err(String::from("Precheck: celldeps is mismatched"));
}
let mock_inputs: Vec<_> = tx.mock_info.inputs.iter().map(|i| i.input.clone()).collect();
let real_inputs: Vec<_> = tx.tx.inputs.clone();
if mock_inputs != real_inputs {
return Err(String::from("Precheck: inputs is mismatched"));
}
let mock_header_deps: Vec<_> = tx.mock_info.header_deps.iter().map(|h| h.hash.clone()).collect();
let read_header_deps: Vec<_> = tx.tx.header_deps.clone();
if mock_header_deps != read_header_deps {
return Err(String::from("Precheck: header deps is mismatched"));
}
Ok(())
}

0 comments on commit 05669f4

Please sign in to comment.