use std::{
borrow::Cow,
fmt::{Debug, Display},
};
pub use sp_externalities::{Externalities, ExternalitiesExt};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub enum CallContext {
Offchain,
Onchain,
}
pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'static {
type Error: Display + Debug + Send + Sync + 'static;
fn call(
&self,
ext: &mut dyn Externalities,
runtime_code: &RuntimeCode,
method: &str,
data: &[u8],
context: CallContext,
) -> (Result<Vec<u8>, Self::Error>, bool);
}
pub trait FetchRuntimeCode {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>>;
}
pub struct WrappedRuntimeCode<'a>(pub std::borrow::Cow<'a, [u8]>);
impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
Some(self.0.as_ref().into())
}
}
pub struct NoneFetchRuntimeCode;
impl FetchRuntimeCode for NoneFetchRuntimeCode {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
None
}
}
#[derive(Clone)]
pub struct RuntimeCode<'a> {
pub code_fetcher: &'a dyn FetchRuntimeCode,
pub heap_pages: Option<u64>,
pub hash: Vec<u8>,
}
impl<'a> PartialEq for RuntimeCode<'a> {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl<'a> RuntimeCode<'a> {
pub fn empty() -> Self {
Self { code_fetcher: &NoneFetchRuntimeCode, hash: Vec::new(), heap_pages: None }
}
}
impl<'a> FetchRuntimeCode for RuntimeCode<'a> {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
self.code_fetcher.fetch_runtime_code()
}
}
#[derive(Debug)]
pub struct CodeNotFound;
impl std::fmt::Display for CodeNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "the storage entry `:code` doesn't have any code")
}
}
pub trait ReadRuntimeVersion: Send + Sync {
fn read_runtime_version(
&self,
wasm_code: &[u8],
ext: &mut dyn Externalities,
) -> Result<Vec<u8>, String>;
}
impl ReadRuntimeVersion for std::sync::Arc<dyn ReadRuntimeVersion> {
fn read_runtime_version(
&self,
wasm_code: &[u8],
ext: &mut dyn Externalities,
) -> Result<Vec<u8>, String> {
(**self).read_runtime_version(wasm_code, ext)
}
}
sp_externalities::decl_extension! {
pub struct ReadRuntimeVersionExt(Box<dyn ReadRuntimeVersion>);
}
impl ReadRuntimeVersionExt {
pub fn new<T: ReadRuntimeVersion + 'static>(inner: T) -> Self {
Self(Box::new(inner))
}
}
#[dyn_clonable::clonable]
pub trait SpawnNamed: Clone + Send + Sync {
fn spawn_blocking(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
);
fn spawn(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
);
}
impl SpawnNamed for Box<dyn SpawnNamed> {
fn spawn_blocking(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
(**self).spawn_blocking(name, group, future)
}
fn spawn(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
(**self).spawn(name, group, future)
}
}
#[dyn_clonable::clonable]
pub trait SpawnEssentialNamed: Clone + Send + Sync {
fn spawn_essential_blocking(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
);
fn spawn_essential(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
);
}
impl SpawnEssentialNamed for Box<dyn SpawnEssentialNamed> {
fn spawn_essential_blocking(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
(**self).spawn_essential_blocking(name, group, future)
}
fn spawn_essential(
&self,
name: &'static str,
group: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
(**self).spawn_essential(name, group, future)
}
}