sp_core/
traits.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//! Shareable Substrate traits.
19
20use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
21use core::fmt::{Debug, Display};
22
23pub use sp_externalities::{Externalities, ExternalitiesExt};
24
25/// The context in which a call is done.
26///
27/// Depending on the context the executor may chooses different kind of heap sizes for the runtime
28/// instance.
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
30pub enum CallContext {
31	/// The call is happening in some offchain context.
32	Offchain,
33	/// The call is happening in some on-chain context like building or importing a block.
34	Onchain,
35}
36
37/// Code execution engine.
38pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'static {
39	/// Externalities error type.
40	type Error: Display + Debug + Send + Sync + 'static;
41
42	/// Call a given method in the runtime.
43	///
44	/// Returns a tuple of the result (either the output data or an execution error) together with a
45	/// `bool`, which is true if native execution was used.
46	fn call(
47		&self,
48		ext: &mut dyn Externalities,
49		runtime_code: &RuntimeCode,
50		method: &str,
51		data: &[u8],
52		context: CallContext,
53	) -> (Result<Vec<u8>, Self::Error>, bool);
54}
55
56/// Something that can fetch the runtime `:code`.
57pub trait FetchRuntimeCode {
58	/// Fetch the runtime `:code`.
59	///
60	/// If the `:code` could not be found/not available, `None` should be returned.
61	fn fetch_runtime_code(&self) -> Option<Cow<[u8]>>;
62}
63
64/// Wrapper to use a `u8` slice or `Vec` as [`FetchRuntimeCode`].
65pub struct WrappedRuntimeCode<'a>(pub Cow<'a, [u8]>);
66
67impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> {
68	fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
69		Some(self.0.as_ref().into())
70	}
71}
72
73/// Type that implements [`FetchRuntimeCode`] and always returns `None`.
74pub struct NoneFetchRuntimeCode;
75
76impl FetchRuntimeCode for NoneFetchRuntimeCode {
77	fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
78		None
79	}
80}
81
82/// The Wasm code of a Substrate runtime.
83#[derive(Clone)]
84pub struct RuntimeCode<'a> {
85	/// The code fetcher that can be used to lazily fetch the code.
86	pub code_fetcher: &'a dyn FetchRuntimeCode,
87	/// The optional heap pages this `code` should be executed with.
88	///
89	/// If `None` are given, the default value of the executor will be used.
90	pub heap_pages: Option<u64>,
91	/// The hash of `code`.
92	///
93	/// The hashing algorithm isn't that important, as long as all runtime
94	/// code instances use the same.
95	pub hash: Vec<u8>,
96}
97
98impl<'a> PartialEq for RuntimeCode<'a> {
99	fn eq(&self, other: &Self) -> bool {
100		self.hash == other.hash
101	}
102}
103
104impl<'a> RuntimeCode<'a> {
105	/// Create an empty instance.
106	///
107	/// This is only useful for tests that don't want to execute any code.
108	pub fn empty() -> Self {
109		Self { code_fetcher: &NoneFetchRuntimeCode, hash: Vec::new(), heap_pages: None }
110	}
111}
112
113impl<'a> FetchRuntimeCode for RuntimeCode<'a> {
114	fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
115		self.code_fetcher.fetch_runtime_code()
116	}
117}
118
119/// Could not find the `:code` in the externalities while initializing the [`RuntimeCode`].
120#[derive(Debug)]
121pub struct CodeNotFound;
122
123impl core::fmt::Display for CodeNotFound {
124	fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
125		write!(f, "the storage entry `:code` doesn't have any code")
126	}
127}
128
129/// A trait that allows reading version information from the binary.
130pub trait ReadRuntimeVersion: Send + Sync {
131	/// Reads the runtime version information from the given wasm code.
132	///
133	/// The version information may be embedded into the wasm binary itself. If it is not present,
134	/// then this function may fallback to the legacy way of reading the version.
135	///
136	/// The legacy mechanism involves instantiating the passed wasm runtime and calling
137	/// `Core_version` on it. This is a very expensive operation.
138	///
139	/// `ext` is only needed in case the calling into runtime happens. Otherwise it is ignored.
140	///
141	/// Compressed wasm blobs are supported and will be decompressed if needed. If uncompression
142	/// fails, the error is returned.
143	///
144	/// # Errors
145	///
146	/// If the version information present in binary, but is corrupted - returns an error.
147	///
148	/// Otherwise, if there is no version information present, and calling into the runtime takes
149	/// place, then an error would be returned if `Core_version` is not provided.
150	fn read_runtime_version(
151		&self,
152		wasm_code: &[u8],
153		ext: &mut dyn Externalities,
154	) -> Result<Vec<u8>, String>;
155}
156
157impl ReadRuntimeVersion for alloc::sync::Arc<dyn ReadRuntimeVersion> {
158	fn read_runtime_version(
159		&self,
160		wasm_code: &[u8],
161		ext: &mut dyn Externalities,
162	) -> Result<Vec<u8>, String> {
163		(**self).read_runtime_version(wasm_code, ext)
164	}
165}
166
167sp_externalities::decl_extension! {
168	/// An extension that provides functionality to read version information from a given wasm blob.
169	pub struct ReadRuntimeVersionExt(Box<dyn ReadRuntimeVersion>);
170}
171
172impl ReadRuntimeVersionExt {
173	/// Creates a new instance of the extension given a version determinator instance.
174	pub fn new<T: ReadRuntimeVersion + 'static>(inner: T) -> Self {
175		Self(Box::new(inner))
176	}
177}
178
179/// Something that can spawn tasks (blocking and non-blocking) with an assigned name
180/// and optional group.
181pub trait SpawnNamed: dyn_clone::DynClone + Send + Sync {
182	/// Spawn the given blocking future.
183	///
184	/// The given `group` and `name` is used to identify the future in tracing.
185	fn spawn_blocking(
186		&self,
187		name: &'static str,
188		group: Option<&'static str>,
189		future: futures::future::BoxFuture<'static, ()>,
190	);
191	/// Spawn the given non-blocking future.
192	///
193	/// The given `group` and `name` is used to identify the future in tracing.
194	fn spawn(
195		&self,
196		name: &'static str,
197		group: Option<&'static str>,
198		future: futures::future::BoxFuture<'static, ()>,
199	);
200}
201
202dyn_clone::clone_trait_object!(SpawnNamed);
203
204impl SpawnNamed for Box<dyn SpawnNamed> {
205	fn spawn_blocking(
206		&self,
207		name: &'static str,
208		group: Option<&'static str>,
209		future: futures::future::BoxFuture<'static, ()>,
210	) {
211		(**self).spawn_blocking(name, group, future)
212	}
213	fn spawn(
214		&self,
215		name: &'static str,
216		group: Option<&'static str>,
217		future: futures::future::BoxFuture<'static, ()>,
218	) {
219		(**self).spawn(name, group, future)
220	}
221}
222
223/// Something that can spawn essential tasks (blocking and non-blocking) with an assigned name
224/// and optional group.
225///
226/// Essential tasks are special tasks that should take down the node when they end.
227pub trait SpawnEssentialNamed: dyn_clone::DynClone + Send + Sync {
228	/// Spawn the given blocking future.
229	///
230	/// The given `group` and `name` is used to identify the future in tracing.
231	fn spawn_essential_blocking(
232		&self,
233		name: &'static str,
234		group: Option<&'static str>,
235		future: futures::future::BoxFuture<'static, ()>,
236	);
237	/// Spawn the given non-blocking future.
238	///
239	/// The given `group` and `name` is used to identify the future in tracing.
240	fn spawn_essential(
241		&self,
242		name: &'static str,
243		group: Option<&'static str>,
244		future: futures::future::BoxFuture<'static, ()>,
245	);
246}
247
248dyn_clone::clone_trait_object!(SpawnEssentialNamed);
249
250impl SpawnEssentialNamed for Box<dyn SpawnEssentialNamed> {
251	fn spawn_essential_blocking(
252		&self,
253		name: &'static str,
254		group: Option<&'static str>,
255		future: futures::future::BoxFuture<'static, ()>,
256	) {
257		(**self).spawn_essential_blocking(name, group, future)
258	}
259
260	fn spawn_essential(
261		&self,
262		name: &'static str,
263		group: Option<&'static str>,
264		future: futures::future::BoxFuture<'static, ()>,
265	) {
266		(**self).spawn_essential(name, group, future)
267	}
268}