use crate::{
crypto::{KeyTypeId, CryptoTypePublicPair},
vrf::{VRFTranscriptData, VRFSignature},
ed25519, sr25519, ecdsa,
};
use std::{
borrow::Cow,
fmt::{Debug, Display},
panic::UnwindSafe,
sync::Arc,
};
pub use sp_externalities::{Externalities, ExternalitiesExt};
#[derive(Debug, derive_more::Display)]
pub enum Error {
#[display(fmt="Key not supported: {:?}", _0)]
KeyNotSupported(KeyTypeId),
#[display(fmt="Pair was not found: {}", _0)]
PairNotFound(String),
#[display(fmt="Validation error: {}", _0)]
ValidationError(String),
#[display(fmt="Keystore unavailable")]
Unavailable,
#[display(fmt="An unknown keystore error occurred: {}", _0)]
Other(String)
}
pub trait BareCryptoStore: Send + Sync {
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
fn sr25519_generate_new(
&mut self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<sr25519::Public, Error>;
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public>;
fn ed25519_generate_new(
&mut self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error>;
fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public>;
fn ecdsa_generate_new(
&mut self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error>;
fn insert_unknown(&mut self, _key_type: KeyTypeId, _suri: &str, _public: &[u8]) -> Result<(), ()>;
fn password(&self) -> Option<&str>;
fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>
) -> Result<Vec<CryptoTypePublicPair>, Error>;
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error>;
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool;
fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
msg: &[u8],
) -> Result<Vec<u8>, Error>;
fn sign_with_any(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8]
) -> Result<(CryptoTypePublicPair, Vec<u8>), Error> {
if keys.len() == 1 {
return self.sign_with(id, &keys[0], msg).map(|s| (keys[0].clone(), s));
} else {
for k in self.supported_keys(id, keys)? {
if let Ok(sign) = self.sign_with(id, &k, msg) {
return Ok((k, sign));
}
}
}
Err(Error::KeyNotSupported(id))
}
fn sign_with_all(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Vec<Result<Vec<u8>, Error>>, ()>{
Ok(keys.iter().map(|k| self.sign_with(id, k, msg)).collect())
}
fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> Result<VRFSignature, Error>;
}
pub type BareCryptoStorePtr = Arc<parking_lot::RwLock<dyn BareCryptoStore>>;
sp_externalities::decl_extension! {
pub struct KeystoreExt(BareCryptoStorePtr);
}
pub trait CodeExecutor: Sized + Send + Sync + CallInWasm + Clone + 'static {
type Error: Display + Debug + Send + 'static;
fn call<
R: codec::Codec + PartialEq,
NC: FnOnce() -> Result<R, String> + UnwindSafe,
>(
&self,
ext: &mut dyn Externalities,
runtime_code: &RuntimeCode,
method: &str,
data: &[u8],
use_native: bool,
native_call: Option<NC>,
) -> (Result<crate::NativeOrEncoded<R>, Self::Error>, bool);
}
pub trait FetchRuntimeCode {
fn fetch_runtime_code<'a>(&'a self) -> Option<Cow<'a, [u8]>>;
}
pub struct WrappedRuntimeCode<'a>(pub std::borrow::Cow<'a, [u8]>);
impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> {
fn fetch_runtime_code<'b>(&'b self) -> Option<Cow<'b, [u8]>> {
Some(self.0.as_ref().into())
}
}
pub struct NoneFetchRuntimeCode;
impl FetchRuntimeCode for NoneFetchRuntimeCode {
fn fetch_runtime_code<'a>(&'a self) -> Option<Cow<'a, [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<'b>(&'b self) -> Option<Cow<'b, [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")
}
}
#[derive(Clone, Copy, Debug)]
pub enum MissingHostFunctions {
Allow,
Disallow,
}
impl MissingHostFunctions {
pub fn allowed(self) -> bool {
matches!(self, Self::Allow)
}
}
pub trait CallInWasm: Send + Sync {
fn call_in_wasm(
&self,
wasm_code: &[u8],
code_hash: Option<Vec<u8>>,
method: &str,
call_data: &[u8],
ext: &mut dyn Externalities,
missing_host_functions: MissingHostFunctions,
) -> Result<Vec<u8>, String>;
}
sp_externalities::decl_extension! {
pub struct CallInWasmExt(Box<dyn CallInWasm>);
}
impl CallInWasmExt {
pub fn new<T: CallInWasm + 'static>(inner: T) -> Self {
Self(Box::new(inner))
}
}
sp_externalities::decl_extension! {
pub struct TaskExecutorExt(Box<dyn SpawnNamed>);
}
impl TaskExecutorExt {
pub fn new(spawn_handle: impl SpawnNamed + Send + 'static) -> Self {
Self(Box::new(spawn_handle))
}
}
#[dyn_clonable::clonable]
pub trait SpawnNamed: Clone + Send + Sync {
fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
}
impl SpawnNamed for Box<dyn SpawnNamed> {
fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
(**self).spawn_blocking(name, future)
}
fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
(**self).spawn(name, future)
}
}