sp_runtime_interface/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Substrate runtime interface
19//!
20//! This crate provides types, traits and macros around runtime interfaces. A runtime interface is
21//! a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the
22//! interface maps to a direct function call of the implementation. For a wasm runtime the interface
23//! maps to an external function call. These external functions are exported by the wasm executor
24//! and they map to the same implementation as the native calls.
25//!
26//! # Using a type in a runtime interface
27//!
28//! Any type that should be used in a runtime interface as argument or return value needs to
29//! implement [`RIType`]. The associated type
30//! [`FFIType`](./trait.RIType.html#associatedtype.FFIType) is the type that is used in the FFI
31//! function to represent the actual type. For example `[T]` is represented by an `u64`. The slice
32//! pointer and the length will be mapped to an `u64` value. For more information see this
33//! [table](#ffi-type-and-conversion). The FFI function definition is used when calling from the
34//! wasm runtime into the node.
35//!
36//! Traits are used to convert from a type to the corresponding
37//! [`RIType::FFIType`](./trait.RIType.html#associatedtype.FFIType).
38//! Depending on where and how a type should be used in a function signature, a combination of the
39//! following traits need to be implemented:
40//! <!-- markdown-link-check-enable -->
41//! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`]
42//! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`]
43//! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`]
44//!
45//! The traits are implemented for most of the common types like `[T]`, `Vec<T>`, arrays and
46//! primitive types.
47//!
48//! For custom types, we provide the [`PassBy`](./pass_by#PassBy) trait and strategies that define
49//! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive
50//! macro to simplify the implementation.
51//!
52//! # Performance
53//!
54//! To not waste any more performance when calling into the node, not all types are SCALE encoded
55//! when being passed as arguments between the wasm runtime and the node. For most types that
56//! are raw bytes like `Vec<u8>`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding
57//! them in front of. The implementation of [`RIType`] each type provides more information on how
58//! the data is passed.
59//!
60//! # Declaring a runtime interface
61//!
62//! Declaring a runtime interface is similar to declaring a trait in Rust:
63//!
64//! ```
65//! #[sp_runtime_interface::runtime_interface]
66//! trait RuntimeInterface {
67//! fn some_function(value: &[u8]) -> bool {
68//! value.iter().all(|v| *v > 125)
69//! }
70//! }
71//! ```
72//!
73//! For more information on declaring a runtime interface, see
74//! [`#[runtime_interface]`](./attr.runtime_interface.html).
75//!
76//! # FFI type and conversion
77//!
78//! The following table documents how values of types are passed between the wasm and
79//! the host side and how they are converted into the corresponding type.
80//!
81//! | Type | FFI type | Conversion |
82//! |----|----|----|
83//! | `u8` | `u32` | zero-extended to 32-bits |
84//! | `u16` | `u32` | zero-extended to 32-bits |
85//! | `u32` | `u32` | `Identity` |
86//! | `u64` | `u64` | `Identity` |
87//! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
88//! | `i8` | `i32` | sign-extended to 32-bits |
89//! | `i16` | `i32` | sign-extended to 32-bits |
90//! | `i32` | `i32` | `Identity` |
91//! | `i64` | `i64` | `Identity` |
92//! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
93//! | `bool` | `u32` | `if v { 1 } else { 0 }` |
94//! | `&str` | `u64` | <code>v.len() 32bit << 32 | v.as_ptr() 32bit</code> |
95//! | `&[u8]` | `u64` | <code>v.len() 32bit << 32 | v.as_ptr() 32bit</code> |
96//! | `Vec<u8>` | `u64` | <code>v.len() 32bit << 32 | v.as_ptr() 32bit</code> |
97//! | `Vec<T> where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 | e.as_ptr() 32bit</code> |
98//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 | e.as_ptr() 32bit</code> |
99//! | `[u8; N]` | `u32` | `v.as_ptr()` |
100//! | `*const T` | `u32` | `Identity` |
101//! | `Option<T>` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 | e.as_ptr() 32bit</code> |
102//! | [`T where T: PassBy<PassBy=Inner>`](./pass_by#Inner) | Depends on inner | Depends on inner |
103//! | [`T where T: PassBy<PassBy=Codec>`](./pass_by#Codec)|`u64`|<code>v.len() 32bit << 32 |v.as_ptr() 32bit</code>|
104//!
105//! `Identity` means that the value is converted directly into the corresponding FFI type.
106
107#![cfg_attr(not(feature = "std"), no_std)]
108
109extern crate self as sp_runtime_interface;
110
111extern crate alloc;
112
113#[doc(hidden)]
114#[cfg(feature = "std")]
115pub use sp_wasm_interface;
116
117#[doc(hidden)]
118pub use sp_tracing;
119
120#[doc(hidden)]
121pub use sp_std;
122
123/// Attribute macro for transforming a trait declaration into a runtime interface.
124///
125/// A runtime interface is a fixed interface between a Substrate compatible runtime and the
126/// native node. This interface is callable from a native and a wasm runtime. The macro will
127/// generate the corresponding code for the native implementation and the code for calling from
128/// the wasm side to the native implementation.
129///
130/// The macro expects the runtime interface declaration as trait declaration:
131///
132/// ```
133/// # use sp_runtime_interface::runtime_interface;
134///
135/// #[runtime_interface]
136/// trait Interface {
137/// /// A function that can be called from native/wasm.
138/// ///
139/// /// The implementation given to this function is only compiled on native.
140/// fn call(data: &[u8]) -> Vec<u8> {
141/// // Here you could call some rather complex code that only compiles on native or
142/// // is way faster in native than executing it in wasm.
143/// Vec::new()
144/// }
145/// /// Call function, but different version.
146/// ///
147/// /// For new runtimes, only function with latest version is reachable.
148/// /// But old version (above) is still accessible for old runtimes.
149/// /// Default version is 1.
150/// #[version(2)]
151/// fn call(data: &[u8]) -> Vec<u8> {
152/// // Here you could call some rather complex code that only compiles on native or
153/// // is way faster in native than executing it in wasm.
154/// [17].to_vec()
155/// }
156///
157/// /// Call function, different version and only being registered.
158/// ///
159/// /// This `register_only` version is only being registered, aka exposed to the runtime,
160/// /// but the runtime will still use the version 2 of this function. This is useful for when
161/// /// new host functions should be introduced. Adding new host functions requires that all
162/// /// nodes have the host functions available, because otherwise they fail at instantiation
163/// /// of the runtime. With `register_only` the function will not be used when compiling the
164/// /// runtime, but it will already be there for a future version of the runtime that will
165/// /// switch to using these host function.
166/// #[version(3, register_only)]
167/// fn call(data: &[u8]) -> Vec<u8> {
168/// // Here you could call some rather complex code that only compiles on native or
169/// // is way faster in native than executing it in wasm.
170/// [18].to_vec()
171/// }
172///
173/// /// A function can take a `&self` or `&mut self` argument to get access to the
174/// /// `Externalities`. (The generated method does not require
175/// /// this argument, so the function can be called just with the `optional` argument)
176/// fn set_or_clear(&mut self, optional: Option<Vec<u8>>) {
177/// match optional {
178/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
179/// None => self.clear_storage(&[1, 2, 3, 4]),
180/// }
181/// }
182///
183/// /// A function can be gated behind a configuration (`cfg`) attribute.
184/// /// To prevent ambiguity and confusion about what will be the final exposed host
185/// /// functions list, conditionally compiled functions can't be versioned.
186/// /// That is, conditionally compiled functions with `version`s greater than 1
187/// /// are not allowed.
188/// #[cfg(feature = "experimental-function")]
189/// fn gated_call(data: &[u8]) -> Vec<u8> {
190/// [42].to_vec()
191/// }
192/// }
193/// ```
194///
195/// The given example will generate roughly the following code for native:
196///
197/// ```
198/// // The name of the trait is converted to snake case and used as mod name.
199/// //
200/// // Be aware that this module is not `public`, the visibility of the module is determined based
201/// // on the visibility of the trait declaration.
202/// mod interface {
203/// trait Interface {
204/// fn call_version_1(data: &[u8]) -> Vec<u8>;
205/// fn call_version_2(data: &[u8]) -> Vec<u8>;
206/// fn call_version_3(data: &[u8]) -> Vec<u8>;
207/// fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>);
208/// #[cfg(feature = "experimental-function")]
209/// fn gated_call_version_1(data: &[u8]) -> Vec<u8>;
210/// }
211///
212/// impl Interface for &mut dyn sp_externalities::Externalities {
213/// fn call_version_1(data: &[u8]) -> Vec<u8> { Vec::new() }
214/// fn call_version_2(data: &[u8]) -> Vec<u8> { [17].to_vec() }
215/// fn call_version_3(data: &[u8]) -> Vec<u8> { [18].to_vec() }
216/// fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>) {
217/// match optional {
218/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
219/// None => self.clear_storage(&[1, 2, 3, 4]),
220/// }
221/// }
222/// #[cfg(feature = "experimental-function")]
223/// fn gated_call_version_1(data: &[u8]) -> Vec<u8> { [42].to_vec() }
224/// }
225///
226/// pub fn call(data: &[u8]) -> Vec<u8> {
227/// // only latest version is exposed
228/// call_version_2(data)
229/// }
230///
231/// fn call_version_1(data: &[u8]) -> Vec<u8> {
232/// <&mut dyn sp_externalities::Externalities as Interface>::call_version_1(data)
233/// }
234///
235/// fn call_version_2(data: &[u8]) -> Vec<u8> {
236/// <&mut dyn sp_externalities::Externalities as Interface>::call_version_2(data)
237/// }
238///
239/// fn call_version_3(data: &[u8]) -> Vec<u8> {
240/// <&mut dyn sp_externalities::Externalities as Interface>::call_version_3(data)
241/// }
242///
243/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
244/// set_or_clear_version_1(optional)
245/// }
246///
247/// fn set_or_clear_version_1(optional: Option<Vec<u8>>) {
248/// sp_externalities::with_externalities(|mut ext| Interface::set_or_clear_version_1(&mut ext, optional))
249/// .expect("`set_or_clear` called outside of an Externalities-provided environment.")
250/// }
251///
252/// #[cfg(feature = "experimental-function")]
253/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
254/// gated_call_version_1(data)
255/// }
256///
257/// #[cfg(feature = "experimental-function")]
258/// fn gated_call_version_1(data: &[u8]) -> Vec<u8> {
259/// <&mut dyn sp_externalities::Externalities as Interface>::gated_call_version_1(data)
260/// }
261///
262/// /// This type implements the `HostFunctions` trait (from `sp-wasm-interface`) and
263/// /// provides the host implementation for the wasm side. The host implementation converts the
264/// /// arguments from wasm to native and calls the corresponding native function.
265/// ///
266/// /// This type needs to be passed to the wasm executor, so that the host functions will be
267/// /// registered in the executor.
268/// pub struct HostFunctions;
269/// }
270/// ```
271///
272/// The given example will generate roughly the following code for wasm:
273///
274/// ```
275/// mod interface {
276/// mod extern_host_functions_impls {
277/// /// Every function is exported by the native code as `ext_FUNCTION_NAME_version_VERSION`.
278/// ///
279/// /// The type for each argument of the exported function depends on
280/// /// `<ARGUMENT_TYPE as RIType>::FFIType`.
281/// ///
282/// /// `key` holds the pointer and the length to the `data` slice.
283/// pub fn call(data: &[u8]) -> Vec<u8> {
284/// extern "C" { pub fn ext_call_version_2(key: u64); }
285/// // Should call into external `ext_call_version_2(<[u8] as IntoFFIValue>::into_ffi_value(key))`
286/// // But this is too much to replicate in a doc test so here we just return a dummy vector.
287/// // Note that we jump into the latest version not marked as `register_only` (i.e. version 2).
288/// Vec::new()
289/// }
290///
291/// /// `key` holds the pointer and the length of the `option` value.
292/// pub fn set_or_clear(option: Option<Vec<u8>>) {
293/// extern "C" { pub fn ext_set_or_clear_version_1(key: u64); }
294/// // Same as above
295/// }
296///
297/// /// `key` holds the pointer and the length to the `data` slice.
298/// #[cfg(feature = "experimental-function")]
299/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
300/// extern "C" { pub fn ext_gated_call_version_1(key: u64); }
301/// /// Same as above
302/// Vec::new()
303/// }
304/// }
305///
306/// /// The type is actually `ExchangeableFunction` (from `sp-runtime-interface`) and
307/// /// by default this is initialized to jump into the corresponding function in
308/// /// `extern_host_functions_impls`.
309/// ///
310/// /// This can be used to replace the implementation of the `call` function.
311/// /// Instead of calling into the host, the callee will automatically call the other
312/// /// implementation.
313/// ///
314/// /// To replace the implementation:
315/// ///
316/// /// `host_call.replace_implementation(some_other_impl)`
317/// pub static host_call: () = ();
318/// pub static host_set_or_clear: () = ();
319/// #[cfg(feature = "experimental-feature")]
320/// pub static gated_call: () = ();
321///
322/// pub fn call(data: &[u8]) -> Vec<u8> {
323/// // This is the actual call: `host_call.get()(data)`
324/// //
325/// // But that does not work for several reasons in this example, so we just return an
326/// // empty vector.
327/// Vec::new()
328/// }
329///
330/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
331/// // Same as above
332/// }
333///
334/// #[cfg(feature = "experimental-feature")]
335/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
336/// // Same as above
337/// Vec::new()
338/// }
339/// }
340/// ```
341///
342/// # Argument types
343///
344/// The macro supports any kind of argument type, as long as it implements [`RIType`] and the
345/// required `FromFFIValue`/`IntoFFIValue`. The macro will convert each
346/// argument to the corresponding FFI representation and will call into the host using this FFI
347/// representation. On the host each argument is converted back to the native representation
348/// and the native implementation is called. Any return value is handled in the same way.
349///
350/// # Wasm only interfaces
351///
352/// Some interfaces are only required from within the wasm runtime e.g. the allocator
353/// interface. To support this, the macro can be called like `#[runtime_interface(wasm_only)]`.
354/// This instructs the macro to make two significant changes to the generated code:
355///
356/// 1. The generated functions are not callable from the native side.
357/// 2. The trait as shown above is not implemented for [`Externalities`] and is instead
358/// implemented for `FunctionContext` (from `sp-wasm-interface`).
359///
360/// # Disable tracing
361/// By adding `no_tracing` to the list of options you can prevent the wasm-side interface from
362/// generating the default `sp-tracing`-calls. Note that this is rarely needed but only meant
363/// for the case when that would create a circular dependency. You usually _do not_ want to add
364/// this flag, as tracing doesn't cost you anything by default anyways (it is added as a no-op)
365/// but is super useful for debugging later.
366pub use sp_runtime_interface_proc_macro::runtime_interface;
367
368#[doc(hidden)]
369#[cfg(feature = "std")]
370pub use sp_externalities::{
371 set_and_run_with_externalities, with_externalities, ExtensionStore, Externalities,
372 ExternalitiesExt,
373};
374
375#[doc(hidden)]
376pub use codec;
377
378#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))]
379pub mod polkavm;
380
381#[cfg(feature = "std")]
382pub mod host;
383pub(crate) mod impls;
384pub mod pass_by;
385#[cfg(any(not(feature = "std"), doc))]
386pub mod wasm;
387
388mod util;
389
390pub use util::{pack_ptr_and_len, unpack_ptr_and_len};
391
392/// Something that can be used by the runtime interface as type to communicate between wasm and the
393/// host.
394///
395/// Every type that should be used in a runtime interface function signature needs to implement
396/// this trait.
397pub trait RIType {
398 /// The ffi type that is used to represent `Self`.
399 #[cfg(feature = "std")]
400 type FFIType: sp_wasm_interface::IntoValue
401 + sp_wasm_interface::TryFromValue
402 + sp_wasm_interface::WasmTy;
403 #[cfg(not(feature = "std"))]
404 type FFIType;
405}
406
407/// A pointer that can be used in a runtime interface function signature.
408#[cfg(not(feature = "std"))]
409pub type Pointer<T> = *mut T;
410
411/// A pointer that can be used in a runtime interface function signature.
412#[cfg(feature = "std")]
413pub type Pointer<T> = sp_wasm_interface::Pointer<T>;