use crate::{
blocks::{extrinsic_types::ExtrinsicPartTypeIds, Extrinsics},
client::{OfflineClientT, OnlineClientT},
config::{Config, Header},
error::{BlockError, Error},
events,
rpc::types::ChainBlockResponse,
runtime_api::RuntimeApi,
storage::Storage,
};
use futures::lock::Mutex as AsyncMutex;
use std::sync::Arc;
pub struct Block<T: Config, C> {
header: T::Header,
client: C,
cached_events: CachedEvents<T>,
}
pub(crate) type CachedEvents<T> = Arc<AsyncMutex<Option<events::Events<T>>>>;
impl<T, C> Block<T, C>
where
T: Config,
C: OfflineClientT<T>,
{
pub(crate) fn new(header: T::Header, client: C) -> Self {
Block {
header,
client,
cached_events: Default::default(),
}
}
pub fn hash(&self) -> T::Hash {
self.header.hash()
}
pub fn number(&self) -> <T::Header as crate::config::Header>::Number {
self.header().number()
}
pub fn header(&self) -> &T::Header {
&self.header
}
}
impl<T, C> Block<T, C>
where
T: Config,
C: OnlineClientT<T>,
{
pub async fn events(&self) -> Result<events::Events<T>, Error> {
get_events(&self.client, self.header.hash(), &self.cached_events).await
}
pub async fn body(&self) -> Result<BlockBody<T, C>, Error> {
let ids = ExtrinsicPartTypeIds::new(&self.client.metadata())?;
let block_hash = self.header.hash();
let Some(block_details) = self.client.rpc().block(Some(block_hash)).await? else {
return Err(BlockError::not_found(block_hash).into());
};
Ok(BlockBody::new(
self.client.clone(),
block_details,
self.cached_events.clone(),
ids,
))
}
pub fn storage(&self) -> Storage<T, C> {
let block_hash = self.hash();
Storage::new(self.client.clone(), block_hash)
}
pub async fn runtime_api(&self) -> Result<RuntimeApi<T, C>, Error> {
Ok(RuntimeApi::new(self.client.clone(), self.hash()))
}
}
pub struct BlockBody<T: Config, C> {
details: ChainBlockResponse<T>,
client: C,
cached_events: CachedEvents<T>,
ids: ExtrinsicPartTypeIds,
}
impl<T, C> BlockBody<T, C>
where
T: Config,
C: OfflineClientT<T>,
{
pub(crate) fn new(
client: C,
details: ChainBlockResponse<T>,
cached_events: CachedEvents<T>,
ids: ExtrinsicPartTypeIds,
) -> Self {
Self {
details,
client,
cached_events,
ids,
}
}
pub fn extrinsics(&self) -> Extrinsics<T, C> {
Extrinsics::new(
self.client.clone(),
self.details.block.extrinsics.clone(),
self.cached_events.clone(),
self.ids,
self.details.block.header.hash(),
)
}
}
pub(crate) async fn get_events<C, T>(
client: &C,
block_hash: T::Hash,
cached_events: &AsyncMutex<Option<events::Events<T>>>,
) -> Result<events::Events<T>, Error>
where
T: Config,
C: OnlineClientT<T>,
{
let lock = cached_events.lock().await;
let events = match &*lock {
Some(events) => events.clone(),
None => {
events::EventsClient::new(client.clone())
.at(block_hash)
.await?
}
};
Ok(events)
}