From 1c9aabf0f5113986aa919573a5409c64b657bd86 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 23 Nov 2022 16:03:04 +0200 Subject: [PATCH] events: Fetch metadata at arbitrary blocks (#727) * subxt/rpc: Fetch metadata at arbitrary blocks Signed-off-by: Alexandru Vasile * subxt/events: Fetch metadata for events at arbitrary blocks Signed-off-by: Alexandru Vasile * Revert "subxt/events: Fetch metadata for events at arbitrary blocks" This reverts commit 381409b7a8916611d7c44dc6ad58a90993b6c297. * subxt/events: Custom constructor with metadata for events Signed-off-by: Alexandru Vasile * Update subxt/src/events/events_type.rs Co-authored-by: James Wilson Signed-off-by: Alexandru Vasile Co-authored-by: James Wilson --- subxt/src/client/online_client.rs | 4 +-- subxt/src/events/events_client.rs | 25 ++++++++++++----- subxt/src/events/events_type.rs | 46 +++++++++++++++++++++++++++++++ subxt/src/rpc/rpc.rs | 4 +-- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index fc85fad5fd..668ddf65b1 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -93,7 +93,7 @@ impl OnlineClient { let (genesis_hash, runtime_version, metadata) = future::join3( rpc.genesis_hash(), rpc.runtime_version(None), - rpc.metadata(), + rpc.metadata(None), ) .await; @@ -310,7 +310,7 @@ impl RuntimeUpdaterStream { Err(err) => return Some(Err(err)), }; - let metadata = match self.client.rpc().metadata().await { + let metadata = match self.client.rpc().metadata(None).await { Ok(metadata) => metadata, Err(err) => return Some(Err(err)), }; diff --git a/subxt/src/events/events_client.rs b/subxt/src/events/events_client.rs index e91bf15c50..eb0e336870 100644 --- a/subxt/src/events/events_client.rs +++ b/subxt/src/events/events_client.rs @@ -66,13 +66,7 @@ where } }; - let event_bytes = client - .rpc() - .storage(&system_events_key().0, Some(block_hash)) - .await? - .map(|e| e.0) - .unwrap_or_else(Vec::new); - + let event_bytes = get_event_bytes(&client, Some(block_hash)).await?; Ok(Events::new(client.metadata(), block_hash, event_bytes)) } } @@ -84,3 +78,20 @@ fn system_events_key() -> StorageKey { storage_key.extend(twox_128(b"Events").to_vec()); StorageKey(storage_key) } + +// Get the event bytes from the provided client, at the provided block hash. +pub(crate) async fn get_event_bytes( + client: &Client, + block_hash: Option, +) -> Result, Error> +where + T: Config, + Client: OnlineClientT, +{ + Ok(client + .rpc() + .storage(&system_events_key().0, block_hash) + .await? + .map(|e| e.0) + .unwrap_or_else(Vec::new)) +} diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index d0b8ade853..234f6aa7b5 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -9,7 +9,9 @@ use super::{ StaticEvent, }; use crate::{ + client::OnlineClientT, error::Error, + events::events_client::get_event_bytes, metadata::EventMetadata, Config, Metadata, @@ -64,6 +66,50 @@ impl Events { } } + /// Obtain the events from a block hash given custom metadata and a client. + /// + /// This method gives users the ability to inspect the events of older blocks, + /// where the metadata changed. For those cases, the user is responsible for + /// providing a valid metadata. + /// + /// # Example + /// + /// ```no_run + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// use subxt::{ OnlineClient, PolkadotConfig, events::Events }; + /// + /// let client = OnlineClient::::new().await.unwrap(); + /// + /// // Get the hash of an older block. + /// let block_hash = client + /// .rpc() + /// .block_hash(Some(1u32.into())) + /// .await? + /// .expect("didn't pass a block number; qed"); + /// // Fetch the metadata of the given block. + /// let metadata = client.rpc().metadata(Some(block_hash)).await?; + /// // Fetch the events from the client. + /// let events = Events::new_from_client(metadata, block_hash, client); + /// # Ok(()) + /// # } + /// ``` + /// + /// # Note + /// + /// Prefer to use [`crate::events::EventsClient::at`] to obtain the events. + pub async fn new_from_client( + metadata: Metadata, + block_hash: T::Hash, + client: Client, + ) -> Result + where + Client: OnlineClientT, + { + let event_bytes = get_event_bytes(&client, Some(block_hash)).await?; + Ok(Events::new(metadata, block_hash, event_bytes)) + } + /// The number of events. pub fn len(&self) -> u32 { self.num_events diff --git a/subxt/src/rpc/rpc.rs b/subxt/src/rpc/rpc.rs index 47f716c8db..c12ce885e6 100644 --- a/subxt/src/rpc/rpc.rs +++ b/subxt/src/rpc/rpc.rs @@ -443,10 +443,10 @@ impl Rpc { } /// Fetch the metadata - pub async fn metadata(&self) -> Result { + pub async fn metadata(&self, at: Option) -> Result { let bytes: Bytes = self .client - .request("state_getMetadata", rpc_params![]) + .request("state_getMetadata", rpc_params![at]) .await?; let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])?; let metadata: Metadata = meta.try_into()?;