avail_rust_client/block/
encoded.rs

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