avail_rust_client/block/
extrinsic.rs

1use crate::{
2	Client, Error, ExtrinsicDecodable, UserError,
3	block::{
4		BlockExtrinsicMetadata,
5		encoded::{BlockEncodedExtrinsic, BlockEncodedExtrinsicsQuery},
6		events::{BlockEvents, BlockEventsQuery},
7		extrinsic_options::Options,
8		signed::BlockSignedExtrinsic,
9	},
10};
11use avail_rust_core::{
12	ExtrinsicSignature, H256, HasHeader, MultiAddress, RpcError, rpc::ExtrinsicFilter, types::HashStringNumber,
13};
14use codec::Decode;
15
16/// View of block extrinsics decoded into calls and optional signatures.
17pub struct BlockExtrinsicsQuery {
18	xt: BlockEncodedExtrinsicsQuery,
19}
20
21impl BlockExtrinsicsQuery {
22	/// Builds a decoded extrinsic view for the specified block.
23	///
24	/// # Parameters
25	/// - `client`: RPC client used to fetch encoded extrinsics before decoding.
26	/// - `block_id`: Identifier convertible into `HashStringNumber`.
27	///
28	/// # Returns
29	/// - `Self`: Helper that decodes extrinsics on demand.
30	pub fn new(client: Client, block_id: HashStringNumber) -> Self {
31		Self { xt: BlockEncodedExtrinsicsQuery::new(client, block_id) }
32	}
33
34	/// Fetches a specific extrinsic by hash, index, or string identifier.
35	///
36	/// # Parameters
37	/// - `extrinsic_id`: Identifier used to select the extrinsic.
38	///
39	/// # Returns
40	/// - `Ok(Some(Extrinsic<T>))`: Matching extrinsic decoded as `T`.
41	/// - `Ok(None)`: No extrinsic matched the identifier.
42	/// - `Err(Error)`: Identifier decoding, the RPC call, or payload decoding failed.
43	///
44	/// # Side Effects
45	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
46	pub async fn get<T: HasHeader + Decode>(
47		&self,
48		extrinsic_id: impl Into<HashStringNumber>,
49	) -> Result<Option<BlockExtrinsic<T>>, Error> {
50		async fn inner<T: HasHeader + Decode>(
51			s: &BlockExtrinsicsQuery,
52			extrinsic_id: HashStringNumber,
53		) -> Result<Option<BlockExtrinsic<T>>, Error> {
54			let filter = match extrinsic_id {
55				HashStringNumber::Hash(x) => ExtrinsicFilter::from(x),
56				HashStringNumber::String(x) => ExtrinsicFilter::try_from(x).map_err(UserError::Decoding)?,
57				HashStringNumber::Number(x) => ExtrinsicFilter::from(x),
58			};
59			s.first::<T>(Options::new().filter(filter)).await
60		}
61
62		inner::<T>(self, extrinsic_id.into()).await
63	}
64
65	/// Returns the first extrinsic that matches the supplied filters.
66	///
67	/// # Parameters
68	/// - `opts`: Filters describing which extrinsic to fetch.
69	///
70	/// # Returns
71	/// - `Ok(Some(Extrinsic<T>))`: First matching extrinsic decoded as `T`.
72	/// - `Ok(None)`: No extrinsic satisfied the filters.
73	/// - `Err(Error)`: The RPC call or payload decoding failed.
74	///
75	/// # Side Effects
76	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
77	pub async fn first<T: HasHeader + Decode>(&self, mut opts: Options) -> Result<Option<BlockExtrinsic<T>>, Error> {
78		opts.filter = opts.filter.or(Some(T::HEADER_INDEX.into()));
79
80		let encoded = self.xt.first(opts).await?;
81		let Some(encoded) = encoded else {
82			return Ok(None);
83		};
84
85		Ok(Some(encoded.as_extrinsic::<T>()?))
86	}
87
88	/// Returns the last extrinsic that matches the supplied filters.
89	///
90	/// # Parameters
91	/// - `opts`: Filters describing which extrinsic to fetch.
92	///
93	/// # Returns
94	/// - `Ok(Some(Extrinsic<T>))`: Final matching extrinsic decoded as `T`.
95	/// - `Ok(None)`: No extrinsic satisfied the filters.
96	/// - `Err(Error)`: The RPC call or payload decoding failed.
97	///
98	/// # Side Effects
99	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
100	pub async fn last<T: HasHeader + Decode>(&self, mut opts: Options) -> Result<Option<BlockExtrinsic<T>>, Error> {
101		opts.filter = opts.filter.or(Some(T::HEADER_INDEX.into()));
102
103		let encoded = self.xt.last(opts).await?;
104		let Some(encoded) = encoded else {
105			return Ok(None);
106		};
107
108		Ok(Some(encoded.as_extrinsic::<T>()?))
109	}
110
111	/// Collects every extrinsic that matches the supplied filters.
112	///
113	/// # Parameters
114	/// - `opts`: Filters describing which extrinsics to decode.
115	///
116	/// # Returns
117	/// - `Ok(Vec<Extrinsic<T>>)`: Zero or more matching extrinsics decoded as `T`.
118	/// - `Err(Error)`: The RPC call or payload decoding failed.
119	///
120	/// # Side Effects
121	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
122	pub async fn all<T: HasHeader + Decode>(&self, mut opts: Options) -> Result<Vec<BlockExtrinsic<T>>, Error> {
123		opts.filter = opts.filter.or(Some(T::HEADER_INDEX.into()));
124
125		let all = self.xt.all(opts).await?;
126		let mut result = Vec::with_capacity(all.len());
127		for encoded in all {
128			result.push(encoded.as_extrinsic::<T>()?);
129		}
130
131		Ok(result)
132	}
133
134	/// Counts matching extrinsics without decoding their payloads.
135	///
136	/// # Parameters
137	/// - `opts`: Filters describing which extrinsics to count.
138	///
139	/// # Returns
140	/// - `Ok(usize)`: Number of matching extrinsics.
141	/// - `Err(Error)`: The RPC call failed.
142	///
143	/// # Side Effects
144	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
145	pub async fn count<T: HasHeader>(&self, mut opts: Options) -> Result<usize, Error> {
146		opts.filter = Some(T::HEADER_INDEX.into());
147		return self.xt.count(opts).await;
148	}
149
150	/// Reports whether any extrinsic matches the supplied filters.
151	///
152	/// # Parameters
153	/// - `opts`: Filters describing which extrinsics to test.
154	///
155	/// # Returns
156	/// - `Ok(true)`: At least one matching extrinsic exists.
157	/// - `Ok(false)`: No extrinsics matched the filters.
158	/// - `Err(Error)`: The RPC call failed.
159	///
160	/// # Side Effects
161	/// - Performs RPC calls via the encoded-extrinsic helper and may retry according to the retry policy.
162	pub async fn exists<T: HasHeader>(&self, mut opts: Options) -> Result<bool, Error> {
163		opts.filter = Some(T::HEADER_INDEX.into());
164		return self.xt.exists(opts).await;
165	}
166
167	/// Overrides the retry behaviour for future decoded-extrinsic lookups.
168	///
169	/// # Parameters
170	/// - `value`: `Some(true)` to force retries, `Some(false)` to disable retries, `None` to inherit the client default.
171	///
172	/// # Returns
173	/// - `()`: The override is stored for subsequent operations.
174	///
175	/// # Side Effects
176	/// - Updates the internal retry setting used by follow-up RPC calls.
177	pub fn set_retry_on_error(&mut self, value: Option<bool>) {
178		self.xt.set_retry_on_error(value);
179	}
180
181	/// Reports whether decoded-extrinsic lookups retry after RPC errors.
182	///
183	/// # Returns
184	/// - `true`: Retries are enabled either explicitly or via the client default.
185	/// - `false`: Retries are disabled.
186	pub fn should_retry_on_error(&self) -> bool {
187		self.xt.should_retry_on_error()
188	}
189}
190
191/// Decoded extrinsic along with metadata and optional signature.
192#[derive(Debug, Clone)]
193pub struct BlockExtrinsic<T: HasHeader + Decode> {
194	/// Optional signature associated with the extrinsic.
195	pub signature: Option<ExtrinsicSignature>,
196	/// Decoded runtime call payload.
197	pub call: T,
198	/// Metadata describing where the extrinsic was found.
199	pub metadata: BlockExtrinsicMetadata,
200}
201
202impl<T: HasHeader + Decode> BlockExtrinsic<T> {
203	/// Creates an extrinsic wrapper from decoded data.
204	///
205	/// # Parameters
206	/// - `signature`: Optional signature attached to the extrinsic.
207	/// - `call`: Decoded call payload.
208	/// - `metadata`: Metadata describing the extrinsic context.
209	///
210	/// # Returns
211	/// - `Self`: Decoded extrinsic wrapper containing the provided data.
212	pub fn new(signature: Option<ExtrinsicSignature>, call: T, metadata: BlockExtrinsicMetadata) -> Self {
213		Self { signature, call, metadata }
214	}
215
216	/// Fetches events emitted by this extrinsic.
217	///
218	/// # Parameters
219	/// - `client`: RPC client used to fetch event data.
220	///
221	/// # Returns
222	/// - `Ok(AllEvents)`: Wrapper containing events for this extrinsic.
223	/// - `Err(Error)`: Extrinsic emitted no events or the RPC request failed.
224	///
225	/// # Side Effects
226	/// - Issues RPC requests for event data and may retry according to the client's configuration.
227	pub async fn events(&self, client: Client) -> Result<BlockEvents, Error> {
228		let events = BlockEventsQuery::new(client, self.metadata.block_id)
229			.extrinsic(self.ext_index())
230			.await?;
231
232		if events.is_empty() {
233			return Err(RpcError::ExpectedData("No events found for extrinsic".into()).into());
234		};
235
236		Ok(events)
237	}
238
239	/// Returns the index of this extrinsic inside the block.
240	///
241	/// # Returns
242	/// - `u32`: Index of the extrinsic within the block.
243	pub fn ext_index(&self) -> u32 {
244		self.metadata.ext_index
245	}
246
247	/// Returns the extrinsic hash.
248	///
249	/// # Returns
250	/// - `H256`: Hash of the extrinsic.
251	pub fn ext_hash(&self) -> H256 {
252		self.metadata.ext_hash
253	}
254
255	/// Returns the application id if the extrinsic was signed.
256	///
257	/// # Returns
258	/// - `Some(u32)`: Application identifier from the signature.
259	/// - `None`: Extrinsic was unsigned.
260	pub fn app_id(&self) -> Option<u32> {
261		Some(self.signature.as_ref()?.extra.app_id)
262	}
263
264	/// Returns the nonce if the extrinsic was signed.
265	///
266	/// # Returns
267	/// - `Some(u32)`: Nonce from the signature.
268	/// - `None`: Extrinsic was unsigned.
269	pub fn nonce(&self) -> Option<u32> {
270		Some(self.signature.as_ref()?.extra.nonce)
271	}
272
273	/// Returns the tip if the extrinsic was signed.
274	///
275	/// # Returns
276	/// - `Some(u128)`: Tip reported by the signature.
277	/// - `None`: Extrinsic was unsigned.
278	pub fn tip(&self) -> Option<u128> {
279		Some(self.signature.as_ref()?.extra.tip)
280	}
281
282	/// Returns the signer as an ss58 string when available.
283	///
284	/// # Returns
285	/// - `Some(String)`: SS58-encoded signer address.
286	/// - `None`: Extrinsic was unsigned or used a non-`Id` multi-address.
287	pub fn ss58_address(&self) -> Option<String> {
288		match &self.signature.as_ref()?.address {
289			MultiAddress::Id(x) => Some(std::format!("{}", x)),
290			_ => None,
291		}
292	}
293
294	/// Converts the extrinsic into a signed variant when a signature is present.
295	///
296	/// # Returns
297	/// - `Ok(SignedExtrinsic<T>)`: Signed wrapper containing the same call and metadata.
298	/// - `Err(String)`: Extrinsic was unsigned, so a signed variant cannot be produced.
299	pub fn as_signed(self) -> Result<BlockSignedExtrinsic<T>, Error> {
300		BlockSignedExtrinsic::<T>::try_from(self).map_err(Error::Other)
301	}
302}
303
304impl<T: HasHeader + Decode> TryFrom<BlockEncodedExtrinsic> for BlockExtrinsic<T> {
305	type Error = String;
306
307	/// Decodes an encoded extrinsic into an `Extrinsic<T>`.
308	///
309	/// # Parameters
310	/// - `value`: Encoded extrinsic containing the SCALE payload.
311	///
312	/// # Returns
313	/// - `Ok(Self)`: Decoded extrinsic with optional signature and metadata.
314	/// - `Err(String)`: Payload failed to decode as `T`.
315	fn try_from(value: BlockEncodedExtrinsic) -> Result<Self, Self::Error> {
316		let call = T::from_call(value.call)?;
317		Ok(Self::new(value.signature, call, value.metadata))
318	}
319}
320
321impl<T: HasHeader + Decode> TryFrom<&BlockEncodedExtrinsic> for BlockExtrinsic<T> {
322	type Error = String;
323
324	/// Decodes a borrowed encoded extrinsic into an `Extrinsic<T>`.
325	///
326	/// # Parameters
327	/// - `value`: Borrowed encoded extrinsic containing the SCALE payload.
328	///
329	/// # Returns
330	/// - `Ok(Self)`: Decoded extrinsic with optional signature and cloned metadata.
331	/// - `Err(String)`: Payload failed to decode as `T`.
332	fn try_from(value: &BlockEncodedExtrinsic) -> Result<Self, Self::Error> {
333		let call = T::from_call(&value.call)?;
334		Ok(Self::new(value.signature.clone(), call, value.metadata.clone()))
335	}
336}
337
338#[cfg(test)]
339pub mod tests {
340	use super::*;
341	use crate::TURING_ENDPOINT;
342	use avail_rust_core::avail::{
343		balances::tx::TransferAllowDeath, data_availability::tx::SubmitData, timestamp::tx::Set,
344		vector::tx::FailedSendMessageTxs,
345	};
346
347	fn match_timestamp(ext: &BlockExtrinsic<Set>) {
348		assert_eq!(
349			std::format!("{:?}", ext.ext_hash()),
350			"0xdbfa60611f72a714100338db1c7b11c66636a76f116b214d879de069afe67a74"
351		);
352		assert_eq!(ext.ext_index(), 0);
353		assert_eq!(ext.nonce(), None);
354		assert!(ext.signature.is_none());
355		assert!(ext.app_id().is_none());
356		assert_eq!(ext.call.now, 1761567760000);
357	}
358
359	fn match_failed_send_message(ext: &BlockExtrinsic<FailedSendMessageTxs>) {
360		assert_eq!(
361			std::format!("{:?}", ext.ext_hash()),
362			"0x92cdb77314063a01930b093516d19a453399710cc8ae635ff5ab6cf76b26f218"
363		);
364		assert_eq!(ext.ext_index(), 3);
365		assert_eq!(ext.nonce(), None);
366		assert!(ext.signature.is_none());
367		assert!(ext.app_id().is_none());
368		assert_eq!(ext.call.failed_txs.len(), 0);
369	}
370
371	fn match_submit_data_1(ext: &BlockExtrinsic<SubmitData>) {
372		assert_eq!(
373			std::format!("{:?}", ext.ext_hash()),
374			"0x8b84294cba5f2b88e2887ac999ebac3806af7be9cca2a521fc889421f240f3ef"
375		);
376		assert_eq!(ext.ext_index(), 1);
377		assert_eq!(ext.nonce(), Some(30));
378		assert!(ext.signature.is_some());
379		assert_eq!(ext.app_id(), Some(1));
380		assert_eq!(ext.ss58_address(), Some("5Ev2jfLbYH6ENZ8ThTmqBX58zoinvHyqvRMvtoiUnLLcv1NJ".to_string()));
381		assert_eq!(String::from_utf8(ext.call.data.clone()).unwrap(), "AABBCC");
382	}
383
384	fn match_submit_data_2(ext: &BlockExtrinsic<SubmitData>) {
385		assert_eq!(
386			std::format!("{:?}", ext.ext_hash()),
387			"0x19fab0492322016c644af12f1547c587ef51edd10311db85cb3aa2680f6ae4ba"
388		);
389		assert_eq!(ext.ext_index(), 2);
390		assert_eq!(ext.nonce(), Some(4));
391		assert!(ext.signature.is_some());
392		assert_eq!(ext.app_id(), Some(2));
393		assert_eq!(ext.ss58_address(), Some("5DPDXCcqk1YNVZ3M9s9iwJnr9XAVfTxf8hNa4LS51fjHKAzk".to_string()));
394		assert_eq!(String::from_utf8(ext.call.data.clone()).unwrap(), "CCBBAA");
395	}
396
397	#[tokio::test]
398	async fn query_get_test() {
399		let client = Client::new(TURING_ENDPOINT).await.unwrap();
400		let query = client.block(2491314).extrinsics();
401
402		let ext = query.get::<Set>(0).await.unwrap().unwrap();
403		match_timestamp(&ext);
404
405		let ext = query.get::<SubmitData>(1).await.unwrap().unwrap();
406		match_submit_data_1(&ext);
407
408		let ext = query.get::<SubmitData>(2).await.unwrap().unwrap();
409		match_submit_data_2(&ext);
410
411		let ext = query.get::<FailedSendMessageTxs>(3).await.unwrap().unwrap();
412		match_failed_send_message(&ext);
413
414		// Wrong type
415		assert!(query.get::<FailedSendMessageTxs>(2).await.is_err());
416
417		// Non Existing
418		assert!(query.get::<FailedSendMessageTxs>(4).await.unwrap().is_none());
419	}
420
421	#[tokio::test]
422	async fn query_first_test() {
423		let client = Client::new(TURING_ENDPOINT).await.unwrap();
424		let query = client.block(2491314).extrinsics();
425
426		// App Id 1
427		let opts = Options::new().app_id(1);
428		let ext = query.first(opts).await.unwrap().unwrap();
429		match_submit_data_1(&ext);
430
431		// App Id 2
432		let opts = Options::new().app_id(2);
433		let ext = query.first(opts).await.unwrap().unwrap();
434		match_submit_data_2(&ext);
435
436		// Nonce 30
437		let opts = Options::new().nonce(30);
438		let ext = query.first(opts).await.unwrap().unwrap();
439		match_submit_data_1(&ext);
440
441		// Nonce 4
442		let opts = Options::new().nonce(4);
443		let ext = query.first(opts).await.unwrap().unwrap();
444		match_submit_data_2(&ext);
445
446		// DA call
447		let opts = Options::new().filter(SubmitData::HEADER_INDEX);
448		let ext = query.first(opts).await.unwrap().unwrap();
449		match_submit_data_1(&ext);
450
451		// Pall Call
452		let opts = Options::new().filter(SubmitData::HEADER_INDEX.0);
453		let ext = query.first(opts).await.unwrap().unwrap();
454		match_submit_data_1(&ext);
455
456		// Nothing
457		let ext = query.first::<Set>(Default::default()).await.unwrap().unwrap();
458		match_timestamp(&ext);
459
460		// Wrong Type
461		let opts = Options::new().filter(1u32);
462		assert!(query.first::<Set>(opts).await.is_err());
463
464		// Non Existing
465		let opts = Options::new().filter(100u32);
466		assert!(query.first::<Set>(opts).await.unwrap().is_none());
467	}
468
469	#[tokio::test]
470	async fn query_last_test() {
471		let client = Client::new(TURING_ENDPOINT).await.unwrap();
472		let query = client.block(2491314).extrinsics();
473
474		// App Id 1
475		let opts = Options::new().app_id(1);
476		let ext = query.last(opts).await.unwrap().unwrap();
477		match_submit_data_1(&ext);
478
479		// App Id 2
480		let opts = Options::new().app_id(2);
481		let ext = query.last(opts).await.unwrap().unwrap();
482		match_submit_data_2(&ext);
483
484		// Nonce 30
485		let opts = Options::new().nonce(30);
486		let ext = query.last(opts).await.unwrap().unwrap();
487		match_submit_data_1(&ext);
488
489		// Nonce 4
490		let opts = Options::new().nonce(4);
491		let ext = query.last(opts).await.unwrap().unwrap();
492		match_submit_data_2(&ext);
493
494		// DA call
495		let opts = Options::new().filter(SubmitData::HEADER_INDEX);
496		let ext = query.last(opts).await.unwrap().unwrap();
497		match_submit_data_2(&ext);
498
499		// Pall Call
500		let opts = Options::new().filter(SubmitData::HEADER_INDEX.0);
501		let ext = query.last(opts).await.unwrap().unwrap();
502		match_submit_data_2(&ext);
503
504		// Nothing
505		let ext = query.last(Default::default()).await.unwrap().unwrap();
506		match_failed_send_message(&ext);
507
508		// Wrong Type
509		let opts = Options::new().filter(1u32);
510		assert!(query.last::<Set>(opts).await.is_err());
511
512		// Non Existing
513		let opts = Options::new().filter(100u32);
514		assert!(query.last::<Set>(opts).await.unwrap().is_none());
515	}
516
517	#[tokio::test]
518	async fn query_all_test() {
519		let client = Client::new(TURING_ENDPOINT).await.unwrap();
520		let query = client.block(2491314).extrinsics();
521
522		// App Id 1
523		let opts = Options::new().app_id(1);
524		let ext = query.all(opts).await.unwrap();
525		match_submit_data_1(&ext[0]);
526
527		// App Id 2
528		let opts = Options::new().app_id(2);
529		let ext = query.all(opts).await.unwrap();
530		match_submit_data_2(&ext[0]);
531		assert_eq!(ext.len(), 1);
532
533		// Nonce 30
534		let opts = Options::new().nonce(30);
535		let ext = query.all(opts).await.unwrap();
536		match_submit_data_1(&ext[0]);
537		assert_eq!(ext.len(), 1);
538
539		// Nonce 4
540		let opts = Options::new().nonce(4);
541		let ext = query.all(opts).await.unwrap();
542		match_submit_data_2(&ext[0]);
543		assert_eq!(ext.len(), 1);
544
545		// DA call
546		let opts = Options::new().filter(SubmitData::HEADER_INDEX);
547		let ext = query.all(opts).await.unwrap();
548		match_submit_data_1(&ext[0]);
549		match_submit_data_2(&ext[1]);
550		assert_eq!(ext.len(), 2);
551
552		// Pall Call
553		let opts = Options::new().filter(SubmitData::HEADER_INDEX.0);
554		let ext = query.all(opts).await.unwrap();
555		match_submit_data_1(&ext[0]);
556		match_submit_data_2(&ext[1]);
557		assert_eq!(ext.len(), 2);
558
559		// Nothing
560		let ext = query.all::<SubmitData>(Default::default()).await.unwrap();
561		match_submit_data_1(&ext[0]);
562		match_submit_data_2(&ext[1]);
563		assert_eq!(ext.len(), 2);
564
565		let ext = query.all::<Set>(Default::default()).await.unwrap();
566		match_timestamp(&ext[0]);
567		assert_eq!(ext.len(), 1);
568
569		let ext = query.all::<FailedSendMessageTxs>(Default::default()).await.unwrap();
570		match_failed_send_message(&ext[0]);
571		assert_eq!(ext.len(), 1);
572
573		// Non Decodable
574		let opts = Options::new().filter(1u32);
575		assert!(query.all::<Set>(opts).await.is_err());
576
577		// Non Existing
578		let opts = Options::new().filter(100u32);
579		let ext = query.all::<Set>(opts).await.unwrap();
580		assert_eq!(ext.len(), 0)
581	}
582
583	#[tokio::test]
584	async fn query_count_test() {
585		let client = Client::new(TURING_ENDPOINT).await.unwrap();
586		let query = client.block(2491314).extrinsics();
587
588		// App Id 1
589		let opts = Options::new().app_id(1);
590		assert_eq!(query.count::<SubmitData>(opts).await.unwrap(), 1);
591
592		// App Id 2
593		let opts = Options::new().app_id(2);
594		assert_eq!(query.count::<SubmitData>(opts).await.unwrap(), 1);
595
596		// Nonce 30
597		let opts = Options::new().nonce(30);
598		assert_eq!(query.count::<SubmitData>(opts).await.unwrap(), 1);
599
600		// Nonce 4
601		let opts = Options::new().nonce(4);
602		assert_eq!(query.count::<SubmitData>(opts).await.unwrap(), 1);
603
604		// DA call
605		assert_eq!(query.count::<SubmitData>(Default::default()).await.unwrap(), 2);
606
607		// DA call
608		assert_eq!(query.count::<Set>(Default::default()).await.unwrap(), 1);
609
610		// Non Existing
611		assert_eq!(query.count::<TransferAllowDeath>(Default::default()).await.unwrap(), 0);
612	}
613
614	#[tokio::test]
615	async fn query_exists_test() {
616		let client = Client::new(TURING_ENDPOINT).await.unwrap();
617		let query = client.block(2491314).extrinsics();
618
619		// App Id 1
620		let opts = Options::new().app_id(1);
621		assert_eq!(query.exists::<SubmitData>(opts).await.unwrap(), true);
622
623		// App Id 2
624		let opts = Options::new().app_id(2);
625		assert_eq!(query.exists::<SubmitData>(opts).await.unwrap(), true);
626
627		// Nonce 30
628		let opts = Options::new().nonce(30);
629		assert_eq!(query.exists::<SubmitData>(opts).await.unwrap(), true);
630
631		// Nonce 4
632		let opts = Options::new().nonce(4);
633		assert_eq!(query.exists::<SubmitData>(opts).await.unwrap(), true);
634
635		// DA call
636		assert_eq!(query.exists::<SubmitData>(Default::default()).await.unwrap(), true);
637
638		// Nothing
639		assert_eq!(query.exists::<Set>(Default::default()).await.unwrap(), true);
640
641		// Non Existing
642		assert_eq!(query.exists::<TransferAllowDeath>(Default::default()).await.unwrap(), false);
643	}
644}