mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 02:21:14 +00:00
Metadata difference command (#1015)
* diffing pallets and runtime apis * print diff * clippy fix and format * change formatting * fmt * diff working with storage details * fix diff * cargo fmt * remove printing of node * change strings * handle parsing differently * clippy fix * cargo fmt * more abstraction * clippy fix and fmt * add unit test and ordering * fix small issue
This commit is contained in:
+20
-5
@@ -20,7 +20,7 @@ mod from_into;
|
||||
mod utils;
|
||||
|
||||
use scale_info::{form::PortableForm, PortableRegistry, Variant};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use utils::ordered_map::OrderedMap;
|
||||
use utils::variant_index::VariantIndex;
|
||||
@@ -138,6 +138,16 @@ impl Metadata {
|
||||
{
|
||||
utils::retain::retain_metadata(self, pallet_filter, api_filter);
|
||||
}
|
||||
|
||||
/// Get type hash for a type in the registry
|
||||
pub fn type_hash(&self, id: u32) -> Option<[u8; 32]> {
|
||||
self.types.resolve(id)?;
|
||||
Some(crate::utils::validation::get_type_hash(
|
||||
&self.types,
|
||||
id,
|
||||
&mut HashSet::<u32>::new(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for a specific pallet.
|
||||
@@ -303,8 +313,8 @@ impl StorageMetadata {
|
||||
}
|
||||
|
||||
/// An iterator over the storage entries.
|
||||
pub fn entries(&self) -> impl ExactSizeIterator<Item = &StorageEntryMetadata> {
|
||||
self.entries.values().iter()
|
||||
pub fn entries(&self) -> &[StorageEntryMetadata] {
|
||||
self.entries.values()
|
||||
}
|
||||
|
||||
/// Return a specific storage entry given its name.
|
||||
@@ -387,7 +397,7 @@ pub enum StorageHasher {
|
||||
}
|
||||
|
||||
/// Is the storage entry optional, or does it have a default value.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum StorageEntryModifier {
|
||||
/// The storage entry returns an `Option<T>`, with `None` if the key is not present.
|
||||
Optional,
|
||||
@@ -490,7 +500,7 @@ pub struct RuntimeApiMetadata<'a> {
|
||||
|
||||
impl<'a> RuntimeApiMetadata<'a> {
|
||||
/// Trait name.
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn name(&self) -> &'a str {
|
||||
&self.inner.name
|
||||
}
|
||||
/// Trait documentation.
|
||||
@@ -509,6 +519,11 @@ impl<'a> RuntimeApiMetadata<'a> {
|
||||
pub fn method_hash(&self, method_name: &str) -> Option<[u8; 32]> {
|
||||
crate::utils::validation::get_runtime_api_hash(self, method_name)
|
||||
}
|
||||
|
||||
/// Return a hash for the runtime API trait.
|
||||
pub fn hash(&self) -> [u8; 32] {
|
||||
crate::utils::validation::get_runtime_trait_hash(*self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -175,7 +175,7 @@ fn get_type_def_hash(
|
||||
}
|
||||
|
||||
/// Obtain the hash representation of a `scale_info::Type` identified by id.
|
||||
fn get_type_hash(
|
||||
pub fn get_type_hash(
|
||||
registry: &PortableRegistry,
|
||||
id: u32,
|
||||
visited_ids: &mut HashSet<u32>,
|
||||
@@ -283,7 +283,7 @@ fn get_runtime_method_hash(
|
||||
}
|
||||
|
||||
/// Obtain the hash of all of a runtime API trait, including all of its methods.
|
||||
fn get_runtime_trait_hash(trait_metadata: RuntimeApiMetadata) -> [u8; HASH_LEN] {
|
||||
pub fn get_runtime_trait_hash(trait_metadata: RuntimeApiMetadata) -> [u8; HASH_LEN] {
|
||||
let mut visited_ids = HashSet::new();
|
||||
let trait_name = &*trait_metadata.inner.name;
|
||||
let method_bytes = trait_metadata
|
||||
@@ -379,14 +379,17 @@ pub fn get_pallet_hash(pallet: PalletMetadata) -> [u8; HASH_LEN] {
|
||||
let storage_bytes = match pallet.storage() {
|
||||
Some(storage) => {
|
||||
let prefix_hash = hash(storage.prefix().as_bytes());
|
||||
let entries_hash = storage.entries().fold([0u8; HASH_LEN], |bytes, entry| {
|
||||
// We don't care what order the storage entries occur in, so XOR them together
|
||||
// to make the order irrelevant.
|
||||
xor(
|
||||
bytes,
|
||||
get_storage_entry_hash(registry, entry, &mut visited_ids),
|
||||
)
|
||||
});
|
||||
let entries_hash = storage
|
||||
.entries()
|
||||
.iter()
|
||||
.fold([0u8; HASH_LEN], |bytes, entry| {
|
||||
// We don't care what order the storage entries occur in, so XOR them together
|
||||
// to make the order irrelevant.
|
||||
xor(
|
||||
bytes,
|
||||
get_storage_entry_hash(registry, entry, &mut visited_ids),
|
||||
)
|
||||
});
|
||||
concat_and_hash2(&prefix_hash, &entries_hash)
|
||||
}
|
||||
None => [0u8; HASH_LEN],
|
||||
@@ -496,6 +499,7 @@ mod tests {
|
||||
struct A {
|
||||
pub b: Box<B>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(scale_info::TypeInfo)]
|
||||
struct B {
|
||||
@@ -507,6 +511,7 @@ mod tests {
|
||||
#[derive(scale_info::TypeInfo)]
|
||||
// TypeDef::Composite with TypeDef::Array with Typedef::Primitive.
|
||||
struct AccountId32([u8; HASH_LEN]);
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(scale_info::TypeInfo)]
|
||||
// TypeDef::Variant.
|
||||
@@ -525,6 +530,7 @@ mod tests {
|
||||
// TypeDef::BitSequence.
|
||||
BitSeq(BitVec<u8, Lsb0>),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(scale_info::TypeInfo)]
|
||||
// Ensure recursive types and TypeDef variants are captured.
|
||||
@@ -533,6 +539,7 @@ mod tests {
|
||||
composite: AccountId32,
|
||||
type_def: DigestItem,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(scale_info::TypeInfo)]
|
||||
// Simulate a PalletCallMetadata.
|
||||
|
||||
Reference in New Issue
Block a user