Rust NEAR协议虚拟机运行库near-vm-runner解析:高效智能合约执行与WASM运行时支持
near-vm-runner
一个运行编译为Wasm的智能合约的引擎。这是nearcore中"合约运行时"部分的主要crate。
运行智能合约包括以下功能:
- Wasm的仪表化(在prepare.rs中实现),用于gas计量和各种安全检查
- 将Wasm编译为特定的VM表示(在cache.rs中处理)
- 向Wasm代码暴露区块链特定功能(在imports.rs中定义对应的宿主函数)
- 实际的代码执行(由wasmer_runner.rs处理)
当前支持三种Wasm执行运行时:
- Wasmer 0.x
- Wasmer 2.0(默认选项)
- Wasmtime
主要使用场景:
- 区块链本身作为主要客户端
- 合约SDK工具作为次要客户端
- 为开发者提供额外API(如获取gas成本明细)
测试方法
运行单元测试:
$ cargo t -p near-vm-runner --features wasmer0_vm,wasmer2_vm,wasmtime_vm,near_vm
运行模糊测试:
$ cd runtime/near-vm-runner && RUSTC_BOOTSTRAP=1 cargo fuzz run runner
性能分析技术
使用tracing crate进行性能分析的基本模式:
fn compute_thing() {
let _span = tracing::debug_span!(target: "vm", "compute_thing").entered();
for i in 0..99 {
do_work()
}
}
配置tracing订阅者:
tracing_subscriber::fmt::Subscriber::builder()
.with_max_level(tracing::level_filters::LevelFilter::DEBUG)
.with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE)
.init();
或者使用分层分析器:
tracing_span_tree::span_tree().enable();
完整示例代码
以下是使用near-vm-runner运行智能合约的完整示例:
use near_vm_runner::{VMConfig, VMContext, VMKind, run};
use near_vm_logic::{External, StorageGetMode, VMOutcome};
// 1. 创建VM配置
let config = VMConfig::default();
// 2. 创建VM上下文
let context = VMContext {
current_account_id: "test.near".to_string(), // 当前合约账户
signer_account_id: "user.near".to_string(), // 签名者账户
signer_account_pk: vec![0; 32], // 签名者公钥
predecessor_account_id: "user.near".to_string(), // 前驱账户
input: vec![], // 输入数据
block_height: 1, // 区块高度
block_timestamp: 1_600_000_000, // 区块时间戳
epoch_height: 1, // 周期高度
account_balance: 100, // 账户余额
account_locked_balance: 0, // 锁定余额
storage_usage: 0, // 存储使用量
attached_deposit: 0, // 附加存款
prepaid_gas: 10_000_000_000_000, // 预支付gas
random_seed: vec![0; 32], // 随机种子
is_view: false, // 是否只读
output_data_receivers: vec![], // 输出数据接收者
};
// 3. 实现外部接口
struct MockExternal;
impl External for MockExternal {
fn storage_get(&self, key: &[u8], mode: StorageGetMode) -> Option<Vec<u8>> {
None // 简单实现,实际需要完整实现所有方法
}
// 这里需要实现其他External trait方法...
}
let external = MockExternal;
// 4. 加载Wasm合约代码
let wasm_code = include_bytes!("../res/test_contract.wasm");
// 5. 执行合约
let outcome = run(
&config, // VM配置
&context, // 执行上下文
&wasm_code, // 合约代码
"method_name", // 要调用的方法
&[], // 方法参数
VMKind::Wasmer2, // 使用的VM类型
&external, // 外部接口
None, // 可选的内存限制
None, // 可选的栈限制
).unwrap();
// 6. 处理执行结果
match outcome {
VMOutcome::Aborted => println!("合约执行中止"),
VMOutcome::Ok(data) => println!("合约执行成功: {:?}", data),
}
使用注意事项:
- 需要准备有效的Wasm合约文件
- 必须完整实现External trait的所有方法
- 需要根据实际情况调整gas和存储参数
- 可以选择不同的VM实现(Wasmer0/Wasmer2/Wasmtime)
1 回复
Rust NEAR协议虚拟机运行库near-vm-runner解析
概述
near-vm-runner是NEAR协议的核心组件之一,负责在NEAR区块链上高效执行智能合约。它提供了一个安全的WASM(WebAssembly)运行时环境,专门为区块链场景优化,支持NEAR协议的智能合约执行。
主要特性
- 高性能WASM执行:针对区块链环境优化的WASM运行时
- 安全沙箱:完全隔离的合约执行环境
- 确定性执行:确保合约在不同节点上执行结果一致
- 资源计量:精确计算和限制gas消耗
- NEAR协议集成:深度集成NEAR区块链核心功能
使用方法
基本使用
首先在Cargo.toml中添加依赖:
[dependencies]
near-vm-runner = "0.0.0" # 使用最新版本
初始化VM运行器
use near_vm_runner::VMContext;
use near_vm_runner::run_vm;
let context = VMContext {
current_account_id: "alice.near".to_string(),
signer_account_id: "bob.near".to_string(),
signer_account_pk: vec![0; 32],
predecessor_account_id: "carol.near".to_string(),
input: vec![],
block_index: 0,
block_timestamp: 0,
account_balance: 100,
account_locked_balance: 0,
storage_usage: 0,
attached_deposit: 0,
prepaid_gas: 10u64.pow(18),
random_seed: vec![0; 32],
output_data_receivers: vec![],
epoch_height: 0,
};
// 加载WASM合约代码
let wasm_code = std::fs::read("contract.wasm").unwrap();
// 执行合约
let outcome = run_vm(
&context,
&wasm_code,
"method_name",
&[],
None,
None,
).unwrap();
合约调用示例
use near_vm_runner::{VMContext, run_vm};
use borsh::{BorshSerialize, BorshDeserialize};
#[derive(BorshSerialize, BorshDeserialize)]
struct InputArgs {
a: u64,
b: u64,
}
let context = VMContext { /* 同上 */ };
let args = InputArgs { a: 5, b: 7 };
let input = args.try_to_vec().unwrap();
let outcome = run_vm(
&context,
&wasm_code,
"add_numbers",
&input,
None,
None,
).unwrap();
println!("Result: {:?}", outcome.return_data);
高级功能
配置VM运行器
use near_vm_runner::{Config, VMKind};
let config = Config {
wasm_config: Default::default(),
vm_kind: VMKind::NearVm, // 或 Wasmer, Wasmtime等
max_gas_burnt: 200_000_000_000_000,
ext_costs: Default::default(),
};
let outcome = run_vm_with_config(
&config,
&context,
&wasm_code,
"method_name",
&[],
None,
None,
).unwrap();
处理合约存储
use near_vm_runner::internal::MemoryLike;
use std::collections::HashMap;
struct MockMemory {
storage: HashMap<Vec<u8>, Vec<u8>>,
}
impl MemoryLike for MockMemory {
// 实现MemoryLike trait的方法
}
let mut memory = MockMemory {
storage: HashMap::new(),
};
let outcome = run_vm(
&context,
&wasm_code,
"write_storage",
&[],
Some(&mut memory),
None,
).unwrap();
完整示例
下面是一个完整的near-vm-runner使用示例,展示了如何初始化、调用合约并处理结果:
use near_vm_runner::{VMContext, run_vm, Config, VMKind};
use borsh::{BorshSerialize, BorshDeserialize};
use std::fs;
// 合约输入参数结构体
#[derive(BorshSerialize, BorshDeserialize)]
struct ContractInput {
x: i32,
y: i32,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 初始化VM上下文
let context = VMContext {
current_account_id: "test.near".to_string(),
signer_account_id: "user.near".to_string(),
signer_account_pk: vec![0; 32],
predecessor_account_id: "user.near".to_string(),
input: vec![],
block_index: 1,
block_timestamp: 1_624_000_000_000_000,
account_balance: 100,
account_locked_balance: 0,
storage_usage: 0,
attached_deposit: 0,
prepaid_gas: 10u64.pow(18),
random_seed: vec![0; 32],
output_data_receivers: vec![],
epoch_height: 0,
};
// 加载WASM合约
let wasm_code = fs::read("contract.wasm")?;
// 准备调用参数
let args = ContractInput { x: 10, y: 20 };
let input = args.try_to_vec()?;
// 配置VM运行器
let config = Config {
wasm_config: Default::default(),
vm_kind: VMKind::NearVm,
max_gas_burnt: 200_000_000_000_000,
ext_costs: Default::default(),
};
// 执行合约方法
let outcome = run_vm(
&context,
&wasm_code,
"add", // 合约方法名
&input,
None,
None,
)?;
// 处理执行结果
println!("执行结果: {:?}", outcome.return_data);
println!("消耗的Gas: {}", outcome.gas_burnt);
println!("执行日志: {:?}", outcome.logs);
Ok(())
}
性能优化建议
- 使用
VMKind::NearVm
获取最佳性能 - 合理设置gas限制
- 避免在合约中执行复杂计算
- 使用borsh进行高效数据序列化
注意事项
- 确保WASM合约符合NEAR协议规范
- 合约执行是确定性的,不能包含随机性
- 所有外部调用必须通过NEAR提供的导入函数
- 注意gas消耗,避免合约执行失败
near-vm-runner是NEAR区块链智能合约执行的核心,通过合理使用可以构建高效、安全的去中心化应用。