fix: Convert vendor/pezkuwi-subxt from submodule to regular directory

This commit is contained in:
2025-12-19 16:45:24 +03:00
parent 9a52edf0df
commit fdd023c499
393 changed files with 154124 additions and 1 deletions
+12
View File
@@ -0,0 +1,12 @@
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! Types associated with accessing and working with storage items.
mod storage_client;
mod storage_client_at;
pub use storage_client::StorageClient;
pub use storage_client_at::{StorageClientAt, StorageEntryClient, StorageKeyValue, StorageValue};
pub use pezkuwi_subxt_core::storage::address::{Address, DynamicAddress, StaticAddress, dynamic};
@@ -0,0 +1,76 @@
// Copyright 2019-2025 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_client_at::StorageClientAt;
use crate::{
backend::BlockRef,
client::{OfflineClientT, OnlineClientT},
config::{Config, HashFor},
error::StorageError,
};
use derive_where::derive_where;
use std::{future::Future, marker::PhantomData};
use pezkuwi_subxt_core::storage::address::Address;
/// Query the runtime storage.
#[derive_where(Clone; Client)]
pub struct StorageClient<T, Client> {
client: Client,
_marker: PhantomData<T>,
}
impl<T, Client> StorageClient<T, Client> {
/// Create a new [`StorageClient`]
pub fn new(client: Client) -> Self {
Self {
client,
_marker: PhantomData,
}
}
}
impl<T, Client> StorageClient<T, Client>
where
T: Config,
Client: OfflineClientT<T>,
{
/// 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<Addr: Address>(&self, address: &Addr) -> Result<(), StorageError> {
pezkuwi_subxt_core::storage::validate(address, &self.client.metadata()).map_err(Into::into)
}
}
impl<T, Client> StorageClient<T, Client>
where
T: Config,
Client: OnlineClientT<T>,
{
/// Obtain storage at some block hash.
pub fn at(&self, block_ref: impl Into<BlockRef<HashFor<T>>>) -> StorageClientAt<T, Client> {
StorageClientAt::new(self.client.clone(), block_ref.into())
}
/// Obtain storage at the latest finalized block.
pub fn at_latest(
&self,
) -> impl Future<Output = Result<StorageClientAt<T, Client>, StorageError>> + 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
.map_err(StorageError::CannotGetLatestFinalizedBlock)?;
Ok(StorageClientAt::new(client, block_ref))
}
}
}
@@ -0,0 +1,383 @@
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{
backend::{BackendExt, BlockRef},
client::{OfflineClientT, OnlineClientT},
config::{Config, HashFor},
error::StorageError,
};
use derive_where::derive_where;
use futures::StreamExt;
use std::marker::PhantomData;
use pezkuwi_subxt_core::Metadata;
use pezkuwi_subxt_core::storage::{PrefixOf, address::Address};
use pezkuwi_subxt_core::utils::{Maybe, Yes};
pub use pezkuwi_subxt_core::storage::{StorageKeyValue, StorageValue};
/// Query the runtime storage.
#[derive_where(Clone; Client)]
pub struct StorageClientAt<T: Config, Client> {
client: Client,
metadata: Metadata,
block_ref: BlockRef<HashFor<T>>,
_marker: PhantomData<T>,
}
impl<T, Client> StorageClientAt<T, Client>
where
T: Config,
Client: OfflineClientT<T>,
{
/// Create a new [`StorageClientAt`].
pub(crate) fn new(client: Client, block_ref: BlockRef<HashFor<T>>) -> Self {
// Retrieve and store metadata here so that we can borrow it in
// subsequent structs, and thus also borrow storage info and
// things that borrow from metadata.
let metadata = client.metadata();
Self {
client,
metadata,
block_ref,
_marker: PhantomData,
}
}
}
impl<T, Client> StorageClientAt<T, Client>
where
T: Config,
Client: OfflineClientT<T>,
{
/// This returns a [`StorageEntryClient`], which allows working with the storage entry at the provided address.
pub fn entry<Addr: Address>(
&self,
address: Addr,
) -> Result<StorageEntryClient<'_, T, Client, Addr, Addr::IsPlain>, StorageError> {
let inner = pezkuwi_subxt_core::storage::entry(address, &self.metadata)?;
Ok(StorageEntryClient {
inner,
client: self.client.clone(),
block_ref: self.block_ref.clone(),
_marker: core::marker::PhantomData,
})
}
}
impl<T, Client> StorageClientAt<T, Client>
where
T: Config,
Client: OnlineClientT<T>,
{
/// This is essentially a shorthand for `client.entry(addr)?.fetch(key_parts)`. See [`StorageEntryClient::fetch()`].
pub async fn fetch<Addr: Address>(
&self,
addr: Addr,
key_parts: Addr::KeyParts,
) -> Result<StorageValue<'_, Addr::Value>, StorageError> {
let entry = pezkuwi_subxt_core::storage::entry(addr, &self.metadata)?;
fetch(&entry, &self.client, self.block_ref.hash(), key_parts).await
}
/// This is essentially a shorthand for `client.entry(addr)?.try_fetch(key_parts)`. See [`StorageEntryClient::try_fetch()`].
pub async fn try_fetch<Addr: Address>(
&self,
addr: Addr,
key_parts: Addr::KeyParts,
) -> Result<Option<StorageValue<'_, Addr::Value>>, StorageError> {
let entry = pezkuwi_subxt_core::storage::entry(addr, &self.metadata)?;
try_fetch(&entry, &self.client, self.block_ref.hash(), key_parts).await
}
/// This is essentially a shorthand for `client.entry(addr)?.iter(key_parts)`. See [`StorageEntryClient::iter()`].
pub async fn iter<Addr: Address, KeyParts: PrefixOf<Addr::KeyParts>>(
&'_ self,
addr: Addr,
key_parts: KeyParts,
) -> Result<
impl futures::Stream<Item = Result<StorageKeyValue<'_, Addr>, StorageError>>
+ use<'_, Addr, Client, T, KeyParts>,
StorageError,
> {
let entry = pezkuwi_subxt_core::storage::entry(addr, &self.metadata)?;
iter(entry, &self.client, self.block_ref.hash(), key_parts).await
}
/// In rare cases, you may wish to fetch a storage value that does not live at a typical address. This method
/// is a fallback for those cases, and allows you to provide the raw storage key bytes corresponding to the
/// entry you wish to obtain. The response will either be the bytes for the value found at that location, or
/// otherwise an error. [`StorageError::NoValueFound`] will be returned in the event that the request was valid
/// but no value lives at the given location).
pub async fn fetch_raw(&self, key_bytes: Vec<u8>) -> Result<Vec<u8>, StorageError> {
let block_hash = self.block_ref.hash();
let value = self
.client
.backend()
.storage_fetch_value(key_bytes, block_hash)
.await
.map_err(StorageError::CannotFetchValue)?
.ok_or(StorageError::NoValueFound)?;
Ok(value)
}
/// The storage version of a pallet.
/// The storage version refers to the `frame_support::traits::Metadata::StorageVersion` type.
pub async fn storage_version(&self, pallet_name: impl AsRef<str>) -> Result<u16, StorageError> {
// construct the storage key. This is done similarly in
// `frame_support::traits::metadata::StorageVersion::storage_key()`:
let mut key_bytes: Vec<u8> = vec![];
key_bytes.extend(&pezsp_crypto_hashing::twox_128(
pallet_name.as_ref().as_bytes(),
));
key_bytes.extend(&pezsp_crypto_hashing::twox_128(b":__STORAGE_VERSION__:"));
// fetch the raw bytes and decode them into the StorageVersion struct:
let storage_version_bytes = self.fetch_raw(key_bytes).await?;
<u16 as codec::Decode>::decode(&mut &storage_version_bytes[..])
.map_err(StorageError::CannotDecodeStorageVersion)
}
/// Fetch the runtime WASM code.
pub async fn runtime_wasm_code(&self) -> Result<Vec<u8>, StorageError> {
// note: this should match the `CODE` constant in `sp_core::storage::well_known_keys`
self.fetch_raw(b":code".to_vec()).await
}
}
/// This represents a single storage entry (be it a plain value or map)
/// and the operations that can be performed on it.
pub struct StorageEntryClient<'atblock, T: Config, Client, Addr, IsPlain> {
inner: pezkuwi_subxt_core::storage::StorageEntry<'atblock, Addr>,
client: Client,
block_ref: BlockRef<HashFor<T>>,
_marker: PhantomData<(T, IsPlain)>,
}
impl<'atblock, T, Client, Addr, IsPlain> StorageEntryClient<'atblock, T, Client, Addr, IsPlain>
where
T: Config,
Addr: Address,
{
/// Name of the pallet containing this storage entry.
pub fn pallet_name(&self) -> &str {
self.inner.pallet_name()
}
/// Name of the storage entry.
pub fn entry_name(&self) -> &str {
self.inner.entry_name()
}
/// Is the storage entry a plain value?
pub fn is_plain(&self) -> bool {
self.inner.is_plain()
}
/// Is the storage entry a map?
pub fn is_map(&self) -> bool {
self.inner.is_map()
}
/// Return the default value for this storage entry, if there is one. Returns `None` if there
/// is no default value.
pub fn default_value(&self) -> Option<StorageValue<'atblock, Addr::Value>> {
self.inner.default_value()
}
}
// Plain values get a fetch method with no extra arguments.
impl<'atblock, T, Client, Addr> StorageEntryClient<'atblock, T, Client, Addr, Yes>
where
T: Config,
Addr: Address,
Client: OnlineClientT<T>,
{
/// Fetch the storage value at this location. If no value is found, the default value will be returned
/// for this entry if one exists. If no value is found and no default value exists, an error will be returned.
pub async fn fetch(&self) -> Result<StorageValue<'atblock, Addr::Value>, StorageError> {
let value = self.try_fetch().await?.map_or_else(
|| self.inner.default_value().ok_or(StorageError::NoValueFound),
Ok,
)?;
Ok(value)
}
/// Fetch the storage value at this location. If no value is found, `None` will be returned.
pub async fn try_fetch(
&self,
) -> Result<Option<StorageValue<'atblock, Addr::Value>>, StorageError> {
let value = self
.client
.backend()
.storage_fetch_value(self.key_prefix().to_vec(), self.block_ref.hash())
.await
.map_err(StorageError::CannotFetchValue)?
.map(|bytes| self.inner.value(bytes));
Ok(value)
}
/// This is identical to [`StorageEntryClient::key_prefix()`] and is the full
/// key for this storage entry.
pub fn key(&self) -> [u8; 32] {
self.inner.key_prefix()
}
/// The keys for plain storage values are always 32 byte hashes.
pub fn key_prefix(&self) -> [u8; 32] {
self.inner.key_prefix()
}
}
// When HasDefaultValue = Yes, we expect there to exist a valid default value and will use that
// if we fetch an entry and get nothing back.
impl<'atblock, T, Client, Addr> StorageEntryClient<'atblock, T, Client, Addr, Maybe>
where
T: Config,
Addr: Address,
Client: OnlineClientT<T>,
{
/// Fetch a storage value within this storage entry.
///
/// This entry may be a map, and so you must provide the relevant values for each part of the storage
/// key that is required in order to point to a single value.
///
/// If no value is found, the default value will be returned for this entry if one exists. If no value is
/// found and no default value exists, an error will be returned.
pub async fn fetch(
&self,
key_parts: Addr::KeyParts,
) -> Result<StorageValue<'atblock, Addr::Value>, StorageError> {
fetch(&self.inner, &self.client, self.block_ref.hash(), key_parts).await
}
/// Fetch a storage value within this storage entry.
///
/// This entry may be a map, and so you must provide the relevant values for each part of the storage
/// key that is required in order to point to a single value.
///
/// If no value is found, `None` will be returned.
pub async fn try_fetch(
&self,
key_parts: Addr::KeyParts,
) -> Result<Option<StorageValue<'atblock, Addr::Value>>, StorageError> {
try_fetch(&self.inner, &self.client, self.block_ref.hash(), key_parts).await
}
/// Iterate over storage values within this storage entry.
///
/// You may provide any prefix of the values needed to point to a single value. Normally you will
/// provide `()` to iterate over _everything_, or `(first_key,)` to iterate over everything underneath
/// `first_key` in the map, or `(first_key, second_key)` to iterate over everything underneath `first_key`
/// and `second_key` in the map, and so on, up to the actual depth of the map - 1.
pub async fn iter<KeyParts: PrefixOf<Addr::KeyParts>>(
&self,
key_parts: KeyParts,
) -> Result<
impl futures::Stream<Item = Result<StorageKeyValue<'atblock, Addr>, StorageError>>
+ use<'atblock, Addr, Client, T, KeyParts>,
StorageError,
> {
iter(
self.inner.clone(),
&self.client,
self.block_ref.hash(),
key_parts,
)
.await
}
/// This returns a full key to a single value in this storage entry.
pub fn key(&self, key_parts: Addr::KeyParts) -> Result<Vec<u8>, StorageError> {
let key = self.inner.fetch_key(key_parts)?;
Ok(key)
}
/// This returns valid keys to iterate over the storage entry at the available levels.
pub fn iter_key<KeyParts: PrefixOf<Addr::KeyParts>>(
&self,
key_parts: KeyParts,
) -> Result<Vec<u8>, StorageError> {
let key = self.inner.iter_key(key_parts)?;
Ok(key)
}
/// The first 32 bytes of the storage entry key, which points to the entry but not necessarily
/// a single storage value (unless the entry is a plain value).
pub fn key_prefix(&self) -> [u8; 32] {
self.inner.key_prefix()
}
}
async fn fetch<'atblock, T: Config, Client: OnlineClientT<T>, Addr: Address>(
entry: &pezkuwi_subxt_core::storage::StorageEntry<'atblock, Addr>,
client: &Client,
block_hash: HashFor<T>,
key_parts: Addr::KeyParts,
) -> Result<StorageValue<'atblock, Addr::Value>, StorageError> {
let value = try_fetch(entry, client, block_hash, key_parts)
.await?
.or_else(|| entry.default_value())
.unwrap();
Ok(value)
}
async fn try_fetch<'atblock, T: Config, Client: OnlineClientT<T>, Addr: Address>(
entry: &pezkuwi_subxt_core::storage::StorageEntry<'atblock, Addr>,
client: &Client,
block_hash: HashFor<T>,
key_parts: Addr::KeyParts,
) -> Result<Option<StorageValue<'atblock, Addr::Value>>, StorageError> {
let key = entry.fetch_key(key_parts)?;
let value = client
.backend()
.storage_fetch_value(key, block_hash)
.await
.map_err(StorageError::CannotFetchValue)?
.map(|bytes| entry.value(bytes))
.or_else(|| entry.default_value());
Ok(value)
}
async fn iter<
'atblock,
T: Config,
Client: OnlineClientT<T>,
Addr: Address,
KeyParts: PrefixOf<Addr::KeyParts>,
>(
entry: pezkuwi_subxt_core::storage::StorageEntry<'atblock, Addr>,
client: &Client,
block_hash: HashFor<T>,
key_parts: KeyParts,
) -> Result<
impl futures::Stream<Item = Result<StorageKeyValue<'atblock, Addr>, StorageError>>
+ use<'atblock, Addr, Client, T, KeyParts>,
StorageError,
> {
let key_bytes = entry.iter_key(key_parts)?;
let stream = client
.backend()
.storage_fetch_descendant_values(key_bytes, block_hash)
.await
.map_err(StorageError::CannotIterateValues)?
.map(move |kv| {
let kv = match kv {
Ok(kv) => kv,
Err(e) => return Err(StorageError::StreamFailure(e)),
};
Ok(entry.key_value(kv.key, kv.value))
});
Ok(Box::pin(stream))
}