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