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