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