avail_rust_client/block/
mod.rs1pub mod encoded;
2pub mod events;
3pub mod extrinsic;
4pub mod extrinsic_options;
5pub mod shared;
6pub mod signed;
7
8pub use encoded::{BlockEncodedExtrinsic, BlockEncodedExtrinsicsQuery};
9pub use events::{BlockEvent, BlockEvents, BlockEventsQuery};
10pub use extrinsic::{BlockExtrinsic, BlockExtrinsicsQuery};
11pub use shared::BlockExtrinsicMetadata;
12pub use signed::BlockSignedExtrinsic;
13
14use crate::{
15 Client, Error,
16 block::{extrinsic_options::Options, shared::BlockContext},
17};
18use avail_rust_core::{
19 AccountId, AvailHeader, BlockInfo, HashNumber, avail,
20 grandpa::GrandpaJustification,
21 rpc::{self},
22 types::{
23 HashStringNumber,
24 substrate::{PerDispatchClassWeight, Weight},
25 },
26};
27
28#[derive(Clone)]
30pub struct Block {
31 ctx: BlockContext,
32}
33
34impl Block {
35 pub fn new(client: Client, block_id: impl Into<HashStringNumber>) -> Self {
44 Block { ctx: BlockContext::new(client, block_id.into()) }
45 }
46
47 pub fn encoded(&self) -> encoded::BlockEncodedExtrinsicsQuery {
52 encoded::BlockEncodedExtrinsicsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
53 }
54
55 pub fn extrinsics(&self) -> extrinsic::BlockExtrinsicsQuery {
60 extrinsic::BlockExtrinsicsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
61 }
62
63 pub async fn extrinsic_infos(&self, opts: rpc::ExtrinsicOpts) -> Result<Vec<rpc::ExtrinsicInfo>, Error> {
79 let chain = self.ctx.chain();
80 chain.system_fetch_extrinsics(self.ctx.block_id.clone(), opts).await
81 }
82
83 pub fn events(&self) -> events::BlockEventsQuery {
88 events::BlockEventsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
89 }
90
91 pub fn set_retry_on_error(&mut self, value: Option<bool>) {
102 self.ctx.set_retry_on_error(value);
103 }
104
105 pub async fn justification(&self) -> Result<Option<GrandpaJustification>, Error> {
115 let block_id: HashNumber = self.ctx.hash_number()?;
116 let chain = self.ctx.chain();
117 let at = match block_id {
118 HashNumber::Hash(h) => chain
119 .block_height(h)
120 .await?
121 .ok_or(Error::Other("Failed to find block from the provided hash".into()))?,
122 HashNumber::Number(n) => n,
123 };
124
125 chain.grandpa_block_justification(at).await.map_err(|e| e.into())
126 }
127
128 pub fn should_retry_on_error(&self) -> bool {
134 self.ctx.should_retry_on_error()
135 }
136
137 pub async fn timestamp(&self) -> Result<u64, Error> {
146 let query = self.extrinsics();
147 let timestamp = query.first::<avail::timestamp::tx::Set>(Default::default()).await?;
148 let Some(timestamp) = timestamp else {
149 return Err(Error::Other(std::format!("No timestamp transaction found in block: {:?}", self.ctx.block_id)));
150 };
151
152 Ok(timestamp.call.now)
153 }
154
155 pub async fn info(&self) -> Result<BlockInfo, Error> {
164 let chain = self.ctx.chain();
165 chain.block_info_from(self.ctx.block_id.clone()).await
166 }
167
168 pub async fn header(&self) -> Result<AvailHeader, Error> {
177 self.ctx.header().await
178 }
179
180 pub async fn author(&self) -> Result<AccountId, Error> {
189 let chain = self.ctx.chain();
190 chain.block_author(self.ctx.block_id.clone()).await
191 }
192
193 pub async fn extrinsic_count(&self) -> Result<usize, Error> {
202 let mut encoded = self.encoded();
203 encoded.set_retry_on_error(Some(self.ctx.should_retry_on_error()));
204 encoded.count(Options::new()).await
205 }
206
207 pub async fn event_count(&self) -> Result<usize, Error> {
216 self.ctx.event_count().await
217 }
218
219 pub async fn weight(&self) -> Result<PerDispatchClassWeight, Error> {
228 let chain = self.ctx.chain();
229 chain.block_weight(self.ctx.block_id.clone()).await
230 }
231
232 pub async fn extrinsic_weight(&self) -> Result<Weight, Error> {
241 self.events().extrinsic_weight().await
242 }
243}
244
245#[cfg(test)]
246pub mod test {
247 use avail_rust_core::{EncodeSelector, HasHeader, avail, rpc::ExtrinsicOpts};
248
249 use crate::{Client, TURING_ENDPOINT};
250
251 #[tokio::test]
252 async fn block_weight_test() {
253 let client = Client::new(TURING_ENDPOINT).await.unwrap();
254 let block = client.block(2042866);
255
256 let extrinsic_weight = block.extrinsic_weight().await.unwrap();
257 let block_weight = block.weight().await.unwrap();
258
259 assert_eq!(extrinsic_weight.ref_time, 39142682750);
260 assert_eq!(extrinsic_weight.proof_size, 1493);
261 assert_eq!(block_weight.normal.ref_time, 14095070750);
262 assert_eq!(block_weight.normal.proof_size, 0);
263 assert_eq!(block_weight.operational.ref_time, 0);
264 assert_eq!(block_weight.operational.proof_size, 0);
265 assert_eq!(block_weight.mandatory.ref_time, 27979773000);
266 assert_eq!(block_weight.mandatory.proof_size, 116950);
267 }
268
269 #[tokio::test]
270 async fn block_info_test() {
271 let client = Client::new(TURING_ENDPOINT).await.unwrap();
272 let block = client.block(2042866);
273
274 let info = block.info().await.unwrap();
275
276 assert_eq!(info.height, 2042866);
277 assert_eq!(
278 std::format!("{:?}", info.hash),
279 "0x66f2847020781416f98137f0c9ed7416e8e9d993d22924f36c6f16e066641429"
280 );
281 }
282
283 #[tokio::test]
284 async fn block_event_count_test() {
285 let client = Client::new(TURING_ENDPOINT).await.unwrap();
286 let block = client.block(2042866);
287 let count = block.event_count().await.unwrap();
288 assert_eq!(count, 10);
289 }
290
291 #[tokio::test]
292 async fn block_extrinsic_count_test() {
293 let client = Client::new(TURING_ENDPOINT).await.unwrap();
294 let block = client.block(2042866);
295
296 let count = block.extrinsic_count().await.unwrap();
297 assert_eq!(count, 3);
298 }
299
300 #[tokio::test]
301 async fn block_author_test() {
302 let client = Client::new(TURING_ENDPOINT).await.unwrap();
303 let block = client.block(2042866);
304
305 let author = block.author().await.unwrap();
306 assert_eq!(author.to_string(), String::from("5Fuedf79TqB6mMWzhu8aazzfPX1mawedb7rLuHpv6iYK2Z6c"));
307 }
308
309 #[tokio::test]
310 async fn block_timestamp_test() {
311 let client = Client::new(TURING_ENDPOINT).await.unwrap();
312 let block = client.block(2042866);
313
314 let timestamp = block.timestamp().await.unwrap();
315 assert_eq!(timestamp, 1752582560000);
316 }
317
318 #[tokio::test]
319 async fn block_header_test() {
320 let client = Client::new(TURING_ENDPOINT).await.unwrap();
321 let block = client.block(2042866);
322
323 let header = block.header().await.unwrap();
324 assert_eq!(header.number, 2042866);
325 assert_eq!(
326 std::format!("{:?}", header.hash()),
327 "0x66f2847020781416f98137f0c9ed7416e8e9d993d22924f36c6f16e066641429"
328 );
329 assert_eq!(
330 std::format!("{:?}", header.parent_hash),
331 "0xfca317c08a9b86bf8b8ae04df0bde83db31fab1b455ebd2317f7eca15e1d688e"
332 )
333 }
334
335 #[tokio::test]
336 async fn block_justification_test() {
337 let client = Client::new(TURING_ENDPOINT).await.unwrap();
338
339 let block = client.block(1900031);
340 let just = block.justification().await.unwrap();
341 assert!(just.is_none());
342
343 let block = client.block(1900032);
344 let just = block.justification().await.unwrap();
345 assert!(just.is_some());
346 }
347
348 #[tokio::test]
349 async fn block_extrinsic_infos_test() {
350 let client = Client::new(TURING_ENDPOINT).await.unwrap();
351
352 let block = client.block(2042863);
353
354 let infos = block
356 .extrinsic_infos(ExtrinsicOpts::new().encode_as(EncodeSelector::None))
357 .await
358 .unwrap();
359 assert_eq!(infos.len(), 4);
360
361 let infos = block
363 .extrinsic_infos(ExtrinsicOpts::new().encode_as(EncodeSelector::None).app_id(428))
364 .await
365 .unwrap();
366 assert_eq!(infos.len(), 1);
367
368 let infos = block
370 .extrinsic_infos(
371 ExtrinsicOpts::new()
372 .encode_as(EncodeSelector::None)
373 .filter(avail::data_availability::tx::SubmitData::HEADER_INDEX),
374 )
375 .await
376 .unwrap();
377 assert_eq!(infos.len(), 1);
378
379 let infos = block
382 .extrinsic_infos(
383 ExtrinsicOpts::new()
384 .encode_as(EncodeSelector::None)
385 .ss58_address("5CAC4rBKRKJi83uCJzeC7PzS27sP8Esfymbeq5jFEFPieyJm"),
386 )
387 .await
388 .unwrap();
389 assert_eq!(infos.len(), 1);
390 }
391}