【元壤】长安链开发之使用Rust进行智能合约开发
公众号:元壤
元壤yr.xyz:一分钟搭建您专属的NFT数字藏品服务平台。
Slogan:品牌自己数字藏品服务平台。
特点:免费数字藏品平台。
介绍:元壤是国内首家区块链职业教育机构孔壹学院旗下控股子公司程序咖科技元宇宙数字藏品SaaS品牌,元壤是 Web3.0 时代 NFT 数字藏品与用户服务的数字化工具。元壤是中国企业数字资产化及数字藏品营销解决方案提供商。元壤致力于通过产品和服务,助力企业资产数字化,数字营销化,通过科技驱动数字商业变革,让数字资产变得更智慧。
使用Rust进行智能合约开发
1.3.1. 使用Docker镜像进行合约开发
ChainMaker官方已经将容器发布至 docker hub
拉取镜像
docker pull chainmakerofficial/chainmaker-rust-contract:2.1.0
请指定你本机的工作目录$WORK_DIR,例如/data/workspace/contract,挂载到docker容器中以方便后续进行必要的一些文件拷贝
docker run -it --name chainmaker-rust-contract -v $WORK_DIR:/home chainmakerofficial/chainmaker-rust-contract:2.1.0 bash
# 或者先后台启动
docker run -d --name chainmaker-rust-contract -v $WORK_DIR:/home chainmakerofficial/chainmaker-rust-contract:2.1.0 bash -c "while true; do echo hello world; sleep 5;done"
# 再进入容器
docker exec -it chainmaker-rust-contract bash
我这里:
docker run -it --name chainmaker-rust-contract -v /Users/hanru/Documents/程序咖/chainmaker/contract:/home chainmakerofficial/chainmaker-rust-contract:2.1.0 bash
也可以在docker下查看:
编译合约
cd /home/
tar xvf /data/contract_rust_template.tar.gz
cd contract_rust
make build
hanru@localhost chainmaker % docker run -it --name chainmaker-rust-contract -v /Users/hanru/Documents/程序咖/chainmaker/contract:/home chainmakerofficial/chainmaker-rust-contract:2.1.0 bash
root@39274bf02d31:/# cd /home/
root@39274bf02d31:/home# tar xvf /data/contract_rust_template.tar.gz
contract_rust/
contract_rust/env.md
contract_rust/LICENSE
contract_rust/README.md
contract_rust/Cargo.toml
contract_rust/NOTICE
contract_rust/src/
contract_rust/src/contract_fact.rs
contract_rust/src/vec_box.rs
contract_rust/src/sim_context_paillier.rs
contract_rust/src/easycodec.rs
contract_rust/src/sim_context_rs.rs
contract_rust/src/sim_context_bulletproofs.rs
contract_rust/src/sim_context.rs
contract_rust/src/lib.rs
contract_rust/Makefile
contract_rust/Cargo.lock
contract_rust/.gitignore
root@39274bf02d31:/home# cd contract_rust
root@39274bf02d31:/home/contract_rust# make build
cargo build --release --target=wasm32-unknown-unknown
Updating `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git` index
Downloaded time v0.1.44 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded num-integer v0.1.44 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded num-traits v0.2.14 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded libc v0.2.99 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded chrono v0.4.19 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded base64 v0.12.3 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded autocfg v1.0.1 (registry `https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git`)
Downloaded 7 crates (847.7 KB) in 0.86s
Compiling autocfg v1.0.1
Compiling libc v0.2.99
Compiling base64 v0.12.3
Compiling num-traits v0.2.14
Compiling num-integer v0.1.44
Compiling time v0.1.44
Compiling chrono v0.4.19
Compiling chainmaker-contract v2.0.0 (/home/contract_rust)
Finished release [optimized] target(s) in 1m 24s
root@39274bf02d31:/home/contract_rust#
生成合约的字节码文件在
/home/contract_rust/target/wasm32-unknown-unknown/release/chainmaker_contract.wasm
查看一下:
1.3.1.1. 框架描述
解压缩contract_rust_template.tar.gz后,文件描述如下:
chainmaker-contract-sdk-rust$ tree -I target
.
├── Cargo.lock # 依赖版本信息
├── Cargo.toml # 项目配置及依赖,参考:https://rustwasm.github.io/wasm-pack/book/cargo-toml-configuration.html
├── Makefile # build一个wasm文件
├── README.md # 编译环境说明
├── src
│ ├── contract_fact.rs # 存证示例代码
│ ├── easycodec.rs # 序列化工具类
│ ├── lib.rs # 程序入口
│ ├── sim_context.rs # 合约SDK主要接口及实现
│ ├── sim_context_bulletproofs.rs # 合约SDK基于bulletproofs的范围证明接口实现
│ ├── sim_context_paillier.rs # 合约SDK基于paillier的半同态运算接口实现
│ ├── sim_context_rs.rs # 合约SDK sql接口实现
│ └── vec_box.rs # 内存管理类
1.3.1.2. 示例代码说明
1.3.1.2.1. 存证合约
存证合约示例:contract_fact.rs 实现如下两个功能
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);
}