跳到主要内容

使用自己的函数读取程序状态

在本课程中,你将学习如何在区块链交易中使用托管智能合约,以增加各方的安全性。

你将了解如何使用托管智能合约的过程,从同意条款到将资金自动转移到卖方的数字钱包。

让我们通过添加程序元数据来扩展我们的托管程序的功能。我们将从在托管程序的目录中创建一个 escrow-io 包开始:

cargo new io --lib

escrow-io 包的 Cargo.toml 文件将包含以下内容:

io/Cargo.toml
[package]
name = "escrow-io"
version = "0.1.0"
edition = "2021"

[dependencies]
gmeta = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1" }
gstd = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1" }
parity-scale-codec = { version = "3", default-features = false }
scale-info = { version = "2", default-features = false }

现在,我们可以将 InitEscrowEscrowActionEscrowEventEscrowStateEscrow 移动到 escrow-io 包中,并定义 ProgramMetadata 如下:

io/src/lib.rs
#![no_std]

use gmeta::{In, InOut, Metadata, Out};
use gstd::{prelude::*, ActorId};
use scale_info::TypeInfo;

pub struct ProgramMetadata;

impl Metadata for ProgramMetadata {
type Init = In<InitEscrow>;
type Handle = InOut<EscrowAction, EscrowEvent>;
type Reply = ();
type Others = ();
type Signal = ();
type State = Out<Escrow>;
}

#[derive(Encode, Decode, TypeInfo)]
pub struct InitEscrow {
pub seller: ActorId,
pub buyer: ActorId,
pub price: u128,
}

#[derive(Encode, Decode, TypeInfo)]
pub enum EscrowAction {
Deposit,
ConfirmDelivery,
}

#[derive(Encode, Decode, TypeInfo)]
pub enum EscrowEvent {
FundsDeposited,
DeliveryConfirmed,
}

#[derive(Default, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)]
pub enum EscrowState {
#[default]
AwaitingPayment,
AwaitingDelivery,
Closed,
}

#[derive(Default, Encode, Decode, TypeInfo)]
pub struct Escrow {
pub seller: ActorId,
pub buyer: ActorId,
pub price: u128,
pub state: EscrowState,
}

要向 escrow 包添加状态函数,我们需要包含以下内容:

src/lib.rs
#[no_mangle]
extern "C" fn state() {
let escrow = unsafe {
ESCROW.get_or_insert(Default::default())
};
msg::reply(escrow, 0).expect("Failed to share state");
}

然后,在托管程序的 Cargo.toml 中添加依赖项:

Cargo.toml
[package]
name = "escrow"
version = "0.1.0"
edition = "2021"

[dependencies]
gstd = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1", features = ["debug"] }
parity-scale-codec = { version = "3", default-features = false }
scale-info = { version = "2", default-features = false }
escrow-io = { path = "io" }

[build-dependencies]
gear-wasm-builder = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1", features = ["wasm-opt"] }
escrow-io = { path = "io" }

[dev-dependencies]
gtest = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1" }

我们将更改 build.rs 文件:

build.rs
fn main() {
gear_wasm_builder::build_with_metadata::<escrow_io::ProgramMetadata>();
}

并创建一个独立的包来读取状态:

cargo new state --lib

这个包的 Cargo.toml 将包含以下内容:

state/Cargo.toml
[package]
name = "escrow-state"
version = "0.1.0"
edition = "2021"

[dependencies]
gmeta = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1", features = ["codegen"] }
gstd = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1" }
parity-scale-codec = { version = "3", default-features = false }
scale-info = { version = "2", default-features = false }
escrow-io = { path = "../io" }

[build-dependencies]
gear-wasm-builder = { git = "https://github.com/gear-tech/gear.git", tag = "v1.4.1", features = ["metawasm", "wasm-opt"] }

lib.rs 文件中,我们应该如下定义 metafns 模块:

state/src/lib.rs
#![no_std]
use gmeta::metawasm;
use gstd::{prelude::*, ActorId};
use escrow_io::*;

#[metawasm]
pub mod metafns {
// ...
}

还需要定义程序状态的类型,这种情况下是 Escrow 类型。我们可以通过添加 type State = Escrow来完成:

state/src/lib.rs
#![no_std]
use gmeta::metawasm;
use gstd::{prelude::*, ActorId};
use escrow_io::*;

#[metawasm]
pub mod metafns {
pub type State = Escrow;
// ...
}

在定义了 trait 和状态类型之后,我们可以编写与 Escrow 状态相关的任何函数。例如:

state/src/lib.rs
#![no_std]
use gmeta::metawasm;
use gstd::{prelude::*, ActorId};
use escrow_io::*;

#[metawasm]
pub mod metafns {
pub type State = Escrow;

pub fn seller(state: State) -> ActorId {
state.seller
}

pub fn buyer(state: State) -> ActorId {
state.buyer
}

pub fn escrow_state(state: State) -> EscrowState {
state.state
}
}

最后,我们将创建该状态的 build.rs 文件如下:

state/build.rs
fn main() {
gear_wasm_builder::build_metawasm();
}

一旦构建了包,我们将在我们的 UI 应用程序中使用 escrow_state.meta.wasm 文件与智能合约进行交互。