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}