From 2681091a53ae3b57aec565bf282144dc1ba4b4a3 Mon Sep 17 00:00:00 2001 From: tarikgul Date: Tue, 2 Dec 2025 19:25:19 -0500 Subject: [PATCH] feat(subxt-historic): Add at_hash to OnlineClient --- historic/src/client/online_client.rs | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/historic/src/client/online_client.rs b/historic/src/client/online_client.rs index 532260f368..d254d41b7a 100644 --- a/historic/src/client/online_client.rs +++ b/historic/src/client/online_client.rs @@ -148,6 +148,59 @@ impl OnlineClient { block_hash, })) } + + /// Pick the block hash at which to operate. This is useful when you already have + /// the block hash and want to avoid the extra RPC call to look it up from a block number. + /// + /// If `block_number` is provided, the spec version cache (keyed by block number) can be used, + /// which avoids an additional RPC call to fetch the spec version. This is the most efficient + /// option when you have both the block number and hash available. + /// + /// This references data from the [`OnlineClient`] it's called on, and so cannot outlive it. + pub async fn at_hash( + &'_ self, + block_hash: ::Hash, + block_number: Option, + ) -> Result, T>, OnlineClientAtBlockError> { + let config = &self.inner.config; + let rpc_methods = &self.inner.rpc_methods; + + // Try to use cached spec version if block_number is provided, otherwise fetch it + let spec_version = if let Some(number) = block_number { + if let Some(cached_spec) = config.spec_version_for_block_number(number) { + cached_spec + } else { + get_spec_version(rpc_methods, block_hash).await? + } + } else { + get_spec_version(rpc_methods, block_hash).await? + }; + + // Use cached metadata if available, otherwise fetch it + let metadata = if let Some(metadata) = config.metadata_for_spec_version(spec_version) { + metadata + } else { + let metadata = get_metadata(rpc_methods, block_hash).await?; + let metadata = Arc::new(metadata); + config.set_metadata_for_spec_version(spec_version, metadata.clone()); + metadata + }; + + let mut historic_types = config.legacy_types_for_spec_version(spec_version); + let types_from_metadata = frame_decode::helpers::type_registry_from_metadata_any(&metadata) + .map_err( + |parse_error| OnlineClientAtBlockError::CannotInjectMetadataTypes { parse_error }, + )?; + historic_types.prepend(types_from_metadata); + + Ok(ClientAtBlock::new(OnlineClientAtBlock { + config, + historic_types, + metadata, + rpc_methods, + block_hash, + })) + } } /// This represents an online client at a specific block.