Skip to main content

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