diff --git a/subxt/src/blocks/block_types.rs b/subxt/src/blocks/block_types.rs index feb97eba25..14087c217f 100644 --- a/subxt/src/blocks/block_types.rs +++ b/subxt/src/blocks/block_types.rs @@ -12,6 +12,7 @@ use crate::{ Error, }, events, + metadata::DecodeWithMetadata, rpc::{ types::{ ChainHeadEvent, @@ -19,6 +20,11 @@ use crate::{ }, ChainBlockResponse, }, + storage::{ + address::Yes, + utils, + StorageAddress, + }, Config, }; use codec::Decode; @@ -100,6 +106,30 @@ impl TryFrom> for Vec { } } +impl TryFrom>> for Option> { + type Error = ChainHeadError; + + fn try_from(event: ChainHeadEvent>) -> Result { + match event { + ChainHeadEvent::Done(ChainHeadResult { result }) => { + let result = match result { + Some(result) => result, + None => return Ok(None), + }; + + let res: Vec = + ChainHeadEvent::Done(ChainHeadResult { result }).try_into()?; + Ok(Some(res)) + } + ChainHeadEvent::Inaccessible(err) => { + Err(ChainHeadError::Inaccessible(err.error)) + } + ChainHeadEvent::Error(err) => Err(ChainHeadError::Error(err.error)), + ChainHeadEvent::Disjoint => Err(ChainHeadError::Disjoint), + } + } +} + impl ChainHeadBlock where T: Config, @@ -117,6 +147,43 @@ where .await } + /// Fetch the raw storage bytes of this block at the provided key. + pub async fn storage_raw<'a>( + &self, + key: &'a [u8], + ) -> Result>, ChainHeadError> { + self.fetch_storage(self.subscription_id.clone(), self.hash, &key, None) + .await + } + + /// Fetch the storage of this block at the provided key. + pub async fn storage<'a, Address>( + &self, + key: &'a Address, + ) -> Result::Target>, ChainHeadError> + where + Address: StorageAddress + 'a, + { + // Look up the return type ID to enable DecodeWithMetadata: + let metadata = self.client.metadata(); + let key_bytes = utils::storage_address_bytes(key, &metadata)?; + + let storage_bytes = self.storage_raw(&key_bytes).await?; + let bytes = match storage_bytes { + Some(bytes) => bytes, + None => return Ok(None), + }; + + let storage = + ::decode_storage_with_metadata( + &mut &*bytes, + key.pallet_name(), + key.entry_name(), + &metadata, + )?; + Ok(Some(storage)) + } + /// Wrapper to fetch the block's body from the `chainHead_body` subscription. async fn fetch_body( &self, @@ -139,7 +206,9 @@ where return Ok(extrinsics) } - Err(Error::Other("Failed to fetch the block body".into()).into()) + Err(ChainHeadError::Other( + "Failed to fetch the block body".into(), + )) } /// Wrapper to fetch the block's header from the `chainHead_header` method. @@ -166,6 +235,32 @@ where Decode::decode(&mut &bytes[..]).map_err(Into::::into)?; Ok(header) } + + /// Wrapper to fetch the block's storage from the `chainHead_storage` subscription. + async fn fetch_storage( + &self, + subscription_id: String, + hash: T::Hash, + key: &[u8], + child_key: Option<&[u8]>, + ) -> Result>, ChainHeadError> { + let mut sub = self + .client + .rpc() + .subscribe_chainhead_storage(subscription_id, hash, key, child_key) + .await?; + + if let Some(event) = sub.next().await { + let event = event?; + + let bytes = Option::>::try_from(event)?; + return Ok(bytes) + } + + Err(ChainHeadError::Other( + "Failed to fetch the block storage".into(), + )) + } } /// A representation of a block.