pub mod encoded;
pub mod events;
pub mod extrinsic;
pub mod extrinsic_options;
pub mod shared;
pub mod signed;
pub use encoded::{BlockEncodedExtrinsic, BlockEncodedExtrinsicsQuery};
pub use events::{BlockEvent, BlockEvents, BlockEventsQuery};
pub use extrinsic::{BlockExtrinsic, BlockExtrinsicsQuery};
pub use shared::BlockExtrinsicMetadata;
pub use signed::BlockSignedExtrinsic;
use crate::{
Client, Error,
block::{extrinsic_options::Options, shared::BlockContext},
};
use avail_rust_core::{
AccountId, AvailHeader, BlockInfo, HashNumber, avail,
grandpa::GrandpaJustification,
rpc::{self},
types::{
HashStringNumber,
substrate::{PerDispatchClassWeight, Weight},
},
};
#[derive(Clone)]
pub struct Block {
ctx: BlockContext,
}
impl Block {
pub fn new(client: Client, block_id: impl Into<HashStringNumber>) -> Self {
Block { ctx: BlockContext::new(client, block_id.into()) }
}
pub fn encoded(&self) -> encoded::BlockEncodedExtrinsicsQuery {
encoded::BlockEncodedExtrinsicsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
}
pub fn extrinsics(&self) -> extrinsic::BlockExtrinsicsQuery {
extrinsic::BlockExtrinsicsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
}
pub async fn extrinsic_infos(&self, opts: rpc::ExtrinsicOpts) -> Result<Vec<rpc::ExtrinsicInfo>, Error> {
let chain = self.ctx.chain();
chain.system_fetch_extrinsics(self.ctx.block_id.clone(), opts).await
}
pub fn events(&self) -> events::BlockEventsQuery {
events::BlockEventsQuery::new(self.ctx.client.clone(), self.ctx.block_id.clone())
}
pub fn set_retry_on_error(&mut self, value: Option<bool>) {
self.ctx.set_retry_on_error(value);
}
pub async fn justification(&self) -> Result<Option<GrandpaJustification>, Error> {
let block_id: HashNumber = self.ctx.hash_number()?;
let chain = self.ctx.chain();
let at = match block_id {
HashNumber::Hash(h) => chain
.block_height(h)
.await?
.ok_or(Error::Other("Failed to find block from the provided hash".into()))?,
HashNumber::Number(n) => n,
};
chain.grandpa_block_justification(at).await.map_err(|e| e.into())
}
pub fn should_retry_on_error(&self) -> bool {
self.ctx.should_retry_on_error()
}
pub async fn timestamp(&self) -> Result<u64, Error> {
let query = self.extrinsics();
let timestamp = query.first::<avail::timestamp::tx::Set>(Default::default()).await?;
let Some(timestamp) = timestamp else {
return Err(Error::Other(std::format!("No timestamp transaction found in block: {:?}", self.ctx.block_id)));
};
Ok(timestamp.call.now)
}
pub async fn info(&self) -> Result<BlockInfo, Error> {
let chain = self.ctx.chain();
chain.block_info_from(self.ctx.block_id.clone()).await
}
pub async fn header(&self) -> Result<AvailHeader, Error> {
self.ctx.header().await
}
pub async fn author(&self) -> Result<AccountId, Error> {
let chain = self.ctx.chain();
chain.block_author(self.ctx.block_id.clone()).await
}
pub async fn extrinsic_count(&self) -> Result<usize, Error> {
let mut encoded = self.encoded();
encoded.set_retry_on_error(Some(self.ctx.should_retry_on_error()));
encoded.count(Options::new()).await
}
pub async fn event_count(&self) -> Result<usize, Error> {
self.ctx.event_count().await
}
pub async fn weight(&self) -> Result<PerDispatchClassWeight, Error> {
let chain = self.ctx.chain();
chain.block_weight(self.ctx.block_id.clone()).await
}
pub async fn extrinsic_weight(&self) -> Result<Weight, Error> {
self.events().extrinsic_weight().await
}
}
#[cfg(test)]
pub mod test {
use avail_rust_core::{EncodeSelector, HasHeader, avail, rpc::ExtrinsicOpts};
use crate::{Client, TURING_ENDPOINT};
#[tokio::test]
async fn block_weight_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let extrinsic_weight = block.extrinsic_weight().await.unwrap();
let block_weight = block.weight().await.unwrap();
assert_eq!(extrinsic_weight.ref_time, 39142682750);
assert_eq!(extrinsic_weight.proof_size, 1493);
assert_eq!(block_weight.normal.ref_time, 14095070750);
assert_eq!(block_weight.normal.proof_size, 0);
assert_eq!(block_weight.operational.ref_time, 0);
assert_eq!(block_weight.operational.proof_size, 0);
assert_eq!(block_weight.mandatory.ref_time, 27979773000);
assert_eq!(block_weight.mandatory.proof_size, 116950);
}
#[tokio::test]
async fn block_info_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let info = block.info().await.unwrap();
assert_eq!(info.height, 2042866);
assert_eq!(
std::format!("{:?}", info.hash),
"0x66f2847020781416f98137f0c9ed7416e8e9d993d22924f36c6f16e066641429"
);
}
#[tokio::test]
async fn block_event_count_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let count = block.event_count().await.unwrap();
assert_eq!(count, 10);
}
#[tokio::test]
async fn block_extrinsic_count_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let count = block.extrinsic_count().await.unwrap();
assert_eq!(count, 3);
}
#[tokio::test]
async fn block_author_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let author = block.author().await.unwrap();
assert_eq!(author.to_string(), String::from("5Fuedf79TqB6mMWzhu8aazzfPX1mawedb7rLuHpv6iYK2Z6c"));
}
#[tokio::test]
async fn block_timestamp_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let timestamp = block.timestamp().await.unwrap();
assert_eq!(timestamp, 1752582560000);
}
#[tokio::test]
async fn block_header_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042866);
let header = block.header().await.unwrap();
assert_eq!(header.number, 2042866);
assert_eq!(
std::format!("{:?}", header.hash()),
"0x66f2847020781416f98137f0c9ed7416e8e9d993d22924f36c6f16e066641429"
);
assert_eq!(
std::format!("{:?}", header.parent_hash),
"0xfca317c08a9b86bf8b8ae04df0bde83db31fab1b455ebd2317f7eca15e1d688e"
)
}
#[tokio::test]
async fn block_justification_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(1900031);
let just = block.justification().await.unwrap();
assert!(just.is_none());
let block = client.block(1900032);
let just = block.justification().await.unwrap();
assert!(just.is_some());
}
#[tokio::test]
async fn block_extrinsic_infos_test() {
let client = Client::new(TURING_ENDPOINT).await.unwrap();
let block = client.block(2042863);
let infos = block
.extrinsic_infos(ExtrinsicOpts::new().encode_as(EncodeSelector::None))
.await
.unwrap();
assert_eq!(infos.len(), 4);
let infos = block
.extrinsic_infos(ExtrinsicOpts::new().encode_as(EncodeSelector::None).app_id(428))
.await
.unwrap();
assert_eq!(infos.len(), 1);
let infos = block
.extrinsic_infos(
ExtrinsicOpts::new()
.encode_as(EncodeSelector::None)
.filter(avail::data_availability::tx::SubmitData::HEADER_INDEX),
)
.await
.unwrap();
assert_eq!(infos.len(), 1);
let infos = block
.extrinsic_infos(
ExtrinsicOpts::new()
.encode_as(EncodeSelector::None)
.ss58_address("5CAC4rBKRKJi83uCJzeC7PzS27sP8Esfymbeq5jFEFPieyJm"),
)
.await
.unwrap();
assert_eq!(infos.len(), 1);
}
}