Files
pezkuwi-subxt/utils/strip-metadata/src/lib.rs
T
James Wilson b13b8ec8d0 [subxt-historic]: extract call and event types from metadata at a block (#2095)
* Inject call and event types from metadata too at some block in subxt-historic

* bump subxt-historic to 0.0.4

* Fix unrelated doc things to try and fix this job

* Other Rust 1.90 fixes

* 'Fix' Test

* Try fixing clippy WASM job

* Try again to get clippy wasm working

* trybuild fix

* trybuild fix take 2
2025-09-25 13:37:09 +01:00

949 lines
33 KiB
Rust

// Copyright 2019-2025 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! This utility crate provides a [`StripMetadata`] trait which exposes a [`StripMetadata::strip_metadata`] method
//! able to remove pallets and runtime APIs from the metadata in question.
use either::Either;
use frame_metadata::{v14, v15, v16};
use scale_info::PortableRegistry;
use std::collections::BTreeSet;
/// This trait is implemented for metadata versions to enable us to strip pallets and runtime APIs from them.
///
/// To implement the [`StripMetadata::strip_metadata`] method for a new metadata version, you'll probably:
/// - Remove any pallets and runtime APIs from the metadata based on the filter functions.
/// - Call `self.iter_type_ids_mut().collect()` to gather all of the type IDs to keep.
/// - This will require implementing `IterateTypeIds`, which is the thing that iterates over all of the
/// type IDs still present in the metadata such that we know what we need to keep.
/// - Call `self.types.retain(..)` to filter any types not matching the type IDs above out of the registry.
/// - Iterate over the type IDs again, mapping those found in the metadata to the new IDs that calling
/// `self.types.retain(..)` handed back.
pub trait StripMetadata {
/// Strip out any pallets and runtime APIs for which the provided filter functions return false.
fn strip_metadata<PalletFilter, RuntimeApiFilter>(
&mut self,
keep_pallet: PalletFilter,
keep_runtime_api: RuntimeApiFilter,
) where
PalletFilter: Fn(&str) -> bool,
RuntimeApiFilter: Fn(&str) -> bool;
}
impl StripMetadata for v14::RuntimeMetadataV14 {
fn strip_metadata<PalletFilter, RuntimeApiFilter>(
&mut self,
keep_pallet: PalletFilter,
_keep_runtime_api: RuntimeApiFilter,
) where
PalletFilter: Fn(&str) -> bool,
RuntimeApiFilter: Fn(&str) -> bool,
{
// Throw away pallets we don't care about:
self.pallets.retain(|pallet| keep_pallet(&pallet.name));
// Now, only retain types we care about in the registry:
retain_types(self);
}
}
impl StripMetadata for v15::RuntimeMetadataV15 {
fn strip_metadata<PalletFilter, RuntimeApiFilter>(
&mut self,
keep_pallet: PalletFilter,
keep_runtime_api: RuntimeApiFilter,
) where
PalletFilter: Fn(&str) -> bool,
RuntimeApiFilter: Fn(&str) -> bool,
{
// Throw away pallets and runtime APIs we don't care about:
self.pallets.retain(|pallet| keep_pallet(&pallet.name));
self.apis.retain(|api| keep_runtime_api(&api.name));
// Now, only retain types we care about in the registry:
retain_types(self);
}
}
impl StripMetadata for v16::RuntimeMetadataV16 {
fn strip_metadata<PalletFilter, RuntimeApiFilter>(
&mut self,
keep_pallet: PalletFilter,
keep_runtime_api: RuntimeApiFilter,
) where
PalletFilter: Fn(&str) -> bool,
RuntimeApiFilter: Fn(&str) -> bool,
{
// Throw away pallets and runtime APIs we don't care about.
// Keep the System pallet, because it has some associated types that we care about in Subxt.
self.pallets
.retain(|pallet| pallet.name == "System" || keep_pallet(&pallet.name));
self.apis.retain(|api| keep_runtime_api(&api.name));
// If the user asked to strip the System pallet, we'll strip most things from it but keep the
// associated types, because Subxt makes use of them.
if !keep_pallet("System") {
if let Some(system_pallet) = self.pallets.iter_mut().find(|p| p.name == "System") {
let index = system_pallet.index;
let associated_types = core::mem::take(&mut system_pallet.associated_types);
*system_pallet = v16::PalletMetadata {
name: "System".to_string(),
index,
associated_types,
// Everything else is empty:
storage: None,
calls: None,
event: None,
constants: vec![],
error: None,
view_functions: vec![],
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
};
}
}
// Now, only retain types we care about in the registry:
retain_types(self);
}
}
fn retain_types<M: GetTypes + IterateTypeIds>(m: &mut M) {
// We want to preserve this type even if it's not used anywhere:
let dispatch_err_type_id = find_dispatch_error_type(m.get_types_mut());
// Iterate over the type IDs and retain any that we still need:
let keep_these_ids: BTreeSet<u32> = m
.iter_type_ids_mut()
.map(|id| *id)
.chain(Some(dispatch_err_type_id))
.collect();
let new_ids = m.get_types_mut().retain(|id| keep_these_ids.contains(&id));
// Map IDs found in the metadata to new ones as needed after the retaining:
for id in m.iter_type_ids_mut() {
if let Some(new_id) = new_ids.get(id) {
*id = *new_id;
};
}
}
/// This trait is implemented for metadatas, and its purpose is to hand back iterators over
/// all of the type IDs (doesn't need to recurse into them) that are used in the metadata,
/// so that we know which ones we need to keep around in the type registry (and thus which
/// ones we can remove).
trait IterateTypeIds {
/// This should iterate over all type IDs found in the metadata.
fn iter_type_ids_mut(&mut self) -> impl Iterator<Item = &mut u32>;
}
impl IterateTypeIds for v14::RuntimeMetadataV14 {
fn iter_type_ids_mut(&mut self) -> impl Iterator<Item = &mut u32> {
// Gather pallet types:
let pallet_types = self.pallets.iter_mut().flat_map(|pallet| {
let pallet_call_types = pallet
.calls
.as_mut()
.into_iter()
.map(|calls| &mut calls.ty.id);
let pallet_storage_types = pallet
.storage
.as_mut()
.into_iter()
.flat_map(|s| &mut s.entries)
.flat_map(|storage_entry| match &mut storage_entry.ty {
v14::StorageEntryType::Plain(ty) => Either::Left(core::iter::once(&mut ty.id)),
v14::StorageEntryType::Map { key, value, .. } => {
Either::Right([&mut key.id, &mut value.id].into_iter())
}
});
let pallet_constant_types = pallet
.constants
.iter_mut()
.map(|constant| &mut constant.ty.id);
let pallet_event_type = pallet
.event
.as_mut()
.into_iter()
.map(|events| &mut events.ty.id);
let pallet_error_type = pallet
.error
.as_mut()
.into_iter()
.map(|error| &mut error.ty.id);
pallet_call_types
.chain(pallet_storage_types)
.chain(pallet_constant_types)
.chain(pallet_event_type)
.chain(pallet_error_type)
});
// Transaction Extension types:
let transaction_extension_types = self
.extrinsic
.signed_extensions
.iter_mut()
.flat_map(|ext| [&mut ext.ty.id, &mut ext.additional_signed.id].into_iter());
// The extrinsic type:
let extrinsic_type_id = &mut self.extrinsic.ty.id;
// Return all IDs gathered:
pallet_types
.chain(Some(extrinsic_type_id))
.chain(transaction_extension_types)
}
}
impl IterateTypeIds for v15::RuntimeMetadataV15 {
fn iter_type_ids_mut(&mut self) -> impl Iterator<Item = &mut u32> {
// Gather pallet types:
let pallet_types = self.pallets.iter_mut().flat_map(|pallet| {
let pallet_call_types = pallet
.calls
.as_mut()
.into_iter()
.map(|calls| &mut calls.ty.id);
let pallet_storage_types = pallet
.storage
.as_mut()
.into_iter()
.flat_map(|s| &mut s.entries)
.flat_map(|storage_entry| match &mut storage_entry.ty {
v14::StorageEntryType::Plain(ty) => Either::Left(core::iter::once(&mut ty.id)),
v14::StorageEntryType::Map { key, value, .. } => {
Either::Right([&mut key.id, &mut value.id].into_iter())
}
});
let pallet_constant_types = pallet
.constants
.iter_mut()
.map(|constant| &mut constant.ty.id);
let pallet_event_type = pallet
.event
.as_mut()
.into_iter()
.map(|events| &mut events.ty.id);
let pallet_error_type = pallet
.error
.as_mut()
.into_iter()
.map(|error| &mut error.ty.id);
pallet_call_types
.chain(pallet_storage_types)
.chain(pallet_constant_types)
.chain(pallet_event_type)
.chain(pallet_error_type)
});
// Runtime APIs:
let runtime_api_types = self
.apis
.iter_mut()
.flat_map(|api| &mut api.methods)
.flat_map(|method| {
let method_inputs = method.inputs.iter_mut().map(|input| &mut input.ty.id);
let method_output = &mut method.output.id;
method_inputs.chain(core::iter::once(method_output))
});
// The extrinsic type IDs:
let extrinsic_type_ids = [
&mut self.extrinsic.call_ty.id,
&mut self.extrinsic.address_ty.id,
&mut self.extrinsic.extra_ty.id,
&mut self.extrinsic.signature_ty.id,
];
// Outer enum type IDs:
let outer_enum_type_ids = [
&mut self.outer_enums.call_enum_ty.id,
&mut self.outer_enums.event_enum_ty.id,
&mut self.outer_enums.error_enum_ty.id,
];
// Transaction Extension types:
let transaction_extension_types = self
.extrinsic
.signed_extensions
.iter_mut()
.flat_map(|ext| [&mut ext.ty.id, &mut ext.additional_signed.id].into_iter());
// Custom types:
let custom_type_ids = self.custom.map.values_mut().map(|value| &mut value.ty.id);
// Return all IDs gathered:
pallet_types
.chain(runtime_api_types)
.chain(extrinsic_type_ids)
.chain(outer_enum_type_ids)
.chain(transaction_extension_types)
.chain(custom_type_ids)
}
}
impl IterateTypeIds for v16::RuntimeMetadataV16 {
fn iter_type_ids_mut(&mut self) -> impl Iterator<Item = &mut u32> {
// Gather pallet types:
let pallet_types = self.pallets.iter_mut().flat_map(|pallet| {
let pallet_call_types = pallet
.calls
.as_mut()
.into_iter()
.map(|calls| &mut calls.ty.id);
let pallet_storage_types = pallet
.storage
.as_mut()
.into_iter()
.flat_map(|s| &mut s.entries)
.flat_map(|storage_entry| match &mut storage_entry.ty {
v16::StorageEntryType::Plain(ty) => Either::Left(core::iter::once(&mut ty.id)),
v16::StorageEntryType::Map { key, value, .. } => {
Either::Right([&mut key.id, &mut value.id].into_iter())
}
});
let pallet_constant_types = pallet
.constants
.iter_mut()
.map(|constant| &mut constant.ty.id);
let pallet_event_type = pallet
.event
.as_mut()
.into_iter()
.map(|events| &mut events.ty.id);
let pallet_error_type = pallet
.error
.as_mut()
.into_iter()
.map(|error| &mut error.ty.id);
let pallet_view_fns = pallet.view_functions.iter_mut().flat_map(|vf| {
let inputs = vf.inputs.iter_mut().map(|input| &mut input.ty.id);
let output = &mut vf.output.id;
inputs.chain(core::iter::once(output))
});
let pallet_associated_types = pallet
.associated_types
.iter_mut()
.map(|associated_type| &mut associated_type.ty.id);
pallet_call_types
.chain(pallet_storage_types)
.chain(pallet_constant_types)
.chain(pallet_event_type)
.chain(pallet_error_type)
.chain(pallet_view_fns)
.chain(pallet_associated_types)
});
// Runtime APIs:
let runtime_api_types = self
.apis
.iter_mut()
.flat_map(|api| &mut api.methods)
.flat_map(|method| {
let method_inputs = method.inputs.iter_mut().map(|input| &mut input.ty.id);
let method_output = &mut method.output.id;
method_inputs.chain(core::iter::once(method_output))
});
// The extrinsic type IDs:
let extrinsic_type_ids = [
&mut self.extrinsic.address_ty.id,
&mut self.extrinsic.signature_ty.id,
];
// Outer enum type IDs:
let outer_enum_type_ids = [
&mut self.outer_enums.call_enum_ty.id,
&mut self.outer_enums.event_enum_ty.id,
&mut self.outer_enums.error_enum_ty.id,
];
// Transaction Extension types:
let transaction_extension_types = self
.extrinsic
.transaction_extensions
.iter_mut()
.flat_map(|ext| [&mut ext.ty.id, &mut ext.implicit.id].into_iter());
// Custom types:
let custom_type_ids = self.custom.map.values_mut().map(|value| &mut value.ty.id);
// Return all IDs gathered:
pallet_types
.chain(runtime_api_types)
.chain(extrinsic_type_ids)
.chain(outer_enum_type_ids)
.chain(transaction_extension_types)
.chain(custom_type_ids)
}
}
/// This trait defines how to get a type registry from the metadata
trait GetTypes {
fn get_types_mut(&mut self) -> &mut PortableRegistry;
}
impl GetTypes for v14::RuntimeMetadataV14 {
fn get_types_mut(&mut self) -> &mut PortableRegistry {
&mut self.types
}
}
impl GetTypes for v15::RuntimeMetadataV15 {
fn get_types_mut(&mut self) -> &mut PortableRegistry {
&mut self.types
}
}
impl GetTypes for v16::RuntimeMetadataV16 {
fn get_types_mut(&mut self) -> &mut PortableRegistry {
&mut self.types
}
}
/// Subxt needs this type so we always ensure to preserve it
/// even if it's not explicitly mentioned anywhere:
fn find_dispatch_error_type(types: &mut PortableRegistry) -> u32 {
types
.types
.iter()
.enumerate()
.find(|(_idx, ty)| ty.ty.path.segments == ["sp_runtime", "DispatchError"])
.expect("Metadata must contain sp_runtime::DispatchError")
.0 as u32
}
#[cfg(test)]
mod test {
use std::collections::BTreeMap;
use super::*;
use codec::Compact;
use scale_info::meta_type;
/// Create dummy types that we can check the presence of with is_in_types.
macro_rules! make_types {
($($name:ident)+) => {
$(
struct $name {}
impl scale_info::TypeInfo for $name {
type Identity = $name;
fn type_info() -> scale_info::Type {
scale_info::Type {
path: scale_info::Path {
segments: vec!["dummy_type", stringify!($name)],
},
type_params: vec![],
type_def: scale_info::TypeDef::Composite(scale_info::TypeDefComposite { fields: vec![] }),
docs: vec![],
}
}
}
impl $name {
#[allow(dead_code)]
pub fn is_in_types(types: &scale_info::PortableRegistry) -> bool {
types.types.iter().any(|ty| ty.ty.path.segments == vec!["dummy_type", stringify!($name)])
}
}
)+
}
}
/// Asserts that a set of the dummy types exist in a registry.
macro_rules! assert_is_in_types {
($($name:ident)+ => $types:expr) => {{
$(
if !$name::is_in_types(&$types) {
panic!("{} was not found in {}", stringify!($name), stringify!($types));
}
)+
}}
}
/// Asserts that a set of the dummy types do not exist in a registry.
macro_rules! assert_not_in_types {
($($name:ident)+ => $types:expr) => {{
$(
if $name::is_in_types(&$types) {
panic!("{} was found in {}", stringify!($name), stringify!($types));
}
)+
}}
}
#[allow(dead_code)]
enum DummyDispatchError {
A,
B,
C,
}
impl scale_info::TypeInfo for DummyDispatchError {
type Identity = DummyDispatchError;
fn type_info() -> scale_info::Type {
scale_info::Type {
path: scale_info::Path {
segments: vec!["sp_runtime", "DispatchError"],
},
type_params: vec![],
type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant {
variants: vec![],
}),
docs: vec![],
}
}
}
#[test]
fn v14_stripping_works() {
make_types!(A B C D E);
let pallets = vec![
v14::PalletMetadata {
name: "First",
index: 0,
calls: None,
storage: Some(v14::PalletStorageMetadata {
prefix: "___",
entries: vec![v14::StorageEntryMetadata {
name: "Hello",
modifier: v14::StorageEntryModifier::Optional,
ty: frame_metadata::v14::StorageEntryType::Plain(meta_type::<A>()),
default: vec![],
docs: vec![],
}],
}),
event: Some(v14::PalletEventMetadata {
ty: meta_type::<B>(),
}),
constants: vec![],
error: None,
},
v14::PalletMetadata {
name: "Second",
index: 1,
calls: Some(v15::PalletCallMetadata {
ty: meta_type::<C>(),
}),
storage: None,
event: None,
constants: vec![v14::PalletConstantMetadata {
name: "SomeConstant",
ty: meta_type::<D>(),
value: vec![],
docs: vec![],
}],
error: None,
},
];
let extrinsic = v14::ExtrinsicMetadata {
version: 0,
signed_extensions: vec![],
ty: meta_type::<E>(),
};
let metadata =
v14::RuntimeMetadataV14::new(pallets, extrinsic, meta_type::<DummyDispatchError>());
assert_eq!(metadata.types.types.len(), 6);
assert_is_in_types!(A B C D E => metadata.types);
let only_first_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "First", |_| true);
md
};
assert_eq!(only_first_pallet.types.types.len(), 4);
assert_is_in_types!(A B E => only_first_pallet.types);
assert_not_in_types!(C D => only_first_pallet.types);
assert_eq!(only_first_pallet.pallets.len(), 1);
assert_eq!(&only_first_pallet.pallets[0].name, "First");
let only_second_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "Second", |_| true);
md
};
assert_eq!(only_second_pallet.types.types.len(), 4);
assert_is_in_types!(C D E => only_second_pallet.types);
assert_not_in_types!(A B => only_second_pallet.types);
assert_eq!(only_second_pallet.pallets.len(), 1);
assert_eq!(&only_second_pallet.pallets[0].name, "Second");
let no_pallets = {
let mut md = metadata.clone();
md.strip_metadata(|_| false, |_| true);
md
};
assert_eq!(no_pallets.types.types.len(), 2);
assert_is_in_types!(E => no_pallets.types);
assert_not_in_types!(A B C D => no_pallets.types);
assert_eq!(no_pallets.pallets.len(), 0);
}
#[test]
fn v15_stripping_works() {
make_types!(A B C D E F G H I J K L M N O P);
let pallets = vec![
v15::PalletMetadata {
name: "First",
index: 0,
calls: None,
storage: Some(v15::PalletStorageMetadata {
prefix: "___",
entries: vec![v15::StorageEntryMetadata {
name: "Hello",
modifier: v15::StorageEntryModifier::Optional,
ty: frame_metadata::v15::StorageEntryType::Plain(meta_type::<A>()),
default: vec![],
docs: vec![],
}],
}),
event: Some(v15::PalletEventMetadata {
ty: meta_type::<B>(),
}),
constants: vec![],
error: None,
docs: vec![],
},
v15::PalletMetadata {
name: "Second",
index: 1,
calls: Some(v15::PalletCallMetadata {
ty: meta_type::<C>(),
}),
storage: None,
event: None,
constants: vec![v15::PalletConstantMetadata {
name: "SomeConstant",
ty: meta_type::<D>(),
value: vec![],
docs: vec![],
}],
error: None,
docs: vec![],
},
];
let extrinsic = v15::ExtrinsicMetadata {
version: 0,
signed_extensions: vec![],
call_ty: meta_type::<E>(),
address_ty: meta_type::<F>(),
signature_ty: meta_type::<G>(),
extra_ty: meta_type::<H>(),
};
let runtime_apis = vec![
v15::RuntimeApiMetadata {
name: "SomeApi",
docs: vec![],
methods: vec![v15::RuntimeApiMethodMetadata {
name: "some_method",
inputs: vec![v15::RuntimeApiMethodParamMetadata {
name: "input1",
ty: meta_type::<I>(),
}],
output: meta_type::<J>(),
docs: vec![],
}],
},
v15::RuntimeApiMetadata {
name: "AnotherApi",
docs: vec![],
methods: vec![v15::RuntimeApiMethodMetadata {
name: "another_method",
inputs: vec![v15::RuntimeApiMethodParamMetadata {
name: "input1",
ty: meta_type::<K>(),
}],
output: meta_type::<L>(),
docs: vec![],
}],
},
];
let outer_enums = v15::OuterEnums {
call_enum_ty: meta_type::<M>(),
error_enum_ty: meta_type::<N>(),
event_enum_ty: meta_type::<O>(),
};
let custom_values = v15::CustomMetadata {
map: BTreeMap::from_iter(vec![(
"Item",
v15::CustomValueMetadata {
ty: meta_type::<P>(),
value: vec![],
},
)]),
};
let metadata = v15::RuntimeMetadataV15::new(
pallets,
extrinsic,
meta_type::<DummyDispatchError>(),
runtime_apis,
outer_enums,
custom_values,
);
assert_is_in_types!(A B C D E F G H I J K L M N O P => metadata.types);
let only_first_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "First", |_| true);
md
};
assert_is_in_types!(A B E F G H I J K L M N O P => only_first_pallet.types);
assert_not_in_types!(C D => only_first_pallet.types);
assert_eq!(only_first_pallet.pallets.len(), 1);
assert_eq!(&only_first_pallet.pallets[0].name, "First");
let only_second_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "Second", |_| true);
md
};
assert_is_in_types!(C D E F G H I J K L M N O P => only_second_pallet.types);
assert_not_in_types!(A B => only_second_pallet.types);
assert_eq!(only_second_pallet.pallets.len(), 1);
assert_eq!(&only_second_pallet.pallets[0].name, "Second");
let no_pallets = {
let mut md = metadata.clone();
md.strip_metadata(|_| false, |_| true);
md
};
assert_is_in_types!(E F G H I J K L M N O P => no_pallets.types);
assert_not_in_types!(A B C D => no_pallets.types);
assert_eq!(no_pallets.pallets.len(), 0);
let only_second_runtime_api = {
let mut md = metadata.clone();
md.strip_metadata(|_| true, |api| api == "AnotherApi");
md
};
assert_is_in_types!(A B C D E F G H K L M N O P => only_second_runtime_api.types);
assert_not_in_types!(I J => only_second_runtime_api.types);
assert_eq!(only_second_runtime_api.pallets.len(), 2);
assert_eq!(only_second_runtime_api.apis.len(), 1);
}
#[test]
fn v16_stripping_works() {
make_types!(A B C D E F G H I J K L M N O P);
let pallets = vec![
v16::PalletMetadata {
name: "First",
index: 0,
calls: None,
storage: Some(v16::PalletStorageMetadata {
prefix: "___",
entries: vec![v16::StorageEntryMetadata {
name: "Hello",
modifier: v16::StorageEntryModifier::Optional,
ty: frame_metadata::v16::StorageEntryType::Plain(meta_type::<A>()),
default: vec![],
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
}],
}),
event: Some(v16::PalletEventMetadata {
ty: meta_type::<B>(),
deprecation_info: v16::EnumDeprecationInfo::nothing_deprecated(),
}),
constants: vec![],
associated_types: vec![],
view_functions: vec![],
error: None,
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
},
v16::PalletMetadata {
name: "Second",
index: 1,
calls: Some(v16::PalletCallMetadata {
ty: meta_type::<C>(),
deprecation_info: v16::EnumDeprecationInfo::nothing_deprecated(),
}),
storage: None,
event: None,
constants: vec![v16::PalletConstantMetadata {
name: "SomeConstant",
ty: meta_type::<D>(),
value: vec![],
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
}],
associated_types: vec![v16::PalletAssociatedTypeMetadata {
name: "Hasher",
ty: meta_type::<E>(),
docs: vec![],
}],
view_functions: vec![v16::PalletViewFunctionMetadata {
name: "some_view_function",
id: [0; 32],
inputs: vec![v16::FunctionParamMetadata {
name: "input1",
ty: meta_type::<F>(),
}],
output: meta_type::<G>(),
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
}],
error: None,
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
},
];
let extrinsic = v16::ExtrinsicMetadata {
call_ty: meta_type::<N>(), // same as outer_enums.call_enum_ty
versions: vec![0],
transaction_extensions_by_version: BTreeMap::new(),
transaction_extensions: vec![],
address_ty: meta_type::<H>(),
signature_ty: meta_type::<I>(),
};
let runtime_apis = vec![
v16::RuntimeApiMetadata {
name: "SomeApi",
version: Compact(2),
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
methods: vec![v16::RuntimeApiMethodMetadata {
name: "some_method",
inputs: vec![v16::FunctionParamMetadata {
name: "input1",
ty: meta_type::<J>(),
}],
output: meta_type::<K>(),
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
}],
},
v16::RuntimeApiMetadata {
name: "AnotherApi",
version: Compact(1),
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
methods: vec![v16::RuntimeApiMethodMetadata {
name: "another_method",
inputs: vec![v16::FunctionParamMetadata {
name: "input1",
ty: meta_type::<L>(),
}],
output: meta_type::<M>(),
docs: vec![],
deprecation_info: v16::ItemDeprecationInfo::NotDeprecated,
}],
},
];
let outer_enums = v16::OuterEnums {
call_enum_ty: meta_type::<N>(),
error_enum_ty: meta_type::<O>(),
event_enum_ty: meta_type::<P>(),
};
let custom_values = v16::CustomMetadata {
map: BTreeMap::from_iter(vec![(
"Item",
v16::CustomValueMetadata {
ty: meta_type::<DummyDispatchError>(),
value: vec![],
},
)]),
};
let metadata = v16::RuntimeMetadataV16::new(
pallets,
extrinsic,
runtime_apis,
outer_enums,
custom_values,
);
assert_is_in_types!(A B C D E F G H I J K L M N O P => metadata.types);
let only_first_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "First", |_| true);
md
};
assert_is_in_types!(A B H I J K L M N O P => only_first_pallet.types);
assert_not_in_types!(C D E F G => only_first_pallet.types);
assert_eq!(only_first_pallet.pallets.len(), 1);
assert_eq!(&only_first_pallet.pallets[0].name, "First");
let only_second_pallet = {
let mut md = metadata.clone();
md.strip_metadata(|name| name == "Second", |_| true);
md
};
assert_is_in_types!(C D E F G H I J K L M N O P => only_second_pallet.types);
assert_not_in_types!(A B => only_second_pallet.types);
assert_eq!(only_second_pallet.pallets.len(), 1);
assert_eq!(&only_second_pallet.pallets[0].name, "Second");
let no_pallets = {
let mut md = metadata.clone();
md.strip_metadata(|_| false, |_| true);
md
};
assert_is_in_types!(H I J K L M N O P => no_pallets.types);
assert_not_in_types!(A B C D E F G => no_pallets.types);
assert_eq!(no_pallets.pallets.len(), 0);
let only_second_runtime_api = {
let mut md = metadata.clone();
md.strip_metadata(|_| true, |api| api == "AnotherApi");
md
};
assert_is_in_types!(A B C D E F G H I L M N O P => only_second_runtime_api.types);
assert_not_in_types!(J K => only_second_runtime_api.types);
assert_eq!(only_second_runtime_api.pallets.len(), 2);
assert_eq!(only_second_runtime_api.apis.len(), 1);
}
}