fix: Resolve cargo clippy errors and add CI workflow plan
## Changes
### Clippy Fixes
- Fixed deprecated `cargo_bin` usage in 27 test files (added #![allow(deprecated)])
- Fixed uninlined_format_args in zombienet-sdk-tests
- Fixed subxt API changes in revive/rpc/tests.rs (fetch signature, StorageValue)
- Fixed dead_code warnings in validator-pool and identity-kyc mocks
- Fixed field name `i` -> `_i` in tasks example
### CI Infrastructure
- Added .claude/WORKFLOW_PLAN.md for tracking CI fix progress
- Updated lychee.toml and taplo.toml configs
### Files Modified
- 27 test files with deprecated cargo_bin fix
- bizinikiwi/pezframe/revive/rpc/src/tests.rs (subxt API)
- pezkuwi/pezpallets/validator-pool/src/{mock,tests}.rs
- pezcumulus/teyrchains/pezpallets/identity-kyc/src/mock.rs
- bizinikiwi/pezframe/examples/tasks/src/tests.rs
## Status
- cargo clippy: PASSING
- Next: cargo fmt, zepter, workspace checks
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
[package]
|
||||
name = "pezkuwi-subxt-utils-fetchmetadata"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = true
|
||||
autotests = false
|
||||
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
documentation.workspace = true
|
||||
homepage.workspace = true
|
||||
description = "subxt utility to fetch metadata"
|
||||
|
||||
[features]
|
||||
url = ["dep:jsonrpsee", "dep:tokio", "dep:url", "frame-metadata"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "std"] }
|
||||
hex = { workspace = true, features = ["std"] }
|
||||
|
||||
# Optional dependencies for the `url` feature.
|
||||
jsonrpsee = { workspace = true, features = ["ws-client", "http-client"], optional = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||
url = { workspace = true, optional = true }
|
||||
frame-metadata = { workspace = true, optional = true, features = ["std"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["url"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.playground]
|
||||
default-features = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
/// Error attempting to fetch metadata.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Error decoding from a hex value.
|
||||
#[error("Cannot decode hex value: {0}")]
|
||||
DecodeError(#[from] hex::FromHexError),
|
||||
/// Some SCALE codec error.
|
||||
#[error("Cannot scale encode/decode value: {0}")]
|
||||
CodecError(#[from] codec::Error),
|
||||
/// JSON-RPC error fetching metadata.
|
||||
#[cfg(feature = "url")]
|
||||
#[error("Request error: {0}")]
|
||||
RequestError(#[from] jsonrpsee::core::ClientError),
|
||||
/// Failed IO when fetching from a file.
|
||||
#[error(
|
||||
"Failed IO for {0}, make sure that you are providing the correct file path for metadata: {1}"
|
||||
)]
|
||||
Io(String, std::io::Error),
|
||||
/// URL scheme is not http, https, ws or wss.
|
||||
#[error("'{0}' not supported, supported URI schemes are http, https, ws or wss.")]
|
||||
InvalidScheme(String),
|
||||
/// Some other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Subxt utils fetch metadata.
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
// Internal helper macros
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod error;
|
||||
|
||||
cfg_fetch_from_url! {
|
||||
mod url;
|
||||
pub use url::{from_url, from_url_blocking, MetadataVersion, Url};
|
||||
}
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
/// Fetch metadata from a file in a blocking manner.
|
||||
pub fn from_file_blocking(path: &std::path::Path) -> Result<Vec<u8>, error::Error> {
|
||||
use std::io::Read;
|
||||
|
||||
let to_err = |err| error::Error::Io(path.to_string_lossy().into(), err);
|
||||
let mut file = std::fs::File::open(path).map_err(to_err)?;
|
||||
let mut bytes = Vec::new();
|
||||
file.read_to_end(&mut bytes).map_err(to_err)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
macro_rules! cfg_feature {
|
||||
($feature:literal, $($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = $feature)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_fetch_from_url {
|
||||
($($item:item)*) => {
|
||||
crate::macros::cfg_feature!("url", $($item)*);
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) use {cfg_feature, cfg_fetch_from_url};
|
||||
@@ -1,197 +0,0 @@
|
||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Fetch metadata from a URL.
|
||||
|
||||
use crate::Error;
|
||||
use codec::{Decode, Encode};
|
||||
use jsonrpsee::{
|
||||
core::client::ClientT, http_client::HttpClientBuilder, rpc_params, ws_client::WsClientBuilder,
|
||||
};
|
||||
|
||||
pub use url::Url;
|
||||
|
||||
/// The metadata version that is fetched from the node.
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub enum MetadataVersion {
|
||||
/// Latest stable version of the metadata.
|
||||
#[default]
|
||||
Latest,
|
||||
/// Fetch a specified version of the metadata.
|
||||
Version(u32),
|
||||
/// Latest unstable version of the metadata.
|
||||
Unstable,
|
||||
}
|
||||
|
||||
// Note: Implementation needed for the CLI tool.
|
||||
impl std::str::FromStr for MetadataVersion {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||
match input {
|
||||
"unstable" => Ok(MetadataVersion::Unstable),
|
||||
"latest" => Ok(MetadataVersion::Latest),
|
||||
version => {
|
||||
let num: u32 = version
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid metadata version specified {version:?}"))?;
|
||||
|
||||
Ok(MetadataVersion::Version(num))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the metadata bytes from the provided URL.
|
||||
pub async fn from_url(url: Url, version: MetadataVersion, at_block_hash: Option<&str>) -> Result<Vec<u8>, Error> {
|
||||
let bytes = match url.scheme() {
|
||||
"http" | "https" => fetch_metadata_http(url, version, at_block_hash).await,
|
||||
"ws" | "wss" => fetch_metadata_ws(url, version, at_block_hash).await,
|
||||
invalid_scheme => Err(Error::InvalidScheme(invalid_scheme.to_owned())),
|
||||
}?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Returns the metadata bytes from the provided URL, blocking the current thread.
|
||||
pub fn from_url_blocking(url: Url, version: MetadataVersion, at_block_hash: Option<&str>) -> Result<Vec<u8>, Error> {
|
||||
tokio_block_on(from_url(url, version, at_block_hash))
|
||||
}
|
||||
|
||||
// Block on some tokio runtime for sync contexts
|
||||
fn tokio_block_on<T, Fut: std::future::Future<Output = T>>(fut: Fut) -> T {
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(fut)
|
||||
}
|
||||
|
||||
async fn fetch_metadata_ws(url: Url, version: MetadataVersion, at_block_hash: Option<&str>) -> Result<Vec<u8>, Error> {
|
||||
let client = WsClientBuilder::default()
|
||||
.request_timeout(std::time::Duration::from_secs(180))
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build(url)
|
||||
.await?;
|
||||
|
||||
fetch_metadata(client, version, at_block_hash).await
|
||||
}
|
||||
|
||||
async fn fetch_metadata_http(url: Url, version: MetadataVersion, at_block_hash: Option<&str>) -> Result<Vec<u8>, Error> {
|
||||
let client = HttpClientBuilder::default()
|
||||
.request_timeout(std::time::Duration::from_secs(180))
|
||||
.build(url)?;
|
||||
|
||||
fetch_metadata(client, version, at_block_hash).await
|
||||
}
|
||||
|
||||
/// The innermost call to fetch metadata:
|
||||
async fn fetch_metadata(client: impl ClientT, version: MetadataVersion, at_block_hash: Option<&str>) -> Result<Vec<u8>, Error> {
|
||||
const UNSTABLE_METADATA_VERSION: u32 = u32::MAX;
|
||||
|
||||
// Ensure always 0x prefix.
|
||||
let at_block_hash = at_block_hash
|
||||
.map(|hash| format!("0x{}", hash.strip_prefix("0x").unwrap_or(hash)));
|
||||
let at_block_hash = at_block_hash.as_deref();
|
||||
|
||||
// Fetch available metadata versions. If error, revert to legacy metadata code.
|
||||
async fn fetch_available_versions(
|
||||
client: &impl ClientT,
|
||||
at_block_hash: Option<&str>,
|
||||
) -> Result<Vec<u32>, Error> {
|
||||
let res: String = client
|
||||
.request("state_call", rpc_params!["Metadata_metadata_versions", "0x", at_block_hash])
|
||||
.await?;
|
||||
let raw_bytes = hex::decode(res.trim_start_matches("0x"))?;
|
||||
Decode::decode(&mut &raw_bytes[..]).map_err(Into::into)
|
||||
}
|
||||
|
||||
// Fetch metadata using the "new" state_call interface
|
||||
async fn fetch_inner(
|
||||
client: &impl ClientT,
|
||||
version: MetadataVersion,
|
||||
supported_versions: Vec<u32>,
|
||||
at_block_hash: Option<&str>,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
// Return the version the user wants if it's supported:
|
||||
let version = match version {
|
||||
MetadataVersion::Latest => *supported_versions
|
||||
.iter()
|
||||
.filter(|&&v| v != UNSTABLE_METADATA_VERSION)
|
||||
.max()
|
||||
.ok_or_else(|| Error::Other("No valid metadata versions returned".to_string()))?,
|
||||
MetadataVersion::Unstable => {
|
||||
if supported_versions.contains(&UNSTABLE_METADATA_VERSION) {
|
||||
UNSTABLE_METADATA_VERSION
|
||||
} else {
|
||||
return Err(Error::Other(
|
||||
"The node does not have an unstable metadata version available".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
MetadataVersion::Version(version) => {
|
||||
if supported_versions.contains(&version) {
|
||||
version
|
||||
} else {
|
||||
return Err(Error::Other(format!(
|
||||
"The node does not have metadata version {version} available"
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let bytes = version.encode();
|
||||
let version: String = format!("0x{}", hex::encode(&bytes));
|
||||
|
||||
// Fetch the metadata at that version:
|
||||
let metadata_string: String = client
|
||||
.request(
|
||||
"state_call",
|
||||
rpc_params!["Metadata_metadata_at_version", &version, at_block_hash],
|
||||
)
|
||||
.await?;
|
||||
// Decode the metadata.
|
||||
let metadata_bytes = hex::decode(metadata_string.trim_start_matches("0x"))?;
|
||||
let metadata: Option<frame_metadata::OpaqueMetadata> =
|
||||
Decode::decode(&mut &metadata_bytes[..])?;
|
||||
let Some(metadata) = metadata else {
|
||||
return Err(Error::Other(format!(
|
||||
"The node does not have metadata version {version} available"
|
||||
)));
|
||||
};
|
||||
Ok(metadata.0)
|
||||
}
|
||||
|
||||
// Fetch metadata using the "old" state_call interface
|
||||
async fn fetch_inner_legacy(
|
||||
client: &impl ClientT,
|
||||
at_block_hash: Option<&str>,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
// Fetch the metadata.
|
||||
let metadata_string: String = client
|
||||
.request("state_call", rpc_params!["Metadata_metadata", "0x", at_block_hash])
|
||||
.await?;
|
||||
|
||||
// Decode the metadata.
|
||||
let metadata_bytes = hex::decode(metadata_string.trim_start_matches("0x"))?;
|
||||
let metadata: frame_metadata::OpaqueMetadata = Decode::decode(&mut &metadata_bytes[..])?;
|
||||
Ok(metadata.0)
|
||||
}
|
||||
|
||||
match fetch_available_versions(&client, at_block_hash).await {
|
||||
Ok(supported_versions) => {
|
||||
fetch_inner(&client, version, supported_versions, at_block_hash).await
|
||||
},
|
||||
Err(e) => {
|
||||
// The "new" interface failed. if the user is asking for V14 or the "latest"
|
||||
// metadata then try the legacy interface instead. Else, just return the
|
||||
// reason for failure.
|
||||
if matches!(version, MetadataVersion::Version(14) | MetadataVersion::Latest) {
|
||||
fetch_inner_legacy(&client, at_block_hash).await
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
[package]
|
||||
name = "pezkuwi-subxt-utils-stripmetadata"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = true
|
||||
autotests = false
|
||||
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
documentation.workspace = true
|
||||
homepage.workspace = true
|
||||
description = "subxt utility to strip metadata"
|
||||
|
||||
[dependencies]
|
||||
codec = { workspace = true }
|
||||
frame-metadata = { workspace = true, features = ["std", "current"] }
|
||||
scale-info = { workspace = true, features = ["std"] }
|
||||
either = { workspace = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["url"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.playground]
|
||||
default-features = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,948 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user