Skip to content

Commit

Permalink
Add storage_version() and runtime_wasm_code() to storage (#1111)
Browse files Browse the repository at this point in the history
* add storage_version function

* get runtime code

* add tests

* clippy fix

* just support CODE, remove other well known keys

* remove u16 wrapper
  • Loading branch information
tadeohepperle authored Aug 10, 2023
1 parent b97acc5 commit 9723a50
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
40 changes: 39 additions & 1 deletion subxt/src/storage/storage_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
// see LICENSE for license details.

use super::storage_address::{StorageAddress, Yes};

use crate::{
client::OnlineClientT,
error::{Error, MetadataError},
metadata::{DecodeWithMetadata, Metadata},
rpc::types::{StorageData, StorageKey},
Config,
};
use codec::Decode;
use derivative::Derivative;
use std::{future::Future, marker::PhantomData};
use subxt_metadata::{PalletMetadata, StorageEntryMetadata, StorageEntryType};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion subxt/src/tx/tx_progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions subxt/src/utils/wrapper_opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ 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.
let scale_info::TypeDef::Composite(_) = &ty.type_def else {
return Err(Error::new(ErrorKind::WrongShape {
actual: Kind::Struct,
expected: type_id,
}))
}));
};

// Check that the name also lines up.
Expand Down
30 changes: 30 additions & 0 deletions testing/integration-tests/src/full_client/storage/mod.rs
Original file line number Diff line number Diff line change
Expand 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(())
}

0 comments on commit 9723a50

Please sign in to comment.