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:
Tadeo Hepperle
2023-06-21 14:33:21 +02:00
committed by GitHub
parent b4eb406ee5
commit 2a990edaca
9 changed files with 541 additions and 23 deletions
+20 -5
View File
@@ -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)]
+17 -10
View File
@@ -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.