来介绍下 Gear 合约的基本结构

Gear 合约揭秘

Gearfans 举办了 3 次 Gear workshop,从第一次的 ping-pong 合约,到 去中心化 twitter,再到 Erc20 。

那我们来介绍下 Gear 合约的基本结构。

Gear 合约最小必要结构

#[no_mangle] pub unsafe extern "C" fn init() {}  #[no_mangle] pub unsafe extern "C" fn handle() {}

这 2 个方法是 Gear 合约的最小必要结构。init() 函数在合约初始化时执行一次。handle() 函数负责处理所有由我们程序处理的传入消息。

小知识点#[no_mangle] 表示禁止 Rust 编译器修改方法的名字,简单来讲 Rust 函数能在其它语言中被调用,必须禁用编译器的名称修改功能。

回到 ping-pong 合约,代码如下:

#![no_std]  use gstd::{msg, prelude::*};  #[no_mangle] pub unsafe extern "C" fn handle() {     let new_msg = String::from_utf8(msg::load_bytes()).expect("Invalid message");      if new_msg == "PING" {         msg::reply_bytes("PONG", 12_000_000, 0);     } }  #[no_mangle] pub unsafe extern "C" fn init() {}

我们只处理了 handle() 了,init() 可以不做任何处理。handle() 的逻辑是:得到新消息 new_msg, 如果 new_msg 是 PING,通过 msg::reply_bytes 发送 PONG 信息。

gstd::msg

在 solidity 合约中,我们也经常使用 msgmsg.sender msg.value

msg::source() 与 solidity 的 msg.sender 含义相同,指信息的发送者或者源头,即调用合约的地址。

gstd::msg 常用的方法:

msg::load() // 获取当前正在处理的消息  msg::source() // 获取消息的发送者  msg::reply() // 发送一条新消息作为对当前正在的消息的回应 msg::reply_bytes() // 发送一条新消息作为对当前正在的消息的回应 msg::reply_to() // 获取当前消息的id  msg::send() // 发送一个新的消息给合约或用户

完整的合约

完整的合约,基本会有 4 部分:metadata! handle() init() meta_state()

#![no_std]  use gstd::msg;  gstd::metadata! {   title: "ERC20",   init:     input: InitConfig,   handle:     input: Action,     output: Event,   state:     input: State,     output: StateReply, }  #[no_mangle] pub unsafe extern "C" fn handle() {}  #[no_mangle] pub unsafe extern "C" fn init() {}  #[no_mangle] pub unsafe extern "C" fn meta_state() -> *mut [i32; 2] {}

metadata! 宏

metadata! 是 Gear 定义的宏,它会定义合约结构,类似 abi。

gstd::metadata! {   title: "ERC20",   init:     input: InitConfig, // 定义初始化参数   handle:     input: Action, // 定义合约方法,供 handle使用     output: Event, // 定义事件,在调用合约方法后,会调用合约事件,供 handle 使用   state:     input: State, // 定义 meta_state 的输入格式,供 meta_state使用     output: StateReply, // 定义 meta_state 的输出格式,供 meta_state使用 }

meta_state

meta_state() 函数,它将立即返回状态,而且不需要任何 Gas。

看下 erc20 的 meta_state,代码如下:

#[no_mangle] pub unsafe extern "C" fn meta_state() -> *mut [i32; 2] {     let query: State = msg::load().expect("failed to decode input argument");      let encoded = match query {         State::Name => StateReply::Name(FUNGIBLE_TOKEN.name.clone()).encode(),         State::Symbol => StateReply::Name(FUNGIBLE_TOKEN.symbol.clone()).encode(),         State::Decimals => StateReply::Decimals(18).encode(),         State::TotalSupply => StateReply::TotalSupply(FUNGIBLE_TOKEN.total_supply).encode(),         State::BalanceOf(account) => {             StateReply::Balance(FUNGIBLE_TOKEN.balance_of(&account)).encode()         }     };      let result = gstd::macros::util::to_wasm_ptr(&(encoded[..]));     core::mem::forget(encoded);     result }

通过 meta_state 我们会读取到合约的 Name Symbol Decimals BalanceOf TotalSupply 这些基本属性。

Gear 合约大揭秘

具体讲讲 handle

handle 是 Gear 合约的重要函数,handle 通过 msg::load() 的信息,然后根据信息种类,用不同的函数处理数据,并发送信息。

以下代码是 去中心化 twitter 的 handle,关键都在 match action {},如果信息是 ChannelAction::Meta 会做什么处理,如果信息是 ChannelAction::Post,又会做什么处理。

#[no_mangle] pub unsafe extern "C" fn handle() {      let action: ChannelAction = msg::load().expect(&format!(         "CHANNEL {:?}: Unable to decode Channel Action",         STATE.name()     ));      match action {         ChannelAction::Meta => {             msg::reply(meta, 100_000_000, 0);         }          ChannelAction::Subscribe => {}          ChannelAction::Unsubscribe => {             msg::reply((), 0, 0);         }          ChannelAction::Post(text) => {             msg::reply((), 0, 0);         }     } }

总结

Gear 合约有一个最基本的结构,实现这个结构,就实现了 1 个简单的合约。 gstd 是 Gear

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注