# NeuroWASM 概览

> NeuroWASM——NeuroChain 的智能合约运行时——wasmi 解释器、fuel 计量、env 宿主模块、同步跨合约调用、哪些宿主函数已上线、哪些在计划中，以及一个最小合约。

Source: https://docs.nro.world/zh/neurowasm/

**NeuroWASM** 是 NeuroChain 的合约运行时：由 `wasmi` 解释器执行的 WebAssembly，以 fuel 计量，宿主函数从模块 **`env`** 导入。其语义遵循 CosmWasm 和 NEAR，另外加入原生的 **AI 宿主**函数。

它与 `wasmd` 或 `nearcore` 不是二进制兼容的——理念相同，接口不同。

## 执行模型

- **同步调用。** 一个合约调用另一个合约时，会先把被调用方执行完毕再继续（与 EVM 相同）。
- **每笔交易一份日志。** 整个调用树的所有存储写入、余额变更和转账一起提交——或者，只要有任何 trap，全都不提交。
- **可读到自己的写入。** 嵌套调用能看到调用方尚未提交的写入。
- **深度限制**为 8 层嵌套调用（`MAX_CALL_DEPTH`）。
- **确定性。** 每个验证者在相同状态上运行相同字节码，得到相同结果；没有时钟、随机数或网络访问。

后续计划：带 `reply` 入口点的异步子消息，然后是 NEAR 风格的 promise 和 IBC v2 数据包。

## 宿主函数

所有导入都来自 `env`。指针和长度是指向合约导出的 `memory` 的 `i32` 偏移量。

| 领域 | 已上线 | 计划中 |
|------|--------|--------|
| [内存](./memory) | `allocate`、`deallocate`、`abort` | — |
| [存储](./storage) | `get_storage`、`set_storage` | `remove_storage`、`storage_has`、`storage_usage` |
| [上下文](./context) | `get_caller`、`get_block_height`、`get_balance`、`get_stake`、`get_stake_at` | `get_self_addr`、`get_signer`、`get_block_time`、`get_shard_id`、`get_attached_deposit`、`gas_remaining` |
| [银行与事件](./bank) | `transfer`、`emit_event`、`set_return` | `log` |
| [跨合约调用](./cross-contract) | `call_contract` | `call_contract_with_value` |
| [加密](./crypto) | — | `sha3_256`、`verify_mldsa65`、`addr_validate` |
| [AI 宿主](./ai-host) | — | 读取模型、证书、Sentinel、信任列表和账户抽象状态 |

合约导出的入口点见[合约导出](./exports)；限制和 fuel 价格见 [Gas 与限制](./gas-limits)。

## 最小合约 {#a-minimal-contract}

一个用 `no_std` Rust 编写的计数器。它读取调用，在存储中保存一个数字并返回它。

```rust
#![no_std]

#[link(wasm_import_module = "env")]
extern "C" {
    fn get_storage(key_ptr: i32, key_len: i32, val_ptr: i32, val_max: i32) -> i32;
    fn set_storage(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32);
    fn set_return(ptr: i32, len: i32);
}

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() }

const KEY: &[u8] = b"count";

fn read_count() -> u64 {
    let mut buf = [0u8; 20];
    let n = unsafe { get_storage(KEY.as_ptr() as i32, KEY.len() as i32, buf.as_mut_ptr() as i32, 20) };
    if n <= 0 { return 0; }
    core::str::from_utf8(&buf[..n as usize]).ok().and_then(|s| s.parse().ok()).unwrap_or(0)
}

#[no_mangle]
pub extern "C" fn call(input_ptr: i32, input_len: i32) {
    let input = unsafe { core::slice::from_raw_parts(input_ptr as *const u8, input_len as usize) };
    let mut n = read_count();
    if input.windows(11).any(|w| w == b"\"increment\"") {
        n += 1;
        let mut out = [0u8; 20];
        let s = fmt_u64(n, &mut out);
        unsafe { set_storage(KEY.as_ptr() as i32, KEY.len() as i32, s.as_ptr() as i32, s.len() as i32) };
    }
    let mut out = [0u8; 20];
    let s = fmt_u64(n, &mut out);
    unsafe { set_return(s.as_ptr() as i32, s.len() as i32) };
}

fn fmt_u64(mut v: u64, buf: &mut [u8; 20]) -> &[u8] {
    let mut i = 20;
    loop { i -= 1; buf[i] = b'0' + (v % 10) as u8; v /= 10; if v == 0 { break; } }
    &buf[i..]
}
```

用 `{"function":"increment"}` 调用它可加一，用其他任何内容调用则只读取。构建和部署方法见[部署合约](/zh/build/deploy)。`neurochain/contracts/nrc20` 中的 NRC-20 代币是一个完整的、更大的示例。

该接口背后的设计文档是仓库中的 `docs/neuro-wasm-spec.md`。
