Nervos 官方提供了 ruby sdk ,可以用来操作 CKB 。官方还给出了一个 demo 仓库 https://github.com/nervosnetwork/ckb-demo-ruby-sdk 。我们这节演示如何在 CKB 上执行 ruby 代码,把这个 demo 跑起来。
先说说基本原理,聊聊 CKB 上是如何支撑 ruby 智能合约的运行的。
首先要介绍的是 CKB VM ,也就是 CKB 虚拟机。官方的 README.md 上 https://github.com/nervosnetwork/ckb-vm 是这样描述的。
CKB VM is a pure software implementation of the RISC-V instruction set used as scripting VM in CKB
翻译过来:CKB VM 是 RISC-V 指令集的一个纯软件实现,是用在 CKB 上的脚本虚拟机。
这句话不太好理解,来解释一下。RISC-V 是一个硬件指令集,任何的语言,例如 C ,只要能够编译成 RISC-V 指令,都可以在 CKB VM 上运行了。就像 CKB VM 开发者 Xuejie ,在他的文章 https://medium.com/nervosnetwork/an-introduction-to-ckb-vm-9d95678a7757 中所说的:
However, any language that can be compiled to the RISC-V instruction set can be used for CKB contract development.
翻译:任何语言只要可以被编译成 RISC-V 指令集,就可以用来在 CKB 上进行合约开发。例如,我们用 C 语言写一个智能合约,直接放到 CKB VM 上是不能执行的,但是只要编译一下,编程 RISC-V 指令集的可执行文件,就可以在 CKB VM 上运行了。
但是 Ruby 不是编译型语言,而是要运行在自己的解释器上的。对于这种情况,Xuejie 文章中也提到
“VM on top of VM”
翻译:虚拟机之上再运行一层虚拟机。
也就是在 CKB VM 之上运行 Ruby VM 的形式。首先把 Ruby VM 本身编译成 RISC-V 指令集的可执行文件,让它在 CKB VM 上运行起来之后,就可以在它上面跑 Ruby 语言了。
下面准备跑文章开头提到的 demo 。这个 demo 中把很多的对 CKB 的 RPC 请求,都封装到了一些 Ruby 命令中,而要执行这些命令就需要有 Ruby 环境。所以需要在咱们的 ubuntu16.04 系统上安装 ruby https://www.phusionpassenger.com/library/walkthroughs/deploy/ruby/ownserver/nginx/oss/install_language_runtime.html 。温馨提示:如果手头没有 ubuntu 机器,还是建议去 aliyun 上申请一个临时的 ECS 。
sudo apt-get update
sudo apt-get install -y curl gnupg build-essential
sudo gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | sudo bash -s stable
sudo usermod -a -G rvm `whoami`
if sudo grep -q secure_path /etc/sudoers; then sudo sh -c "echo export rvmsudo_secure_path=1 >> /etc/profile.d/rvm_secure_path.sh" && echo Environment variable installed; fi
上面的命令都是为了安装 rvm ,具体的解释上面给出的链接中有,这里就不展开了。注意,文档中说不让用类似 tmux 这样的 terminal multiplexer 来进行这里的操作。
ssh the_ecs_ip
所以来重新登录,获得一个新的命令行界面。
rvm install ruby
rvm --default use ruby
gem install bundler --no-rdoc --no-ri
这样 ruby 语言和 bundle 命令就都装好了。
下面进入 demo 项目 https://github.com/nervosnetwork/ckb-demo-ruby-sdk ,运行 bundle 装包,然后启动 irb ,也就是 ruby 的交互环境。
cd ckb-demo-ruby-sdk
bundle
bundle exec pry -r ./lib/ckb/wallet.rb
但是最后一步会报错,报错信息是:
Could not open library 'libsecp256k1': libsecp256k1: cannot open shared object file: No suchfile or directory. (LoadError)
Could not open library 'libsecp256k1.so': libsecp256k1.so: cannot open shared object file: No such file or directory
报错原因是项目中用到了 bitcoin-secp256k1 这个 gem (见项目内的 Gemfile )。而这个包是有依赖的。解决报错的方法在这个包的官方 README 中给出了 https://github.com/cryptape/ruby-bitcoin-secp256k1#prerequiste 。
执行完上面链接中的操作。
bundle exec pry -r ./lib/ckb/wallet.rb
这样 irb 就启动成功了。
接下来,跟着 demo 的 README https://github.com/nervosnetwork/ckb-demo-ruby-sdk 继续往下做。
cp -r ckb/nodes_template/ node1
把 ckb 仓库中国的 nodes_template 拷贝出来一份,放到系统上的任意一个位置。
scp argv_source_entry the_ecs_ip:
peter@ckbrocks:~$ cp argv_source_entry node1/spec/cells/
argv_source_entry 就是编译成 RISC-V 指令集的 Ruby VM ,下载位置在 demo 仓库的 README.md 中 https://github.com/nervosnetwork/ckb-demo-ruby-sdk#prerequisites 。如果对这个文件执行 file argv_source_entry
命令,可以看到这是一个 RISC-V 指令集的可执行文件,它不是在我们自己的 ubuntu 操作系统上执行的,而是要加载到 CKB VM 上执行的。把这个文件上传到服务器,然后保存到刚刚拷贝出来的 node1 文件夹中的 spec/cells 中。
接下来参照文档修改 default.json 和 spec/dev.json 的内容。
这样就可以启动 CKB ,去加载 node1 的设置了。
cd ckb
./target/release/ckb -c /home/peter/node1/default.json run
CKB 运行起来之后,来到另一个命令行中运行的 irb 环境。并在 irb 中执行下面的内容:
miner = Ckb::Wallet.from_hex(Ckb::Api.new, "e79f3207ea4980b7fed79956d5934249ceac4751a4fae01a0f7c4a96884bc4e3")
alice = Ckb::Wallet.from_hex(Ckb::Api.new, "76e853efa8245389e33f6fe49dcbd359eb56be2f6c3594e12521d2a806d32156")
创建两个账户,一个是 miner ,另外一个是 alice 。上面两串长长的数字是钱包私钥。
执行
[6] pry(main)> miner.address
=> "0x0c513cacdef7cd46b64087dc36a0e6ca4889a96bdeda031a2b8e6d3b4d30fc8b"
拿到 miner 的钱包地址。下面我们要把 miner 当矿工,这样 minner 就可以获得挖矿奖励了。需要做的就是到 node1/default.json 中,把 type_hash 替换为上面的 address 的值。
Ctrl-C 停下 ckb 启动命令。
rm -rf node1/default/*
删除刚才 ckb 运行过程产生的数据。
./target/release/ckb -c /home/peter/node1/default.json run
重新启动 ckb 。这样,过十多秒中,就会挖矿成功一次。
miner.get_balance
=> 50000
到 irb 中,查看一下矿工 miner 的账户余额,发现挖矿奖励已经到账了。
[13] pry(main)> miner.send_capacity(alice.address, 12345)
=> "0xbf4924c8a2945cf4e702a8bf90988f5b68a65cc34ef4d98ef3da11adef62efa4"
接下来给 alice 转账。
[16] pry(main)> alice.get_balance
=> 12345
注意,转账操作不会马上生效,而是需要经过几十多秒之后才生效。
这样,整个 ruby demo 项目就成功运行起来了。
这节关于如何在 CKB 上执行 Ruby 代码,内容就是这些了。我们主要介绍了 CKB 执行解释型高级语言的思路,也就是是 “vm on vm” 。接下来安装了 ruby ,下载了官方的 ruby sdk 的 demo 来运行。关于 demo 中的技术细节,本节没有展开,后续小节中再去介绍。
参考: