mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 23:51:05 +00:00
Support custom runtime interfaces in native executor (#4129)
This makes it possible to use custom runtime interfaces within your runtime by registering them at the native executor.
This commit is contained in:
Generated
+1
@@ -5760,6 +5760,7 @@ dependencies = [
|
|||||||
"substrate-runtime-test 2.0.0",
|
"substrate-runtime-test 2.0.0",
|
||||||
"substrate-serializer 2.0.0",
|
"substrate-serializer 2.0.0",
|
||||||
"substrate-state-machine 2.0.0",
|
"substrate-state-machine 2.0.0",
|
||||||
|
"substrate-test-runtime 2.0.0",
|
||||||
"substrate-trie 2.0.0",
|
"substrate-trie 2.0.0",
|
||||||
"substrate-wasm-interface 2.0.0",
|
"substrate-wasm-interface 2.0.0",
|
||||||
"test-case 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"test-case 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -37,13 +37,17 @@ assert_matches = "1.3.0"
|
|||||||
wabt = "0.9.2"
|
wabt = "0.9.2"
|
||||||
hex-literal = "0.2.1"
|
hex-literal = "0.2.1"
|
||||||
runtime-test = { package = "substrate-runtime-test", path = "runtime-test" }
|
runtime-test = { package = "substrate-runtime-test", path = "runtime-test" }
|
||||||
|
test-runtime = { package = "substrate-test-runtime", path = "../../test/utils/runtime" }
|
||||||
|
runtime-interface = { package = "substrate-runtime-interface", path = "../../primitives/runtime-interface" }
|
||||||
client-api = { package = "substrate-client-api", path = "../api" }
|
client-api = { package = "substrate-client-api", path = "../api" }
|
||||||
substrate-offchain = { path = "../offchain/" }
|
substrate-offchain = { path = "../offchain/" }
|
||||||
state_machine = { package = "substrate-state-machine", path = "../../primitives/state-machine" }
|
state_machine = { package = "substrate-state-machine", path = "../../primitives/state-machine" }
|
||||||
test-case = "0.3.3"
|
test-case = "0.3.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = [ "std" ]
|
||||||
|
# This crate does not have `no_std` support, we just require this for tests
|
||||||
|
std = []
|
||||||
wasm-extern-trace = []
|
wasm-extern-trace = []
|
||||||
wasmtime = [
|
wasmtime = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ const DEFAULT_HEAP_PAGES: u64 = 1024;
|
|||||||
pub(crate) fn safe_call<F, U>(f: F) -> Result<U>
|
pub(crate) fn safe_call<F, U>(f: F) -> Result<U>
|
||||||
where F: UnwindSafe + FnOnce() -> U
|
where F: UnwindSafe + FnOnce() -> U
|
||||||
{
|
{
|
||||||
// Substrate uses custom panic hook that terminates process on panic. Disable termination for the native call.
|
// Substrate uses custom panic hook that terminates process on panic. Disable
|
||||||
|
// termination for the native call.
|
||||||
let _guard = panic_handler::AbortGuard::force_unwind();
|
let _guard = panic_handler::AbortGuard::force_unwind();
|
||||||
std::panic::catch_unwind(f).map_err(|_| Error::Runtime)
|
std::panic::catch_unwind(f).map_err(|_| Error::Runtime)
|
||||||
}
|
}
|
||||||
@@ -59,6 +60,10 @@ pub fn with_native_environment<F, U>(ext: &mut dyn Externalities, f: F) -> Resul
|
|||||||
///
|
///
|
||||||
/// By dispatching we mean that we execute a runtime function specified by it's name.
|
/// By dispatching we mean that we execute a runtime function specified by it's name.
|
||||||
pub trait NativeExecutionDispatch: Send + Sync {
|
pub trait NativeExecutionDispatch: Send + Sync {
|
||||||
|
/// Host functions for custom runtime interfaces that should be callable from within the runtime
|
||||||
|
/// besides the default Substrate runtime interfaces.
|
||||||
|
type ExtendHostFunctions: HostFunctions;
|
||||||
|
|
||||||
/// Dispatch a method in the runtime.
|
/// Dispatch a method in the runtime.
|
||||||
///
|
///
|
||||||
/// If the method with the specified name doesn't exist then `Err` is returned.
|
/// If the method with the specified name doesn't exist then `Err` is returned.
|
||||||
@@ -99,6 +104,9 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
|
|||||||
crate::deprecated_host_interface::SubstrateExternals::host_functions(),
|
crate::deprecated_host_interface::SubstrateExternals::host_functions(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add the custom host functions provided by the user.
|
||||||
|
host_functions.extend(D::ExtendHostFunctions::host_functions());
|
||||||
|
|
||||||
NativeExecutor {
|
NativeExecutor {
|
||||||
_dummy: Default::default(),
|
_dummy: Default::default(),
|
||||||
fallback_method,
|
fallback_method,
|
||||||
@@ -259,17 +267,65 @@ impl<D: NativeExecutionDispatch> CodeExecutor for NativeExecutor<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a `NativeExecutionDispatch` for provided parameters.
|
/// Implements a `NativeExecutionDispatch` for provided parameters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// substrate_executor::native_executor_instance!(
|
||||||
|
/// pub MyExecutor,
|
||||||
|
/// test_runtime::api::dispatch,
|
||||||
|
/// test_runtime::native_version,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # With custom host functions
|
||||||
|
///
|
||||||
|
/// When you want to use custom runtime interfaces from within your runtime, you need to make the
|
||||||
|
/// executor aware of the host functions for these interfaces.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use runtime_interface::runtime_interface;
|
||||||
|
///
|
||||||
|
/// #[runtime_interface]
|
||||||
|
/// trait MyInterface {
|
||||||
|
/// fn say_hello_world(data: &str) {
|
||||||
|
/// println!("Hello world from: {}", data);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// substrate_executor::native_executor_instance!(
|
||||||
|
/// pub MyExecutor,
|
||||||
|
/// test_runtime::api::dispatch,
|
||||||
|
/// test_runtime::native_version,
|
||||||
|
/// my_interface::HostFunctions,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// When you have multiple interfaces, you can give the host functions as a tuple e.g.:
|
||||||
|
/// `(my_interface::HostFunctions, my_interface2::HostFunctions)`
|
||||||
|
///
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! native_executor_instance {
|
macro_rules! native_executor_instance {
|
||||||
( $pub:vis $name:ident, $dispatcher:path, $version:path $(,)?) => {
|
( $pub:vis $name:ident, $dispatcher:path, $version:path $(,)?) => {
|
||||||
/// A unit struct which implements `NativeExecutionDispatch` feeding in the hard-coded runtime.
|
/// A unit struct which implements `NativeExecutionDispatch` feeding in the
|
||||||
|
/// hard-coded runtime.
|
||||||
$pub struct $name;
|
$pub struct $name;
|
||||||
$crate::native_executor_instance!(IMPL $name, $dispatcher, $version);
|
$crate::native_executor_instance!(IMPL $name, $dispatcher, $version, ());
|
||||||
};
|
};
|
||||||
(IMPL $name:ident, $dispatcher:path, $version:path) => {
|
( $pub:vis $name:ident, $dispatcher:path, $version:path, $custom_host_functions:ty $(,)?) => {
|
||||||
|
/// A unit struct which implements `NativeExecutionDispatch` feeding in the
|
||||||
|
/// hard-coded runtime.
|
||||||
|
$pub struct $name;
|
||||||
|
$crate::native_executor_instance!(
|
||||||
|
IMPL $name, $dispatcher, $version, $custom_host_functions
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(IMPL $name:ident, $dispatcher:path, $version:path, $custom_host_functions:ty) => {
|
||||||
impl $crate::NativeExecutionDispatch for $name {
|
impl $crate::NativeExecutionDispatch for $name {
|
||||||
|
type ExtendHostFunctions = $custom_host_functions;
|
||||||
|
|
||||||
fn dispatch(
|
fn dispatch(
|
||||||
ext: &mut $crate::Externalities,
|
ext: &mut dyn $crate::Externalities,
|
||||||
method: &str,
|
method: &str,
|
||||||
data: &[u8]
|
data: &[u8]
|
||||||
) -> $crate::error::Result<Vec<u8>> {
|
) -> $crate::error::Result<Vec<u8>> {
|
||||||
@@ -283,3 +339,34 @@ macro_rules! native_executor_instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use runtime_interface::runtime_interface;
|
||||||
|
|
||||||
|
#[runtime_interface]
|
||||||
|
trait MyInterface {
|
||||||
|
fn say_hello_world(data: &str) {
|
||||||
|
println!("Hello world from: {}", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
native_executor_instance!(
|
||||||
|
pub MyExecutor,
|
||||||
|
test_runtime::api::dispatch,
|
||||||
|
test_runtime::native_version,
|
||||||
|
(my_interface::HostFunctions, my_interface::HostFunctions),
|
||||||
|
);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn native_executor_registers_custom_interface() {
|
||||||
|
let executor = NativeExecutor::<MyExecutor>::new(WasmExecutionMethod::Interpreted, None);
|
||||||
|
my_interface::HostFunctions::host_functions().iter().for_each(|function| {
|
||||||
|
assert_eq!(
|
||||||
|
executor.host_functions.iter().filter(|f| f == &function).count(),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user