各位游戏大佬大家好,今天小编为大家分享关于gg修改器脚本要root吗_gg修改器免root的内容,轻松修改游戏数据,赶快来一起来看看吧。
Xuejie 是 CKB-VM的核心开发者,他在自己的博客「Less is More」中,创作了一系列介绍 CKB 脚本编程的文章,用于补充白皮书中编写 CKB 脚本所需的所有缺失的细节实现。本文是该系列的第五篇,详细介绍了 CKB 的调试过程,快来一起查看吧 ~^.^~
作者:Xuejie
原文链接:https://xuejie.space/2019_10_18_introduction_to_ckb_script_programming_debugging/
译者:史迪仔
事实上,CKB 脚本工作的层级要比其他智能合约低很多,因此 CKB 的调试过程就显得相当神秘。在本文中,我们将展示如何调试 CKB 脚本。你会发现,其实调试 CKB 脚本和你日常调试程序并没有太大区别。本文建立在 ckb v0.23.0 之上。具体的,我在每个项目中使用的是如下版本的 commit:
• ckb:
7e2ad2d9ed6718360587f3762163229eccd2cf10
• ckb-sdk-ruby:
18a89d8c69e173ad59ce3e3b3bf79b5d11c5f8f8
• ckb-duktape:
347bf730c08eb0aab7e56e0357945a4d6cee109a
• ckb-standalone-debugger:
2379e89ae285e4e639b961756c22d8e4fde4d6ab
使用 GDB 调试 C 程序
CKB 脚本调试的第一种方案,通常适用于 C、Rust 等编程语言。也许你已经习惯了写 C 的程序,而 GDB 也是你的好搭档。你想知道是不是可以用 GDB 来调试 C 程序,答案当然是:Yes!你肯定可以通过 GDB 来调试用 C 编写的 CKB 脚本!让我来演示一下:
首先,我们还是用之前文章中用到的关于 carrot 的例子:
#include
int main(int argc, char* argv[]) {
int ret;
size_t index = 0;
uint64_t len = 0;
unsigned char buffer[6];
while (1) {
len = 6;
memset(buffer, 0, 6);
ret = ckb_load_cell_data(buffer, &len, 0, index, CKB_SOURCE_OUTPUT);
if (ret == CKB_INDEX_OUT_OF_BOUND) {
break;
}
int cmp = memcmp(buffer, "carrot", 6);
if (cmp) {
return -1;
}
index++;
}
return 0;
}
这里我进行了两处修改:
- 首先我更新了这个脚本,让它可以兼容 ckb v0.23.0。在这个版本中,我们可以使用
ckb_load_cell_data
来获取 cell 的数据。- 我还在这段代码中加入了一个小 bug,这样我们等会儿就可以进行调试的工作流程。如果你非常熟悉 C,你可能已经注意到了,当然你没有在意到的话也完全不用担心,稍后我会解释的。
和往常一样,我们使用官方的 toolchain 来将其编译成 RISC-V 的代码:
$ ls
carrot.c
$ git clone https:///nervosnetwork/ckb-system-scripts
$ cp ckb-system-scripts/c/ckb_*.h ./
$ ls
carrot.c ckb_consts.h ckb_syscalls.h ckb-system-scripts/
$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 bash
root@3efa454be9af:/# cd /code
root@3efa454be9af:/code# riscv64-unknown-elf-gcc carrot.c -g -o carrot
root@3efa454be9af:/code# exit
请注意,当我编译脚本的时候,我添加了
-g
,以便生成调试信息,这在 GDB 中非常有用。对于实际使用的脚本,你总是希望尽量地完善它们来尽量节省存储在链上的空间。现在,让我们将脚本部署到 CKB 上。保持 CKB 节点处于运行状态,并启动 Ruby SDK:
pry(main)> api = CKB::API.new
pry(main)> wallet = CKB::Wallet.from_hex(api, "
pry(main)> wallet2 = CKB::Wallet.from_hex(api, CKB::Key.random_private_key)
pry(main)> carrot_data = File.read("carrot")
pry(main)> carrot_data.bytesize
=> 19296
pry(main)> carrot_tx_hash = wallet.send_capacity(wallet2.address, CKB::Utils.byte_to_shannon(20000), CKB::Utils.bin_to_hex(carrot_data), fee: 21000)
pry(main)> carrot_data_hash = CKB::Blake2b.hexdigest(carrot_data)
pry(main)> carrot_type_script = CKB::Types::Script.new(code_hash: carrot_data_hash, args: "0x")
pry(main)> carrot_cell_dep = CKB::Types::CellDep.new(out_point: CKB::Types::OutPoint.new(tx_hash: carrot_tx_hash, index: 0))
现在链上有了 carrot 的脚本,我们可以创建一笔交易来测试这个 carrot 脚本:
pry(main)> tx = wallet.generate_tx(wallet2.address, CKB::Utils.byte_to_shannon(100), use_dep_group: false, fee: 5000)
pry(main)> tx.outputs[0].type = carrot_type_script
pry(main)> tx.cell_deps
pry(main)> tx.witnesses[0] = "0x"
pry(main)> tx = tx.sign(wallet.key, pute_transaction_hash(tx))
pry(main)> api.send_transaction(tx)
CKB::RPCError: jsonrpc error: {:code=>-3, :message=>"Script(ValidationFailure(-1))"}
如果你仔细检查这笔交易,你会发现在输出的 cell 中,并没有以
carrot
开头的数据。然而我们运行之后仍然是验证失败,这意味着我们的脚本一定存在 bug。先前,没什么别的办法,你可能需要返回去检查代码,希望可以找到出错的地方。但现在没有这个必要了,你可以跳过这里的交易,然后将其输入到一个独立的 CKB 调试器开始调试它!首先,让我们将这笔交易连同使用的环境,都转存到一个本地文件中:
pry(main)> CKB::MockTransactionDumper.new(api, tx).write("carrot.json")
在这里你还需要跟踪 carrot 类型脚本的哈希:
pry(main)> carrot_type_pute_hash
=> "0x039c2fba64f389575cdecff8173882b97be5f8d3bdb2bb0770d8a7e265b91933"
请注意,你可能会得到和我这里不一样的哈希,这得看你使用的环境。现在,让我们来试试 ckb-standalone-debugger:
$ git clone https:///nervosnetwork/ckb-standalone-debugger
$ cd ckb-standalone-debugger/bins
$ cargo build --release
$ ./target/release/ckb-debugger -l 0.0.0.0:2000 -g type -h 0x039c2fba64f389575cdecff8173882b97be5f8d3bdb2bb0770d8a7e265b91933 -t carrot.json
注意,你可能需要根据你的环境,调整 carrot 类型脚本的哈希或者
carrot.json
的路径。现在让我们试试在一个不同的终端内通过 GDB 连接调试器:
$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 bash
root@66e3b39e0dfd:/# cd /code
root@66e3b39e0dfd:/code# riscv64-unknown-elf-gdb carrot
GNU gdb (GDB) 8.3.0.20190516-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search mands related to "word"...
Reading symbols from carrot...
(gdb) target remote 192.168.1.230:2000
Remote debugging using 192.168.1.230:2000
0x00000000000100c6 in _start
(gdb)
注意,这里的
192.168.1.230
是我的工作站在本地网络中的 IP 地址,你可能需要调整该地址,因为你的计算机可能是不同的 IP 地址。现在我们可以试一下常见的 GDB 调试过程:
(gdb) b main
Breakpoint 1 at 0x106b0: file carrot.c, line 6.
(gdb) c
Continuing.
Breakpoint 1, main (argc=0, argv=0x400000) at carrot.c:6
6 size_t index = 0;
(gdb) n
7 uint64_t len = 0;
(gdb) n
11 len = 6;
(gdb) n
12 memset(buffer, 0, 6);
(gdb) n
13 ret = ckb_load_cell_data(buffer, &len, 0, index, CKB_SOURCE_OUTPUT);
(gdb) n
14 if (ret == CKB_INDEX_OUT_OF_BOUND) {
(gdb) n
18 int cmp = memcmp(buffer, "carrot", 6);
(gdb) n
19 if (cmp) {
(gdb) p cmp
$1 = -99
(gdb) p buffer[0]
$2 = 0 ’ 00’
(gdb) n
20 return -1;
这里我们可以看到哪里出问题了:
buffer
中第一个字节的值是0
,这和c
不同,因此我们的buffer
和carrot
不同。条件if (cap) {
没有跳转到下一个循环,而是跳到了 true 的情况,返回了-1
,表明与carrot
匹配。出现这样问题的原因是,当两个buffers
相等的时候,memcmp
将会返回 0,当它们不相等的时候,将返回非零值。但是我们没有测试memcmp
的返回值是否为 0,就直接在if
条件中使用了它,这样 C 会把所有的非零值都视为 true,这里返回的-99
就会被判断为 true。对于初学者而言,这是在 C 中会遇到的典型的错误,我希望你不会再犯这样的错误。:)现在我们知道了错误的原因,接下来去修复 carrot 脚本中的错误就非常简单了。但是正如你看到的,我们设法从 CKB 上获取一笔错误交易在运行时的状态,然后通过 GDB(一个业界常见的工具)来对其进行调试。而且您在 GDB 上现有的工作流程和工具也可以在这里使用,是不是很棒?基于 REPL 的开发/调试
然而,GDB 仅仅是现代软件开发中的一部分。动态语言在很大程度上占据了主导地位,很多程序员都使用基于 REPL 的开发/调试工作流。这与编译语言中的 GDB 完全不同,基本上你需要的是一个运行的环境,你可以输入任何你想要与环境进行交互的代码,然后得到不同的结果。正如我们将在这里展示的,CKB 也会支持这种类型的开发/调试工作流。: p在这里,我们将使用 ckb-duktape 来展示基于 JavaScript 的 REPL。但是请注意,这只是一个 demo 用来演示一下工作流程,没有任何东西阻止您将自己喜爱的动态语言(不管是 Ruby、Rython、Lisp 等等)移植到 CKB 中去,并为该语言启动 REPL。首先,让我们尝试编译 duktape:
$ git clone https:///nervosnetwork/ckb-duktape
$ cd ckb-duktape
$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 bash
root@982d1e906b76:/# cd /code
root@982d1e906b76:/code# make
riscv64-unknown-elf-gcc -Os -DCKB_NO_MMU -D__riscv_soft_float -D__riscv_float_abi_soft -Iduktape -Ic -Wall -Werror c/entry.c -c -o build/entry.o
riscv64-unknown-elf-gcc -Os -DCKB_NO_MMU -D__riscv_soft_float -D__riscv_float_abi_soft -Iduktape -Ic -Wall -Werror duktape/duktape.c -c -o build/duktape.o
riscv64-unknown-elf-gcc build/entry.o build/duktape.o -o build/duktape -lm -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s
riscv64-unknown-elf-gcc -Os -DCKB_NO_MMU -D__riscv_soft_float -D__riscv_float_abi_soft -Iduktape -Ic -Wall -Werror c/repl.c -c -o build/repl.o
riscv64-unknown-elf-gcc build/repl.o build/duktape.o -o build/repl -lm -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s
root@982d1e906b76:/code# exit
你需要在这里生成
build/repl
二进制文件。和 carrot 的例子类似,我们先将 duktape REPL 的二进制文件部署在 CKB 上:
pry(main)> api = CKB::API.new
pry(main)> wallet = CKB::Wallet.from_hex(api, "
pry(main)> wallet2 = CKB::Wallet.from_hex(api, CKB::Key.random_private_key)
pry(main)> duktape_repl_data = File.read("build/repl")
pry(main)> duktape_repl_data.bytesize
=> 283048
pry(main)> duktape_repl_tx_hash = wallet.send_capacity(wallet2.address, CKB::Utils.byte_to_shannon(300000), CKB::Utils.bin_to_hex(duktape_repl_data), fee: 310000)
pry(main)> duktape_repl_data_hash = CKB::Blake2b.hexdigest(duktape_repl_data)
pry(main)> duktape_repl_type_script = CKB::Types::Script.new(code_hash: duktape_repl_data_hash, args: "0x")
pry(main)> duktape_repl_cell_dep = CKB::Types::CellDep.new(out_point: CKB::Types::OutPoint.new(tx_hash: duktape_repl_tx_hash, index: 0))
我们还需要创建一笔包含 duktape 脚本的交易,我这里使用一个非常简单的脚本,当然你可以加入更多的数据,这样你就可以在 CKB 上玩起来了
pry(main)> tx = wallet.generate_tx(wallet2.address, CKB::Utils.byte_to_shannon(100), use_dep_group: false, fee: 5000)
pry(main)> tx.outputs[0].type = duktape_repl_type_script
pry(main)> tx.cell_deps
pry(main)> tx.witnesses[0] = "0x"
然后让我们把它转存到文件中,并检查 duktape 类型脚本的哈希:
pry(main)> CKB::MockTransactionDumper.new(api, tx).write("duktape.json")
=> 2765824
pry(main)> duktape_repl_type_pute_hash
=> "0xa8b79392c857e29cb283e452f2cd48a8e06c51af64be175e0fe0e2902c482837"
与上面不同的是,我们不需要启动 GDB,而是可以直接启动程序:
$ ./target/release/ckb-debugger -g type -h 0xa8b79392c857e29cb283e452f2cd48a8e06c51af64be175e0fe0e2902c482837 -t duktape.json
duk>
你可以看到一个
duk>
提示你输入 JS 代码!同样,如果遇到错误,请检查是否需要更改类型脚本的哈希,或者使用正确的duktape.json
路径。我们看到常见的 JS 代码可以在这里工作运行:
duk> print(1 + 2)
3
= undefined
duk> function foo(a) { return a + 1; }
= undefined
duk> foo(123)
= 124
您还可以使用与 CKB 相关的功能:
duk> var hash = CKB.load_script_hash
= undefined
duk> function buf2hex(buffer) { return Array.prototype.map.call(new Uint8Array(buffer), function(x) { return (’00’ + x.toString(16)).slice(-2); }).join(’’); }
= undefined
duk> buf2hex(hash)
= a8b79392c857e29cb283e452f2cd48a8e06c51af64be175e0fe0e2902c482837
请注意,我们在这里得到的脚本哈希正是我们当前执行的类型脚本的哈希!这将证明 CKB 系统调试在这里是有效的,我们也可以尝试更多有趣的东西:
duk> print(CKB.SOURCE.OUTPUT)
2
= undefined
duk> print(CKB.CELL.CAPACITY)
0
= undefined
duk> capacity_field = CKB.load_cell_by_field(0, 0, CKB.SOURCE.OUTPUT, CKB.CELL.CAPACITY)
= [object ArrayBuffer]
duk> buf2hex(capacity_field)
= 00e40b5402000000
这个
00e40b5402000000
可能在一开始看起来有点神秘,但是请注意 RISC-V 使用的是 little endian(低字节序),所以如果在这里我们将字节序列颠倒,我们将得到00000002540be400
,在十进制中正好是10000000000
。还要记住,在 CKB 中容量使用的单位是shannons
,所以10000000000
正好是100
个字节,这正是我们生成上面的交易时,想要发送的代币的数量!现在你看到了如何在 duktape 环境中与 CKB 愉快地玩耍了 :)结论
我们已经介绍了两种不同的在 CKB 中调试的过程,你可以随意使用其中一种(或者两种)。我已经迫不及待地想看你们在 CKB 上玩出花来啦!
以上就是关于gg修改器脚本要root吗_gg修改器免root的全部内容,游戏大佬们学会了吗?
怎样开gg修改器的root_怎么用GG修改器 分类:免root版 6,467人在玩 各位游戏大佬大家好,今天小编为大家分享关于怎样开gg修改器的root_怎么用GG修改器的内容,轻松修改游戏数据,赶快来一起来看看吧。 原文作者:IT奶爸也是煮男 群晖6.1版本修改挂载……
下载gg修改器root小米手机_gg修改器root权限怎么开启小米 分类:免root版 4,234人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器root小米手机_gg修改器root权限怎么开启小米的内容,轻松修改游戏数据,赶快来一起来看看吧。 小编有一些时日没有更新过头条内……
下载gg修改器手机版root,下载gg修改器手机版root,让你的手机更强大 分类:免root版 3,787人在玩 如果你是一个安卓手机用户,你可能知道root是一个非常有用的工具。它可以使你的手机实现各种高级操作,从改变系统设置到卸载系统应用程序等等。不过,要想使用root功能,需要很多技……
下载gg修改器必须得root吗,GG修改器是否需要Root权限? 分类:免root版 1,969人在玩 GG修改器是一款在手机游戏中广泛使用的辅助工具。为了能够实现它的功能,有很多人会问:GG修改器是否需要Root权限?事实上,GG修改器并不需要Root权限。 GG修改器是通过模拟内存进……
下载免root修改器GG大玩家_gg修改器免root万能修改器 分类:免root版 6,266人在玩 各位游戏大佬大家好,今天小编为大家分享关于免root修改器GG大玩家_gg修改器免root万能修改器的内容,轻松修改游戏数据,赶快来一起来看看吧。 「无高刷,不旗舰」似乎已经成为很多……
下载gg修改器免root正版_gg修改器免root版官网 分类:免root版 6,612人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器免root正版_gg修改器免root版官网的内容,轻松修改游戏数据,赶快来一起来看看吧。 昨天!发文时就提到 CoolStar 越狱大神正在……
下载gg修改器可以不root,软件推荐:GG修改器,不需要ROOT就能用 分类:免root版 2,226人在玩 GG修改器是一款非常实用的工具,可以帮助用户修改各种游戏中的数据信息。相比其他修改器,GG修改器最大的优点就在于它不需要ROOT权限,用户可以直接安装使用。 无需ROOT,操作简便 ……
下载GG修改器适合的root,标题:GG修改器适合的root软件下载 分类:免root版 2,394人在玩 如果你是一名玩家,那么你肯定知道GG修改器这个软件。它可以用于修改手机游戏中的一些参数,比如金币、钻石等。但是,有些游戏需要root权限才能进行修改。因此,我们需要一款适合GG……
下载gg修改器免root版冷冰雪_gg修改器免root版雪冷水制作 分类:免root版 6,371人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器免root版冷冰雪_gg修改器免root版雪冷水制作的内容,轻松修改游戏数据,赶快来一起来看看吧。 疑似火星“生命”明显增多且变大……
下载gg修改器如免ROOT修改_gg修改器免root修改造梦西游OL 分类:免root版 4,893人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器如免ROOT修改_gg修改器免root修改造梦西游OL的内容,轻松修改游戏数据,赶快来一起来看看吧。 一、开源背景 随着移动互联网的……
下载