diff --git a/metadata/src/utils/validation.rs b/metadata/src/utils/validation.rs index 0f5d9f7666..93dd612ff0 100644 --- a/metadata/src/utils/validation.rs +++ b/metadata/src/utils/validation.rs @@ -268,7 +268,6 @@ fn get_extrinsic_hash( &get_type_hash(registry, signed_extension.additional_ty, &mut cache), ) } - bytes } @@ -522,7 +521,10 @@ pub fn get_pallet_hash( let registry = pallet.types; let call_bytes = match pallet.call_ty_id() { - Some(calls) => get_type_hash(registry, calls, &mut cache), + Some(calls) => { + get_type_hash(registry, calls, &mut cache) + + }, None => [0u8; HASH_LEN], }; let event_bytes = match pallet.event_ty_id() { @@ -666,7 +668,6 @@ impl<'a> MetadataHasher<'a> { .include_custom_values .then(|| get_custom_metadata_hash(&metadata.custom(), Some(&mut cache))) .unwrap_or_default(); - concat_and_hash6( &pallet_hash, &apis_hash, @@ -682,7 +683,10 @@ impl<'a> MetadataHasher<'a> { mod tests { use super::*; use bitvec::{order::Lsb0, vec::BitVec}; - use frame_metadata::v15; + use frame_metadata::v15::{ + self, PalletEventMetadata, PalletStorageMetadata, StorageEntryMetadata, + StorageEntryModifier, + }; use scale_info::{meta_type, Registry}; // Define recursive types. @@ -1136,4 +1140,141 @@ mod tests { to_hash(meta_type::()) ); } + + fn metadata_with_pallet_events() -> Metadata { + #[allow(dead_code)] + #[derive(scale_info::TypeInfo)] + struct FirstEvent { + s: String, + } + + #[allow(dead_code)] + #[derive(scale_info::TypeInfo)] + struct SecondEvent { + n: u8, + } + + #[allow(dead_code)] + #[derive(scale_info::TypeInfo)] + enum Events { + First(FirstEvent), + Second(SecondEvent), + } + + #[allow(dead_code)] + #[derive(scale_info::TypeInfo)] + enum Errors { + First(DispatchError), + Second(DispatchError), + } + + #[allow(dead_code)] + #[derive(scale_info::TypeInfo)] + enum Calls { + First(u8), + Second(u8), + } + + #[allow(dead_code)] + enum DispatchError { + A, + B, + C, + } + + impl scale_info::TypeInfo for DispatchError { + type Identity = DispatchError; + + fn type_info() -> scale_info::Type { + scale_info::Type { + path: scale_info::Path { + segments: vec!["sp_runtime", "DispatchError"], + }, + type_params: vec![], + type_def: TypeDef::Variant(TypeDefVariant { variants: vec![] }), + docs: vec![], + } + } + } + + let pallets = vec![ + v15::PalletMetadata { + name: "First", + index: 0, + calls: Some(v15::PalletCallMetadata { + ty: meta_type::(), + }), + storage: Some(PalletStorageMetadata { + prefix: "___", + entries: vec![StorageEntryMetadata { + name: "Hello", + modifier: StorageEntryModifier::Optional, + // Note: This is the important part here: + // The Events type will be trimmed down and this trimming needs to be reflected + // when the hash of this storage item is computed. + ty: frame_metadata::v14::StorageEntryType::Plain(meta_type::>()), + default: vec![], + docs: vec![], + }], + }), + event: Some(PalletEventMetadata { + ty: meta_type::(), + }), + constants: vec![], + error: None, + docs: vec![], + }, + v15::PalletMetadata { + name: "Second", + index: 1, + calls: Some(v15::PalletCallMetadata { + ty: meta_type::(), + }), + storage: None, + event: Some(PalletEventMetadata { + ty: meta_type::(), + }), + constants: vec![], + error: None, + docs: vec![], + }, + ]; + + v15::RuntimeMetadataV15::new( + pallets, + build_default_extrinsic(), + meta_type::<()>(), + vec![], + v15::OuterEnums { + call_enum_ty: meta_type::(), + event_enum_ty: meta_type::(), + error_enum_ty: meta_type::(), + }, + v15::CustomMetadata { + map: Default::default(), + }, + ) + .try_into() + .expect("can build valid metadata") + } + + #[test] + fn hash_comparison_trimmed_metadata() { + // trim the metadata: + let metadata = metadata_with_pallet_events(); + let trimmed_metadata = { + let mut m = metadata.clone(); + m.retain(|e| e == "First", |_| true); + m + }; + + // test that the hashes are the same: + let hash = MetadataHasher::new(&metadata) + .only_these_pallets(&["First"]) + .hash(); + let hash_trimmed = MetadataHasher::new(&trimmed_metadata) + .hash(); + + assert_eq!(hash, hash_trimmed); + } }