substrate_api_client/api/
mod.rs1use crate::error::FailedExtrinsicError;
19use ac_node_api::{events::RawEventDetails, EventDetails, Metadata};
20use alloc::{string::String, vec::Vec};
21use codec::{Decode, Encode};
22use serde::{Deserialize, Serialize};
23use sp_core::Bytes;
24
25pub use api_client::Api;
26pub use error::{Error, Result};
27pub use rpc_api::{
28 FetchEvents, GetAccountInformation, GetBalance, GetChainInfo, GetStorage,
29 GetTransactionPayment, SubmitAndWatch, SubmitExtrinsic, SubscribeChain, SubscribeEvents,
30 SystemApi,
31};
32
33pub mod api_client;
34pub mod error;
35pub mod rpc_api;
36pub mod runtime_api;
37
38#[derive(Debug, Clone, Encode, Decode, PartialEq)]
41pub struct ExtrinsicReport<Hash: Encode + Decode> {
42 pub extrinsic_hash: Hash,
44 pub block_hash: Option<Hash>,
47 pub status: TransactionStatus<Hash, Hash>,
49 pub events: Option<Vec<RawEventDetails<Hash>>>,
53}
54
55impl<Hash: Encode + Decode> ExtrinsicReport<Hash> {
56 pub fn new(
57 extrinsic_hash: Hash,
58 block_hash: Option<Hash>,
59 status: TransactionStatus<Hash, Hash>,
60 events: Option<Vec<RawEventDetails<Hash>>>,
61 ) -> Self {
62 Self { extrinsic_hash, block_hash, status, events }
63 }
64
65 pub fn add_events(&mut self, events: Vec<EventDetails<Hash>>) {
66 self.events = Some(events.into_iter().map(|event| event.to_raw()).collect());
67 }
68
69 pub fn check_events_for_dispatch_error(&self, metadata: &Metadata) -> Result<()> {
72 if self.events.is_none() {
73 return Err(Error::EventsMissing)
74 }
75 let events = self.events.as_ref().unwrap();
77 for event in events {
78 if let Some(dispatch_error) = event.get_associated_dispatch_error(metadata) {
79 return Err(Error::FailedExtrinsic(FailedExtrinsicError::new(
80 dispatch_error,
81 self.encode(),
82 )))
83 }
84 }
85 Ok(())
86 }
87}
88
89#[derive(Debug, PartialEq, PartialOrd, Eq, Copy, Clone)]
93pub enum XtStatus {
94 Ready = 1,
95 Broadcast = 2,
96 InBlock = 3,
97 Retracted = 4,
98 Finalized = 6,
99}
100
101#[derive(Debug, PartialEq, Eq, Copy, Clone)]
104pub enum UnexpectedTxStatus {
105 Future,
106 FinalityTimeout,
107 Usurped,
108 Dropped,
109 Invalid,
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)]
117#[serde(rename_all = "camelCase")]
118pub enum TransactionStatus<Hash: Encode + Decode, BlockHash: Encode + Decode> {
119 Future,
121 Ready,
123 Broadcast(Vec<String>),
125 InBlock(BlockHash),
127 Retracted(BlockHash),
129 FinalityTimeout(BlockHash),
132 Finalized(BlockHash),
134 Usurped(Hash),
137 Dropped,
139 Invalid,
141}
142
143impl<Hash: Encode + Decode, BlockHash: Encode + Decode> TransactionStatus<Hash, BlockHash> {
144 pub fn as_u8(&self) -> u8 {
145 match self {
146 Self::Future => 0,
147 Self::Ready => 1,
148 Self::Broadcast(_) => 2,
149 Self::InBlock(_) => 3,
150 Self::Retracted(_) => 4,
151 Self::FinalityTimeout(_) => 5,
152 Self::Finalized(_) => 6,
153 Self::Usurped(_) => 7,
154 Self::Dropped => 8,
155 Self::Invalid => 9,
156 }
157 }
158
159 pub fn is_expected(&self) -> Result<()> {
160 match self {
161 Self::Ready
162 | Self::Broadcast(_)
163 | Self::InBlock(_)
164 | Self::Retracted(_)
165 | Self::Finalized(_) => Ok(()),
166 Self::Future => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future)),
167 Self::FinalityTimeout(_) =>
168 Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::FinalityTimeout)),
169 Self::Usurped(_) => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Usurped)),
170 Self::Dropped => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Dropped)),
171 Self::Invalid => Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Invalid)),
172 }
173 }
174
175 pub fn reached_status(&self, status: XtStatus) -> bool {
178 self.as_u8() >= status as u8
179 }
180
181 pub fn get_maybe_block_hash(&self) -> Option<&BlockHash> {
182 match self {
183 Self::InBlock(block_hash) => Some(block_hash),
184 Self::Retracted(block_hash) => Some(block_hash),
185 Self::FinalityTimeout(block_hash) => Some(block_hash),
186 Self::Finalized(block_hash) => Some(block_hash),
187 _ => None,
188 }
189 }
190
191 pub fn is_final(&self) -> bool {
194 matches!(
195 self,
196 Self::Usurped(_)
197 | Self::Finalized(_)
198 | Self::FinalityTimeout(_)
199 | Self::Invalid
200 | Self::Dropped
201 )
202 }
203}
204
205#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct ReadProof<Hash> {
211 pub at: Hash,
213 pub proof: Vec<Bytes>,
215}
216
217#[cfg(test)]
218mod tests {
219 use super::{TransactionStatus as GenericTransactionStatus, *};
220 use sp_core::H256;
221
222 type TransactionStatus = GenericTransactionStatus<H256, H256>;
223
224 #[test]
225 fn test_xt_status_as_u8() {
226 assert_eq!(1, XtStatus::Ready as u8);
227 assert_eq!(2, XtStatus::Broadcast as u8);
228 assert_eq!(3, XtStatus::InBlock as u8);
229 assert_eq!(6, XtStatus::Finalized as u8);
230 }
231
232 #[test]
233 fn test_transaction_status_as_u8() {
234 assert_eq!(0, TransactionStatus::Future.as_u8());
235 assert_eq!(1, TransactionStatus::Ready.as_u8());
236 assert_eq!(2, TransactionStatus::Broadcast(vec![]).as_u8());
237 assert_eq!(3, TransactionStatus::InBlock(H256::random()).as_u8());
238 assert_eq!(4, TransactionStatus::Retracted(H256::random()).as_u8());
239 assert_eq!(5, TransactionStatus::FinalityTimeout(H256::random()).as_u8());
240 assert_eq!(6, TransactionStatus::Finalized(H256::random()).as_u8());
241 assert_eq!(7, TransactionStatus::Usurped(H256::random()).as_u8());
242 assert_eq!(8, TransactionStatus::Dropped.as_u8());
243 assert_eq!(9, TransactionStatus::Invalid.as_u8());
244 }
245
246 #[test]
247 fn test_transaction_status_is_expected() {
248 assert!(TransactionStatus::Ready.is_expected().is_ok());
250 assert!(TransactionStatus::Broadcast(vec![]).is_expected().is_ok());
251 assert!(TransactionStatus::InBlock(H256::random()).is_expected().is_ok());
252 assert!(TransactionStatus::Retracted(H256::random()).is_expected().is_ok());
253 assert!(TransactionStatus::Finalized(H256::random()).is_expected().is_ok());
254
255 assert!(TransactionStatus::Future.is_expected().is_err());
257 assert!(TransactionStatus::FinalityTimeout(H256::random()).is_expected().is_err());
258 assert!(TransactionStatus::Usurped(H256::random()).is_expected().is_err());
259 assert!(TransactionStatus::Dropped.is_expected().is_err());
260 assert!(TransactionStatus::Invalid.is_expected().is_err());
261 }
262
263 #[test]
264 fn test_reached_xt_status_for_ready() {
265 let status = XtStatus::Ready;
266
267 assert!(!TransactionStatus::Future.reached_status(status));
269
270 assert!(TransactionStatus::Ready.reached_status(status));
272 assert!(TransactionStatus::Broadcast(vec![]).reached_status(status));
273 assert!(TransactionStatus::InBlock(H256::random()).reached_status(status));
274 assert!(TransactionStatus::FinalityTimeout(H256::random()).reached_status(status));
275 assert!(TransactionStatus::Finalized(H256::random()).reached_status(status));
276 assert!(TransactionStatus::Retracted(H256::random()).reached_status(status));
277 assert!(TransactionStatus::Usurped(H256::random()).reached_status(status));
278 assert!(TransactionStatus::Dropped.reached_status(status));
279 assert!(TransactionStatus::Invalid.reached_status(status));
280 }
281
282 #[test]
283 fn test_reached_xt_status_for_broadcast() {
284 let status = XtStatus::Broadcast;
285
286 assert!(!TransactionStatus::Future.reached_status(status));
288 assert!(!TransactionStatus::Ready.reached_status(status));
289
290 assert!(TransactionStatus::Broadcast(vec![]).reached_status(status));
292 assert!(TransactionStatus::InBlock(H256::random()).reached_status(status));
293 assert!(TransactionStatus::FinalityTimeout(H256::random()).reached_status(status));
294 assert!(TransactionStatus::Finalized(H256::random()).reached_status(status));
295 assert!(TransactionStatus::Retracted(H256::random()).reached_status(status));
296 assert!(TransactionStatus::Usurped(H256::random()).reached_status(status));
297 assert!(TransactionStatus::Dropped.reached_status(status));
298 assert!(TransactionStatus::Invalid.reached_status(status));
299 }
300
301 #[test]
302 fn test_reached_xt_status_for_in_block() {
303 let status = XtStatus::InBlock;
304
305 assert!(!TransactionStatus::Future.reached_status(status));
307 assert!(!TransactionStatus::Ready.reached_status(status));
308 assert!(!TransactionStatus::Broadcast(vec![]).reached_status(status));
309
310 assert!(TransactionStatus::InBlock(H256::random()).reached_status(status));
312 assert!(TransactionStatus::FinalityTimeout(H256::random()).reached_status(status));
313 assert!(TransactionStatus::Finalized(H256::random()).reached_status(status));
314 assert!(TransactionStatus::Retracted(H256::random()).reached_status(status));
315 assert!(TransactionStatus::Usurped(H256::random()).reached_status(status));
316 assert!(TransactionStatus::Dropped.reached_status(status));
317 assert!(TransactionStatus::Invalid.reached_status(status));
318 }
319
320 #[test]
321 fn test_reached_xt_status_for_finalized() {
322 let status = XtStatus::Finalized;
323
324 assert!(!TransactionStatus::Future.reached_status(status));
326 assert!(!TransactionStatus::Ready.reached_status(status));
327 assert!(!TransactionStatus::Broadcast(vec![]).reached_status(status));
328 assert!(!TransactionStatus::InBlock(H256::random()).reached_status(status));
329 assert!(!TransactionStatus::Retracted(H256::random()).reached_status(status));
330 assert!(!TransactionStatus::FinalityTimeout(H256::random()).reached_status(status));
331
332 assert!(TransactionStatus::Finalized(H256::random()).reached_status(status));
334 assert!(TransactionStatus::Usurped(H256::random()).reached_status(status));
335 assert!(TransactionStatus::Dropped.reached_status(status));
336 assert!(TransactionStatus::Invalid.reached_status(status));
337 }
338
339 #[test]
340 fn encode_decode_extrinsic_report() {
341 let hash = H256::random();
342 let block_hash = H256::random();
343 let status = TransactionStatus::InBlock(block_hash);
344 let report = ExtrinsicReport::new(hash, Some(block_hash), status, None);
346
347 let encoded = report.encode();
348 let decoded = ExtrinsicReport::<H256>::decode(&mut encoded.as_slice()).unwrap();
349
350 assert_eq!(report, decoded);
351 }
352}