make offline event and extrinsic ops possible

This commit is contained in:
James Wilson
2025-12-09 15:44:08 +00:00
parent 4d2b4a6755
commit 744a513aeb
3 changed files with 119 additions and 54 deletions
+13 -13
View File
@@ -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<T, Client> {
CustomValuesClient::new(self.client.clone())
}
/// Work with the extrinsics in this block.
pub fn extrinsics(&self) -> ExtrinsicsClient<T, Client> {
ExtrinsicsClient::new(self.client.clone())
}
/// Work with the events at this block.
pub fn events(&self) -> EventsClient<T, Client> {
EventsClient::new(self.client.clone())
}
/// Access runtime APIs at this block.
pub fn runtime_apis(&self) -> RuntimeApisClient<T, Client> {
RuntimeApisClient::new(self.client.clone())
@@ -83,16 +93,6 @@ where
T: Config,
Client: OnlineClientAtBlockT<T>,
{
/// Obtain the extrinsics in this block.
pub async fn extrinsics(&self) -> Result<Extrinsics<T, Client>, ExtrinsicError> {
Extrinsics::fetch(self.client.clone()).await
}
/// Obtain the extrinsic events at this block.
pub async fn events(&self) -> Result<Events<T>, EventsError> {
Events::fetch(self.client.clone()).await
}
/// The current block hash.
pub fn block_hash(&self) -> HashFor<T> {
self.client.block_hash()
+63 -32
View File
@@ -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<T, Client> {
client: Client,
marker: PhantomData<T>,
}
impl<T, Client> EventsClient<T, Client> {
pub(crate) fn new(client: Client) -> Self {
EventsClient {
client,
marker: PhantomData,
}
}
}
impl<T: Config, Client: OfflineClientAtBlockT<T>> EventsClient<T, Client> {
/// 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<u8>) -> Events<T> {
// 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 = <Compact<u32>>::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<T: Config, Client: OnlineClientAtBlockT<T>> EventsClient<T, Client> {
/// Fetch the events at this block.
pub async fn fetch(&self) -> Result<Events<T>, 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<T> {
@@ -25,37 +87,6 @@ pub struct Events<T> {
}
impl<T: Config> Events<T> {
pub(crate) async fn fetch(client: impl OnlineClientAtBlockT<T>) -> Result<Self, EventsError> {
// 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 = <Compact<u32>>::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
+43 -9
View File
@@ -18,16 +18,39 @@ pub use extrinsic_transaction_extensions::{
ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions,
};
/// The extrinsics in a block.
#[derive(Debug, Clone)]
pub struct Extrinsics<T, C> {
client: C,
extrinsics: Arc<Vec<Vec<u8>>>,
/// A client for working with extrinsics.
pub struct ExtrinsicsClient<T, Client> {
client: Client,
marker: PhantomData<T>,
}
impl<T: Config, C: OnlineClientAtBlockT<T>> Extrinsics<T, C> {
pub(crate) async fn fetch(client: C) -> Result<Self, ExtrinsicError> {
impl<T, Client> ExtrinsicsClient<T, Client> {
pub(crate) fn new(client: Client) -> Self {
ExtrinsicsClient {
client,
marker: PhantomData,
}
}
}
impl<T: Config, Client: OfflineClientAtBlockT<T>> ExtrinsicsClient<T, Client> {
/// 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<Vec<u8>>) -> Extrinsics<T, Client> {
Extrinsics {
client: self.client.clone(),
extrinsics: Arc::new(extrinsics),
marker: PhantomData,
}
}
}
impl<T: Config, Client: OnlineClientAtBlockT<T>> ExtrinsicsClient<T, Client> {
/// Fetch the extrinsics at this block.
pub async fn fetch(&self) -> Result<Extrinsics<T, Client>, ExtrinsicError> {
let client = &self.client;
let block_hash = client.block_hash();
let extrinsics = client
.backend()
@@ -37,13 +60,21 @@ impl<T: Config, C: OnlineClientAtBlockT<T>> Extrinsics<T, C> {
.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<T, C> {
client: C,
extrinsics: Arc<Vec<Vec<u8>>>,
marker: PhantomData<T>,
}
impl<T: Config, C: OfflineClientAtBlockT<T>> Extrinsics<T, C> {
/// The number of extrinsics.
pub fn len(&self) -> usize {
@@ -334,7 +365,10 @@ impl<T: Config> ExtrinsicEvents<T> {
extrinsic_hash: HashFor<T>,
extrinsic_index: usize,
) -> Result<Self, EventsError> {
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,