Rust Wasm虚拟机库soroban-wasmi的使用,为智能合约执行提供高效Wasm运行环境
Rust Wasm虚拟机库soroban-wasmi的使用,为智能合约执行提供高效Wasm运行环境
Wasmi - WebAssembly (Wasm) 解释器
Wasmi是一个高效且轻量级的WebAssembly解释器,专注于受限和嵌入式系统。
主要特性
Wasmi具有以下显著特性:
- 简单、正确和确定性的WebAssembly执行
- 适用于嵌入式环境的低开销、跨平台WebAssembly运行时
- 抵抗JIT炸弹的翻译
- 松散地镜像Wasmtime API
- 100%通过WebAssembly规范测试套件
- 内置燃料计量支持
- 支持官方的Wasm C-API
WebAssembly提案支持
新的Wasmi引擎支持多种WebAssembly提案,未来还将支持更多。
WebAssembly提案 | 状态 | 注释 |
---|---|---|
mutable-global |
✅ | 自版本0.14.0 起 |
saturating-float-to-int |
✅ | 自版本0.14.0 起 |
sign-extension |
✅ | 自版本0.14.0 起 |
multi-value |
✅ | 自版本0.14.0 起 |
bulk-memory |
✅ | 自版本0.24.0 起 |
reference-types |
✅ | 自版本0.24.0 起 |
simd |
❌ | 不太可能支持 |
tail-calls |
✅ | 自版本0.28.0 起 |
extended-const |
✅ | 自版本0.29.0 起 |
function-references |
📅 | 计划中但尚未实现 |
gc |
📅 | 计划中但尚未实现 |
multi-memory |
📅 | 计划中但尚未实现 |
threads |
📅 | 计划中但尚未实现 |
relaxed-simd |
❌ | 不太可能支持,因为simd 不太可能支持 |
component-model |
📅 | 计划中但尚未实现 |
exception-handling |
📅 | 计划中但尚未实现 |
branch-hinting |
📅 | 计划中但尚未实现 |
WASI | 👨🔬 | 通过wasmi_wasi crate实验性支持WASI (wasip1 ) |
C-API | 👨🔬 | 通过wasmi_c_api_impl crate实验性支持官方Wasm C-API |
开发
构建与测试
克隆Wasmi仓库并使用cargo
构建:
git clone https://github.com/wasmi-labs/wasmi.git --recursive
cd wasmi
cargo build
cargo test
基准测试
使用以下命令对Wasmi进行基准测试:
cargo bench
支持的平台
Wasmi支持广泛的架构和平台。
- Wasmi可以在
no_std
嵌入式环境中使用,因此不需要标准库(std
) - 只有部分平台在CI中检查并由Wasmi维护者保证完全工作
示例代码
以下是一个使用soroban-wasmi执行Wasm智能合约的完整示例:
use soroban_wasmi::{
Config, Engine, Externals, FuncRef, ImportsBuilder, Module, ModuleRef, Store, Value,
};
// 定义自定义的外部函数调用接口
struct MyExternals;
impl Externals for MyExternals {
fn invoke_index(
&mut self,
_index: u32,
_args: &[Value],
) -> Result<Option<Value>, soroban_wasmi::Trap> {
// 在这里实现外部函数调用逻辑
Ok(None)
}
}
fn main() -> anyhow::Result<()> {
// 1. 创建Wasm引擎配置
let config = Config::default();
// 2. 创建引擎和存储
let engine = Engine::new(&config);
let mut store = Store::new(&engine, ());
// 3. 加载Wasm模块
let wasm_bytes = include_bytes!("contract.wasm");
let module = Module::new(&engine, &wasm_bytes[..])?;
// 4. 设置导入函数(可选)
let imports = ImportsBuilder::new(); // 可以添加需要的导入
// 5. 实例化模块
let mut externals = MyExternals;
let instance = ModuleRef::new(&mut store, &module, &imports)?;
// 6. 查找并调用合约函数
let add_func = instance.get_func(&store, "add").expect("add function not found");
let result = add_func.call(
&mut store,
&mut externals,
&[Value::I32(1), Value::I32(2)],
)?;
println!("Result: {:?}", result);
Ok(())
}
完整示例代码
以下是一个更完整的soroban-wasmi使用示例,包含合约加载、实例化和调用的完整流程:
use soroban_wasmi::{
Config, Engine, Externals, ImportsBuilder, Module, ModuleRef, Store, Value
};
use std::fs;
// 自定义外部函数实现
struct ContractExternals {
call_count: u32,
}
impl Externals for ContractExternals {
fn invoke_index(
&mut self,
index: u32,
args: &[Value],
) -> Result<Option<Value>, soroban_wasmi::Trap> {
self.call_count += 1;
println!("Called external function {} with args: {:?}", index, args);
// 示例:当调用index为0的外部函数时返回42
if index == 0 {
return Ok(Some(Value::I32(42)));
}
Ok(None)
}
}
fn main() -> anyhow::Result<()> {
// 1. 配置Wasm引擎
let config = Config::default()
.with_stack_limit(1024 * 1024) // 设置栈大小限制
.with_fuel_metering(true); // 启用燃料计量
// 2. 创建引擎和存储
let engine = Engine::new(&config);
let mut store = Store::new(&engine, ());
// 3. 加载Wasm合约
let wasm_bytes = fs::read("smart_contract.wasm")?;
let module = Module::new(&engine, &wasm_bytes[..])?;
// 4. 设置导入函数
let imports = ImportsBuilder::new()
// 可以在这里添加需要的导入函数
// .with("env", "log", FuncType::new(vec![ValueType::I32], vec![]))
;
// 5. 实例化模块
let mut externals = ContractExternals { call_count: 0 };
let instance = ModuleRef::new(&mut store, &module, &imports)?;
// 6. 调用合约函数
// 6.1 调用add函数
if let Ok(add_func) = instance.get_func(&store, "add") {
let result = add_func.call(
&mut store,
&mut externals,
&[Value::I32(2), Value::I32(3)],
)?;
println!("add(2, 3) = {:?}", result);
}
// 6.2 调用get_value函数
if let Ok(get_value_func) = instance.get_func(&store, "get_value") {
let result = get_value_func.call(
&mut store,
&mut externals,
&[],
)?;
println!("get_value() = {:?}", result);
}
println!("Total external calls: {}", externals.call_count);
Ok(())
}
安装
在项目目录中运行以下Cargo命令:
cargo add soroban-wasmi
或者在Cargo.toml中添加以下行:
soroban-wasmi = "0.36.1-soroban.22.0.0"
许可证
根据以下任一许可证授权:
- Apache License, Version 2.0
- MIT license
1 回复
Rust Wasm虚拟机库soroban-wasmi的使用指南
soroban-wasmi是一个为智能合约执行优化的Wasm虚拟机库,基于wasmi项目开发,专为Stellar区块链上的Soroban智能合约平台设计。
主要特性
- 高性能Wasm执行环境
- 专为智能合约场景优化
- 完善的沙盒安全机制
- 支持WASI接口
- 轻量级设计
安装方法
在Cargo.toml中添加依赖:
[dependencies]
soroban-wasmi = "0.3.0"
基本使用方法
1. 初始化虚拟机
use soroban_wasmi::{Engine, Module, Instance, Linker};
// 创建Wasm引擎
let engine = Engine::default();
// 加载Wasm模块
let wasm_bytes = include_bytes!("contract.wasm");
let module = Module::new(&engine, &wasm_bytes[..]).expect("Failed to load module");
2. 执行智能合约
// 创建链接器并定义主机函数
let mut linker = Linker::new(&engine);
linker.func_wrap("env", "log", |caller: &mut soroban_wasmi::Caller<()>, ptr: u32, len: u32| {
// 处理日志逻辑
Ok(())
}).expect("Failed to define host function");
// 创建实例
let mut store = soroban_wasmi::Store::new(&engine, ());
let instance = linker.instantiate(&mut store, &module)
.expect("Failed to instantiate module");
// 获取入口函数
let run = instance.get_typed_func::<(), i32>(&store, "run")
.expect("Failed to get function");
// 执行合约
let result = run.call(&mut store, ()).expect("Execution failed");
println!("Contract execution result: {}", result);
高级功能
1. 内存访问
let memory = instance.get_memory(&store, "memory")
.expect("Failed to get memory");
// 写入数据到Wasm内存
let data = b"Hello, Soroban!";
let offset = 0x1000;
memory.write(&mut store, offset, data)
.expect("Failed to write memory");
// 从Wasm内存读取数据
let mut buffer = vec![0; data.len()];
memory.read(&store, offset, &mut buffer)
.expect("Failed to read memory");
2. 燃料计量
use soroban_wasmi::Config;
// 配置燃料限制
let mut config = Config::default();
config.consume_fuel(true);
config.set_fuel(10_000_000).expect("Failed to set fuel");
let engine = Engine::new(&config);
3. 使用WASI
use soroban_wasmi::wasi::WasiCtxBuilder;
// 配置WASI环境
let wasi = WasiCtxBuilder::new()
.inherit_stdio()
.inherit_args().unwrap()
.build();
let mut store = Store::new(&engine, wasi);
性能优化建议
- 对于高频调用的合约,缓存Module实例
- 合理设置燃料限制
- 限制内存使用量
- 使用预编译的Wasm模块
错误处理
match run.call(&mut store, ()) {
Ok(result) => println!("Success: {}", result),
Err(e) => match e {
soroban_wasmi::Error::Trap(trap) => {
println!("Trap occurred: {:?}", trap);
}
soroban_wasmi::Error::Link(_) => {
println!("Linking error");
}
_ => println!("Other error: {:?}", e),
},
}
完整示例代码
use soroban_wasmi::{
Config, Engine, Module, Instance, Linker,
Store, wasi::WasiCtxBuilder, Error
};
fn main() -> Result<(), Error> {
// 1. 配置引擎
let mut config = Config::default();
config.consume_fuel(true);
config.set_fuel(1_000_000)?;
// 2. 创建引擎
let engine = Engine::new(&config);
// 3. 加载Wasm模块
let wasm_bytes = include_bytes!("contract.wasm");
let module = Module::new(&engine, &wasm_bytes[..])?;
// 4. 配置WASI环境
let wasi = WasiCtxBuilder::new()
.inherit_stdio()
.inherit_args()?
.build();
// 5. 创建存储
let mut store = Store::new(&engine, wasi);
// 6. 创建链接器并定义主机函数
let mut linker = Linker::new(&engine);
linker.func_wrap("env", "log", |caller: &mut soroban_wasmi::Caller<()>, ptr: u32, len: u32| {
// 从内存中读取日志内容
let memory = caller.get_memory("memory").unwrap();
let mut buffer = vec![0; len as usize];
memory.read(caller, ptr as usize, &mut buffer)?;
let message = String::from_utf8_lossy(&buffer);
println!("[合约日志] {}", message);
Ok(())
})?;
// 7. 实例化模块
let instance = linker.instantiate(&mut store, &module)?;
// 8. 获取内存
let memory = instance.get_memory(&store, "memory")?;
// 9. 写入输入数据到内存
let input = b"测试输入数据";
let input_offset = 0x1000;
memory.write(&mut store, input_offset, input)?;
// 10. 获取并调用合约函数
let process = instance.get_typed_func::<(u32, u32), i32>(&store, "process")?;
let result = process.call(&mut store, (input_offset as u32, input.len() as u32))?;
println!("合约处理结果: {}", result);
Ok(())
}
soroban-wasmi为智能合约执行提供了安全高效的Wasm运行环境,特别适合区块链场景下的合约执行需求。