Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (runtime): Wasmer ExceptionCode support #2505

Merged
merged 34 commits into from
Apr 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
14cdd7b
fix: Upgrade Wasmer
lexfrl Mar 27, 2020
ef572fa
panic node on internal Wasmer error
lexfrl Mar 30, 2020
5ecfcde
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Mar 30, 2020
64e0363
use Wasmer error output for WasmTrap
lexfrl Mar 30, 2020
1902d77
Merge branch 'fckt/wasmer-16-update' of github.com:nearprotocol/nearc…
lexfrl Mar 30, 2020
07f65c3
panic node on Internal Wasmer error
lexfrl Mar 31, 2020
150b6ab
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 1, 2020
d58f6f0
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 2, 2020
ebd0c12
revert WasmTrap WasmTrap {msg: unknown}
lexfrl Apr 3, 2020
a69e2fd
Merge branch 'fckt/wasmer-16-update' of github.com:nearprotocol/nearc…
lexfrl Apr 3, 2020
ce68f5f
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 6, 2020
5127568
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 6, 2020
63dc36e
show msg if RuntimeError is String or &str
lexfrl Apr 8, 2020
7c179ef
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 8, 2020
7857400
Merge branch 'fckt/wasmer-16-update' of github.com:nearprotocol/nearc…
lexfrl Apr 8, 2020
081e16c
add a TODO comment
lexfrl Apr 8, 2020
f4e4768
add non-deterministic warning for all cases
lexfrl Apr 9, 2020
e4117b2
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 9, 2020
757c0b2
Merge refs/heads/master into fckt/wasmer-16-update
nearprotocol-bulldozer[bot] Apr 9, 2020
45f3209
Merge refs/heads/master into fckt/wasmer-16-update
nearprotocol-bulldozer[bot] Apr 9, 2020
066f207
Merge refs/heads/master into fckt/wasmer-16-update
nearprotocol-bulldozer[bot] Apr 10, 2020
05c4b8e
Merge refs/heads/master into fckt/wasmer-16-update
nearprotocol-bulldozer[bot] Apr 10, 2020
ebf42b5
return FunctionCallError::WasmTrap { msg: unknown.into() } for all er…
lexfrl Apr 14, 2020
eaadcbe
Merge branch 'master' into fckt/wasmer-16-update
lexfrl Apr 14, 2020
7fb296d
fix eprintln message
lexfrl Apr 14, 2020
ddeb383
Merge branch 'fckt/wasmer-16-update' of github.com:nearprotocol/nearc…
lexfrl Apr 14, 2020
f3c5fee
Wasm ExceptionCode's support added
lexfrl Apr 20, 2020
7de946b
fix CI
lexfrl Apr 20, 2020
d566583
Merge branch 'master' into fckt/wasmer-exception-code
lexfrl Apr 20, 2020
619e74c
fix tests
lexfrl Apr 20, 2020
e0053b3
Merge branch 'fckt/wasmer-exception-code' of github.com:nearprotocol/…
lexfrl Apr 20, 2020
655e4de
Merge branch 'master' into fckt/wasmer-exception-code
lexfrl Apr 20, 2020
75716e8
Merge branch 'master' into fckt/wasmer-exception-code
lexfrl Apr 21, 2020
1f3467f
Merge branch 'master' into fckt/wasmer-exception-code
lexfrl Apr 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 58 additions & 69 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions chain/jsonrpc/build_errors_schema.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash
rm ../../target/rpc_errors_schema.json
cargo build --features dump_errors_schema
cp ../../target/rpc_errors_schema.json ./res/rpc_errors_schema.json
47 changes: 44 additions & 3 deletions chain/jsonrpc/res/rpc_errors_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
"subtypes": [],
"props": {}
},
"CallIndirectOOB": {
"name": "CallIndirectOOB",
"subtypes": [],
"props": {}
},
"CannotAppendActionToJointPromise": {
"name": "CannotAppendActionToJointPromise",
"subtypes": [],
Expand Down Expand Up @@ -73,6 +78,7 @@
"LinkError",
"MethodResolveError",
"WasmTrap",
"WasmUnknownError",
"HostError"
],
"props": {}
Expand Down Expand Up @@ -135,6 +141,16 @@
],
"props": {}
},
"IllegalArithmetic": {
"name": "IllegalArithmetic",
"subtypes": [],
"props": {}
},
"IncorrectCallIndirectSignature": {
"name": "IncorrectCallIndirectSignature",
"subtypes": [],
"props": {}
},
"Instantiate": {
"name": "Instantiate",
"subtypes": [],
Expand Down Expand Up @@ -232,6 +248,11 @@
"subtypes": [],
"props": {}
},
"MemoryOutOfBounds": {
"name": "MemoryOutOfBounds",
"subtypes": [],
"props": {}
},
"MethodEmptyName": {
"name": "MethodEmptyName",
"subtypes": [],
Expand Down Expand Up @@ -262,6 +283,11 @@
"subtypes": [],
"props": {}
},
"MisalignedAtomicAccess": {
"name": "MisalignedAtomicAccess",
"subtypes": [],
"props": {}
},
"NumberInputDataDependenciesExceeded": {
"name": "NumberInputDataDependenciesExceeded",
"subtypes": [],
Expand Down Expand Up @@ -331,6 +357,11 @@
"limit": ""
}
},
"Unreachable": {
"name": "Unreachable",
"subtypes": [],
"props": {}
},
"ValueLengthExceeded": {
"name": "ValueLengthExceeded",
"subtypes": [],
Expand All @@ -341,10 +372,20 @@
},
"WasmTrap": {
"name": "WasmTrap",
"subtypes": [
"Unreachable",
"IncorrectCallIndirectSignature",
"MemoryOutOfBounds",
"CallIndirectOOB",
"IllegalArithmetic",
"MisalignedAtomicAccess"
],
"props": {}
},
"WasmUnknownError": {
"name": "WasmUnknownError",
"subtypes": [],
"props": {
"msg": ""
}
"props": {}
},
"WasmerCompileError": {
"name": "WasmerCompileError",
Expand Down
51 changes: 48 additions & 3 deletions runtime/near-vm-errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,37 @@ pub enum VMError {
Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
)]
pub enum FunctionCallError {
/// Wasm compilation error
CompilationError(CompilationError),
LinkError { msg: String },
/// Wasm binary env link error
LinkError {
msg: String,
},
/// Import/export resolve error
MethodResolveError(MethodResolveError),
WasmTrap { msg: String },
/// A trap happened during execution of a binary
WasmTrap(WasmTrap),
WasmUnknownError,
HostError(HostError),
}
/// A kind of a trap happened during execution of a binary
#[derive(
Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
)]
pub enum WasmTrap {
/// An `unreachable` opcode was executed.
Unreachable,
/// Call indirect incorrect signature trap.
IncorrectCallIndirectSignature,
/// Memory out of bounds trap.
MemoryOutOfBounds,
/// Call indirect out of bounds trap.
CallIndirectOOB,
/// An arithmetic exception, e.g. divided by zero.
IllegalArithmetic,
/// Misaligned atomic access trap.
MisalignedAtomicAccess,
}

#[derive(
Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
Expand Down Expand Up @@ -198,7 +223,27 @@ impl fmt::Display for FunctionCallError {
FunctionCallError::MethodResolveError(e) => e.fmt(f),
FunctionCallError::HostError(e) => e.fmt(f),
FunctionCallError::LinkError { msg } => write!(f, "{}", msg),
FunctionCallError::WasmTrap { msg } => write!(f, "WebAssembly trap: {}", msg),
FunctionCallError::WasmTrap(trap) => write!(f, "WebAssembly trap: {}", trap),
FunctionCallError::WasmUnknownError => {
write!(f, "Unknown error during Wasm contract execution")
}
}
}
}

impl fmt::Display for WasmTrap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
WasmTrap::Unreachable => write!(f, "An `unreachable` opcode was executed."),
WasmTrap::IncorrectCallIndirectSignature => {
write!(f, "Call indirect incorrect signature trap.")
}
WasmTrap::MemoryOutOfBounds => write!(f, "Memory out of bounds trap."),
WasmTrap::CallIndirectOOB => write!(f, "Call indirect out of bounds trap."),
WasmTrap::IllegalArithmetic => {
write!(f, "An arithmetic exception, e.g. divided by zero.")
}
WasmTrap::MisalignedAtomicAccess => write!(f, "Misaligned atomic access trap."),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/near-vm-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ This crate implements the specification of the interface that Near blockchain ex

[dependencies]
cached = "0.12.0"
wasmer-runtime = { version = "0.13.1", features = ["default-backend-singlepass"], default-features = false }
wasmer-runtime-core = { version = "0.13.1" }
wasmer-runtime = { version = "0.16.2", features = ["default-backend-singlepass"], default-features = false }
wasmer-runtime-core = { version = "0.16.2" }
near-runtime-fees = { path="../near-runtime-fees", version = "0.8.0" }
near-vm-logic = { path="../near-vm-logic", version = "0.8.0", default-features = false, features = []}
near-vm-errors = { path = "../near-vm-errors", version = "0.8.0" }
Expand Down
80 changes: 52 additions & 28 deletions runtime/near-vm-runner/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use near_vm_errors::{CompilationError, FunctionCallError, MethodResolveError, VMError};
use near_vm_errors::{CompilationError, FunctionCallError, MethodResolveError, VMError, WasmTrap};
use near_vm_logic::VMLogicError;

pub trait IntoVMError {
Expand Down Expand Up @@ -33,9 +33,15 @@ impl IntoVMError for wasmer_runtime::error::CallError {

impl IntoVMError for wasmer_runtime::error::CompileError {
fn into_vm_error(self) -> VMError {
VMError::FunctionCallError(FunctionCallError::CompilationError(
CompilationError::WasmerCompileError { msg: self.to_string() },
))
match self {
wasmer_runtime::error::CompileError::InternalError { .. } => {
// An internal Wasmer error the most probably is a result of a node malfunction
panic!("Internal Wasmer error on Wasm compilation: {}", self);
}
_ => VMError::FunctionCallError(FunctionCallError::CompilationError(
CompilationError::WasmerCompileError { msg: self.to_string() },
)),
}
}
}

Expand All @@ -58,33 +64,51 @@ impl IntoVMError for wasmer_runtime::error::ResolveError {

impl IntoVMError for wasmer_runtime::error::RuntimeError {
fn into_vm_error(self) -> VMError {
use wasmer_runtime::error::RuntimeError;
match &self {
RuntimeError::Trap { msg } => {
VMError::FunctionCallError(FunctionCallError::WasmTrap { msg: msg.to_string() })
use wasmer_runtime::ExceptionCode;
let data = &*self.0;

if let Some(err) = data.downcast_ref::<VMLogicError>() {
match err {
VMLogicError::HostError(h) => {
VMError::FunctionCallError(FunctionCallError::HostError(h.clone()))
}
VMLogicError::ExternalError(s) => VMError::ExternalError(s.clone()),
VMLogicError::InconsistentStateError(e) => {
VMError::InconsistentStateError(e.clone())
}
}
RuntimeError::Error { data } => {
if let Some(err) = data.downcast_ref::<VMLogicError>() {
match err {
VMLogicError::HostError(h) => {
VMError::FunctionCallError(FunctionCallError::HostError(h.clone()))
}
VMLogicError::ExternalError(s) => VMError::ExternalError(s.clone()),
VMLogicError::InconsistentStateError(e) => {
VMError::InconsistentStateError(e.clone())
}
}
} else {
eprintln!(
"Bad error case! Output is non-deterministic {:?} {:?}",
data.type_id(),
self.to_string()
);
VMError::FunctionCallError(FunctionCallError::WasmTrap {
msg: "unknown".to_string(),
})
} else if let Some(err) = data.downcast_ref::<ExceptionCode>() {
use wasmer_runtime::ExceptionCode::*;
match err {
Unreachable => {
VMError::FunctionCallError(FunctionCallError::WasmTrap(WasmTrap::Unreachable))
}
IncorrectCallIndirectSignature => VMError::FunctionCallError(
FunctionCallError::WasmTrap(WasmTrap::IncorrectCallIndirectSignature),
),
MemoryOutOfBounds => VMError::FunctionCallError(FunctionCallError::WasmTrap(
WasmTrap::MemoryOutOfBounds,
)),
CallIndirectOOB => VMError::FunctionCallError(FunctionCallError::WasmTrap(
WasmTrap::CallIndirectOOB,
)),
IllegalArithmetic => VMError::FunctionCallError(FunctionCallError::WasmTrap(
WasmTrap::IllegalArithmetic,
)),
MisalignedAtomicAccess => VMError::FunctionCallError(FunctionCallError::WasmTrap(
WasmTrap::MisalignedAtomicAccess,
)),
}
} else {
// TODO: Wasmer provides no way to distingush runtime Internal Wasmer errors or host panics
// (at least for a single-pass backend)
// https://github.com/wasmerio/wasmer/issues/1338
eprintln!(
"Bad error case! Output might be non-deterministic {:?} {:?}",
data.type_id(),
self.to_string()
);
VMError::FunctionCallError(FunctionCallError::WasmUnknownError)
}
}
}
12 changes: 3 additions & 9 deletions runtime/near-vm-runner/tests/test_error_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,7 @@ fn test_trap_contract() {
make_simple_contract_call(&trap_contract(), b"hello"),
(
Some(vm_outcome_with_gas(3856371)),
Some(VMError::FunctionCallError(FunctionCallError::WasmTrap {
msg: "unknown".to_string()
}))
Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError))
)
);
}
Expand All @@ -157,9 +155,7 @@ fn test_trap_initializer() {
make_simple_contract_call(&trap_initializer(), b"hello"),
(
Some(vm_outcome_with_gas(3856371)),
Some(VMError::FunctionCallError(FunctionCallError::WasmTrap {
msg: "unknown".to_string()
}))
Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError))
)
);
}
Expand Down Expand Up @@ -257,9 +253,7 @@ fn test_stack_overflow() {
make_simple_contract_call(&stack_overflow(), b"hello"),
(
Some(vm_outcome_with_gas(63182782464)),
Some(VMError::FunctionCallError(FunctionCallError::WasmTrap {
msg: "unknown".to_string()
}))
Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError))
)
);
}
Expand Down
7 changes: 1 addition & 6 deletions runtime/near-vm-runner/tests/test_rs_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,5 @@ pub fn test_out_of_memory() {
&fees,
&promise_results,
);
assert_eq!(
result.1,
Some(VMError::FunctionCallError(FunctionCallError::WasmTrap {
msg: "unknown".to_string()
}))
);
assert_eq!(result.1, Some(VMError::FunctionCallError(FunctionCallError::WasmUnknownError)));
}