// Copyright 2019-2023 Parity Technologies (UK) Ltd. // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. use super::{ storage_type::{validate_storage_address, Storage}, StorageAddress, }; use crate::{ backend::BlockRef, client::{OfflineClientT, OnlineClientT}, error::Error, Config, }; use derive_where::derive_where; use std::{future::Future, marker::PhantomData}; /// Query the runtime storage. #[derive_where(Clone; Client)] pub struct StorageClient { client: Client, _marker: PhantomData, } impl StorageClient { /// Create a new [`StorageClient`] pub fn new(client: Client) -> Self { Self { client, _marker: PhantomData, } } } impl StorageClient where T: Config, Client: OfflineClientT, { /// Run the validation logic against some storage address you'd like to access. Returns `Ok(())` /// if the address is valid (or if it's not possible to check since the address has no validation hash). /// Return an error if the address was not valid or something went wrong trying to validate it (ie /// the pallet or storage entry in question do not exist at all). pub fn validate(&self, address: &Address) -> Result<(), Error> { let metadata = self.client.metadata(); let pallet_metadata = metadata.pallet_by_name_err(address.pallet_name())?; validate_storage_address(address, pallet_metadata) } /// Convert some storage address into the raw bytes that would be submitted to the node in order /// to retrieve the entries at the root of the associated address. pub fn address_root_bytes(&self, address: &Address) -> Vec { subxt_core::storage::utils::storage_address_root_bytes(address) } /// Convert some storage address into the raw bytes that would be submitted to the node in order /// to retrieve an entry. This fails if [`StorageAddress::append_entry_bytes`] does; in the built-in /// implementation this would be if the pallet and storage entry being asked for is not available on the /// node you're communicating with, or if the metadata is missing some type information (which should not /// happen). pub fn address_bytes( &self, address: &Address, ) -> Result, Error> { subxt_core::storage::utils::storage_address_bytes(address, &self.client.metadata()) .map_err(Into::into) } } impl StorageClient where T: Config, Client: OnlineClientT, { /// Obtain storage at some block hash. pub fn at(&self, block_ref: impl Into>) -> Storage { Storage::new(self.client.clone(), block_ref.into()) } /// Obtain storage at the latest block hash. pub fn at_latest( &self, ) -> impl Future, Error>> + Send + 'static { // Clone and pass the client in like this so that we can explicitly // return a Future that's Send + 'static, rather than tied to &self. let client = self.client.clone(); async move { // get the ref for the latest finalized block and use that. let block_ref = client.backend().latest_finalized_block_ref().await?; Ok(Storage::new(client, block_ref)) } } }