use crate::{
blocks::block_types::{get_events, CachedEvents},
client::{OfflineClientT, OnlineClientT},
config::{Config, HashFor},
error::{EventsError, ExtrinsicDecodeErrorAt, ExtrinsicError},
events,
};
use derive_where::derive_where;
use pezkuwi_subxt_core::blocks::{
ExtrinsicDetails as CoreExtrinsicDetails, Extrinsics as CoreExtrinsics,
};
use scale_decode::{DecodeAsFields, DecodeAsType};
pub use pezkuwi_subxt_core::blocks::{
ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions, StaticExtrinsic,
};
pub struct Extrinsics<T: Config, C> {
inner: CoreExtrinsics<T>,
client: C,
cached_events: CachedEvents<T>,
hash: HashFor<T>,
}
impl<T, C> Extrinsics<T, C>
where
T: Config,
C: OfflineClientT<T>,
{
pub(crate) fn new(
client: C,
extrinsics: Vec<Vec<u8>>,
cached_events: CachedEvents<T>,
hash: HashFor<T>,
) -> Result<Self, ExtrinsicDecodeErrorAt> {
let inner = CoreExtrinsics::decode_from(extrinsics, client.metadata())?;
Ok(Self { inner, client, cached_events, hash })
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn block_hash(&self) -> HashFor<T> {
self.hash
}
pub fn iter(&self) -> impl Iterator<Item = ExtrinsicDetails<T, C>> + Send + Sync + 'static {
let client = self.client.clone();
let cached_events = self.cached_events.clone();
let block_hash = self.hash;
self.inner.iter().map(move |inner| {
ExtrinsicDetails::new(inner, client.clone(), block_hash, cached_events.clone())
})
}
pub fn find<'a, E: StaticExtrinsic + 'a>(
&'a self,
) -> impl Iterator<Item = Result<FoundExtrinsic<T, C, E>, ExtrinsicError>> + 'a {
self.inner.find::<E>().map(|res| {
match res {
Err(e) => Err(ExtrinsicError::from(e)),
Ok(ext) => {
let details = ExtrinsicDetails::new(
ext.details,
self.client.clone(),
self.hash,
self.cached_events.clone(),
);
Ok(FoundExtrinsic { details, value: ext.value })
},
}
})
}
pub fn find_first<E: StaticExtrinsic>(
&self,
) -> Result<Option<FoundExtrinsic<T, C, E>>, ExtrinsicError> {
self.find::<E>().next().transpose()
}
pub fn find_last<E: StaticExtrinsic>(
&self,
) -> Result<Option<FoundExtrinsic<T, C, E>>, ExtrinsicError> {
self.find::<E>().last().transpose()
}
pub fn has<E: StaticExtrinsic>(&self) -> Result<bool, ExtrinsicError> {
Ok(self.find::<E>().next().transpose()?.is_some())
}
}
pub struct ExtrinsicDetails<T: Config, C> {
inner: CoreExtrinsicDetails<T>,
block_hash: HashFor<T>,
client: C,
cached_events: CachedEvents<T>,
}
impl<T, C> ExtrinsicDetails<T, C>
where
T: Config,
C: OfflineClientT<T>,
{
pub(crate) fn new(
inner: CoreExtrinsicDetails<T>,
client: C,
block_hash: HashFor<T>,
cached_events: CachedEvents<T>,
) -> ExtrinsicDetails<T, C> {
ExtrinsicDetails { inner, client, block_hash, cached_events }
}
pub fn hash(&self) -> HashFor<T> {
self.inner.hash()
}
pub fn is_signed(&self) -> bool {
self.inner.is_signed()
}
pub fn index(&self) -> u32 {
self.inner.index()
}
pub fn bytes(&self) -> &[u8] {
self.inner.bytes()
}
pub fn call_bytes(&self) -> &[u8] {
self.inner.call_bytes()
}
pub fn field_bytes(&self) -> &[u8] {
self.inner.field_bytes()
}
pub fn address_bytes(&self) -> Option<&[u8]> {
self.inner.address_bytes()
}
pub fn signature_bytes(&self) -> Option<&[u8]> {
self.inner.signature_bytes()
}
pub fn transaction_extensions_bytes(&self) -> Option<&[u8]> {
self.inner.transaction_extensions_bytes()
}
pub fn transaction_extensions(&self) -> Option<ExtrinsicTransactionExtensions<'_, T>> {
self.inner.transaction_extensions()
}
pub fn pallet_index(&self) -> u8 {
self.inner.pallet_index()
}
pub fn call_index(&self) -> u8 {
self.inner.call_index()
}
pub fn pallet_name(&self) -> &str {
self.inner.pallet_name()
}
pub fn call_name(&self) -> &str {
self.inner.call_name()
}
pub fn decode_as_fields<E: DecodeAsFields>(&self) -> Result<E, ExtrinsicError> {
self.inner.decode_as_fields().map_err(Into::into)
}
pub fn as_extrinsic<E: StaticExtrinsic>(&self) -> Result<Option<E>, ExtrinsicError> {
self.inner.as_extrinsic::<E>().map_err(Into::into)
}
pub fn as_root_extrinsic<E: DecodeAsType>(&self) -> Result<E, ExtrinsicError> {
self.inner.as_root_extrinsic::<E>().map_err(Into::into)
}
}
impl<T, C> ExtrinsicDetails<T, C>
where
T: Config,
C: OnlineClientT<T>,
{
pub async fn events(&self) -> Result<ExtrinsicEvents<T>, EventsError> {
let events = get_events(&self.client, self.block_hash, &self.cached_events).await?;
let ext_hash = self.inner.hash();
Ok(ExtrinsicEvents::new(ext_hash, self.index(), events))
}
}
pub struct FoundExtrinsic<T: Config, C, E> {
pub details: ExtrinsicDetails<T, C>,
pub value: E,
}
#[derive_where(Debug)]
pub struct ExtrinsicEvents<T: Config> {
ext_hash: HashFor<T>,
idx: u32,
events: events::Events<T>,
}
impl<T: Config> ExtrinsicEvents<T> {
#[doc(hidden)]
pub fn new(ext_hash: HashFor<T>, idx: u32, events: events::Events<T>) -> Self {
Self { ext_hash, idx, events }
}
pub fn extrinsic_index(&self) -> u32 {
self.idx
}
pub fn extrinsic_hash(&self) -> HashFor<T> {
self.ext_hash
}
pub fn all_events_in_block(&self) -> &events::Events<T> {
&self.events
}
pub fn iter(&self) -> impl Iterator<Item = Result<events::EventDetails<T>, EventsError>> + '_ {
self.events.iter().filter(|ev| {
ev.as_ref()
.map(|ev| ev.phase() == events::Phase::ApplyExtrinsic(self.idx))
.unwrap_or(true) })
}
pub fn find<'a, Ev: events::StaticEvent + 'a>(
&'a self,
) -> impl Iterator<Item = Result<Ev, EventsError>> + 'a {
self.iter().filter_map(|ev| ev.and_then(|ev| ev.as_event::<Ev>()).transpose())
}
pub fn find_first<Ev: events::StaticEvent>(&self) -> Result<Option<Ev>, EventsError> {
self.find::<Ev>().next().transpose()
}
pub fn find_last<Ev: events::StaticEvent>(&self) -> Result<Option<Ev>, EventsError> {
self.find::<Ev>().last().transpose()
}
pub fn has<Ev: events::StaticEvent>(&self) -> Result<bool, EventsError> {
Ok(self.find::<Ev>().next().transpose()?.is_some())
}
}