referrerpolicy=no-referrer-when-downgrade

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