diff --git a/script/src/syscalls/debugger.rs b/script/src/syscalls/debugger.rs new file mode 100644 index 0000000000..32b0ac795a --- /dev/null +++ b/script/src/syscalls/debugger.rs @@ -0,0 +1,41 @@ +use syscalls::DEBUG_PRINT_SYSCALL_NUMBER; +use vm::{CoreMachine, Error as VMError, Memory, Register, Syscalls, A0, A7}; + +pub struct Debugger<'a> { + prefix: &'a str, +} + +impl<'a> Debugger<'a> { + pub fn new(prefix: &'a str) -> Debugger<'a> { + Debugger { prefix } + } +} + +impl<'a, R: Register, M: Memory> Syscalls for Debugger<'a> { + fn initialize(&mut self, _machine: &mut CoreMachine) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut CoreMachine) -> Result { + let number = machine.registers()[A7].to_u64(); + if number != DEBUG_PRINT_SYSCALL_NUMBER { + return Ok(false); + } + + let mut addr = machine.registers()[A0].to_usize(); + let mut buffer = Vec::new(); + + loop { + let byte = machine.memory_mut().load8(addr)?; + if byte == 0 { + break; + } + buffer.push(byte); + addr += 1; + } + + let s = String::from_utf8(buffer).map_err(|_| VMError::ParseError)?; + debug!(target: "script", "{} DEBUG OUTPUT: {}", self.prefix, s); + Ok(true) + } +} diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index c0d499413b..7ec8737cc6 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -1,9 +1,11 @@ mod builder; +mod debugger; mod fetch_script_hash; mod mmap_cell; mod mmap_tx; pub use self::builder::build_tx; +pub use self::debugger::Debugger; pub use self::fetch_script_hash::FetchScriptHash; pub use self::mmap_cell::MmapCell; pub use self::mmap_tx::MmapTx; @@ -17,6 +19,7 @@ pub const ITEM_MISSING: u8 = 2; pub const MMAP_TX_SYSCALL_NUMBER: u64 = 2049; pub const MMAP_CELL_SYSCALL_NUMBER: u64 = 2050; pub const FETCH_SCRIPT_HASH_SYSCALL_NUMBER: u64 = 2051; +pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; #[derive(Debug, PartialEq, Clone, Copy, Eq)] pub enum Mode { diff --git a/script/src/verify.rs b/script/src/verify.rs index e32c08a001..404260cb09 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -5,7 +5,7 @@ use core::script::Script; use core::transaction::{CellInput, CellOutput}; use flatbuffers::FlatBufferBuilder; use fnv::FnvHashMap; -use syscalls::{build_tx, FetchScriptHash, MmapCell, MmapTx}; +use syscalls::{build_tx, Debugger, FetchScriptHash, MmapCell, MmapTx}; use vm::{DefaultMachine, SparseMemory}; // This struct leverages CKB VM to verify transaction inputs. @@ -85,7 +85,7 @@ impl<'a> TransactionScriptsVerifier<'a> { Err(ScriptError::NoScript) } - pub fn verify_script(&self, script: &Script) -> Result<(), ScriptError> { + pub fn verify_script(&self, script: &Script, prefix: &str) -> Result<(), ScriptError> { self.extract_script(script).and_then(|script_binary| { let mut args = vec![b"verify".to_vec()]; args.extend_from_slice(&script.signed_args.as_slice()); @@ -95,6 +95,7 @@ impl<'a> TransactionScriptsVerifier<'a> { machine.add_syscall_module(Box::new(self.build_mmap_tx())); machine.add_syscall_module(Box::new(self.build_mmap_cell())); machine.add_syscall_module(Box::new(self.build_fetch_script_hash())); + machine.add_syscall_module(Box::new(Debugger::new(prefix))); machine .run(script_binary, &args) .map_err(ScriptError::VMError) @@ -110,14 +111,16 @@ impl<'a> TransactionScriptsVerifier<'a> { pub fn verify(&self) -> Result<(), ScriptError> { for (i, input) in self.inputs.iter().enumerate() { - self.verify_script(&input.unlock).map_err(|e| { + let prefix = format!("Transaction {}, input {}", self.hash, i); + self.verify_script(&input.unlock, &prefix).map_err(|e| { info!(target: "script", "Error validating input {} of transaction {}: {:?}", i, self.hash, e); e })?; } for (i, output) in self.outputs.iter().enumerate() { if let Some(ref contract) = output.contract { - self.verify_script(contract).map_err(|e| { + let prefix = format!("Transaction {}, output {}", self.hash, i); + self.verify_script(contract, &prefix).map_err(|e| { info!(target: "script", "Error validating output {} of transaction {}: {:?}", i, self.hash, e); e })?;