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 &#124; v.as_ptr() 32bit</code> |
95//! | `&[u8]` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
96//! | `Vec<u8>` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
97//! | `Vec<T> where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
98//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; 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 &#124; 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 &#124;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>;