智能合约构成
ChainMaker Rust 语言的智能合约代码主要由以下接口构成:
/*Copyright (C) BABEC. All rights reserved.SPDX-License-Identifier: Apache-2.0一个 ChainMaker 的 Rust 版本智能合约主要包括以下函数:*/use crate::easycodec::*;use crate::sim_context;use sim_context::*;// 安装合约时会执行此方法,必须#[no_mangle]pub extern "C" fn init_contract() {// 安装时的业务逻辑,内容可为空sim_context::log("init_contract");}// 升级合约时会执行此方法,必须#[no_mangle]pub extern "C" fn upgrade() {// 升级时的业务逻辑,内容可为空sim_context::log("upgrade");let ctx = &mut sim_context::get_sim_context();ctx.ok("upgrade success".as_bytes());}// 对 SDK 暴露的函数// 对外暴露 test1 方法,供用户由 SDK 调用#[no_mangle]pub extern "C" fn test1() {}// 对外暴露 test2 方法,供用户由 SDK 调用#[no_mangle]pub extern "C" fn test2() {}// 其他函数,不对外暴露fn test3() {}
智能合约示例
存证合约示例
可实现以下功能:
1. 存储文件哈希、文件名称和时间等信息。
2. 通过文件哈希查询该条记录。
use crate::easycodec::*;use crate::sim_context;use sim_context::*;// 安装合约时会执行此方法,必须#[no_mangle]pub extern "C" fn init_contract() {// 安装时的业务逻辑,内容可为空sim_context::log("init_contract");}// 升级合约时会执行此方法,必须#[no_mangle]pub extern "C" fn upgrade() {// 升级时的业务逻辑,内容可为空sim_context::log("upgrade");let ctx = &mut sim_context::get_sim_context();ctx.ok("upgrade success".as_bytes());}struct Fact {file_hash: String,file_name: String,time: i32,ec: EasyCodec,}impl Fact {fn new_fact(file_hash: String, file_name: String, time: i32) -> Fact {let mut ec = EasyCodec::new();ec.add_string("file_hash", file_hash.as_str());ec.add_string("file_name", file_name.as_str());ec.add_i32("time", time);Fact {file_hash,file_name,time,ec,}}fn get_emit_event_data(&self) -> Vec<String> {let mut arr: Vec<String> = Vec::new();arr.push(self.file_hash.clone());arr.push(self.file_name.clone());arr.push(self.time.to_string());arr}fn to_json(&self) -> String {self.ec.to_json()}fn marshal(&self) -> Vec<u8> {self.ec.marshal()}fn unmarshal(data: &Vec<u8>) -> Fact {let ec = EasyCodec::new_with_bytes(data);Fact {file_hash: ec.get_string("file_hash").unwrap(),file_name: ec.get_string("file_name").unwrap(),time: ec.get_i32("time").unwrap(),ec,}}}// save 保存存证数据#[no_mangle]pub extern "C" fn save() {// 获取上下文let ctx = &mut sim_context::get_sim_context();// 获取传入参数let file_hash = ctx.arg_as_utf8_str("file_hash");let file_name = ctx.arg_as_utf8_str("file_name");let time_str = ctx.arg_as_utf8_str("time");// 构造结构体let r_i32 = time_str.parse::<i32>();if r_i32.is_err() {let msg = format!("time is {:?} not int32 number.", time_str);ctx.log(&msg);ctx.error(&msg);return;}let time: i32 = r_i32.unwrap();let fact = Fact::new_fact(file_hash, file_name, time);// 事件ctx.emit_event("topic_vx", &fact.get_emit_event_data());// 序列化后存储ctx.put_state("fact_ec",fact.file_hash.as_str(),fact.marshal().as_slice(),);}// find_by_file_hash 根据 file_hash 查询存证数据#[no_mangle]pub extern "C" fn find_by_file_hash() {// 获取上下文let ctx = &mut sim_context::get_sim_context();// 获取传入参数let file_hash = ctx.arg_as_utf8_str("file_hash");// 校验参数if file_hash.len() == 0 {ctx.log("file_hash is null");ctx.ok("".as_bytes());return;}// 查询let r = ctx.get_state("fact_ec", &file_hash);// 校验返回结果if r.is_err() {ctx.log("get_state fail");ctx.error("get_state fail");return;}let fact_vec = r.unwrap();if fact_vec.len() == 0 {ctx.log("None");ctx.ok("".as_bytes());return;}// 查询let r = ctx.get_state("fact_ec", &file_hash).unwrap();let fact = Fact::unmarshal(&r);let json_str = fact.to_json();// 返回查询结果ctx.ok(json_str.as_bytes());ctx.log(&json_str);}
存证合约代码说明
参数名称 | 描述 |
init_contract | 合约的初始化函数,在合约部署时被调用,在本合约中打印了日志"init_contract"。 |
upgrade | 合约升级时调用的函数。 |
save | save 函数实现将文件哈希和文件名称记录到链上的功能。步骤如下: 1. save 函数先通过 get_sim_context 和 [交易信息提取]API 接口 arg_as_utf8_str 函数拿到时间,文件哈希和文件名字等信息。 2. 构造 Fact 结构体并进行序列化;且当序列化错误时调用 [其他辅助类]API 接口 log 函数和 error 函数记录相应日志。 3. 通过调用 [其他辅助类]API 接口 emit_event 函数发送标识为 topic_vx 的合约事件。 4. 通过调用 [账本交互]API 接口 put_state 函数将文件等信息记录到链上。 |
find_by_file_hash | 通过文件哈希查询该条记录。步骤如下: 1. find_by_file_hash 通过 get_sim_context 和 [参数处理]API 接口 arg_as_utf8_str 函数拿到要查找的文件的文件哈希。 2. 通过 [账本交互]API 接口 get_state 函数获取文件的信息;若失败则通过 [其他辅助类]API 接口 error 函数将操作结果记录到链上,否则,通过 [其他辅助类]API 接口 log 函数和 ok 函数记录相关日志并返回结果。 |