From ae0fce8dff839e8a21348059c01e9e80a40d5e37 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko <45178695+pkhry@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:41:14 +0200 Subject: [PATCH] Strip metadata fix (#1774) * Fix metadata stripping being too eager closes #1659 --------- Co-authored-by: James Wilson Co-authored-by: Niklas Adolfsson --- Cargo.lock | 1 - artifacts/regressions/1659.scale | Bin 0 -> 60428 bytes metadata/Cargo.toml | 1 - metadata/src/lib.rs | 5 +- metadata/src/utils/retain.rs | 521 ++++++++++-------- metadata/src/utils/validation.rs | 6 +- .../src/utils/validation/outer_enum_hashes.rs | 37 +- 7 files changed, 344 insertions(+), 227 deletions(-) create mode 100644 artifacts/regressions/1659.scale diff --git a/Cargo.lock b/Cargo.lock index 3b6987d36c..a7cf7827bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10712,7 +10712,6 @@ dependencies = [ name = "subxt-metadata" version = "0.37.0" dependencies = [ - "assert_matches", "bitvec", "criterion", "frame-decode", diff --git a/artifacts/regressions/1659.scale b/artifacts/regressions/1659.scale new file mode 100644 index 0000000000000000000000000000000000000000..7f1975306496e2392ef0c5730fa3fb3c46fdacbd GIT binary patch literal 60428 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 literal 0 HcmV?d00001 diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 92bff27b5b..fb34cfa2fd 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -29,7 +29,6 @@ hashbrown = { workspace = true } bitvec = { workspace = true, features = ["alloc"] } criterion = { workspace = true } scale-info = { workspace = true, features = ["bit-vec"] } -assert_matches = { workspace = true } [lib] # Without this, libtest cli opts interfere with criteron benches: diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 8e0900ea7d..1d81efe200 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -214,7 +214,10 @@ impl Metadata { MetadataHasher::new(self) } - /// Filter out any pallets that we don't want to keep, retaining only those that we do. + /// Filter out any pallets and/or runtime_apis that we don't want to keep, retaining only those that we do. + /// Note: + /// only filter by `pallet`s will not lead to significant metadata size reduction because the return types are kept to ensure that those can be decoded. + /// pub fn retain(&mut self, pallet_filter: F, api_filter: G) where F: FnMut(&str) -> bool, diff --git a/metadata/src/utils/retain.rs b/metadata/src/utils/retain.rs index a160609597..4e13982a69 100644 --- a/metadata/src/utils/retain.rs +++ b/metadata/src/utils/retain.rs @@ -5,187 +5,139 @@ //! Utility functions to generate a subset of the metadata. use crate::{ - ExtrinsicMetadata, Metadata, OuterEnumsMetadata, PalletMetadataInner, RuntimeApiMetadataInner, - StorageEntryType, + ExtrinsicMetadata, Metadata, PalletMetadataInner, RuntimeApiMetadataInner, StorageEntryType, }; -use alloc::collections::BTreeMap; -use hashbrown::HashSet; -use scale_info::TypeDef; - -/// Collect all type IDs needed to represent the provided pallet. -fn collect_pallet_types(pallet: &PalletMetadataInner, type_ids: &mut HashSet) { - if let Some(storage) = &pallet.storage { - for entry in storage.entries() { - match entry.entry_type { - StorageEntryType::Plain(ty) => { - type_ids.insert(ty); - } - StorageEntryType::Map { - key_ty, value_ty, .. - } => { - type_ids.insert(key_ty); - type_ids.insert(value_ty); - } - } - } - } +use alloc::collections::BTreeSet; +use alloc::vec::Vec; +use scale_info::{ + PortableType, TypeDef, TypeDefArray, TypeDefBitSequence, TypeDefCompact, TypeDefComposite, + TypeDefSequence, TypeDefTuple, TypeDefVariant, +}; + +#[derive(Clone)] +struct TypeSet { + seen_ids: BTreeSet, + pub work_set: Vec, +} - if let Some(ty) = pallet.call_ty { - type_ids.insert(ty); +impl TypeSet { + fn new() -> Self { + Self { + seen_ids: BTreeSet::new(), + // Average work set size is around 30-50 elements, depending on the metadata size + work_set: Vec::with_capacity(32), + } } - if let Some(ty) = pallet.event_ty { - type_ids.insert(ty); + fn insert(&mut self, id: u32) -> bool { + self.seen_ids.insert(id) } - for constant in pallet.constants.values() { - type_ids.insert(constant.ty); + fn contains(&mut self, id: u32) -> bool { + self.seen_ids.contains(&id) } - if let Some(ty) = pallet.error_ty { - type_ids.insert(ty); + fn push_to_workset(&mut self, id: u32) { + // Check if wee hit a type we've already inserted; avoid infinite loops and stop. + if self.insert(id) { + self.work_set.push(id); + } } -} -/// Update all type IDs of the provided pallet using the new type IDs from the portable registry. -fn update_pallet_types(pallet: &mut PalletMetadataInner, map_ids: &BTreeMap) { - if let Some(storage) = &mut pallet.storage { - for entry in storage.entries.values_mut() { - match &mut entry.entry_type { - StorageEntryType::Plain(ty) => { - update_type(ty, map_ids); + /// This function will deeply traverse the inital type and it's dependencies to collect the relevant type_ids + fn collect_types(&mut self, metadata: &Metadata, id: u32) { + self.push_to_workset(id); + while let Some(typ) = self.work_set.pop() { + let typ = resolve_typ(metadata, typ); + match &typ.ty.type_def { + TypeDef::Composite(TypeDefComposite { fields }) => { + for field in fields { + self.push_to_workset(field.ty.id); + } + } + TypeDef::Variant(TypeDefVariant { variants }) => { + for variant in variants { + for field in &variant.fields { + self.push_to_workset(field.ty.id); + } + } } - StorageEntryType::Map { - key_ty, value_ty, .. - } => { - update_type(key_ty, map_ids); - update_type(value_ty, map_ids); + TypeDef::Array(TypeDefArray { len: _, type_param }) + | TypeDef::Sequence(TypeDefSequence { type_param }) + | TypeDef::Compact(TypeDefCompact { type_param }) => { + self.push_to_workset(type_param.id); + } + TypeDef::Tuple(TypeDefTuple { fields }) => { + for field in fields { + self.push_to_workset(field.id); + } + } + TypeDef::Primitive(_) => (), + TypeDef::BitSequence(TypeDefBitSequence { + bit_store_type, + bit_order_type, + }) => { + for typ in [bit_order_type, bit_store_type] { + self.push_to_workset(typ.id); + } } } } } - if let Some(ty) = &mut pallet.call_ty { - update_type(ty, map_ids); - } - - if let Some(ty) = &mut pallet.event_ty { - update_type(ty, map_ids); - } - - if let Some(ty) = &mut pallet.error_ty { - update_type(ty, map_ids); - } - - for constant in pallet.constants.values_mut() { - update_type(&mut constant.ty, map_ids); - } -} - -/// Collect all type IDs needed to represent the extrinsic metadata. -fn collect_extrinsic_types(extrinsic: &ExtrinsicMetadata, type_ids: &mut HashSet) { - type_ids.insert(extrinsic.address_ty); - type_ids.insert(extrinsic.call_ty); - type_ids.insert(extrinsic.signature_ty); - type_ids.insert(extrinsic.extra_ty); - - for signed in &extrinsic.signed_extensions { - type_ids.insert(signed.extra_ty); - type_ids.insert(signed.additional_ty); - } -} - -/// Update all type IDs of the provided extrinsic metadata using the new type IDs from the portable registry. -fn update_extrinsic_types(extrinsic: &mut ExtrinsicMetadata, map_ids: &BTreeMap) { - update_type(&mut extrinsic.address_ty, map_ids); - update_type(&mut extrinsic.call_ty, map_ids); - update_type(&mut extrinsic.signature_ty, map_ids); - update_type(&mut extrinsic.extra_ty, map_ids); + fn collect_extrinsic_types(&mut self, extrinsic: &ExtrinsicMetadata) { + for ty in [ + extrinsic.address_ty, + extrinsic.call_ty, + extrinsic.signature_ty, + extrinsic.extra_ty, + ] { + self.insert(ty); + } - for signed in &mut extrinsic.signed_extensions { - update_type(&mut signed.extra_ty, map_ids); - update_type(&mut signed.additional_ty, map_ids); + for signed in &extrinsic.signed_extensions { + self.insert(signed.extra_ty); + self.insert(signed.additional_ty); + } } -} -/// Collect all type IDs needed to represent the runtime APIs. -fn collect_runtime_api_types(api: &RuntimeApiMetadataInner, type_ids: &mut HashSet) { - for method in api.methods.values() { - for input in &method.inputs { - type_ids.insert(input.ty); + /// Collect all type IDs needed to represent the runtime APIs. + fn collect_runtime_api_types(&mut self, metadata: &Metadata, api: &RuntimeApiMetadataInner) { + for method in api.methods.values() { + self.collect_types(metadata, method.output_ty); } - type_ids.insert(method.output_ty); } -} -/// Update all type IDs of the provided runtime APIs metadata using the new type IDs from the portable registry. -fn update_runtime_api_types(apis: &mut [RuntimeApiMetadataInner], map_ids: &BTreeMap) { - for api in apis { - for method in api.methods.values_mut() { - for input in &mut method.inputs { - update_type(&mut input.ty, map_ids); + /// Collect all type IDs needed to represent the provided pallet. + fn collect_pallet_types(&mut self, pallet: &PalletMetadataInner, metadata: &Metadata) { + if let Some(storage) = &pallet.storage { + for entry in storage.entries() { + match entry.entry_type { + StorageEntryType::Plain(ty) => { + self.collect_types(metadata, ty); + } + StorageEntryType::Map { + key_ty, value_ty, .. + } => { + self.collect_types(metadata, key_ty); + self.collect_types(metadata, value_ty); + } + } } - update_type(&mut method.output_ty, map_ids); } - } -} - -/// Collect the outer enums type IDs. -fn collect_outer_enums(enums: &OuterEnumsMetadata, type_ids: &mut HashSet) { - type_ids.insert(enums.call_enum_ty); - type_ids.insert(enums.event_enum_ty); - type_ids.insert(enums.error_enum_ty); -} -/// Update all the type IDs for outer enums. -fn update_outer_enums(enums: &mut OuterEnumsMetadata, map_ids: &BTreeMap) { - update_type(&mut enums.call_enum_ty, map_ids); - update_type(&mut enums.event_enum_ty, map_ids); - update_type(&mut enums.error_enum_ty, map_ids); -} - -/// Update the given type using the new type ID from the portable registry. -/// -/// # Panics -/// -/// Panics if the [`scale_info::PortableRegistry`] did not retain all needed types. -fn update_type(ty: &mut u32, map_ids: &BTreeMap) { - let old_id = *ty; - let new_id = map_ids - .get(&old_id) - .copied() - .unwrap_or_else(|| panic!("PortableRegistry did not retain type id {old_id}. This is a bug. Please open an issue.")); - *ty = new_id; + for constant in pallet.constants.values() { + self.collect_types(metadata, constant.ty); + } + } } -/// Retain the enum type identified by ID and keep only the variants that -/// match the provided filter. -fn retain_variants_in_enum_type(metadata: &mut Metadata, id: u32, mut filter: F) -where - F: FnMut(&str) -> bool, -{ - let ty = metadata +fn resolve_typ(metadata: &Metadata, typ: u32) -> &PortableType { + metadata .types .types - .get_mut(id as usize) - .expect("Metadata should contain enum type in registry"); - - let TypeDef::Variant(variant) = &mut ty.ty.type_def else { - panic!("Metadata type is expected to be a variant type"); - }; - - // Remove all variants from the type that aren't the pallet(s) we want to keep. - variant.variants.retain(|v| filter(&v.name)); -} - -/// Strip any pallets out of the outer enum types that aren't the ones we want to keep. -fn retain_pallets_in_runtime_outer_types(metadata: &mut Metadata, mut filter: F) -where - F: FnMut(&str) -> bool, -{ - retain_variants_in_enum_type(metadata, metadata.outer_enums.call_enum_ty, &mut filter); - retain_variants_in_enum_type(metadata, metadata.outer_enums.event_enum_ty, &mut filter); - retain_variants_in_enum_type(metadata, metadata.outer_enums.error_enum_ty, &mut filter); + .get(typ as usize) + .expect("Metadata should contain enum type in registry") } /// Generate a subset of the metadata that contains only the @@ -208,27 +160,10 @@ pub fn retain_metadata( F: FnMut(&str) -> bool, G: FnMut(&str) -> bool, { - let mut type_ids = HashSet::new(); - - // There are special outer enum types that point to all pallets types (call, error, event) by default. - // This brings in a significant chunk of types. We trim this down to only include variants - // for the pallets we're retaining, to avoid this. - retain_pallets_in_runtime_outer_types(metadata, &mut pallets_filter); - - // Collect the stripped outer enums. - collect_outer_enums(&metadata.outer_enums, &mut type_ids); - - // Filter our pallet list to only those pallets we want to keep. Keep hold of all - // type IDs in the pallets we're keeping. Retain all, if no filter specified. - metadata.pallets.retain(|pallet| { - let should_retain = pallets_filter(&pallet.name); - if should_retain { - collect_pallet_types(pallet, &mut type_ids); - } - should_retain - }); - - // We index pallets by their u8 index for easy access. Rebuild this index. + // 1. Delete pallets we don't want to keep. + metadata + .pallets + .retain(|pallet| pallets_filter(&pallet.name)); metadata.pallets_by_index = metadata .pallets .values() @@ -237,58 +172,188 @@ pub fn retain_metadata( .map(|(pos, p)| (p.index, pos)) .collect(); - // Keep the extrinsic stuff referenced in our metadata. - collect_extrinsic_types(&metadata.extrinsic, &mut type_ids); - - // Keep the "runtime" type ID, since it's referenced in our metadata. - type_ids.insert(metadata.runtime_ty); - - // Keep only the runtime API types that the filter allows for. Keep hold of all - // type IDs in the runtime apis we're keeping. Retain all, if no filter specified. - metadata.apis.retain(|api| { - let should_retain = runtime_apis_filter(&api.name); - if should_retain { - collect_runtime_api_types(api, &mut type_ids); + // 2. Delete runtime APIs we don't want to keep. + metadata.apis.retain(|api| runtime_apis_filter(&api.name)); + + // 3. For each outer enum type, strip it if possible, ie if it is not returned by any + // of the things we're keeping (because if it is, we need to keep all of it so that we + // can still decode values into it). + let outer_enums = metadata.outer_enums(); + let mut find_type_id = keep_outer_enum(metadata, &mut pallets_filter, &mut runtime_apis_filter); + for outer_enum_ty_id in [ + outer_enums.call_enum_ty(), + outer_enums.error_enum_ty(), + outer_enums.event_enum_ty(), + ] { + if !find_type_id(outer_enum_ty_id) { + strip_variants_in_enum_type(metadata, &mut pallets_filter, outer_enum_ty_id); } - should_retain - }); + } + + // 4. Collect all of the type IDs we still want to keep after deleting. + let mut keep_these_type_ids: BTreeSet = + iterate_metadata_types(metadata).map(|x| *x).collect(); - // Additionally, subxt depends on the `DispatchError` type existing; we use the same - // logic here that is used when building our `Metadata`. + // 5. Additionally, subxt depends on the `DispatchError` type existing; we use the same + // logic here that is used when building our `Metadata` to ensure we keep it too. let dispatch_error_ty = metadata .types .types .iter() .find(|ty| ty.ty.path.segments == ["sp_runtime", "DispatchError"]) .expect("Metadata must contain sp_runtime::DispatchError"); - type_ids.insert(dispatch_error_ty.id); - // Now, keep the type IDs we've asked for. This recursively keeps any types referenced from these. - // This will return a map from old to new type ID, because IDs may change. - let map_ids = metadata.types.retain(|id| type_ids.contains(&id)); + keep_these_type_ids.insert(dispatch_error_ty.id); - // And finally, we can go and update all of our type IDs in the metadata as a result of this: - update_outer_enums(&mut metadata.outer_enums, &map_ids); - for pallets in metadata.pallets.values_mut() { - update_pallet_types(pallets, &map_ids); + // 5. Strip all of the type IDs we no longer need, based on the above set. + let map_ids = metadata + .types + .retain(|id| keep_these_type_ids.contains(&id)); + + // 6. Now, update the type IDs referenced in our metadata to reflect this. + for id in iterate_metadata_types(metadata) { + if let Some(new_id) = map_ids.get(id) { + *id = *new_id; + } else { + panic!("Type id {id} was not retained. This is a bug"); + } } - update_extrinsic_types(&mut metadata.extrinsic, &map_ids); - update_type(&mut metadata.runtime_ty, &map_ids); - update_runtime_api_types(metadata.apis.values_mut(), &map_ids); +} + +fn strip_variants_in_enum_type(metadata: &mut Metadata, mut pallets_filter: F, id: u32) +where + F: FnMut(&str) -> bool, +{ + let ty = { + metadata + .types + .types + .get_mut(id as usize) + .expect("Metadata should contain enum type in registry") + }; + + let TypeDef::Variant(variant) = &mut ty.ty.type_def else { + panic!("Metadata type is expected to be a variant type"); + }; + + variant.variants.retain(|v| pallets_filter(&v.name)); +} + +/// Returns an iterator that allows modifying each type ID seen in the metadata (not recursively). +/// This will iterate over every type referenced in the metadata outside of `metadata.types`. +fn iterate_metadata_types(metadata: &mut Metadata) -> impl Iterator { + let mut types = alloc::vec::Vec::new(); + + // collect outer_enum top-level types + let outer_enum = &mut metadata.outer_enums; + types.push(&mut outer_enum.call_enum_ty); + types.push(&mut outer_enum.event_enum_ty); + types.push(&mut outer_enum.error_enum_ty); + + // collect pallet top-level type ids + for pallet in metadata.pallets.values_mut() { + if let Some(storage) = &mut pallet.storage { + for entry in storage.entries.values_mut() { + match &mut entry.entry_type { + StorageEntryType::Plain(ty) => { + types.push(ty); + } + StorageEntryType::Map { + key_ty, value_ty, .. + } => { + types.push(key_ty); + types.push(value_ty); + } + } + } + }; + if let Some(ty) = &mut pallet.call_ty { + types.push(ty); + } + + if let Some(ty) = &mut pallet.event_ty { + types.push(ty); + } + + if let Some(ty) = &mut pallet.error_ty { + types.push(ty); + } + + for constant in pallet.constants.values_mut() { + types.push(&mut constant.ty); + } + } + + // collect extrinsic type_ids + for ty in [ + &mut metadata.extrinsic.extra_ty, + &mut metadata.extrinsic.address_ty, + &mut metadata.extrinsic.signature_ty, + &mut metadata.extrinsic.call_ty, + ] { + types.push(ty); + } + + for signed in &mut metadata.extrinsic.signed_extensions { + types.push(&mut signed.extra_ty); + types.push(&mut signed.additional_ty); + } + + types.push(&mut metadata.runtime_ty); + + // collect runtime_api_types + for api in metadata.apis.values_mut() { + for method in api.methods.values_mut() { + for input in &mut method.inputs.iter_mut() { + types.push(&mut input.ty); + } + types.push(&mut method.output_ty); + } + } + + types.into_iter() +} + +/// Look for a type ID anywhere that we can be given back, ie in constants, storage, extrinsics or runtime API return types. +/// This will recurse deeply into those type IDs to find them. +pub fn keep_outer_enum( + metadata: &Metadata, + pallets_filter: &mut F, + runtime_apis_filter: &mut G, +) -> impl FnMut(u32) -> bool +where + F: FnMut(&str) -> bool, + G: FnMut(&str) -> bool, +{ + let mut type_set = TypeSet::new(); + for pallet in metadata.pallets.values() { + if pallets_filter(&pallet.name) { + type_set.collect_pallet_types(pallet, metadata); + } + } + for api in metadata.apis.values() { + if runtime_apis_filter(&api.name) { + type_set.collect_runtime_api_types(metadata, api); + } + } + type_set.collect_extrinsic_types(&metadata.extrinsic); + move |type_id| type_set.contains(type_id) } #[cfg(test)] mod tests { use super::*; use crate::Metadata; - use assert_matches::assert_matches; use codec::Decode; use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed}; use std::{fs, path::Path}; fn load_metadata() -> Metadata { - let bytes = fs::read(Path::new("../artifacts/polkadot_metadata_full.scale")) - .expect("Cannot read metadata blob"); + load_metadata_custom("../artifacts/polkadot_metadata_full.scale") + } + + fn load_metadata_custom(path: impl AsRef) -> Metadata { + let bytes = fs::read(path).expect("Cannot read metadata blob"); let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &*bytes).expect("Cannot decode scale metadata"); @@ -305,8 +370,8 @@ mod tests { // Retain one pallet at a time ensuring the test does not panic. for pallet in metadata_cache.pallets() { + let original_meta = metadata_cache.clone(); let mut metadata = metadata_cache.clone(); - retain_metadata( &mut metadata, |pallet_name| pallet_name == pallet.name(), @@ -319,20 +384,11 @@ mod tests { pallet.name() ); - let id = metadata.outer_enums().call_enum_ty; - let ty = metadata.types.resolve(id).unwrap(); - let num_variants = if pallet.call_ty_id().is_some() { 1 } else { 0 }; - assert_matches!(&ty.type_def, TypeDef::Variant(variant) if variant.variants.len() == num_variants); - - let id = metadata.outer_enums().error_enum_ty; - let ty = metadata.types.resolve(id).unwrap(); - let num_variants = if pallet.error_ty_id().is_some() { 1 } else { 0 }; - assert_matches!(&ty.type_def, TypeDef::Variant(variant) if variant.variants.len() == num_variants); - - let id = metadata.outer_enums().event_enum_ty; - let ty = metadata.types.resolve(id).unwrap(); - let num_variants = if pallet.event_ty_id().is_some() { 1 } else { 0 }; - assert_matches!(&ty.type_def, TypeDef::Variant(variant) if variant.variants.len() == num_variants); + assert!( + metadata.types.types.len() < original_meta.types.types.len(), + "Stripped metadata must have less retained types than the non-stripped one: stripped amount {}, original amount {}", + metadata.types.types.len(), original_meta.types.types.len() + ); } } @@ -356,4 +412,33 @@ mod tests { ); } } + + #[test] + fn issue_1659() { + let full_metadata = load_metadata_custom("../artifacts/regressions/1659.scale"); + // Strip metadata to the pallets as described in the issue. + let mut stripped_metadata = full_metadata.clone(); + retain_metadata( + &mut stripped_metadata, + { + let set = "Balances,Timestamp,Contracts,ContractsEvm,System" + .split(",") + .collect::>(); + move |s| set.contains(&s) + }, + |_| true, + ); + + // check that call_enum did not change as it is referenced inside runtime_api + assert_eq!( + stripped_metadata.type_hash(stripped_metadata.outer_enums.call_enum_ty), + full_metadata.type_hash(full_metadata.outer_enums.call_enum_ty) + ); + + // check that event_num did not change as it is referenced inside runtime_api + assert_eq!( + stripped_metadata.type_hash(stripped_metadata.outer_enums.event_enum_ty), + full_metadata.type_hash(full_metadata.outer_enums.event_enum_ty) + ); + } } diff --git a/metadata/src/utils/validation.rs b/metadata/src/utils/validation.rs index dd76a359ea..11c51ad4d2 100644 --- a/metadata/src/utils/validation.rs +++ b/metadata/src/utils/validation.rs @@ -589,7 +589,11 @@ impl<'a> MetadataHasher<'a> { // Get the hashes of outer enums, considering only `specific_pallets` (if any are set). // If any of the typed that represent outer enums are encountered later, hashes from `top_level_enum_hashes` can be substituted. - let outer_enum_hashes = OuterEnumHashes::new(metadata, self.specific_pallets.as_deref()); + let outer_enum_hashes = OuterEnumHashes::new( + metadata, + self.specific_pallets.as_deref(), + self.specific_runtime_apis.as_deref(), + ); let pallet_hash = metadata.pallets().fold([0u8; HASH_LEN], |bytes, pallet| { // If specific pallets are given, only include this pallet if it is in the specific pallets. diff --git a/metadata/src/utils/validation/outer_enum_hashes.rs b/metadata/src/utils/validation/outer_enum_hashes.rs index 5e50fcb40e..9144c6b6a6 100644 --- a/metadata/src/utils/validation/outer_enum_hashes.rs +++ b/metadata/src/utils/validation/outer_enum_hashes.rs @@ -5,7 +5,10 @@ use hashbrown::HashMap; use scale_info::{PortableRegistry, TypeDef}; use crate::{ - utils::validation::{get_type_def_variant_hash, get_type_hash}, + utils::{ + retain, + validation::{get_type_def_variant_hash, get_type_hash}, + }, Metadata, }; @@ -20,7 +23,28 @@ pub struct OuterEnumHashes { impl OuterEnumHashes { /// Constructs new `OuterEnumHashes` from metadata. If `only_these_variants` is set, the enums are stripped down to only these variants, before their hashes are calculated. - pub fn new(metadata: &Metadata, only_these_variants: Option<&[&str]>) -> Self { + pub fn new( + metadata: &Metadata, + specific_pallets: Option<&[&str]>, + specific_runtimes: Option<&[&str]>, + ) -> Self { + let filter = |names: Option<&[&str]>, name: &str| match names { + Some(names) => names.contains(&name), + None => true, + }; + let mut check_enum_type_id = retain::keep_outer_enum( + metadata, + &mut |name| filter(specific_pallets, name), + &mut |name| filter(specific_runtimes, name), + ); + + let variants = |filter: bool| { + if !filter { + specific_pallets + } else { + None + } + }; fn get_enum_hash( registry: &PortableRegistry, id: u32, @@ -46,9 +70,12 @@ impl OuterEnumHashes { } let enums = &metadata.outer_enums; - let call_hash = get_enum_hash(metadata.types(), enums.call_enum_ty, only_these_variants); - let event_hash = get_enum_hash(metadata.types(), enums.event_enum_ty, only_these_variants); - let error_hash = get_enum_hash(metadata.types(), enums.error_enum_ty, only_these_variants); + let call_variants = variants(check_enum_type_id(enums.call_enum_ty)); + let call_hash = get_enum_hash(metadata.types(), enums.call_enum_ty, call_variants); + let event_variants = variants(check_enum_type_id(enums.event_enum_ty)); + let event_hash = get_enum_hash(metadata.types(), enums.event_enum_ty, event_variants); + let error_variants = variants(check_enum_type_id(enums.error_enum_ty)); + let error_hash = get_enum_hash(metadata.types(), enums.error_enum_ty, error_variants); Self { call_hash: (enums.call_enum_ty, call_hash),