mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 13:31:10 +00:00
Add storage_version() and runtime_wasm_code() to storage (#1111)
* add storage_version function * get runtime code * add tests * clippy fix * just support CODE, remove other well known keys * remove u16 wrapper
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::storage_address::{StorageAddress, Yes};
|
||||
|
||||
use crate::{
|
||||
client::OnlineClientT,
|
||||
error::{Error, MetadataError},
|
||||
@@ -10,6 +11,7 @@ use crate::{
|
||||
rpc::types::{StorageData, StorageKey},
|
||||
Config,
|
||||
};
|
||||
use codec::Decode;
|
||||
use derivative::Derivative;
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
use subxt_metadata::{PalletMetadata, StorageEntryMetadata, StorageEntryType};
|
||||
@@ -237,6 +239,42 @@ where
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, Error> {
|
||||
// check that the pallet exists in the metadata:
|
||||
self.client
|
||||
.metadata()
|
||||
.pallet_by_name(pallet_name.as_ref())
|
||||
.ok_or_else(|| MetadataError::PalletNameNotFound(pallet_name.as_ref().into()))?;
|
||||
|
||||
// construct the storage key. This is done similarly in `frame_support::traits::metadata::StorageVersion::storage_key()`.
|
||||
pub const STORAGE_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__STORAGE_VERSION__:";
|
||||
let mut key_bytes: Vec<u8> = vec![];
|
||||
key_bytes.extend(&sp_core_hashing::twox_128(pallet_name.as_ref().as_bytes()));
|
||||
key_bytes.extend(&sp_core_hashing::twox_128(
|
||||
STORAGE_VERSION_STORAGE_KEY_POSTFIX,
|
||||
));
|
||||
|
||||
// fetch the raw bytes and decode them into the StorageVersion struct:
|
||||
let storage_version_bytes = self.fetch_raw(&key_bytes).await?.ok_or_else(|| {
|
||||
format!(
|
||||
"Unexpected: entry for storage version in pallet \"{}\" not found",
|
||||
pallet_name.as_ref()
|
||||
)
|
||||
})?;
|
||||
u16::decode(&mut &storage_version_bytes[..]).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Fetches the Wasm code of the runtime.
|
||||
pub async fn runtime_wasm_code(&self) -> Result<Vec<u8>, Error> {
|
||||
// note: this should match the `CODE` constant in `sp_core::storage::well_known_keys`
|
||||
const CODE: &str = ":code";
|
||||
self.fetch_raw(CODE.as_bytes()).await?.ok_or_else(|| {
|
||||
format!("Unexpected: entry for well known key \"{CODE}\" not found").into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over key value pairs in a map.
|
||||
@@ -338,7 +376,7 @@ fn validate_storage(
|
||||
hash: [u8; 32],
|
||||
) -> Result<(), Error> {
|
||||
let Some(expected_hash) = pallet.storage_hash(storage_name) else {
|
||||
return Err(MetadataError::IncompatibleCodegen.into())
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
};
|
||||
if expected_hash != hash {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
|
||||
@@ -389,7 +389,7 @@ impl<T: Config, C: OnlineClientT<T>> TxInBlock<T, C> {
|
||||
.iter()
|
||||
.position(|ext| {
|
||||
use crate::config::Hasher;
|
||||
let Ok((_,stripped)) = strip_compact_prefix(&ext.0) else {
|
||||
let Ok((_, stripped)) = strip_compact_prefix(&ext.0) else {
|
||||
return false;
|
||||
};
|
||||
let hash = T::Hasher::hash_of(&stripped);
|
||||
|
||||
@@ -83,7 +83,7 @@ impl<T> EncodeAsType for WrapperKeepOpaque<T> {
|
||||
use scale_encode::error::{Error, ErrorKind, Kind};
|
||||
|
||||
let Some(ty) = types.resolve(type_id) else {
|
||||
return Err(Error::new(ErrorKind::TypeNotFound(type_id)))
|
||||
return Err(Error::new(ErrorKind::TypeNotFound(type_id)));
|
||||
};
|
||||
|
||||
// Do a basic check that the target shape lines up.
|
||||
@@ -91,7 +91,7 @@ impl<T> EncodeAsType for WrapperKeepOpaque<T> {
|
||||
return Err(Error::new(ErrorKind::WrongShape {
|
||||
actual: Kind::Struct,
|
||||
expected: type_id,
|
||||
}))
|
||||
}));
|
||||
};
|
||||
|
||||
// Check that the name also lines up.
|
||||
|
||||
@@ -125,3 +125,33 @@ async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error> {
|
||||
assert_eq!(entry.map(|a| a.amount), Some(123));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn storage_runtime_wasm_code() -> Result<(), subxt::Error> {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
let wasm_blob = api.storage().at_latest().await?.runtime_wasm_code().await?;
|
||||
assert!(wasm_blob.len() > 1000); // the wasm should be super big
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn storage_pallet_storage_version() -> Result<(), subxt::Error> {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
// cannot assume anything about version number, but should work to fetch it
|
||||
let _version = api
|
||||
.storage()
|
||||
.at_latest()
|
||||
.await?
|
||||
.storage_version("System")
|
||||
.await?;
|
||||
let _version = api
|
||||
.storage()
|
||||
.at_latest()
|
||||
.await?
|
||||
.storage_version("Balances")
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user