# 为 Gear 合约添加自定义状态查询函数
## 上节回顾: [使用 `gmeta` 为 Gear 合约生成 Metadata](https://hackmd.io/@btwiuse/gear-metadata)
https://github.com/gear-dapps/app
在 `./src/lib.rs` 中定义 wasm 入口函数
```
#[no_mangle]
extern "C" fn init() { ... }
#[no_mangle]
extern "C" fn handle() { ... }
#[no_mangle]
extern "C" fn state() { ... }
```
在 `./io/src/lib.rs` 中定义 Metadata
```
use gmeta::{InOut, Metadata};
use gstd::{prelude::*, ActorId};
...
pub struct ContractMetadata;
impl Metadata for ContractMetadata {
type Init = ();
type Handle = InOut<PingPong, PingPong>;
type Others = ();
type Reply = ();
type Signal = ();
type State = Vec<(ActorId, u128)>;
}
// Metadata::repr() -> MetadataRepr
```
在 `./build.rs` 中生成 `app.meta.txt` 以及 `app.opt.wasm`
```
use app_io::ContractMetadata;
fn main() {
gear_wasm_builder::build_with_metadata::<ContractMetadata>();
}
```
## 查询合约状态
https://idea.gear-tech.io/programs/0x56cc25f6e1f2102563bb2bbf1365d756b8a647d6cba993836515e524a31e99f9?node=wss%3A%2F%2Fnode-workshop.gear.rs
```
[
[
"0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
2
]
]
```
## 查询部分状态
### 在 `./state` 中创建 "app-state" crate
#### `./Cargo.toml` 注册路径
```
# It's necessary to include all metawasm crates in the workspace section,
# otherwise they'll be ignored by Cargo and won't be built.
[workspace]
members = ["state"]
```
#### `./state/Cargo.toml` 导入依赖
```
[package]
name = "app-state"
version = "0.1.0"
edition = "2021"
[dependencies]
gstd = { git = "https://github.com/gear-tech/gear.git", branch = "testnet" }
gmeta = { git = "https://github.com/gear-tech/gear.git", branch = "testnet", features = ["codegen"] }
app-io = { path = "../io" }
[build-dependencies]
gear-wasm-builder = { git = "https://github.com/gear-tech/gear.git", branch = "testnet", features = ["metawasm"] }
```
#### `./state/src/lib.rs` 自定义查询函数
```
use app_io::*;
use gmeta::{metawasm, Metadata};
use gstd::{prelude::*, ActorId};
#[metawasm]
pub mod metafns {
pub type State = <ContractMetadata as Metadata>::State;
pub fn pingers(state: State) -> Vec<ActorId> {
state.into_iter().map(|(pinger, _)| pinger).collect()
}
pub fn ping_count(state: State, actor: ActorId) -> u128 {
state
.into_iter()
.find_map(|(pinger, ping_count)| (pinger == actor).then_some(ping_count))
.unwrap_or_default()
}
}
```
#### `./state/build.rs` 构建脚本
```
fn main() {
gear_wasm_builder::build_metawasm();
}
```
最终编译为 `./target/wasm32-unknown-unknown/release/app_state.meta.wasm`
## 上传到 Gear IDEA
https://idea.gear-tech.io/programs/0x56cc25f6e1f2102563bb2bbf1365d756b8a647d6cba993836515e524a31e99f9?node=wss%3A%2F%2Fnode-workshop.gear.rs
# 作业
在 GitHub 上 Fork https://github.com/gear-dapps/app, 增加名为 `counts` 的自定义状态查询函数, 用于获取合约收到 PING 消息的总数, 并在 [Gear IDEA](https://idea.gear-tech.io) 上部署,将调用 `counts` 函数结果的截图放在 README 中
作业提交频道: https://t.me/Gear_CN
<!--
pub fn counts(state: State) -> u128 {
state.into_iter().map(|(_, count)| count).sum()
}
-->
## 附: `#[metawasm]` 属性宏定义与参考文档
https://github.com/gear-tech/gear/blob/master/gmeta/codegen/src/lib.rs