前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >佛萨奇2.0系统丨佛萨奇dapp智能合约系统开发(详情)丨佛萨奇2.0源码模式

佛萨奇2.0系统丨佛萨奇dapp智能合约系统开发(详情)丨佛萨奇2.0源码模式

原创
作者头像
VX_I357O98O7I8
发布2022-12-15 15:39:37
3930
发布2022-12-15 15:39:37
举报
文章被收录于专栏:商业模式策划

5. 使用Rust进行智能合约开发

读者对象:本章节主要描述使用Rust进行ChainMaker合约编写的方法,主要面向于使用Rust进行ChainMaker的合约开发的开发者。

5.1. 环境依赖

使用Rust开发用于ChainMaker的wasm合约,需要安装Rust开发环境,并将 wasm32-unknown-unknown(目标平台)加入到Rust开发环境的工具链中。

rust 安装及教程请参考:rust 官网

安装指令如下:

代码语言:javascript
复制
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 让 Rust 的环境变量生效 
source "$HOME/.cargo/env"
# 加入 wasm32-unknown-unknown
rustup target add wasm32-unknown-unknown

5.2. 编写Rust智能合约

5.2.1. 搭建开发环境

1)推荐使用 GoLand集成开发环境 + Rust插件

2)下载 contracts-rust 示例工程

代码语言:javascript
复制
git clone git@git.chainmaker.org.cn:contracts/contracts-rust.git -b v2.3.0

3)进入下载的Rust工程

代码语言:javascript
复制
cd contracts-rust/fact

5.2.2. 代码编写规则

对链暴露方法写法为:

  • #[no_mangle] 表示方法名编译后是固定的,不写会生成 _ZN4rustfn1_34544tert54grt5 类似的混淆名
  • pub extern “C”
  • method_name(): 不可带参数,无返回值
代码语言:javascript
复制
#[no_mangle]// no_mangle注解,表明对外暴露方法名称不可变
pub extern "C" fn init_contract() { // pub extern "C" 集成C
    let ctx = &mut sim_context::get_sim_context();
    // do something 
    ctx.ok("contract init success.".as_bytes());
}

其中init_contract、upgrade方法必须有且对外暴露

  • init_contract:创建合约会执行该方法
  • upgrade: 升级合约会执行该方法
代码语言:javascript
复制
// 安装合约时会执行此方法。ChainMaker不允许用户直接调用该方法。
#[no_mangle]
pub extern "C" fn init_contract() {
    let ctx = &mut sim_context::get_sim_context();
    // do something
    ctx.ok("contract init success.".as_bytes());
}

// 升级合约时会执行此方法。ChainMaker不允许用户直接调用该方法。
#[no_mangle]
pub extern "C" fn upgrade() {
    let ctx = &mut sim_context::get_sim_context();
    // do something
    ctx.ok("contract upgrade success.".as_bytes());
}

获取与链交互的上下文sim_context

1、在Cargo.toml中引入对于 contract-sdk-rust 项目的依赖

代码语言:javascript
复制
[dependencies]
contract_sdk_rust = { git = "https://git.chainmaker.org.cn/chainmaker/contract-sdk-rust", branch="v2.3.0" }

2、在使用时引入sim_context

代码语言:javascript
复制
use contract_sdk_rust::sim_context;
use contract_sdk_rust::sim_context::SimContext;
use contract_sdk_rust::easycodec::*;

fn method_name() {
    // 获取上下文
    let ctx = &mut sim_context::get_sim_context();
    
}

5.2.3. 存证合约示例源码展示

存证合约示例:fact.rs 实现如下两个功能

1、存储文件哈希和文件名称和时间。

2、通过文件哈希查询该条记录

代码语言:javascript
复制
use contract_sdk_rust::sim_context;
use contract_sdk_rust::sim_context::SimContext;
use contract_sdk_rust::easycodec::*;

// 安装合约时会执行此方法,必须
#[no_mangle]
pub extern "C" fn init_contract() {
    sim_context::log("init_contract");
    let ctx = &mut sim_context::get_sim_context();
    
    // 安装时的业务逻辑,内容可为空
    
    ctx.ok("contract init success.".as_bytes());
}

// 升级合约时会执行此方法,必须
#[no_mangle]
pub extern "C" fn upgrade() {
    sim_context::log("upgrade");
    let ctx = &mut sim_context::get_sim_context();
    
    // 升级时的业务逻辑,内容可为空

    ctx.ok("contract 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);
}

5.2.4. 合约SDK接口描述

长安链提供Rust合约与链交互的相关接口,代码存在单独的项目(https://git.chainmaker.org.cn/chainmaker/contract-sdk-rust)中。写合约时可直接指定依赖,并进行引用,具体信息可参考文章末尾”接口描述章节”。

5.2.5. 编译示例合约

代码语言:javascript
复制
cd contracts_rust/fact/
cargo build --release --target=wasm32-unknown-unknown

生成合约的字节码文件在

代码语言:javascript
复制
contracts_rust/fact/target/wasm32-unknown-unknown/release/fact.wasm
5.2.5.1. 示例合约框架描述
代码语言:javascript
复制
contract-sdk-rust$ tree -I target

├── Cargo.lock # 依赖版本信息
├── Cargo.toml # 项目配置及依赖,参考:https://rustwasm.github.io/wasm-pack/book/cargo-toml-configuration.html
├── README.md  # 编译环境说明
├── src
│   ├── fact.rs			# 存证示例代码
│   └── lib.rs          # 程序入口

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 5. 使用Rust进行智能合约开发
    • 5.1. 环境依赖
      • 5.2. 编写Rust智能合约
        • 5.2.1. 搭建开发环境
        • 5.2.2. 代码编写规则
        • 5.2.3. 存证合约示例源码展示
        • 5.2.4. 合约SDK接口描述
        • 5.2.5. 编译示例合约
    相关产品与服务
    区块链
    云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档