Ontology Wasm 自从上线测试网以来,得到了社区开发人员的极大关注。同时,Ontology Wasm 也即将上线主网。我们知道,Ontology Wasm 合约支持 Rust 和 C++ 语言开发。在前面的技术视点文章中,我们曾经介绍过如何用 C++ 来实现一个简单的红包合约帮助开发者了解如何采用 C++ 语言来在 Ontology 上进行合约开发。另外,我们也简单介绍过使用 Rust 语言的开发注意事项。
在此次的技术视点以及以后的相关系列文章中,我们将会详细介绍如何使用 Rust 语言开发 Ontology Wasm 合约。本次技术视点中,我们将简单介绍如何进行相关环境搭建和使用合约模板来进行开发。
1
一、环境搭建
为了提高开发的效率,建议在开发合约之前,先准备好如下的开发环境。
这里需要注意的一点是:本地测试节点的搭建可以方便合约测试。同时,可以通过在合约中添加 debug 信息,在节点日志中监控合约运行信息。当然,如果觉得自己搭建测试节点较复杂,我们也可以使用 Ontology 测试网来进行合约测试。
1.1 Rust 开发环境搭建
Rust 开发环境可以通过以下几步来完成:
1. 安装 rustup。如果是 Linux、Mac OS 以及其它类 Unix 系统可以直接执行下面的命令,并根据屏幕上的提示进行操作。
curl https://sh.rustup.rs -sSf | sh
如果是 Windows 等系统,请访问官网下载合适的版本进行安装。
2. 安装 rust 编译器。
安装完 rustup 后可以通过以下命令安装 rust 编译器:
rustup install nightly
同时,设置默认的编译版本为 nightly:
rustup default nightly
3. 安装 Wasm32 编译目标。
开发者可以通过以下命令安装 Wasm32 编译目标:
rustup target add wasm32-unknown-unknown
4. 安装ontio-wasm-build
工具。
我们使用cargo
工具把合约编译成 Wasm 字节码时,生成的文件会比较大,ontio-wasm-build
可以优化字节码,从而减小合约文件大小,将合约部署到链上之前,必须通过该工具进行合约的优化与检查。
1.2 安装集成开发环境
集成开发环境 IDE 和编辑工具有很多种选择,比如 Clion、IntelliJ 以及 vim 等。其中, Clion 是一款功能强大的 C/C++/Rust 开发工具,支持单步调式,方便 Wasm 合约本地调试。开发者可以选择自己喜欢的 IDE 或编辑工具来进行开发。
1.3 本地测试节点搭建
该部分请参考 Ontology 官方文档:本地测试节点环境搭建。
注意:就像在前面强调过的一样,编译好的可执行文件在启动时,请设置日志级别为 debug 模式。该模式下,开发者可以十分方便地查看合约运行的 debug 信息。
1
二、使用合约模板开发 Wasm 合约
使用 Rust 开发的合约源代码要想在 Ontology 链上运行,要经过以下步骤:
1. 需要先将源码编译成 Wasm 字节码。
2. 使用 ontio-wasm-build 工具优化一下 Wasm 字节码。
3. 将优化后的 Wasm 字节码部署到链上。
4. 进行合约中方法的调用。
下面这是一个简单的使用合约模板开发 Wasm 合约的例子,以此来介绍一下上述整个流程。
2.1 取得 Wasm 合约模板
为了方便开发者入手 Ontology Wasm 合约开发,我们提供了一个合约模板(Rust 版),开发者仅需 clone 该代码,然后添加自己的合约逻辑即可。
git clone https://github.com/ontio/rust-wasm-contract-template.git
目录结构如下所示:
.
├── .cargo
│ └── config
├── Cargo.toml
├── build.sh
└── src
└── lib.rs
我们对其中一些文件进行说明:
.cargo
文件夹下面的config
文件中配置了合约编译时的一些配置信息, config
文件内容如下:[target.wasm32-unknown-unknown]
rustflags = [
"-C", "link-args=-z stack-size=32768"
]
[target.wasm32-unknown-unknown]
表示编译目标, rustflags
配置了编译的链接参数,此处设置了默认的栈大小为32768,即32 kb,合约在运行的过程中可以使用的栈的最大值。
Cargo.toml
文件是合约的一些基本配置信息,其内容如下:[package]
name = "rust-wasm-contract-template"
version = "0.1.0"
authors = ["name <test@email.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"] #Compile as a dynamic link library
[dependencies]
ontio-std = {git = "https://github.com/ontio/ontology-wasm-cdt-rust"}
[features]
mock = ["ontio-std/mock"]
其中,在[lib]
配置模块中, crate-type = ["cdylib"]
表示将项目编译动态链接库,用于被其他语言调用。
[dependencies]
用于配置项目依赖信息,这里引入了 Ontology Wasm 合约开发需要的ontio-std
库。
[features]
用于开启一些不稳定特性,只可在 nightly 版的编译器中使用。
build.sh
文件里面封装好了编译合约和优化合约的功能,待合约开发完成后,执行该脚本会将优化后的合约字节码放到output
目录下面。src/lib.rs
用于编写合约逻辑代码,合约模板里面的代码如下:#![no_std]
use ontio_std::runtime;
#[no_mangle]
fn invoke() {
runtime::ret(b"hello");
}
该合约模板实现了一个简单的返回 hello 功能。对于该模板的一些简单说明如下:
#![no_std]
表示屏蔽 rust std 库中的接口,但是开发者可以调用 rust core 库中的 api。#[no_mangle]
表示在编译成wasm字节码时候,将 invoke 函数导出,invoke 函数是 Ontology Wasm 合约的入口函数,需要将其导出。runtime
模块封装了合约与链交互的接口,runtime::ret()
用于将合约执行的结果返回给调用方。2.2 编译合约
开发者可以直接执行build.sh
脚本即可实现合约编译和合约字节码优化。
./build.sh
如果在执行的过程中出现如下权限错误:
-bash: ./build.sh: Permission denied
那么,可以先给该文件可执行权限:
sudo chmod +x ./build.sh
执行成功后,会在当前目录下生成output
目录。output 的目录结构如下:
├── output
│ ├── rust_wasm_contract_template.wasm
│ └── rust_wasm_contract_template.wasm.str
其中, rust_wasm_contract_template.wasm
是我们编译合约源代码生成的 Wasm 字节码文件。rust_wasm_contract_template.wasm.str
是 Wasm 字节码的 hex 编码格式的文件。
2.3 部署合约
编译好的 Wasm 合约需要部署到链上才能运行。我们可以将上面的合约字节码文件部署到测试网,或者本地测试节点,下面以部署到本地测试网为例:
首先,启动本地测试节点,在启动之前,我们需要先生成钱包文件:
./ontology account add
上面命令在执行的过程中用默认配置即可,再执行下面的命令启动本地测试节点:
./ontology --testmode --loglevel 1
--loglevel 1
表示节点的日志级别是debug
,测试合约中如果有 debug 信息,会在节点日志中显示出来。
然后,打开另外一个终端窗口,进行合约部署。
$ ./ontology contract deploy --vmtype 3 --code ./rust_wasm_contract_template.wasm.str --name helloworld --author "author" --email "email" --desc "desc" --gaslimit 22200000
Password:
Deploy contract:
Contract Address:0be3df2e320f86f55709806425dc1f0b91966634
TxHash:bd83f796bfd79bbb2546978ebd02d5ff3a54c2a4a6550d484689f627513f5770
Tip:
Using './ontology info status bd83f796bfd79bbb2546978ebd02d5ff3a54c2a4a6550d484689f627513f5770' to query transaction status.
如果出现 gaslimit 不够的错误信息,请设置更大的 gaslimit 参数。
2.4 测试合约
现在我们来调用合约中的方法,执行如下的命令:
$ ./ontology contract invoke --address 0be3df2e320f86f55709806425dc1f0b91966634 --vmtype 3 --params '' --version 0 --prepare
Invoke:346696910b1fdc2564800957f5860f322edfe30b Params:null
Contract invoke successfully
Gas limit:20000
Return:68656c6c6f (raw value)
为了能够看到合约执行返回的结果,我们在命令后面加了--prepare
标签,表示该交易是预执行交易。
可以看到,在命令行中,我们得到了68656c6c6f
,这是预期结果hello
的 hex 编码格式而已,我们仅需用 hex 解码即可得到预期结果。
1
三、结论
在本期技术视点中,我们简单介绍了使用 Rust 语言在 Ontology 上进行 Wasm 开发时,如何进行相关环境搭建和使用合约模板来进行开发。此外,支持 Ontology Wasm 合约部署和调用的新版 SmartX 正在开发中,即将上线。它的上线会大大方便开发者进行 Ontology Wasm 合约的部署以及相关函数的调用。