Skip to content

Commit

Permalink
Error processing.
Browse files Browse the repository at this point in the history
  • Loading branch information
olonho committed Jun 16, 2020
1 parent c2e0016 commit 3cd17b2
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 33 deletions.
1 change: 1 addition & 0 deletions neard/res/genesis_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
]
},
"wasm_config": {
"vm_kind": "Wasmer",
"ext_costs": {
"base": 265261758,
"read_memory_base": 2584050225,
Expand Down
11 changes: 10 additions & 1 deletion runtime/near-vm-runner/src/cache.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#[cfg(not(feature = "no_cache"))]
use cached::{cached_key, SizedCache};
use wasmer_runtime;

use crate::errors::IntoVMError;
use crate::prepare;
Expand All @@ -26,3 +25,13 @@ cached_key! {
wasmer_runtime::compile(&prepared_code).map_err(|err| err.into_vm_error())
}
}

#[cfg(feature = "no_cache")]
pub(crate) fn compile_module(
_code_hash: Vec<u8>,
code: &[u8],
config: &VMConfig,
) -> Result<wasmer_runtime::Module, VMError> {
let prepared_code = prepare::prepare_contract(code, config)?;
wasmer_runtime::compile(&prepared_code).map_err(|err| err.into_vm_error())
}
10 changes: 0 additions & 10 deletions runtime/near-vm-runner/src/wasmer_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,6 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError {
}
}

#[cfg(feature = "no_cache")]
pub(crate) fn compile_module(
_code_hash: Vec<u8>,
code: &[u8],
config: &VMConfig,
) -> Result<wasmer_runtime::Module, VMError> {
let prepared_code = prepare::prepare_contract(code, config)?;
wasmer_runtime::compile(&prepared_code).map_err(|err| err.into_vm_error())
}

pub fn run_wasmer<'a>(
code_hash: Vec<u8>,
code: &[u8],
Expand Down
97 changes: 82 additions & 15 deletions runtime/near-vm-runner/src/wasmtime_runner.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::errors::IntoVMError;
use crate::{imports, prepare};
use near_runtime_fees::RuntimeFeesConfig;
use near_vm_errors::FunctionCallError::LinkError;
use near_vm_errors::FunctionCallError::{LinkError, WasmUnknownError};
use near_vm_errors::{FunctionCallError, MethodResolveError, VMError, VMLogicError};
use near_vm_logic::types::PromiseResult;
use near_vm_logic::{External, MemoryLike, VMConfig, VMContext, VMLogic, VMOutcome};
use std::ffi::c_void;
use std::str;
use wasmtime::ExternType::Func;
use wasmtime::{Engine, Limits, Linker, Memory, MemoryType, Module, Store};

pub struct WasmtimeMemory(Memory);
Expand Down Expand Up @@ -59,28 +60,42 @@ impl MemoryLike for WasmtimeMemory {
}
}

fn trap_to_error(trap: &wasmtime::Trap) -> VMError {
if trap.i32_exit_status() == Some(239) {
match imports::last_wasmtime_error() {
Some(VMLogicError::HostError(h)) => {
VMError::FunctionCallError(FunctionCallError::HostError(h.clone()))
}
Some(VMLogicError::ExternalError(s)) => VMError::ExternalError(s.clone()),
Some(VMLogicError::InconsistentStateError(e)) => {
VMError::InconsistentStateError(e.clone())
}
None => panic!("Error is not properly set"),
}
} else {
// VMError::FunctionCallError(LinkError { msg: format!("{:#?}", trap) })
VMError::FunctionCallError(WasmUnknownError)
}
}

impl IntoVMError for anyhow::Error {
fn into_vm_error(self) -> VMError {
// TODO: incorrect
VMError::FunctionCallError(LinkError { msg: format!("{:#?}", self) })
let cause = self.root_cause();
match cause.downcast_ref::<wasmtime::Trap>() {
Some(trap) => trap_to_error(trap),
None => VMError::FunctionCallError(LinkError { msg: format!("{:#?}", cause) }),
}
}
}

impl IntoVMError for wasmtime::Trap {
fn into_vm_error(self) -> VMError {
if self.i32_exit_status() == Some(239) {
match imports::last_wasmtime_error() {
Some(VMLogicError::HostError(h)) => {
VMError::FunctionCallError(FunctionCallError::HostError(h.clone()))
}
Some(VMLogicError::ExternalError(s)) => VMError::ExternalError(s.clone()),
Some(VMLogicError::InconsistentStateError(e)) => {
VMError::InconsistentStateError(e.clone())
}
None => panic!("Error is not properly set"),
}
trap_to_error(&self)
} else {
VMError::FunctionCallError(LinkError { msg: format!("{:#?}", self) })
// VMError::FunctionCallError(LinkError { msg: format!("{:#?}", self) })
VMError::FunctionCallError(WasmUnknownError)
}
}
}
Expand All @@ -103,7 +118,10 @@ pub fn run_wasmtime<'a>(
wasm_config.limit_config.max_memory_pages,
)
.unwrap();
let prepared_code = prepare::prepare_contract(code, wasm_config).unwrap();
let prepared_code = match prepare::prepare_contract(code, wasm_config) {
Ok(code) => code,
Err(err) => return (None, Some(VMError::from(err))),
};
let module = Module::new(&engine, prepared_code).unwrap();
// Note that we don't clone the actual backing memory, just increase the RC.
let memory_copy = memory.clone();
Expand All @@ -114,8 +132,57 @@ pub fn run_wasmtime<'a>(
// lifetimes of the logic instance and pass raw pointers here.
let raw_logic = &mut logic as *mut _ as *mut c_void;
imports::link_wasmtime(&mut linker, memory_copy, raw_logic);
let func_name = match str::from_utf8(method_name) {
Ok(name) => name,
Err(_) => {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodUTF8Error,
))),
)
}
};
if method_name.is_empty() {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodEmptyName,
))),
);
}
match module.get_export(func_name) {
Some(export) => match export {
Func(func_type) => {
if !func_type.params().is_empty() || !func_type.results().is_empty() {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodInvalidSignature,
))),
);
}
}
_ => {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodNotFound,
))),
)
}
},
None => {
return (
None,
Some(VMError::FunctionCallError(FunctionCallError::MethodResolveError(
MethodResolveError::MethodNotFound,
))),
)
}
}
match linker.instantiate(&module) {
Ok(instance) => match instance.get_func(str::from_utf8(method_name).unwrap()) {
Ok(instance) => match instance.get_func(func_name) {
Some(func) => match func.get0::<()>() {
Ok(run) => match run() {
Ok(_) => (Some(logic.outcome()), None),
Expand Down
17 changes: 11 additions & 6 deletions runtime/near-vm-runner/tests/test_error_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,26 +348,31 @@ fn test_bad_import_2() {

#[test]
fn test_bad_import_3() {
let msg = match VMKind::default() {
VMKind::Wasmer => "link error: Incorrect import type, namespace: env, name: input, expected type: global, found type: function",
VMKind::Wasmtime => "\"incompatible import type for `env::input` specified\\ndesired signature was: Global(GlobalType { content: I32, mutability: Const })\\nsignatures available:\\n\\n * Func(FuncType { params: [I64], results: [] })\\n\"",
}.to_string();
assert_eq!(
make_simple_contract_call(&bad_import_global("env"), b"hello"),
(
Some(vm_outcome_with_gas(0)),
Some(VMError::FunctionCallError(FunctionCallError::LinkError{
msg: "link error: Incorrect import type, namespace: env, name: input, expected type: global, found type: function".to_string()
}))
Some(VMError::FunctionCallError(FunctionCallError::LinkError { msg: msg }))
)
);
}

#[test]
fn test_bad_import_4() {
let msg = match VMKind::default() {
VMKind::Wasmer => "link error: Import not found, namespace: env, name: wtf",
VMKind::Wasmtime => "\"unknown import: `env::wtf` has not been defined\"",
}
.to_string();
assert_eq!(
make_simple_contract_call(&bad_import_func("env"), b"hello"),
(
Some(vm_outcome_with_gas(0)),
Some(VMError::FunctionCallError(FunctionCallError::LinkError {
msg: "link error: Import not found, namespace: env, name: wtf".to_string()
}))
Some(VMError::FunctionCallError(FunctionCallError::LinkError { msg: msg }))
)
);
}
Expand Down
3 changes: 2 additions & 1 deletion runtime/runtime-params-estimator/src/cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use near_runtime_fees::{
AccessKeyCreationConfig, ActionCreationConfig, DataReceiptCreationConfig, Fee,
RuntimeFeesConfig,
};
use near_vm_logic::{ExtCosts, ExtCostsConfig, VMConfig, VMLimitConfig};
use near_vm_logic::{ExtCosts, ExtCostsConfig, VMConfig, VMLimitConfig, VMKind};
use node_runtime::config::RuntimeConfig;

/// How much gas there is in a nanosecond worth of computation.
Expand Down Expand Up @@ -616,6 +616,7 @@ fn get_ext_costs_config(measurement: &Measurements) -> ExtCostsConfig {

fn get_vm_config(measurement: &Measurements) -> VMConfig {
VMConfig {
vm_kind: VMKind::default(),
ext_costs: get_ext_costs_config(measurement),
// TODO: Figure out whether we need this fee at all. If we do what should be the memory
// growth cost.
Expand Down

0 comments on commit 3cd17b2

Please sign in to comment.