1use crate::{Hash, Statement, Topic};
21use alloc::vec::Vec;
22use codec::{Decode, Encode};
23use scale_info::TypeInfo;
24use sp_runtime::RuntimeDebug;
25use sp_runtime_interface::{
26 pass_by::{
27 AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndDecodeSlice,
28 PassPointerAndRead, PassPointerAndReadCopy, ReturnAs,
29 },
30 runtime_interface,
31};
32
33#[cfg(feature = "std")]
34use sp_externalities::ExternalitiesExt;
35
36#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
38pub struct ValidStatement {
39 pub max_count: u32,
41 pub max_size: u32,
43}
44
45#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug, TypeInfo)]
47pub enum InvalidStatement {
48 BadProof,
50 NoProof,
52 InternalError,
54}
55
56#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
60pub enum StatementSource {
61 Chain,
63 Network,
65 Local,
67}
68
69impl StatementSource {
70 pub fn can_be_resubmitted(&self) -> bool {
73 match self {
74 StatementSource::Chain | StatementSource::Local => true,
75 StatementSource::Network => false,
76 }
77 }
78}
79
80sp_api::decl_runtime_apis! {
81 pub trait ValidateStatement {
83 fn validate_statement(
85 source: StatementSource,
86 statement: Statement,
87 ) -> Result<ValidStatement, InvalidStatement>;
88 }
89}
90
91#[cfg(feature = "std")]
92sp_externalities::decl_extension! {
93 pub struct StatementStoreExt(std::sync::Arc<dyn crate::StatementStore>);
95}
96
97#[cfg(feature = "std")]
99impl StatementStoreExt {
100 pub fn new(store: std::sync::Arc<dyn crate::StatementStore>) -> Self {
102 Self(store)
103 }
104}
105
106#[derive(Debug, Eq, PartialEq, Clone, Copy, Encode, Decode)]
108pub enum SubmitResult {
109 OkNew = 0,
111 OkKnown = 1,
113 Bad = 2,
115 NotAvailable = 3,
117 Full = 4,
119}
120
121impl TryFrom<u8> for SubmitResult {
122 type Error = ();
123 fn try_from(value: u8) -> Result<Self, Self::Error> {
124 match value {
125 0 => Ok(SubmitResult::OkNew),
126 1 => Ok(SubmitResult::OkKnown),
127 2 => Ok(SubmitResult::Bad),
128 3 => Ok(SubmitResult::NotAvailable),
129 4 => Ok(SubmitResult::Full),
130 _ => Err(()),
131 }
132 }
133}
134
135impl From<SubmitResult> for u8 {
136 fn from(value: SubmitResult) -> Self {
137 value as u8
138 }
139}
140
141#[cfg(feature = "std")]
143pub type HostFunctions = (statement_store::HostFunctions,);
144
145#[runtime_interface]
147pub trait StatementStore {
148 fn submit_statement(
151 &mut self,
152 statement: PassFatPointerAndDecode<Statement>,
153 ) -> ReturnAs<SubmitResult, u8> {
154 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
155 match store.submit(statement, StatementSource::Chain) {
156 crate::SubmitResult::New(_) => SubmitResult::OkNew,
157 crate::SubmitResult::Known => SubmitResult::OkKnown,
158 crate::SubmitResult::Ignored => SubmitResult::Full,
159 crate::SubmitResult::KnownExpired => SubmitResult::Bad,
162 crate::SubmitResult::Bad(_) => SubmitResult::Bad,
163 crate::SubmitResult::InternalError(_) => SubmitResult::Bad,
164 }
165 } else {
166 SubmitResult::NotAvailable
167 }
168 }
169
170 fn statements(&mut self) -> AllocateAndReturnByCodec<Vec<(Hash, Statement)>> {
172 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
173 store.statements().unwrap_or_default()
174 } else {
175 Vec::default()
176 }
177 }
178
179 fn broadcasts(
182 &mut self,
183 match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
184 ) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
185 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
186 store.broadcasts(match_all_topics).unwrap_or_default()
187 } else {
188 Vec::default()
189 }
190 }
191
192 fn posted(
196 &mut self,
197 match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
198 dest: PassPointerAndReadCopy<[u8; 32], 32>,
199 ) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
200 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
201 store.posted(match_all_topics, dest).unwrap_or_default()
202 } else {
203 Vec::default()
204 }
205 }
206
207 fn posted_clear(
210 &mut self,
211 match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>,
212 dest: PassPointerAndReadCopy<[u8; 32], 32>,
213 ) -> AllocateAndReturnByCodec<Vec<Vec<u8>>> {
214 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
215 store.posted_clear(match_all_topics, dest).unwrap_or_default()
216 } else {
217 Vec::default()
218 }
219 }
220
221 fn remove(&mut self, hash: PassPointerAndRead<&Hash, 32>) {
223 if let Some(StatementStoreExt(store)) = self.extension::<StatementStoreExt>() {
224 store.remove(hash).unwrap_or_default()
225 }
226 }
227}