1use 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#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
33pub enum CallContext {
34 Offchain,
36 Onchain {
38 import: bool,
40 },
41}
42
43pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'static {
45 type Error: Display + Debug + Send + Sync + 'static;
47
48 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 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
76pub trait FetchRuntimeCode {
78 fn fetch_runtime_code(&self) -> Option<Cow<'_, [u8]>>;
82}
83
84pub 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
93pub struct NoneFetchRuntimeCode;
95
96impl FetchRuntimeCode for NoneFetchRuntimeCode {
97 fn fetch_runtime_code(&self) -> Option<Cow<'_, [u8]>> {
98 None
99 }
100}
101
102#[derive(Clone)]
104pub struct RuntimeCode<'a> {
105 pub code_fetcher: &'a dyn FetchRuntimeCode,
107 pub heap_pages: Option<u64>,
111 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 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#[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
149pub trait ReadRuntimeVersion: Send + Sync {
151 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 pub struct ReadRuntimeVersionExt(Box<dyn ReadRuntimeVersion>);
190}
191
192impl ReadRuntimeVersionExt {
193 pub fn new<T: ReadRuntimeVersion + 'static>(inner: T) -> Self {
195 Self(Box::new(inner))
196 }
197}
198
199pub trait SpawnNamed: dyn_clone::DynClone + Send + Sync {
202 fn spawn_blocking(
206 &self,
207 name: &'static str,
208 group: Option<&'static str>,
209 future: futures::future::BoxFuture<'static, ()>,
210 );
211 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
243pub trait SpawnEssentialNamed: dyn_clone::DynClone + Send + Sync {
248 fn spawn_essential_blocking(
252 &self,
253 name: &'static str,
254 group: Option<&'static str>,
255 future: futures::future::BoxFuture<'static, ()>,
256 );
257 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}