use crate::{Hash, Statement, Topic};
use alloc::vec::Vec;
use codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;
use sp_runtime_interface::{
pass_by::{
AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndDecodeSlice,
PassPointerAndRead, PassPointerAndReadCopy, ReturnAs,
},
runtime_interface,
};
#[cfg(feature = "std")]
use sp_externalities::ExternalitiesExt;
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct ValidStatement {
pub max_count: u32,
pub max_size: u32,
}
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)]
pub enum InvalidStatement {
BadProof,
NoProof,
InternalError,
}
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum StatementSource {
Chain,
Network,
Local,
}
impl StatementSource {
pub fn can_be_resubmitted(&self) -> bool {
match self {
StatementSource::Chain | StatementSource::Local => true,
StatementSource::Network => false,
}
}
}
sp_api::decl_runtime_apis! {
pub trait ValidateStatement {
fn validate_statement(
source: StatementSource,
statement: Statement,
) -> Result<ValidStatement, InvalidStatement>;
}
}
#[cfg(feature = "std")]
sp_externalities::decl_extension! {
pub struct StatementStoreExt(std::sync::Arc<dyn crate::StatementStore>);
}
#[cfg(feature = "std")]
impl StatementStoreExt {
pub fn new(store: std::sync::Arc<dyn crate::StatementStore>) -> Self {
Self(store)
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Encode, Decode)]
pub enum SubmitResult {
OkNew = 0,
OkKnown = 1,
Bad = 2,
NotAvailable = 3,
Full = 4,
}
impl TryFrom<u8> for SubmitResult {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(SubmitResult::OkNew),
1 => Ok(SubmitResult::OkKnown),
2 => Ok(SubmitResult::Bad),
3 => Ok(SubmitResult::NotAvailable),
4 => Ok(SubmitResult::Full),
_ => Err(()),
}
}
}
impl From<SubmitResult> for u8 {
fn from(value: SubmitResult) -> Self {
value as u8
}
}
#[cfg(feature = "std")]
pub type HostFunctions = (statement_store::HostFunctions,);
#[runtime_interface]
pub trait StatementStore {
fn submit_statement(
&mut self,
statement: PassFatPointerAndDecode<Statement>,
) -> ReturnAs<SubmitResult, u8> {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
match store.submit(statement, StatementSource::Chain) {
crate::SubmitResult::New(_) => SubmitResult::OkNew,
crate::SubmitResult::Known => SubmitResult::OkKnown,
crate::SubmitResult::Ignored => SubmitResult::Full,
crate::SubmitResult::KnownExpired => SubmitResult::Bad,
crate::SubmitResult::Bad(_) => SubmitResult::Bad,
crate::SubmitResult::InternalError(_) => SubmitResult::Bad,
}
} else {
SubmitResult::NotAvailable
}
}
fn statements(&mut self) -> AllocateAndReturnByCodec<Vec<(Hash, Statement)>> {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
store.statements().unwrap_or_default()
} else {
Vec::default()
}
}
fn broadcasts(
&mut self,
match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
store.broadcasts(match_all_topics).unwrap_or_default()
} else {
Vec::default()
}
}
fn posted(
&mut self,
match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
dest: PassPointerAndReadCopy<[u8; 32], 32>,
) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
store.posted(match_all_topics, dest).unwrap_or_default()
} else {
Vec::default()
}
}
fn posted_clear(
&mut self,
match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
dest: PassPointerAndReadCopy<[u8; 32], 32>,
) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
store.posted_clear(match_all_topics, dest).unwrap_or_default()
} else {
Vec::default()
}
}
fn remove(&mut self, hash: PassPointerAndRead<&Hash, 32>) {
if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
store.remove(hash).unwrap_or_default()
}
}
}