技术视点 | 想用Wasm开发dApp?你不得不读的入门教程(一)

技术视点 | 想用Wasm开发dApp?你不得不读的入门教程(一)

本体Ontology 发布在 技术指南 海盗号 6387760

在前面的技术视点文章中,我们曾经介绍过如何用 C++ 来实现一个简单的红包合约帮助开发者了解如何采用 C++ 语言来在 Ontology 上进行合约开发。另外,我们也简单介绍过使用 Rust 语言的开发注意事项。

在此次的技术视点以及以后的相关系列文章中,我们将会详细介绍如何使用 Rust 语言开发 Ontology Wasm 合约。本次技术视点中,我们将简单介绍如何进行相关环境搭建和使用合约模板来进行开发。

图 | 网络

一、环境搭建

为了提高开发的效率,建议在开发合约之前,先准备好如下的开发环境。
  • Rust 开发环境(必须)
  • 集成开发环境(推荐)
  • 本地 Wasm 合约测试节点(推荐)
这里需要注意的一点是:本地测试节点的搭建可以方便合约测试。同时,可以通过在合约中添加 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可以优化字节码,从而减小合约文件大小,将合约部署到链上之前,必须通过该工具进行合约的优化与检查。
  • 具体安装方法如下:cargo install --git=https://github.com/ontio/ontio-wasm-build

1.2 安装集成开发环境

集成开发环境 IDE 和编辑工具有很多种选择,比如 Clion、IntelliJ 以及 vim 等。其中, Clion 是一款功能强大的 C/C++/Rust 开发工具,支持单步调式,方便 Wasm 合约本地调试。开发者可以选择自己喜欢的 IDE 或编辑工具来进行开发。

1.3 本地测试节点搭建

该部分请参考 Ontology 官方文档:本地测试节点环境搭建。

注意:就像在前面强调过的一样,编译好的可执行文件在启动时,请设置日志级别为 debug 模式。该模式下,开发者可以十分方便地查看合约运行的 debug 信息。

二、使用合约模板开发 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 解码即可得到预期结果。

三、结论

在本期技术视点中,我们简单介绍了使用 Rust 语言在 Ontology 上进行 Wasm 开发时,如何进行相关环境搭建和使用合约模板来进行开发。此外,支持 Ontology Wasm 合约部署和调用的新版 SmartX 正在开发中,即将上线。它的上线会大大方便开发者进行 Ontology Wasm 合约的部署以及相关函数的调用。

Ontology欢迎更多的 Wasm 技术爱好者加入本体开发社区,共同打造技术生态。

文章标签: 技术指南 本体
评论
登录 账号发表你的看法,还没有账号?立即免费 注册