开发第一个 EOS 智能合约
Hello World!
稍微了解 EOS 系统,你就会知道 EOS 的智能合约基于 WebAssembly(WASM) 技术,这种技术在性能和跨平台兼容性之间取得了很好的平衡,通过将原始代码编译成字节码,使得代码可以在多种平台的 WASM 虚拟机(或者叫解释器)中执行。得到了苹果和谷歌等科技巨头的支持,被誉为下一代互联网前端技术。目前的 WebAssembly 技术支持 C/C++ 语言,并开发了 JavaScript 接口,并被 Chrome、Edge、Safari、Firefox 等几乎所有的主流浏览器支持。
因为使用了 WebAssembly,目前的 EOS 智能合约只支持 C/C++ 语言,简单的智能合约由 3 种文件组成:.hpp文件、.cpp文件、.abi 文件。其中 hpp 为 C++ 头文件,一般用来定义类及其成员变量与成员函数。cpp 为 C++ 文件,用来实现 hpp 中声明的成员函数,实现智能合约的业务逻辑。abi(Application Binary Interface) 文件为二进制接口文件,文件格式类似 JSON,用来定义智能合约与 EOS 系统外部交互的数据接口。
如果智能合约的非常简单,只有一个 cpp 文件,可以省略 hpp 文件,将类与成员定义在 cpp 文件中。abi 文件应该由 C++ 程序需要的数据库空间和外部接口生成,不过 EOS 开发了 abi 自动生成工具,可以根据智能合约代码自动生成 abi 文件,减轻了开发工作量。所以最简单的智能合约只需实现 cpp 文件。
Hello 智能合约
一般的操作系统上手时,惯例是编写一个 Hello World 程序,是主动输出一句话。但我们不一样,我们编写的是一个智能合约,智能合约强调的是互动,在 EOS 里叫做 Action,Action 表示别人可以对合约做什么动作,所有智能合约代码都是对 Action 的回应,是被动的。下面就是第一个 Hello 智能合约:
hello.cpp:
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class hello : public eosio::contract {
public:
using contract::contract;
/// @abi action
void hi( account_name user ) {
print( "Hello, ", name{user} );
}
};
EOSIO_ABI( hello, (hi) )
我们在代码中定义了一个类:hello,这个类名与合约的账户名没关系,类中只有一个简单的方法:
void hi( account_name user ) {
print( "Hello, ", name{user} );
}
这就是 EOS 智能合约里所谓的 Action
,我们定义了一个叫 hi 的 Action,参数是另一个账户名,函数体是打印一句话,回应 hello。 也就是说别的账户可以调用这个合约的 hi Action,这个 hello 合约就会打印一句 hello 来回应。
最后一行代码:
EOSIO_ABI( hello, (hi) )
EOSIO_ABI
是一个宏,将特定类的特定方法暴漏给系统,成为别的账户可以调用的 Action。
编译智能合约
我们使用 eosiocpp 工具将写好的 hello.cpp 编译成为字节码文件(.wast):
$ eosiocpp -o hello.wast hello.cpp
然后使用 eosiocpp 工具自动生成 abi 文件:
$ eosiocpp -g hello.abi hello.cpp
Generated hello.abi
看一下生成的 abi 文件内容:
{
"____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-04-16T13:37:55",
"types": [],
"structs": [{
"name": "hi",
"base": "",
"fields": [{
"name": "user",
"type": "account_name"
}
]
}
],
"actions": [{
"name": "hi",
"type": "hi",
"ricardian_contract": "# CONTRACT FOR hello::hi## ACTION NAME: hi\n
### Parameters### Parameters\nInput paramters:Input paramters:\n
\n
* `user` (string to include in the output)* `user` (string to include in the output)\n
\n
Implied parameters: Implied parameters: \n
\n
* `account_name` (name of the party invoking and signing the contract)* `account_name` (name of the party invoking and signing the contract)\n
\n
### Intent### Intent\n
INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.\n
\n
### Term### Term\n
TERM. This Contract expires at the conclusion of code execution.TERM. This Contract expires at the conclusion of code execution.\n"
}
],
"tables": [],
"ricardian_clauses": [
...
...
...
]
}
我们省略了 ricardian_clauses
,也就是李嘉图条款部分(李嘉图合约指的是人与机器都能读懂的合同,EOS 最近才将其加入智能合约中)。我们看到 abi 文件中已经声明了 hi
这个 Action
,并说明了这个 Action
的李嘉图合约,大概意思是本合约的输入为一串字符(user),本合约意图是打印输出,没有其他效果。
上传智能合约
上传智能合约之前,我们要先给智能合约建立一个账户 EOS 里账户和智能合约是一一对应的。使用 EOS 的 cleos 命令行工具创建账户:
$ cleos create account eosio hello.code EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4 EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4
命令中,hello.code
就是这个智能合约的账户名,EOS系统的账户名要求 12 字符以内。后面两个公钥是在本地测试网络中有建立账户权限的公钥(对应本地测试网络中的 eosio 账户)。
然后就可以上传智能合约了:
$ cleos set contract hello.code ../hello -p hello.code
使用智能合约
我们使用 user
账户调用 hello.code
的 hi
Action
:
$ cleos push action hello.code hi '["user"]' -p user
hello.code
表示执行 hello.code 合约,hi
表示执行合约里的 hi Action,'["user"]'
是根据 abi 写的传入参数, -p
参数表示使用哪个账户的权限 (permission)。
以下是系统回应:
executed transaction: 4c10c1426c16b1656e802f3302677594731b380b18a44851d38e8b5275072857 244 bytes 1000 cycles
# hello.code <= hello.code::hi {"user":"user"}
>> Hello, user
说明执行了 hello.code
合约的 hi
Action,并且系统输出为 Hello, user
,智能合约成功对 Action 进行了回应。
相关文章和视频推荐
【许晓笛】EOS 新增的 WebAssembly 解释器,是什么鬼?
https://www.jianshu.com/p/06f86dd434ad
圆方圆学院汇集大批区块链名师,打造精品的区块链技术课程。 在各大平台都长期有优质免费公开课,欢迎报名收看。