深入分析MetaForce佛萨奇2.0波场链丨币安链丨马蹄链智能合约系统开发成熟技术案例及代码详解
6.2.4. 编译合约
6.2.4.1. 搭建编译环境
开发者可使用ChainMaker已经打包好的Docker镜像编译C++合约代码,ChainMaker官方已经将容器发布至 docker hub。
拉取镜像
请使用以下命令拉取用于编译C++合约的镜像。
docker pull chainmakerofficial/chainmaker-cpp-contract:2.1.0
启动镜像
启动镜像前,需要指定本地开发目录,用于映射为docker镜像的home目录。用于映射的本地开发目录一般为SDK工程目录,例如/data/workspace/chainmaker-contract-sdk-cpp,这样编辑开发的C++合约就可以在docker容器内的home目录直接编译了。
# 启动并进入容器,$WORK_DIR即本地工作目录
docker run -it --name chainmaker-cpp-contract -v $WORK_DIR:/home chainmakerofficial/chainmaker-cpp-contract:2.1.0 bash
# 或者先后台启动
docker run -d --name chainmaker-cpp-contract -v $WORK_DIR:/home chainmakerofficial/chainmaker-cpp-contract:2.1.0 bash -c "while true; do echo hello world; sleep 5;done"
# 再进入容器
docker exec -it chainmaker-cpp-contract bash
6.2.4.2. 编译示例合约
进入编译容器后,切换到home目录,这个home目录对应启动编译容器时映射的本地开发目录,进入后执行以下命令。
cd /home/
make clean
emmake make
编译完成后,将生成合约的字节码文件main.wasm
/home/main.wasm
6.2.4.3. SDK工程框架描述
chainmaker-contract-sdk-cpp工程的结构和文件描述如下:
- chainmaker
- basic_iterator.cc: 迭代器实现
- basic_iterator.h: 迭代器头文件声明
- chainmaker.h: sdk主要接口头文件声明,详情见SDK API描述
- context_impl.cc: 与链交互接口实现
- context_impl.h: 与链交互头文件声明
- contract.cc: 合约基础工具类
- error.h: 异常处理类
- exports.js: 编译合约导出函数
- safemath.h: assert异常处理
- syscall.cc: 与链交互入口
- syscall.h: 与链交互头文件声明
- pb
- contract.pb.cc:与链交互数据协议
- contract.pb.h:与链交互数据协议头文件声明
- main.cc: 用户写合约入口
- Makefile: 常用build命令
6.2.4.4. 编译说明
在ChainMaker提供的Docker容器中中集成了编译器,可以对合约进行编译,集成的编译器是emcc 1.38.48版本,protobuf 使用3.7.1版本。用户如果手工编译需要先使用emcc 编译 protobuf ,编译之后执行emmake make即可。
6.2.4.5. 模拟运行示例合约
通过本地模拟环境运行合约(首次编译运行合约可能需要10秒左右,下面以存证作为示例)
# wxvm main.wasm save time 20210304 file_hash 12345678 file_name a.txt
2021-03-25 09:10:36.441 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] call save() tx_id:
2021-03-25 09:10:36.463 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] call save() file_hash:12345678
2021-03-25 09:10:36.464 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] call save() file_name:a.txt
2021-03-25 09:10:36.465 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] put success: a.txt 12345678
2021-03-25 09:10:36.466 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] save====================================end
2021-03-25 09:10:36.467 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1]
2021-03-25 09:10:36.467 [DEBUG] [Vm] xvm/context_service.go:257 wxvm log >>[1234567890123456789012345678901234567890123456789012345678901234] [1] result: a.txt 12345678
2021-03-25 09:10:36.469 [INFO] [Vm] @chain01 main/main.go:31 contractResult :result:" a.txt 12345678"
6.2.5. 部署调用合约
编译完成后,将得到一个.wasm
格式的合约文件,可将之部署到指定到长安链上,完成合约部署。 部署合约的使用教程可详见:部署示例合约。
6.3. C++ SDK API描述
arg
// 该接口可返回属性名为 “name” 的参数的属性值。
// @param name: 要获取值的参数名称
// @param value: 获取的参数值
// @return: 是否成功
bool arg(const std::string& name, std::string& value){}
需要注意的是通过arg接口返回的参数,全都都是字符串,合约开发者有必要将其他数据类型的参数与字符串做转换,包括atoi、itoa、自定义序列化方式等。
get_object
// 获取key为"key"的值
// @param key: 获取对象的key
// @param value: 获取的对象值
// @return: 是否成功
bool get_object(const std::string& key, std::string* value){}
put_object
// 存储key为"key"的值
// @param key: 存储的对象key,注意key长度不允许超过64,且只允许大小写字母、数字、下划线、减号、小数点符号
// @param value: 存储的对象值install
// @return: 是否成功
bool put_object(const std::string& key, const std::string& value){}
delete_object
// 删除key为"key"的值
// @param key: 删除的对象key
// @return: 是否成功
bool delete_object(const std::string& key) {}
emit_event
// 发送合约事件
// @param topic: 合约事件主题
// @data_amount: 合约事件数据数量(data),data_amount的值必须要和data数量一致,最多不可大于16,最少不可小于1,不可为空
// @data ...: 可变参数合约事件数据,数量与data_amount一致。
bool emit_event(const std::string &topic, int data_amount, const std::string data, ...)
success
// 返回成功的结果
// @param body: 成功信息
void success(const std::string& body) {}
error
// 返回失败结果
// @param body: 失败信息
void error(const std::string& body) {}
call
// 跨合约调用
// @param contract: 合约名称
// @param method: 合约方法
// @param args: 调用合约的参数
// @param resp: 调用合约的响应
// @return: 是否成功
bool call(const std::string &contract,
const std::string &method,
EasyCodecItems *args,
std::string *resp){}
log
// 输出日志事件。查看方式为在链配置的log.yml中,开启vm:debug即可看到类似:wxvm log>> + msg
// @param body: 事件信息
void log(const std::string& body) {}
相关文章
- SAP数据迁移规划:准备、工具和合作伙伴是关键
- 疫情之下,IT部门该如何为企业创造更多价值?
- 阅读推荐:容易被忽略的12册人工智能书籍
- 超级App,助力突破小游戏变现瓶颈
- 用于轨迹预测的多模态深度生成模型:一种条件变分自编码器方法
- 两万字 | 视觉SLAM研究综述与未来趋势讨论
- VP-SLAM:具有点、线和灭点的单目实时VSLAM
- 小白系列(2)| 图像识别中的Vision Transformers
- 实时语义SLAM:激光+IMU+GPS/MAV
- 图神经网络框架-PyTorch Geometric(PyG)的使用及踩坑
- 书籍推荐 -《深度强化学习》
- 基于LEBERT的多模态领域知识图谱构建
- 2023年机器学习趋势分析
- ECCV 2022 | 76小时动捕,最大规模数字人多模态数据集开源
- LPCG:用激光点云指导单目的3D物体检测
- 多模态数据的行为识别综述
- 水尺监测识别系统
- 麦肯锡报告-2022年人工智能现状及5年回顾
- mask
- pug