Tips for Debugging CKB Script
CKB uses RISC-V ISA to implement VM layer and CKB VM is very different from other VMs with hard-code functionality through opcodes. Given the generalized nature of CKB VM, various languages and toolchains can be supported- every language and toolchain will be a bit different and implementers should provide appropriate documentation and support for the community.
This document introduces several tips about debugging CKB scripts.
Error codes
The CKB node only reports an exit code on transaction verification failure; the most straightforward way to distinguish errors is to use a different exit code (between -128 and 127) to represent errors.
For example, see the default lock script error codes: secp256k1 error codes
A common mistake is mixing up lock script errors and type script errors. It is recommended that remove the type script, then run again; if the error still exists, you can make sure the error is being caused by the lock script; otherwise, it is caused by the type script.
Debug syscall
When we want to output additional information from the script; we need use the debug syscall.
By default, the CKB node does not output the debug syscall message, however ckb.toml
can be configured to enable it.
[logger]
filter = "info,ckb-script=debug"
You can also choose to run the script under a debugging environment like ckb-cli, VM debugger, or ckb-contract-tool.
For language / toolchain developers, it is recommended that integrate debug syscall to print the error backtrace if the language supports it.
Rust and ckb-std
Rust developers who use the ckb-std crate can utilize the debug
macro.
debug!("there is a universal error caused by {}", 42);
This macro triggers the debug syscall in Rust's debug build profile. In the release build profile, it does nothing. To debug the release build, append the --cfg debug_assertions
arguments to cargo build.
For users of Capsule, the debug macro can be enabled in the release build by running capsule build --release --debug-output
.
ckb-cli
ckb-cli supports to generate mock transactions and verification under the debugging environment.
1. Generate mock-tx template
ckb-cli mock-tx template --lock-arg <your lock-arg> --output-file debug-tx.json
2. Modify the template
Add your script cell to the cell_deps
and modify the transaction structure to use a lock script or type script.
3. Complete the template
ckb-cli mock-tx complete --tx-file debug-tx.json
This command is used to sign the transaction with the private key according to your lock arg.
4. Verify the transaction
ckb-cli mock-tx verify --tx-file debug-tx.json
You will see the verification result and the debug output.
Please refer to the transaction RFC for constructing a transaction.
Using VM debugger and GDB
1. Install ckb-standalone-debugger
git clone https://github.com/nervosnetwork/ckb-standalone-debugger
cd ckb-standalone-debugger/bins
cargo build --release
2. Start standalone debugger
ckb-standalone-debugger supports a ckb-cli generated template. To debug a script, we indicate the script group type with -g <script type>
. This indicates the script group we want to debug with the referenced -h <script hash>
.
ckb-debugger -l 0.0.0.0:2000 -g type -h <type script hash> -t debug-tx.json
3. Start GDB
docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 bash
# start gdb
riscv64-unknown-elf-gdb <path of script binary>
# connect to debugger server
target remote <ip>:2000
You may refer to the tutorial: introduction to CKB script programming for more details.
Report bugs
When you find security-related bugs in script, please don't post them on public issues. Instead, try to contact maintainers privately, they can be found on the CKB dev telegram. Responsible disclosure could help maintainers, as well as prevent users from losing funds.
When you find security-related bugs in CKB official scripts or CKB VM, join the bug bounty program to be rewarded for your valuable contribution!