-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Metadata difference command #1015
Conversation
cli/src/commands/diff.rs
Outdated
node1: String, | ||
node2: String, | ||
#[clap(long, short)] | ||
version: Option<MetadataVersion>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get why version
is a CLI parameter, how would one insert --version
here and why?
Better to read that from the metadata itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version is which version of metadata is being requested when a url is given (eg are we downloading V14 metadatas or unstable-v15 metadatas or "whatever is latest stable"; something like that)
cli/src/commands/diff.rs
Outdated
#[clap(long, short)] | ||
version: Option<MetadataVersion>, | ||
#[clap(long, short)] | ||
pallet: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't used AFAIU, what's intention behind it? Just compare a single pallet in the metadata?
If we want this, it would be better with Vec to compare a one or more pallets
doesn't subwasm already have something like this? |
Yes, subwasm has something similar but it compares Both are useful but if you are already a user of subxt the |
Some small feedback bits re the output:
Otherwise, the output looks fantastic and I love the use of colours :) |
cli/src/commands/diff.rs
Outdated
let mut calls: CallsHashmap = HashMap::new(); | ||
if let Some(call_variants) = pallet_metadata_1.call_variants() { | ||
for call_variant in call_variants { | ||
let (e1, _) = calls.entry(&call_variant.name).or_default(); | ||
*e1 = Some(call_variant); | ||
} | ||
} | ||
if let Some(call_variants) = pallet_metadata_2.call_variants() { | ||
for call_variant in call_variants { | ||
let (e1, e2) = calls.entry(&call_variant.name).or_default(); | ||
// skip all entries with the same hash: | ||
if let Some(e1_inner) = e1 { | ||
let e1_hash = pallet_metadata_1 | ||
.call_hash(&e1_inner.name) | ||
.expect("call should be present"); | ||
let e2_hash = pallet_metadata_2 | ||
.call_hash(&call_variant.name) | ||
.expect("call should be present"); | ||
if e1_hash == e2_hash { | ||
calls.remove(call_variant.name.as_str()); | ||
continue; | ||
} | ||
} | ||
*e2 = Some(call_variant); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general pattern of "give me a list of the differences between two things" feels like something that could be abstracted here since it's repeated several times; the only logic that changes each time is "how do I turn a thing into something comparable".
I'd propose it'd be a fun challenge to have a go at doing this abstracting; I could imagine ultimately ending with a signature something like this:
fn diff<T, C: PartialEq>(
items_a: impl IntoIterator<Item = T>,
comparable_a: impl Fn(&T) -> C
items_b: impl IntoIterator<Item = T>,
comparable_b: impl Fn(&T) -> C
) -> Vec<Diff<T>>
Doing this might also negate the need for a slightly arbitrary TryFrom<(a,b)>
type thing from tuples to Diff, since it would all be done in this one place, and would make it easier to check the diffing logic is all good in one place rather than several :)
metadata/src/lib.rs
Outdated
@@ -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 entire pallet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Return a hash for the entire pallet. | |
/// Return a hash for the entire runtime API trait. |
The comment on 519 is also wrong, whoops! It should be "Return a hash for the method, or None if it was not found"
cli/src/commands/diff.rs
Outdated
entry1: FileOrUrl, | ||
entry2: FileOrUrl, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a slightly more descriptive name for these like metadata_or_url1
and metadata_or_url2
would make the output a little clearer.
I wonder whether adding comments above these would lead to nicer help being shown in the output too :)
Looks great; just a few suggestions :) |
@jsdw I think maybe you understood it wrong. It shows things with a
indicating that some pallets are removed going from |
Oh interesting; hopefully I just got it wrong then, lemme check! I compared kuama to polkadot iirc and it seemed as if it was the otherway round but I'll try again to confirm :) Edit: yup my mistake; I played around some more and must have just confused myself! |
@@ -303,8 +313,8 @@ impl StorageMetadata { | |||
} | |||
|
|||
/// An iterator over the storage entries. | |||
pub fn entries(&self) -> impl ExactSizeIterator<Item = &StorageEntryMetadata> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really a big deal, but I was wodnering whether there was a reason for this change?
IIRC the reason I tended to iterate over other metadata structs exposed here rather than give back slices was just to give a little more wiggle room in case we wanted to change the internals a bit in the future. There are a couple of other places in this API that return the ExactSizeIterator even though they could return slices too for this reason :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it because I needed to do an unwrap_or_default()
and I could not get a default impl ExactSizeIterator
working properly that is the exact same type as the self.entries.values().iter()
.
Hmm, do you have an idea how I could solve this?
pallet_metadata_1
.storage()
.map(|s| s.entries())
.unwrap_or_default()
cli/src/commands/diff.rs
Outdated
Removed(T), | ||
} | ||
|
||
fn diff<T, C: PartialEq, I: Hash + PartialEq + Eq>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Much prefer this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and with this logic now separated, you could also have a quick unit test or two that diffing things using this function works as expected :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a unit test. This also made me realize that the output order was random because of the random nature of hash maps. So I added alphabetical ordering as well.
Awesome stuff; good job @tadeohepperle! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lovely PR! Amazing job here 🙏
Explore the differences between two nodes
Example
Example output (colored in cli):