6. 使用C 进行智能合约开发
读者对象:本章节主要描述使用C 进行ChainMaker合约编写的方法,主要面向于使用C 进行ChainMaker的合约开发的开发者。
6.1. 环境依赖
操作系统
目前仅支持Linux和MAC系统。
软件依赖
软件依赖表如下:
名称 | 版本 | 描述 | 是否必须 |
---|---|---|---|
GCC | 7.3 | C编译器 | 是 |
依赖软件安装:
Mac:brew install gcc
Linux:
- yum install gcc —— Ubuntu/Debian安装命令。
- apt-get install gcc —— CentOS/Redhat安装命令。
长安链环境准备
准备一条支持WXVM的长安链,以及长安链CMC工具,用于将写编写好的合约,部署到链上进行测试。相关安装教程请详见:
- 部署长安链教程。
- 部署长安链CMC工具的教程。
6.2. 编写C 智能合约
6.2.1. 搭建开发环境
开发者可根据ChainMaker提供的SDK开发C 合约,C 合约的SDK工程下载地址为:chainmaker-contract-sdk-cpp。
SDK下载完成后,开发者可根据自身习惯选择熟悉的C 编辑器或IDE。推荐使用CLion,CLion下载和安装请参见官网:https://www.jetbrains.com/clion/。
安装完成后,使用CLion打开SDK工程,通过编辑main.cc文件即可编辑自己的C 合约。
6.2.2. 代码编写规则
外部方法声明
只有声明为外部方法的函数,才可以(被用户或其他合约)从外部调用,否则,只能用于合约内部调用。外部方法声明规则如下:
WASM_EXPORT
: 必须,暴露声明void
: 必须,无返回值method_name()
: 必须,暴露方法名称
// 示例
WASM_EXPORT void init_contract() {
}
强制声明外部方法
强制声明外部方法为合约必须提供且必须对外暴露的方法,有以下两个:
init_contract
:创建合约会自动执行该方法,无需指定方法名。upgrade
: 升级合约会自动执行该方法,无需指定方法名。
// 在创建本合约时, 调用一次init方法. ChainMaker不允许用户直接调用该方法.
WASM_EXPORT void init_contract() {
// 安装时的业务逻辑,可为空
}
// 在升级本合约时, 对于每一个升级的版本调用一次upgrade方法. ChainMaker不允许用户直接调用该方法.
WASM_EXPORT void upgrade() {
// 升级时的业务逻辑,可为空
}
获取SDK 接口上下文
C 合约通过SDK接口上下文与链进行交互,具体信息可参考文章末尾[C SDK API描述](C SDK API描述)。
代码语言:javascript复制//获取SDK接口上下文
Context* ctx = context();
6.2.3. 合约示例源码展示
下文代码框内为一个C 编写的存证合约示例,该合约示例实现以下功能:
1、存储文件哈希、文件名称和该交易的ID;
2、通过文件哈希查询该条记录。
代码语言:javascript复制#include "chainmaker/chainmaker.h"
using namespace chainmaker;
class Counter : public Contract {
public:
void init_contract() {}
void upgrade() {}
// 保存
void save() {
// 获取SDK 接口上下文
Context* ctx = context();
// 定义变量
std::string time;
std::string file_hash;
std::string file_name;
std::string tx_id;
// 获取参数
ctx->arg("time", time);
ctx->arg("file_hash", file_hash);
ctx->arg("file_name", file_name);
ctx->arg("tx_id", tx_id);
// 发送合约事件
// 向topic:"topic_vx"发送2个event数据,file_hash,file_name
ctx->emit_event("topic_vx",2,file_hash.c_str(),file_name.c_str());
// 存储数据
ctx->put_object("fact" file_hash, tx_id " " time " " file_hash " " file_name);
// 记录日志
ctx->log("call save() result:" tx_id " " time " " file_hash " " file_name);
// 返回结果
ctx->success(tx_id " " time " " file_hash " " file_name);
}
// 查询
void find_by_file_hash() {
// 获取SDK 接口上下文
Context* ctx = context();
// 获取参数
std::string file_hash;
ctx->arg("file_hash", file_hash);
// 查询数据
std::string value;
ctx->get_object("fact" file_hash, &value);
// 记录日志
ctx->log("call find_by_file_hash()-" file_hash ",result:" value);
// 返回结果
ctx->success(value);
}
};
// 在创建本合约时, 调用一次init方法. ChainMaker不允许用户直接调用该方法.
WASM_EXPORT void init_contract() {
Counter counter;
counter.init_contract();
}
// 在升级本合约时, 对于每一个升级的版本调用一次upgrade方法. ChainMaker不允许用户直接调用该方法.
WASM_EXPORT void upgrade() {
Counter counter;
counter.upgrade();
}
WASM_EXPORT void save() {
Counter counter;
counter.save();
}
WASM_EXPORT void find_by_file_hash() {
Counter counter;
counter.find_by_file_hash();
}