tp_runtime_interface/
lib.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2019-2021 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//! Tetcore runtime interface
19//!
20//! This crate provides types, traits and macros around runtime interfaces. A runtime interface is
21//! a fixed interface between a Tetcore runtime and a Tetcore 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 [`FFIType`](./trait.RIType.html#associatedtype.FFIType)
30//! is the type that is used in the FFI function to represent the actual type. For example `[T]` is
31//! represented by an `u64`. The slice pointer and the length will be mapped to an `u64` value.
32//! For more information see this [table](#ffi-type-and-conversion).
33//! The FFI function definition is used when calling from the wasm runtime into the node.
34//!
35//! Traits are used to convert from a type to the corresponding
36//! [`RIType::FFIType`](./trait.RIType.html#associatedtype.FFIType).
37//! Depending on where and how a type should be used in a function signature, a combination of the
38//! following traits need to be implemented:
39//! <!-- markdown-link-check-enable -->
40//! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`]
41//! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`]
42//! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`]
43//!
44//! The traits are implemented for most of the common types like `[T]`, `Vec<T>`, arrays and
45//! primitive types.
46//!
47//! For custom types, we provide the [`PassBy`](./pass_by#PassBy) trait and strategies that define
48//! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive
49//! macro to simplify the implementation.
50//!
51//! # Performance
52//!
53//! To not waste any more performance when calling into the node, not all types are SCALE encoded
54//! when being passed as arguments between the wasm runtime and the node. For most types that
55//! are raw bytes like `Vec<u8>`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding
56//! them in front of. The implementation of [`RIType`] each type provides more information on how
57//! the data is passed.
58//!
59//! # Declaring a runtime interface
60//!
61//! Declaring a runtime interface is similar to declaring a trait in Rust:
62//!
63//! ```
64//! #[tp_runtime_interface::runtime_interface]
65//! trait RuntimeInterface {
66//!     fn some_function(value: &[u8]) -> bool {
67//!         value.iter().all(|v| *v > 125)
68//!     }
69//! }
70//! ```
71//!
72//! For more information on declaring a runtime interface, see
73//! [`#[runtime_interface]`](./attr.runtime_interface.html).
74//!
75//! # FFI type and conversion
76//!
77//! The following table documents how values of types are passed between the wasm and
78//! the host side and how they are converted into the corresponding type.
79//!
80//! | Type | FFI type | Conversion |
81//! |----|----|----|
82//! | `u8` | `u8` | `Identity` |
83//! | `u16` | `u16` | `Identity` |
84//! | `u32` | `u32` | `Identity` |
85//! | `u64` | `u64` | `Identity` |
86//! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
87//! | `i8` | `i8` | `Identity` |
88//! | `i16` | `i16` | `Identity` |
89//! | `i32` | `i32` | `Identity` |
90//! | `i64` | `i64` | `Identity` |
91//! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
92//! | `bool` | `u8` | `if v { 1 } else { 0 }` |
93//! | `&str` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
94//! | `&[u8]` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
95//! | `Vec<u8>` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
96//! | `Vec<T> where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
97//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
98//! | `[u8; N]` | `u32` | `v.as_ptr()` |
99//! | `*const T` | `u32` | `Identity` |
100//! | `Option<T>` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
101//! | [`T where T: PassBy<PassBy=Inner>`](./pass_by#Inner) | Depends on inner | Depends on inner |
102//! | [`T where T: PassBy<PassBy=Codec>`](./pass_by#Codec)|`u64`|<code>v.len() 32bit << 32 &#124;v.as_ptr() 32bit</code>|
103//!
104//! `Identity` means that the value is converted directly into the corresponding FFI type.
105
106#![cfg_attr(not(feature = "std"), no_std)]
107
108extern crate self as tp_runtime_interface;
109
110#[doc(hidden)]
111#[cfg(feature = "std")]
112pub use tetcore_wasm_interface;
113
114#[doc(hidden)]
115pub use tetcore_tracing;
116
117#[doc(hidden)]
118pub use tetcore_std;
119
120/// Attribute macro for transforming a trait declaration into a runtime interface.
121///
122/// A runtime interface is a fixed interface between a Tetcore compatible runtime and the native
123/// node. This interface is callable from a native and a wasm runtime. The macro will generate the
124/// corresponding code for the native implementation and the code for calling from the wasm
125/// side to the native implementation.
126///
127/// The macro expects the runtime interface declaration as trait declaration:
128///
129/// ```
130/// # use tp_runtime_interface::runtime_interface;
131///
132/// #[runtime_interface]
133/// trait Interface {
134///     /// A function that can be called from native/wasm.
135///     ///
136///     /// The implementation given to this function is only compiled on native.
137///     fn call(data: &[u8]) -> Vec<u8> {
138///         // Here you could call some rather complex code that only compiles on native or
139///         // is way faster in native than executing it in wasm.
140///         Vec::new()
141///     }
142///     /// Call function, but different version.
143///     ///
144///     /// For new runtimes, only function with latest version is reachable.
145///     /// But old version (above) is still accessible for old runtimes.
146///     /// Default version is 1.
147///     #[version(2)]
148///     fn call(data: &[u8]) -> Vec<u8> {
149///         // Here you could call some rather complex code that only compiles on native or
150///         // is way faster in native than executing it in wasm.
151///         [17].to_vec()
152///     }
153///
154///     /// A function can take a `&self` or `&mut self` argument to get access to the
155///     /// `Externalities`. (The generated method does not require
156///     /// this argument, so the function can be called just with the `optional` argument)
157///     fn set_or_clear(&mut self, optional: Option<Vec<u8>>) {
158///         match optional {
159///             Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
160///             None => self.clear_storage(&[1, 2, 3, 4]),
161///         }
162///     }
163/// }
164/// ```
165///
166///
167/// The given example will generate roughly the following code for native:
168///
169/// ```
170/// // The name of the trait is converted to snake case and used as mod name.
171/// //
172/// // Be aware that this module is not `public`, the visibility of the module is determined based
173/// // on the visibility of the trait declaration.
174/// mod interface {
175///     trait Interface {
176///         fn call_version_1(data: &[u8]) -> Vec<u8>;
177///         fn call_version_2(data: &[u8]) -> Vec<u8>;
178///         fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>);
179///     }
180///
181///     impl Interface for &mut dyn externalities::Externalities {
182///         fn call_version_1(data: &[u8]) -> Vec<u8> { Vec::new() }
183///         fn call_version_2(data: &[u8]) -> Vec<u8> { [17].to_vec() }
184///         fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>) {
185///             match optional {
186///                 Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
187///                 None => self.clear_storage(&[1, 2, 3, 4]),
188///             }
189///         }
190///     }
191///
192///     pub fn call(data: &[u8]) -> Vec<u8> {
193///         // only latest version is exposed
194///         call_version_2(data)
195///     }
196///
197///     fn call_version_1(data: &[u8]) -> Vec<u8> {
198///         <&mut dyn externalities::Externalities as Interface>::call_version_1(data)
199///     }
200///
201///     fn call_version_2(data: &[u8]) -> Vec<u8> {
202///         <&mut dyn externalities::Externalities as Interface>::call_version_2(data)
203///     }
204///
205///     pub fn set_or_clear(optional: Option<Vec<u8>>) {
206///         set_or_clear_version_1(optional)
207///     }
208///
209///     fn set_or_clear_version_1(optional: Option<Vec<u8>>) {
210///         externalities::with_externalities(|mut ext| Interface::set_or_clear_version_1(&mut ext, optional))
211///             .expect("`set_or_clear` called outside of an Externalities-provided environment.")
212///     }
213///
214///     /// This type implements the `HostFunctions` trait (from `tetcore-wasm-interface`) and
215///     /// provides the host implementation for the wasm side. The host implementation converts the
216///     /// arguments from wasm to native and calls the corresponding native function.
217///     ///
218///     /// This type needs to be passed to the wasm executor, so that the host functions will be
219///     /// registered in the executor.
220///     pub struct HostFunctions;
221/// }
222/// ```
223///
224///
225/// The given example will generate roughly the following code for wasm:
226///
227/// ```
228/// mod interface {
229///     mod extern_host_functions_impls {
230///         extern "C" {
231///             /// Every function is exported as `ext_TRAIT_NAME_FUNCTION_NAME_version_VERSION`.
232///             ///
233///             /// `TRAIT_NAME` is converted into snake case.
234///             ///
235///             /// The type for each argument of the exported function depends on
236///             /// `<ARGUMENT_TYPE as RIType>::FFIType`.
237///             ///
238///             /// `data` holds the pointer and the length to the `[u8]` slice.
239///             pub fn ext_Interface_call_version_1(data: u64) -> u64;
240///             /// `optional` holds the pointer and the length of the encoded value.
241///             pub fn ext_Interface_set_or_clear_version_1(optional: u64);
242///         }
243///     }
244///
245///     /// The type is actually `ExchangeableFunction` (from `tp-runtime-interface`).
246///     ///
247///     /// This can be used to replace the implementation of the `call` function.
248///     /// Instead of calling into the host, the callee will automatically call the other
249///     /// implementation.
250///     ///
251///     /// To replace the implementation:
252///     ///
253///     /// `host_call.replace_implementation(some_other_impl)`
254///     pub static host_call: () = ();
255///     pub static host_set_or_clear: () = ();
256///
257///     pub fn call(data: &[u8]) -> Vec<u8> {
258///         // This is the actual call: `host_call.get()(data)`
259///         //
260///         // But that does not work for several reasons in this example, so we just return an
261///         // empty vector.
262///         Vec::new()
263///     }
264///
265///     pub fn set_or_clear(optional: Option<Vec<u8>>) {
266///         // Same as above
267///     }
268/// }
269/// ```
270///
271/// # Argument types
272///
273/// The macro supports any kind of argument type, as long as it implements [`RIType`] and the
274/// required `FromFFIValue`/`IntoFFIValue`. The macro will convert each
275/// argument to the corresponding FFI representation and will call into the host using this FFI
276/// representation. On the host each argument is converted back to the native representation andt
277/// the native implementation is called. Any return value is handled in the same way.
278///
279/// # Wasm only interfaces
280///
281/// Some interfaces are only required from within the wasm runtime e.g. the allocator interface.
282/// To support this, the macro can be called like `#[runtime_interface(wasm_only)]`. This instructs
283/// the macro to make two significant changes to the generated code:
284///
285/// 1. The generated functions are not callable from the native side.
286/// 2. The trait as shown above is not implemented for `Externalities` and is instead implemented
287///    for `FunctionExecutor` (from `tetcore-wasm-interface`).
288///
289/// # Disable tracing
290/// By addding `no_tracing` to the list of options you can prevent the wasm-side interface from
291/// generating the default `tetcore-tracing`-calls. Note that this is rarely needed but only meant for
292/// the case when that would create a circular dependency. You usually _do not_ want to add this
293/// flag, as tracing doesn't cost you anything by default anyways (it is added as a no-op) but is
294/// super useful for debugging later.
295///
296pub use tp_runtime_interface_proc_macro::runtime_interface;
297
298#[doc(hidden)]
299#[cfg(feature = "std")]
300pub use externalities::{
301	set_and_run_with_externalities, with_externalities, Externalities, ExternalitiesExt, ExtensionStore,
302};
303
304#[doc(hidden)]
305pub use codec;
306
307pub(crate) mod impls;
308#[cfg(feature = "std")]
309pub mod host;
310#[cfg(any(not(feature = "std"), doc))]
311pub mod wasm;
312pub mod pass_by;
313
314mod util;
315
316pub use util::{unpack_ptr_and_len, pack_ptr_and_len};
317
318/// Something that can be used by the runtime interface as type to communicate between wasm and the
319/// host.
320///
321/// Every type that should be used in a runtime interface function signature needs to implement
322/// this trait.
323pub trait RIType {
324	/// The ffi type that is used to represent `Self`.
325	#[cfg(feature = "std")]
326	type FFIType: tetcore_wasm_interface::IntoValue + tetcore_wasm_interface::TryFromValue;
327	#[cfg(not(feature = "std"))]
328	type FFIType;
329}
330
331/// A pointer that can be used in a runtime interface function signature.
332#[cfg(not(feature = "std"))]
333pub type Pointer<T> = *mut T;
334
335/// A pointer that can be used in a runtime interface function signature.
336#[cfg(feature = "std")]
337pub type Pointer<T> = tetcore_wasm_interface::Pointer<T>;