diff --git a/new/src/client.rs b/new/src/client.rs index 8c073e0222..b5cea2eebd 100644 --- a/new/src/client.rs +++ b/new/src/client.rs @@ -4,9 +4,8 @@ mod online_client; use crate::config::{Config, HashFor}; use crate::constants::ConstantsClient; use crate::custom_values::CustomValuesClient; -use crate::error::{EventsError, ExtrinsicError}; -use crate::events::Events; -use crate::extrinsics::Extrinsics; +use crate::events::EventsClient; +use crate::extrinsics::ExtrinsicsClient; use crate::runtime_apis::RuntimeApisClient; use crate::storage::StorageClient; use crate::transactions::TransactionsClient; @@ -54,10 +53,21 @@ where ConstantsClient::new(self.client.clone()) } + /// Access custom values at this block. pub fn custom_values(&self) -> CustomValuesClient { CustomValuesClient::new(self.client.clone()) } + /// Work with the extrinsics in this block. + pub fn extrinsics(&self) -> ExtrinsicsClient { + ExtrinsicsClient::new(self.client.clone()) + } + + /// Work with the events at this block. + pub fn events(&self) -> EventsClient { + EventsClient::new(self.client.clone()) + } + /// Access runtime APIs at this block. pub fn runtime_apis(&self) -> RuntimeApisClient { RuntimeApisClient::new(self.client.clone()) @@ -83,16 +93,6 @@ where T: Config, Client: OnlineClientAtBlockT, { - /// Obtain the extrinsics in this block. - pub async fn extrinsics(&self) -> Result, ExtrinsicError> { - Extrinsics::fetch(self.client.clone()).await - } - - /// Obtain the extrinsic events at this block. - pub async fn events(&self) -> Result, EventsError> { - Events::fetch(self.client.clone()).await - } - /// The current block hash. pub fn block_hash(&self) -> HashFor { self.client.block_hash() diff --git a/new/src/events.rs b/new/src/events.rs index fbced5aeb5..772678ecb5 100644 --- a/new/src/events.rs +++ b/new/src/events.rs @@ -1,8 +1,9 @@ mod decode_as_event; +use crate::backend::BackendExt; +use crate::client::{OfflineClientAtBlockT, OnlineClientAtBlockT}; use crate::config::{Config, HashFor}; use crate::error::EventsError; -use crate::{backend::BackendExt, client::OnlineClientAtBlockT}; use codec::{Compact, Decode, Encode}; use scale_decode::{DecodeAsFields, DecodeAsType}; use std::marker::PhantomData; @@ -11,6 +12,67 @@ use subxt_metadata::Metadata; pub use decode_as_event::DecodeAsEvent; +/// A client for working with events. +pub struct EventsClient { + client: Client, + marker: PhantomData, +} + +impl EventsClient { + pub(crate) fn new(client: Client) -> Self { + EventsClient { + client, + marker: PhantomData, + } + } +} + +impl> EventsClient { + /// Work with the block event bytes given. + /// + /// No attempt to validate the provided bytes is made here; if invalid bytes are + /// provided then attempting to iterate and decode them will fail. + pub fn from_bytes(&self, event_bytes: Vec) -> Events { + // event_bytes is a SCALE encoded vector of events. So, pluck the + // compact encoded length from the front, leaving the remaining bytes + // for our iterating to decode. + // + // Note: if we get no bytes back, avoid an error reading vec length + // and default to 0 events. + let cursor = &mut &*event_bytes; + let num_events = >::decode(cursor).unwrap_or(Compact(0)).0; + + // Start decoding after the compact encoded bytes. + let start_idx = event_bytes.len() - cursor.len(); + + Events { + metadata: self.client.metadata(), + event_bytes, + start_idx, + num_events, + marker: PhantomData, + } + } +} + +impl> EventsClient { + /// Fetch the events at this block. + pub async fn fetch(&self) -> Result, EventsError> { + let client = &self.client; + + // Fetch the bytes. Ensure things work if we get 0 bytes back. + let block_hash = client.block_hash(); + let event_bytes = client + .backend() + .storage_fetch_value(system_events_key().to_vec(), block_hash) + .await + .map_err(EventsError::CannotFetchEventBytes)? + .unwrap_or_default(); + + Ok(self.from_bytes(event_bytes)) + } +} + /// The events at some block. #[derive(Debug)] pub struct Events { @@ -25,37 +87,6 @@ pub struct Events { } impl Events { - pub(crate) async fn fetch(client: impl OnlineClientAtBlockT) -> Result { - // Fetch the bytes. Ensure things work if we get 0 bytes back. - let block_hash = client.block_hash(); - let event_bytes = client - .backend() - .storage_fetch_value(system_events_key().to_vec(), block_hash) - .await - .map_err(EventsError::CannotFetchEventBytes)? - .unwrap_or_default(); - - // event_bytes is a SCALE encoded vector of events. So, pluck the - // compact encoded length from the front, leaving the remaining bytes - // for our iterating to decode. - // - // Note: if we get no bytes back, avoid an error reading vec length - // and default to 0 events. - let cursor = &mut &*event_bytes; - let num_events = >::decode(cursor).unwrap_or(Compact(0)).0; - - // Start decoding after the compact encoded bytes. - let start_idx = event_bytes.len() - cursor.len(); - - Ok(Self { - metadata: client.metadata(), - event_bytes, - start_idx, - num_events, - marker: PhantomData, - }) - } - /// The number of events. pub fn len(&self) -> u32 { self.num_events diff --git a/new/src/extrinsics.rs b/new/src/extrinsics.rs index 09d0fbf9b7..80670740a0 100644 --- a/new/src/extrinsics.rs +++ b/new/src/extrinsics.rs @@ -18,16 +18,39 @@ pub use extrinsic_transaction_extensions::{ ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions, }; -/// The extrinsics in a block. -#[derive(Debug, Clone)] -pub struct Extrinsics { - client: C, - extrinsics: Arc>>, +/// A client for working with extrinsics. +pub struct ExtrinsicsClient { + client: Client, marker: PhantomData, } -impl> Extrinsics { - pub(crate) async fn fetch(client: C) -> Result { +impl ExtrinsicsClient { + pub(crate) fn new(client: Client) -> Self { + ExtrinsicsClient { + client, + marker: PhantomData, + } + } +} + +impl> ExtrinsicsClient { + /// Work with the block body bytes given. + /// + /// No attempt to validate the provided bytes is made here; if invalid bytes are + /// provided then attempting to iterate and decode them will fail. + pub async fn from_bytes(&self, extrinsics: Vec>) -> Extrinsics { + Extrinsics { + client: self.client.clone(), + extrinsics: Arc::new(extrinsics), + marker: PhantomData, + } + } +} + +impl> ExtrinsicsClient { + /// Fetch the extrinsics at this block. + pub async fn fetch(&self) -> Result, ExtrinsicError> { + let client = &self.client; let block_hash = client.block_hash(); let extrinsics = client .backend() @@ -37,13 +60,21 @@ impl> Extrinsics { .ok_or_else(|| ExtrinsicError::BlockNotFound(block_hash.into()))?; Ok(Extrinsics { - client, + client: client.clone(), extrinsics: Arc::new(extrinsics), marker: PhantomData, }) } } +/// The extrinsics in a block. +#[derive(Debug, Clone)] +pub struct Extrinsics { + client: C, + extrinsics: Arc>>, + marker: PhantomData, +} + impl> Extrinsics { /// The number of extrinsics. pub fn len(&self) -> usize { @@ -334,7 +365,10 @@ impl ExtrinsicEvents { extrinsic_hash: HashFor, extrinsic_index: usize, ) -> Result { - let events = crate::client::ClientAtBlock::new(client).events().await?; + let events = crate::client::ClientAtBlock::new(client) + .events() + .fetch() + .await?; Ok(ExtrinsicEvents { extrinsic_hash, extrinsic_index,