Debug Script
CKB-Debugger
Debugging Scripts on the Nervos CKB can be challenging without the right tools. We recommend using the CKB-Debugger, a powerful standalone command-line tool designed for off-chain Script development. With CKB-Debugger, you can efficiently identify and resolve issues in your Scripts, ensuring smooth execution and optimal performance.
Install
Install CKB-Debugger using cargo. We recommend using ≥v0.113.0.
cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger
On MacOS, the protoc
binary must be available to compile ckb-vm-pprof-converter
. This can be installed via Homebrew:
brew install protobuf
Usage
ckb-debugger 0.113.0
USAGE:
ckb-debugger [FLAGS] [OPTIONS] --mode <mode> --tx-file <tx-file> [args]...
FLAGS:
-h, --help Prints help information
--prompt Set to true to prompt for stdin input before executing
--step Set to true to enable step mode, where we print PC address for each instruction
-V, --version Prints version information
OPTIONS:
--bin <bin> File used to replace the binary denoted in the script
-i, --cell-index <cell-index> Index of cell to run
-t, --cell-type <cell-type> Type of cell to run [possible values: input, output]
--decode <decode> Decode RISC-V instruction
--dump-file <dump-file> Dump file name
--gdb-listen <gdb-listen> Address to listen for GDB remote debugging server
--gdb-specify-depth <gdb-specify-depth> Specifies the depth of the exec/spawn stack [default: 0]
--max-cycles <max-cycles> Max cycles [default: 70000000]
--mode <mode>
Execution mode of debugger [default: full] [possible values: full, fast, gdb, probe, gdb_gdbstub]
--pprof <pprof> Performance profiling, specify output file for further use
--read-file <read-file>
Read content from local file or stdin. Then feed the content to syscall in scripts
-s, --script-group-type <script-group-type> Script group type [possible values: lock, type]
--script-hash <script-hash> Script hash
--script-version <script-version> Script version [default: 2]
--skip-end <skip-end> End address to skip printing debug info
--skip-start <skip-start> Start address to skip printing debug info
-f, --tx-file <tx-file> Filename containing JSON formatted transaction dump
ARGS:
<args>...
Examples
1. Execute Transactions Locally
To download an on-chain transaction from the network and execute it locally, use ckb-cli:
$ ckb-cli --url https://mainnet.ckbapp.dev/rpc mock-tx dump --tx-hash 0x5f0a4162622daa0e50b2cf8f49bc6ece22d1458d96fc12a094d6f074d6adbb55 --output-file mock_tx.json
Then execute the Lock Script or Type Script in the transaction:
$ ckb-debugger --tx-file mock_tx.json --cell-index 0 --cell-type input --script-group-type lock
Run result: 0
Total cycles consumed: 1697297(1.6M)
Transfer cycles: 12680(12.4K), running cycles: 1684617(1.6M)
To replace the Script in the transaction with a new version of the lock, use the --bin
option:
// always_failure.c
int main() {
return 1;
}
$ ckb-debugger --tx-file mock_tx.json --cell-index 0 --cell-type input --script-group-type lock --bin always_failure
Run result: 1
Total cycles consumed: 1706(1.7K)
Transfer cycles: 764, running cycles: 942
2. Debug Failed Transactions
In most case, you want to debug failed transactions instead of successful ones to find out the reasons for the failures.
First, dump the transaction into a local file. Assume you are using the Lumos SDK to build the transaction,
you can convert the txSkeleton
type into a JSON file:
> let txJson = rpc.paramsFormatter.toRawTransaction(lumos.helpers.createTransactionFromSkeleton(txSkeleton))
> fs.writeFileSync('failed-tx.json', JSON.stringify(txJson, null, 2))
Next, convert the failed-tx.json
to a dump transaction with context info using ckb-transaction-dumper:
$ ckb-transaction-dumper -t failed-tx.json -o full-failed-tx.json -r <mainnet/testnet/devnet RPC url>
Then, debug the Script. Remember to replace the cell-type
and cell-index
with the actual values in the following command:
$ ckb-debugger --tx-file full-failed-tx.json --cell-index 0 --cell-type output --script-group-type type
3. Debug Script with GDB
You can debug Scripts using GDB with ckb-debugger
. Assume the Script is in fib.c
:
int fib(int n) {
if (n == 0 || n == 1) {
return n;
} else {
return fib(n-1) + fib(n-2);
}
}
int main() {
if (fib(5) != 5) {
return 1;
}
return 0;
}
After compiling fib.c
to RISC-V binary fib
, we can debug this Script in GDB mode:
$ ckb-debugger --mode gdb --gdb-listen 127.0.0.1:9999 --bin fib
$ riscv64-unknown-elf-gdb fib
$ (gdb) target remote 127.0.0.1:9999
$ (gdb) b fib
$ (gdb) c
Breakpoint 1, fib (n=5) at fib.c:2
At the Breakpoint 1, we see that fib (n=5)
at fib.c:2
.
4. Profiling Data with Flamegraph Visualization Tool
Use ckb-debugger
to profile data for flamegraph visualization:
$ ckb-debugger --bin fib --pprof fib.pprof
Install inferno to conver the profile data:
$ cargo install inferno
Then, pass the file created by ckb-debugger into inferno-flamegraph:
$ cat fib.pprof | inferno-flamegraph > fib.svg
Open the resulting SVG file to view the flamegraph: