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 偏移量。
| 领域 | 已上线 | 计划中 |
|---|---|---|
| 内存 | allocate、deallocate、abort | — |
| 存储 | get_storage、set_storage | remove_storage、storage_has、storage_usage |
| 上下文 | 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 |
| 银行与事件 | transfer、emit_event、set_return | log |
| 跨合约调用 | call_contract | call_contract_with_value |
| 加密 | — | sha3_256、verify_mldsa65、addr_validate |
| AI 宿主 | — | 读取模型、证书、Sentinel、信任列表和账户抽象状态 |
合约导出的入口点见合约导出;限制和 fuel 价格见 Gas 与限制。
最小合约
一个用 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"} 调用它可加一,用其他任何内容调用则只读取。构建和部署方法见部署合约。neurochain/contracts/nrc20 中的 NRC-20 代币是一个完整的、更大的示例。
该接口背后的设计文档是仓库中的 docs/neuro-wasm-spec.md。