diff --git a/substrate/core/executor/src/error.rs b/substrate/core/executor/src/error.rs index 6b3c45ee4948760d4ad883530264dcc41cb15496..e1221bea54aefd7b1bc4a896f082bd170b2fdc44 100644 --- a/substrate/core/executor/src/error.rs +++ b/substrate/core/executor/src/error.rs @@ -99,6 +99,12 @@ impl From<String> for Error { } } +impl From<WasmError> for Error { + fn from(err: WasmError) -> Error { + Error::Other(err.to_string()) + } +} + /// Type for errors occurring during Wasm runtime construction. #[derive(Debug, derive_more::Display)] pub enum WasmError { diff --git a/substrate/core/executor/src/lib.rs b/substrate/core/executor/src/lib.rs index ccc78afdb4e547af025dfcd0f065a186ec664583..582ebbca349fe65a27ca3bacf0931c77a168d506 100644 --- a/substrate/core/executor/src/lib.rs +++ b/substrate/core/executor/src/lib.rs @@ -50,6 +50,33 @@ pub use primitives::traits::Externalities; pub use wasm_interface; pub use wasm_runtime::WasmExecutionMethod; +/// Call the given `function` in the given wasm `code`. +/// +/// The signature of `function` needs to follow the default Substrate function signature. +/// +/// - `call_data`: Will be given as input parameters to `function` +/// - `execution_method`: The execution method to use. +/// - `ext`: The externalities that should be set while executing the wasm function. +/// - `heap_pages`: The number of heap pages to allocate. +/// +/// Returns the `Vec<u8>` that contains the return value of the function. +pub fn call_in_wasm<E: Externalities>( + function: &str, + call_data: &[u8], + execution_method: WasmExecutionMethod, + ext: &mut E, + code: &[u8], + heap_pages: u64, +) -> error::Result<Vec<u8>> { + let mut instance = wasm_runtime::create_wasm_runtime_with_code( + ext, + execution_method, + heap_pages, + code, + )?; + instance.call(ext, function, call_data) +} + /// Provides runtime information. pub trait RuntimeInfo { /// Native runtime information. @@ -61,3 +88,24 @@ pub trait RuntimeInfo { ext: &mut E, ) -> Option<RuntimeVersion>; } + +#[cfg(test)] +mod tests { + use super::*; + use runtime_test::WASM_BINARY; + use runtime_io::TestExternalities; + + #[test] + fn call_in_interpreted_wasm_works() { + let mut ext = TestExternalities::default(); + let res = call_in_wasm( + "test_empty_return", + &[], + WasmExecutionMethod::Interpreted, + &mut ext, + &WASM_BINARY, + 8, + ).unwrap(); + assert_eq!(res, vec![0u8; 0]); + } +} diff --git a/substrate/core/executor/src/wasm_runtime.rs b/substrate/core/executor/src/wasm_runtime.rs index d88ae7b9edc21b69db1f092b21f41dee5f07ac05..8d2291fe048932cedf247cf5c05c02a5f8d5a8fd 100644 --- a/substrate/core/executor/src/wasm_runtime.rs +++ b/substrate/core/executor/src/wasm_runtime.rs @@ -157,17 +157,27 @@ impl RuntimesCache { } } -fn create_wasm_runtime<E: Externalities>( +/// Create a wasm runtime with the given `code`. +pub fn create_wasm_runtime_with_code<E: Externalities>( ext: &mut E, wasm_method: WasmExecutionMethod, heap_pages: u64, + code: &[u8], ) -> Result<Box<dyn WasmRuntime>, WasmError> { - let code = ext - .original_storage(well_known_keys::CODE) - .ok_or(WasmError::CodeNotFound)?; match wasm_method { WasmExecutionMethod::Interpreted => - wasmi_execution::create_instance(ext, &code, heap_pages) + wasmi_execution::create_instance(ext, code, heap_pages) .map(|runtime| -> Box<dyn WasmRuntime> { Box::new(runtime) }), } } + +fn create_wasm_runtime<E: Externalities>( + ext: &mut E, + wasm_method: WasmExecutionMethod, + heap_pages: u64, +) -> Result<Box<dyn WasmRuntime>, WasmError> { + let code = ext + .original_storage(well_known_keys::CODE) + .ok_or(WasmError::CodeNotFound)?; + create_wasm_runtime_with_code(ext, wasm_method, heap_pages, &code) +}