diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 4ea14fd1d9223..d196ff6906dbc 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -312,29 +312,40 @@ sp_core::wasm_export_functions! { fn test_fork() { let data = vec![1u8, 2u8]; - let data_new = sp_io::tasks::spawn(incrementer, data).join(); + let data_new = sp_io::tasks::spawn(tasks::incrementer, data).join(); assert_eq!(data_new, vec![2u8, 3u8]); } fn test_nested_fork() { let data = vec![7u8, 13u8]; - let data_new = sp_io::tasks::spawn(parallel_incrementer, data).join(); + let data_new = sp_io::tasks::spawn(tasks::parallel_incrementer, data).join(); assert_eq!(data_new, vec![10u8, 16u8]); } - } - #[cfg(not(feature = "std"))] - fn incrementer(data: Vec) -> Vec { - data.into_iter().map(|v| v + 1).collect() + fn test_panic_in_fork_panics_on_join() { + let data_new = sp_io::tasks::spawn(tasks::panicker, vec![]).join(); + } } #[cfg(not(feature = "std"))] - fn parallel_incrementer(data: Vec) -> Vec { - let first = data.into_iter().map(|v| v + 2).collect::>(); - let second = sp_io::tasks::spawn(incrementer, first).join(); - second + mod tasks { + use sp_std::prelude::*; + + pub fn incrementer(data: Vec) -> Vec { + data.into_iter().map(|v| v + 1).collect() + } + + pub fn panicker(_: Vec) -> Vec { + panic!() + } + + pub fn parallel_incrementer(data: Vec) -> Vec { + let first = data.into_iter().map(|v| v + 2).collect::>(); + let second = sp_io::tasks::spawn(incrementer, first).join(); + second + } } #[cfg(not(feature = "std"))] diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 8be744322d75a..66c85f1aa1070 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -788,3 +788,21 @@ fn nested_forking_should_work(wasm_method: WasmExecutionMethod) { ).unwrap(); } +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn panic_in_fork_panics_on_join(wasm_method: WasmExecutionMethod) { + + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + if let Err(e) = call_in_wasm( + "test_panic_in_fork_panics_on_join", + &[], + wasm_method, + &mut ext, + ) { + assert!(format!("{}", e).contains("Runtime panicked: No signal from forked execution")); + } else { + panic!("wasm call should be error") + } +} diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 79d7915acde01..e1ec0ffcfca83 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -323,7 +323,7 @@ impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn { // FIXME: Should be refactored to shared "instance factory". // Instantiating wasm here every time is suboptimal at the moment, shared - // pool of istances should be used. + // pool of instances should be used. let instance = module.new_instance().expect("Failed to create new instance for fork"); instance.call( diff --git a/primitives/io/src/tasks.rs b/primitives/io/src/tasks.rs index d29177f709a95..cb3b17f18ee5a 100644 --- a/primitives/io/src/tasks.rs +++ b/primitives/io/src/tasks.rs @@ -18,7 +18,6 @@ //! Runtime tasks. //! //! Contains runtime-usable functions for spawning parallel purely computational tasks. -//! #[cfg(feature = "std")] mod inner { @@ -79,19 +78,19 @@ mod inner { #[cfg(not(feature = "std"))] mod inner { + use core::mem; use sp_std::{vec::Vec, prelude::Box}; - - /// Dynamic dispatch of wasm blob. + /// Dispatch wrapper for wasm blob. /// - /// Arguments are expected to be scale encoded in vector at address `payload_ptr` with length of - /// `payload_len`. + /// Serves as trampoline to call any rust function with (Vec) -> Vec compiled + /// into the runtime. /// - /// Arguments: function pointer (u32), input (Vec). + /// Function item should be provided with `func_ref`. Argument for the call + /// will be generated from bytes at `payload_ptr` with `payload_len`. /// - /// Function at pointer is expected to have signature of `(Vec) -> Vec`. Since this dynamic dispatch - /// function and the invoked function are compiled with the same compiler, there should be no problem with - /// ABI incompatibility. + /// NOTE: Since this dynamic dispatch function and the invoked function are compiled with + /// the same compiler, there should be no problem with ABI incompatibility. extern "C" fn dispatch_wrapper(func_ref: u32, payload_ptr: u32, payload_len: u32) -> u64 { let payload_len = payload_len as usize; let output = unsafe { @@ -107,13 +106,11 @@ mod inner { pub fn spawn(entry_point: fn(Vec) -> Vec, payload: Vec) -> DataJoinHandle { let func_ptr: usize = unsafe { core::mem::transmute(entry_point) }; - let handle = unsafe { - crate::runtime_tasks::spawn( - dispatch_wrapper as usize as _, - func_ptr as u32, - payload, - ) - }; + let handle = crate::runtime_tasks::spawn( + dispatch_wrapper as usize as _, + func_ptr as u32, + payload, + ); DataJoinHandle { handle } }