gear_subxt/storage/
storage_client.rs

1// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use super::{
6    storage_type::{validate_storage_address, Storage},
7    utils, StorageAddress,
8};
9
10use crate::{
11    client::{OfflineClientT, OnlineClientT},
12    error::Error,
13    Config,
14};
15use derivative::Derivative;
16use std::{future::Future, marker::PhantomData};
17
18/// Query the runtime storage.
19#[derive(Derivative)]
20#[derivative(Clone(bound = "Client: Clone"))]
21pub struct StorageClient<T, Client> {
22    client: Client,
23    _marker: PhantomData<T>,
24}
25
26impl<T, Client> StorageClient<T, Client> {
27    /// Create a new [`StorageClient`]
28    pub fn new(client: Client) -> Self {
29        Self {
30            client,
31            _marker: PhantomData,
32        }
33    }
34}
35
36impl<T, Client> StorageClient<T, Client>
37where
38    T: Config,
39    Client: OfflineClientT<T>,
40{
41    /// Run the validation logic against some storage address you'd like to access. Returns `Ok(())`
42    /// if the address is valid (or if it's not possible to check since the address has no validation hash).
43    /// Return an error if the address was not valid or something went wrong trying to validate it (ie
44    /// the pallet or storage entry in question do not exist at all).
45    pub fn validate<Address: StorageAddress>(&self, address: &Address) -> Result<(), Error> {
46        let metadata = self.client.metadata();
47        let pallet_metadata = metadata.pallet_by_name_err(address.pallet_name())?;
48        validate_storage_address(address, pallet_metadata)
49    }
50
51    /// Convert some storage address into the raw bytes that would be submitted to the node in order
52    /// to retrieve the entries at the root of the associated address.
53    pub fn address_root_bytes<Address: StorageAddress>(&self, address: &Address) -> Vec<u8> {
54        utils::storage_address_root_bytes(address)
55    }
56
57    /// Convert some storage address into the raw bytes that would be submitted to the node in order
58    /// to retrieve an entry. This fails if [`StorageAddress::append_entry_bytes`] does; in the built-in
59    /// implementation this would be if the pallet and storage entry being asked for is not available on the
60    /// node you're communicating with, or if the metadata is missing some type information (which should not
61    /// happen).
62    pub fn address_bytes<Address: StorageAddress>(
63        &self,
64        address: &Address,
65    ) -> Result<Vec<u8>, Error> {
66        utils::storage_address_bytes(address, &self.client.metadata())
67    }
68}
69
70impl<T, Client> StorageClient<T, Client>
71where
72    T: Config,
73    Client: OnlineClientT<T>,
74{
75    /// Obtain storage at some block hash.
76    pub fn at(&self, block_hash: T::Hash) -> Storage<T, Client> {
77        Storage::new(self.client.clone(), block_hash)
78    }
79
80    /// Obtain storage at the latest block hash.
81    pub fn at_latest(
82        &self,
83    ) -> impl Future<Output = Result<Storage<T, Client>, Error>> + Send + 'static {
84        // Clone and pass the client in like this so that we can explicitly
85        // return a Future that's Send + 'static, rather than tied to &self.
86        let client = self.client.clone();
87        async move {
88            // get the hash for the latest block and use that.
89            let block_hash = client
90                .rpc()
91                .block_hash(None)
92                .await?
93                .expect("didn't pass a block number; qed");
94
95            Ok(Storage::new(client, block_hash))
96        }
97    }
98}