// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Custom inner attributes are unstable, so we need to faky disable the attribute. // rustfmt still honors the attribute to not format the rustdocs below. #![cfg_attr(feature = "never", rustfmt::skip)] //! Substrate runtime interface //! //! This crate provides types, traits and macros around runtime interfaces. A runtime interface is //! a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the //! interface maps to a direct function call of the implementation. For a wasm runtime the interface //! maps to an external function call. These external functions are exported by the wasm executor //! and they map to the same implementation as the native calls. //! //! # Using a type in a runtime interface //! //! Any type that should be used in a runtime interface as argument or return value needs to //! implement [`RIType`]. The associated type //! [`FFIType`](./trait.RIType.html#associatedtype.FFIType) is the type that is used in the FFI //! function to represent the actual type. For example `[T]` is represented by an `u64`. The slice //! pointer and the length will be mapped to an `u64` value. For more information see this //! [table](#ffi-type-and-conversion). The FFI function definition is used when calling from the //! wasm runtime into the node. //! //! Traits are used to convert from a type to the corresponding //! [`RIType::FFIType`](./trait.RIType.html#associatedtype.FFIType). //! Depending on where and how a type should be used in a function signature, a combination of the //! following traits need to be implemented: //! //! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`] //! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`] //! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`] //! //! The traits are implemented for most of the common types like `[T]`, `Vec`, arrays and //! primitive types. //! //! For custom types, we provide the [`PassBy`](./pass_by#PassBy) trait and strategies that define //! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive //! macro to simplify the implementation. //! //! # Performance //! //! To not waste any more performance when calling into the node, not all types are SCALE encoded //! when being passed as arguments between the wasm runtime and the node. For most types that //! are raw bytes like `Vec`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding //! them in front of. The implementation of [`RIType`] each type provides more information on how //! the data is passed. //! //! # Declaring a runtime interface //! //! Declaring a runtime interface is similar to declaring a trait in Rust: //! //! ``` //! #[sp_runtime_interface::runtime_interface] //! trait RuntimeInterface { //! fn some_function(value: &[u8]) -> bool { //! value.iter().all(|v| *v > 125) //! } //! } //! ``` //! //! For more information on declaring a runtime interface, see //! [`#[runtime_interface]`](./attr.runtime_interface.html). //! //! # FFI type and conversion //! //! The following table documents how values of types are passed between the wasm and //! the host side and how they are converted into the corresponding type. //! //! | Type | FFI type | Conversion | //! |----|----|----| //! | `u8` | `u32` | zero-extended to 32-bits | //! | `u16` | `u32` | zero-extended to 32-bits | //! | `u32` | `u32` | `Identity` | //! | `u64` | `u64` | `Identity` | //! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | //! | `i8` | `i32` | sign-extended to 32-bits | //! | `i16` | `i32` | sign-extended to 32-bits | //! | `i32` | `i32` | `Identity` | //! | `i64` | `i64` | `Identity` | //! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | //! | `bool` | `u32` | `if v { 1 } else { 0 }` | //! | `&str` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `&[u8]` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `Vec` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | //! | `Vec where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | //! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | //! | `[u8; N]` | `u32` | `v.as_ptr()` | //! | `*const T` | `u32` | `Identity` | //! | `Option` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | //! | [`T where T: PassBy`](./pass_by#Inner) | Depends on inner | Depends on inner | //! | [`T where T: PassBy`](./pass_by#Codec)|`u64`|v.len() 32bit << 32 |v.as_ptr() 32bit| //! //! `Identity` means that the value is converted directly into the corresponding FFI type. #![cfg_attr(not(feature = "std"), no_std)] extern crate self as sp_runtime_interface; #[doc(hidden)] #[cfg(feature = "std")] pub use sp_wasm_interface; #[doc(hidden)] pub use sp_tracing; #[doc(hidden)] pub use sp_std; /// Attribute macro for transforming a trait declaration into a runtime interface. /// /// A runtime interface is a fixed interface between a Substrate compatible runtime and the /// native node. This interface is callable from a native and a wasm runtime. The macro will /// generate the corresponding code for the native implementation and the code for calling from /// the wasm side to the native implementation. /// /// The macro expects the runtime interface declaration as trait declaration: /// /// ``` /// # use sp_runtime_interface::runtime_interface; /// /// #[runtime_interface] /// trait Interface { /// /// A function that can be called from native/wasm. /// /// /// /// The implementation given to this function is only compiled on native. /// fn call(data: &[u8]) -> Vec { /// // Here you could call some rather complex code that only compiles on native or /// // is way faster in native than executing it in wasm. /// Vec::new() /// } /// /// Call function, but different version. /// /// /// /// For new runtimes, only function with latest version is reachable. /// /// But old version (above) is still accessible for old runtimes. /// /// Default version is 1. /// #[version(2)] /// fn call(data: &[u8]) -> Vec { /// // Here you could call some rather complex code that only compiles on native or /// // is way faster in native than executing it in wasm. /// [17].to_vec() /// } /// /// /// Call function, different version and only being registered. /// /// /// /// This `register_only` version is only being registered, aka exposed to the runtime, /// /// but the runtime will still use the version 2 of this function. This is useful for when /// /// new host functions should be introduced. Adding new host functions requires that all /// /// nodes have the host functions available, because otherwise they fail at instantiation /// /// of the runtime. With `register_only` the function will not be used when compiling the /// /// runtime, but it will already be there for a future version of the runtime that will /// /// switch to using these host function. /// #[version(3, register_only)] /// fn call(data: &[u8]) -> Vec { /// // Here you could call some rather complex code that only compiles on native or /// // is way faster in native than executing it in wasm. /// [18].to_vec() /// } /// /// /// A function can take a `&self` or `&mut self` argument to get access to the /// /// `Externalities`. (The generated method does not require /// /// this argument, so the function can be called just with the `optional` argument) /// fn set_or_clear(&mut self, optional: Option>) { /// match optional { /// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value), /// None => self.clear_storage(&[1, 2, 3, 4]), /// } /// } /// /// /// A function can be gated behind a configuration (`cfg`) attribute. /// /// To prevent ambiguity and confusion about what will be the final exposed host /// /// functions list, conditionally compiled functions can't be versioned. /// /// That is, conditionally compiled functions with `version`s greater than 1 /// /// are not allowed. /// #[cfg(feature = "experimental-function")] /// fn gated_call(data: &[u8]) -> Vec { /// [42].to_vec() /// } /// } /// ``` /// /// The given example will generate roughly the following code for native: /// /// ``` /// // The name of the trait is converted to snake case and used as mod name. /// // /// // Be aware that this module is not `public`, the visibility of the module is determined based /// // on the visibility of the trait declaration. /// mod interface { /// trait Interface { /// fn call_version_1(data: &[u8]) -> Vec; /// fn call_version_2(data: &[u8]) -> Vec; /// fn call_version_3(data: &[u8]) -> Vec; /// fn set_or_clear_version_1(&mut self, optional: Option>); /// #[cfg(feature = "experimental-function")] /// fn gated_call_version_1(data: &[u8]) -> Vec; /// } /// /// impl Interface for &mut dyn sp_externalities::Externalities { /// fn call_version_1(data: &[u8]) -> Vec { Vec::new() } /// fn call_version_2(data: &[u8]) -> Vec { [17].to_vec() } /// fn call_version_3(data: &[u8]) -> Vec { [18].to_vec() } /// fn set_or_clear_version_1(&mut self, optional: Option>) { /// match optional { /// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value), /// None => self.clear_storage(&[1, 2, 3, 4]), /// } /// } /// #[cfg(feature = "experimental-function")] /// fn gated_call_version_1(data: &[u8]) -> Vec { [42].to_vec() } /// } /// /// pub fn call(data: &[u8]) -> Vec { /// // only latest version is exposed /// call_version_2(data) /// } /// /// fn call_version_1(data: &[u8]) -> Vec { /// <&mut dyn sp_externalities::Externalities as Interface>::call_version_1(data) /// } /// /// fn call_version_2(data: &[u8]) -> Vec { /// <&mut dyn sp_externalities::Externalities as Interface>::call_version_2(data) /// } /// /// fn call_version_3(data: &[u8]) -> Vec { /// <&mut dyn sp_externalities::Externalities as Interface>::call_version_3(data) /// } /// /// pub fn set_or_clear(optional: Option>) { /// set_or_clear_version_1(optional) /// } /// /// fn set_or_clear_version_1(optional: Option>) { /// sp_externalities::with_externalities(|mut ext| Interface::set_or_clear_version_1(&mut ext, optional)) /// .expect("`set_or_clear` called outside of an Externalities-provided environment.") /// } /// /// #[cfg(feature = "experimental-function")] /// pub fn gated_call(data: &[u8]) -> Vec { /// gated_call_version_1(data) /// } /// /// #[cfg(feature = "experimental-function")] /// fn gated_call_version_1(data: &[u8]) -> Vec { /// <&mut dyn sp_externalities::Externalities as Interface>::gated_call_version_1(data) /// } /// /// /// This type implements the `HostFunctions` trait (from `sp-wasm-interface`) and /// /// provides the host implementation for the wasm side. The host implementation converts the /// /// arguments from wasm to native and calls the corresponding native function. /// /// /// /// This type needs to be passed to the wasm executor, so that the host functions will be /// /// registered in the executor. /// pub struct HostFunctions; /// } /// ``` /// /// The given example will generate roughly the following code for wasm: /// /// ``` /// mod interface { /// mod extern_host_functions_impls { /// /// Every function is exported by the native code as `ext_FUNCTION_NAME_version_VERSION`. /// /// /// /// The type for each argument of the exported function depends on /// /// `::FFIType`. /// /// /// /// `key` holds the pointer and the length to the `data` slice. /// pub fn call(data: &[u8]) -> Vec { /// extern "C" { pub fn ext_call_version_2(key: u64); } /// // Should call into external `ext_call_version_2(<[u8] as IntoFFIValue>::into_ffi_value(key))` /// // But this is too much to replicate in a doc test so here we just return a dummy vector. /// // Note that we jump into the latest version not marked as `register_only` (i.e. version 2). /// Vec::new() /// } /// /// /// `key` holds the pointer and the length of the `option` value. /// pub fn set_or_clear(option: Option>) { /// extern "C" { pub fn ext_set_or_clear_version_1(key: u64); } /// // Same as above /// } /// /// /// `key` holds the pointer and the length to the `data` slice. /// #[cfg(feature = "experimental-function")] /// pub fn gated_call(data: &[u8]) -> Vec { /// extern "C" { pub fn ext_gated_call_version_1(key: u64); } /// /// Same as above /// Vec::new() /// } /// } /// /// /// The type is actually `ExchangeableFunction` (from `sp-runtime-interface`) and /// /// by default this is initialized to jump into the corresponding function in /// /// `extern_host_functions_impls`. /// /// /// /// This can be used to replace the implementation of the `call` function. /// /// Instead of calling into the host, the callee will automatically call the other /// /// implementation. /// /// /// /// To replace the implementation: /// /// /// /// `host_call.replace_implementation(some_other_impl)` /// pub static host_call: () = (); /// pub static host_set_or_clear: () = (); /// #[cfg(feature = "experimental-feature")] /// pub static gated_call: () = (); /// /// pub fn call(data: &[u8]) -> Vec { /// // This is the actual call: `host_call.get()(data)` /// // /// // But that does not work for several reasons in this example, so we just return an /// // empty vector. /// Vec::new() /// } /// /// pub fn set_or_clear(optional: Option>) { /// // Same as above /// } /// /// #[cfg(feature = "experimental-feature")] /// pub fn gated_call(data: &[u8]) -> Vec { /// // Same as above /// Vec::new() /// } /// } /// ``` /// /// # Argument types /// /// The macro supports any kind of argument type, as long as it implements [`RIType`] and the /// required `FromFFIValue`/`IntoFFIValue`. The macro will convert each /// argument to the corresponding FFI representation and will call into the host using this FFI /// representation. On the host each argument is converted back to the native representation /// and the native implementation is called. Any return value is handled in the same way. /// /// # Wasm only interfaces /// /// Some interfaces are only required from within the wasm runtime e.g. the allocator /// interface. To support this, the macro can be called like `#[runtime_interface(wasm_only)]`. /// This instructs the macro to make two significant changes to the generated code: /// /// 1. The generated functions are not callable from the native side. /// 2. The trait as shown above is not implemented for [`Externalities`] and is instead /// implemented for `FunctionContext` (from `sp-wasm-interface`). /// /// # Disable tracing /// By adding `no_tracing` to the list of options you can prevent the wasm-side interface from /// generating the default `sp-tracing`-calls. Note that this is rarely needed but only meant /// for the case when that would create a circular dependency. You usually _do not_ want to add /// this flag, as tracing doesn't cost you anything by default anyways (it is added as a no-op) /// but is super useful for debugging later. pub use sp_runtime_interface_proc_macro::runtime_interface; #[doc(hidden)] #[cfg(feature = "std")] pub use sp_externalities::{ set_and_run_with_externalities, with_externalities, ExtensionStore, Externalities, ExternalitiesExt, }; #[doc(hidden)] pub use codec; #[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))] pub mod polkavm; #[cfg(feature = "std")] pub mod host; pub(crate) mod impls; pub mod pass_by; #[cfg(any(not(feature = "std"), doc))] pub mod wasm; mod util; pub use util::{pack_ptr_and_len, unpack_ptr_and_len}; /// Something that can be used by the runtime interface as type to communicate between wasm and the /// host. /// /// Every type that should be used in a runtime interface function signature needs to implement /// this trait. pub trait RIType { /// The ffi type that is used to represent `Self`. #[cfg(feature = "std")] type FFIType: sp_wasm_interface::IntoValue + sp_wasm_interface::TryFromValue + sp_wasm_interface::WasmTy; #[cfg(not(feature = "std"))] type FFIType; } /// A pointer that can be used in a runtime interface function signature. #[cfg(not(feature = "std"))] pub type Pointer = *mut T; /// A pointer that can be used in a runtime interface function signature. #[cfg(feature = "std")] pub type Pointer = sp_wasm_interface::Pointer;