#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]
extern crate alloc;
mod from;
mod utils;
use alloc::borrow::Cow;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use frame_decode::constants::{ConstantEntry, ConstantInfo, ConstantInfoError};
use frame_decode::custom_values::{CustomValue, CustomValueInfo, CustomValueInfoError};
use frame_decode::extrinsics::{
ExtrinsicCallInfo, ExtrinsicCallInfoArg, ExtrinsicExtensionInfo, ExtrinsicExtensionInfoArg,
ExtrinsicInfoError, ExtrinsicSignatureInfo,
};
use frame_decode::runtime_apis::{
RuntimeApiEntry, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
};
use frame_decode::storage::{StorageEntry, StorageInfo, StorageInfoError, StorageKeyInfo};
use frame_decode::view_functions::{
ViewFunctionEntry, ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionInput,
};
use hashbrown::HashMap;
use scale_info::{PortableRegistry, Variant, form::PortableForm};
use utils::{
ordered_map::OrderedMap,
validation::{HASH_LEN, get_custom_value_hash},
variant_index::VariantIndex,
};
pub use frame_decode::storage::StorageHasher;
pub use from::SUPPORTED_METADATA_VERSIONS;
pub use from::TryFromError;
pub use utils::validation::MetadataHasher;
#[cfg(feature = "legacy")]
pub use from::legacy::Error as LegacyFromError;
type CustomMetadataInner = frame_metadata::v15::CustomMetadata<PortableForm>;
pub type ArcMetadata = Arc<Metadata>;
#[derive(Debug)]
pub struct Metadata {
types: PortableRegistry,
pallets: OrderedMap<String, PalletMetadataInner>,
pallets_by_call_index: HashMap<u8, usize>,
pallets_by_event_index: HashMap<u8, usize>,
pallets_by_error_index: HashMap<u8, usize>,
extrinsic: ExtrinsicMetadata,
outer_enums: OuterEnumsMetadata,
dispatch_error_ty: Option<u32>,
apis: OrderedMap<String, RuntimeApiMetadataInner>,
custom: CustomMetadataInner,
}
impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
type TypeId = u32;
fn extrinsic_call_info_by_index(
&self,
pallet_index: u8,
call_index: u8,
) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
let pallet = self.pallet_by_call_index(pallet_index).ok_or({
ExtrinsicInfoError::PalletNotFound {
index: pallet_index,
}
})?;
let call = pallet.call_variant_by_index(call_index).ok_or_else(|| {
ExtrinsicInfoError::CallNotFound {
index: call_index,
pallet_index,
pallet_name: Cow::Borrowed(pallet.name()),
}
})?;
Ok(ExtrinsicCallInfo {
call_index,
pallet_index,
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Borrowed(&call.name),
args: call
.fields
.iter()
.map(|f| ExtrinsicCallInfoArg {
name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
id: f.ty.id,
})
.collect(),
})
}
fn extrinsic_call_info_by_name(
&self,
pallet_name: &str,
call_name: &str,
) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
let pallet = self.pallet_by_name(pallet_name).ok_or({
ExtrinsicInfoError::PalletNotFoundByName {
name: Cow::Owned(pallet_name.to_string()),
}
})?;
let call = pallet.call_variant_by_name(call_name).ok_or_else(|| {
ExtrinsicInfoError::CallNotFoundByName {
pallet_index: pallet.call_index(),
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Owned(call_name.to_string()),
}
})?;
Ok(ExtrinsicCallInfo {
call_index: call.index,
pallet_index: pallet.call_index(),
pallet_name: Cow::Borrowed(pallet.name()),
call_name: Cow::Borrowed(&call.name),
args: call
.fields
.iter()
.map(|f| ExtrinsicCallInfoArg {
name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
id: f.ty.id,
})
.collect(),
})
}
fn extrinsic_signature_info(
&self,
) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
Ok(ExtrinsicSignatureInfo {
address_id: self.extrinsic().address_ty,
signature_id: self.extrinsic().signature_ty,
})
}
fn extrinsic_extension_version_info(
&self,
) -> Result<impl Iterator<Item = u8>, ExtrinsicInfoError<'_>> {
Ok(self
.extrinsic
.transaction_extensions_by_version
.keys()
.copied())
}
fn extrinsic_extension_info(
&self,
extension_version: Option<u8>,
) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
let extension_version = extension_version.unwrap_or_else(|| {
self.extrinsic()
.transaction_extension_version_to_use_for_decoding()
});
let extension_ids = self
.extrinsic()
.transaction_extensions_by_version(extension_version)
.ok_or(ExtrinsicInfoError::ExtrinsicExtensionVersionNotFound { extension_version })?
.map(|f| ExtrinsicExtensionInfoArg {
name: Cow::Borrowed(f.identifier()),
id: f.extra_ty(),
implicit_id: f.additional_ty(),
})
.collect();
Ok(ExtrinsicExtensionInfo { extension_ids })
}
}
impl frame_decode::storage::StorageTypeInfo for Metadata {
type TypeId = u32;
fn storage_info(
&self,
pallet_name: &str,
storage_entry: &str,
) -> Result<StorageInfo<'_, Self::TypeId>, StorageInfoError<'_>> {
let pallet =
self.pallet_by_name(pallet_name)
.ok_or_else(|| StorageInfoError::PalletNotFound {
pallet_name: pallet_name.to_string(),
})?;
let entry = pallet
.storage()
.and_then(|storage| storage.entry_by_name(storage_entry))
.ok_or_else(|| StorageInfoError::StorageNotFound {
name: storage_entry.to_string(),
pallet_name: Cow::Borrowed(pallet.name()),
})?;
let info = StorageInfo {
keys: Cow::Borrowed(&*entry.info.keys),
value_id: entry.info.value_id,
default_value: entry
.info
.default_value
.as_ref()
.map(|def| Cow::Borrowed(&**def)),
use_old_v9_storage_hashers: false,
};
Ok(info)
}
}
impl frame_decode::storage::StorageEntryInfo for Metadata {
fn storage_entries(&self) -> impl Iterator<Item = StorageEntry<'_>> {
self.pallets().flat_map(|pallet| {
let pallet_name = pallet.name();
let pallet_iter = core::iter::once(StorageEntry::In(pallet_name.into()));
let entries_iter = pallet.storage().into_iter().flat_map(|storage| {
storage
.entries()
.iter()
.map(|entry| StorageEntry::Name(entry.name().into()))
});
pallet_iter.chain(entries_iter)
})
}
}
impl frame_decode::runtime_apis::RuntimeApiTypeInfo for Metadata {
type TypeId = u32;
fn runtime_api_info(
&self,
trait_name: &str,
method_name: &str,
) -> Result<RuntimeApiInfo<'_, Self::TypeId>, RuntimeApiInfoError<'_>> {
let api_trait =
self.apis
.get_by_key(trait_name)
.ok_or_else(|| RuntimeApiInfoError::TraitNotFound {
trait_name: trait_name.to_string(),
})?;
let api_method = api_trait.methods.get_by_key(method_name).ok_or_else(|| {
RuntimeApiInfoError::MethodNotFound {
trait_name: Cow::Borrowed(&api_trait.name),
method_name: method_name.to_string(),
}
})?;
let info = RuntimeApiInfo {
inputs: Cow::Borrowed(&api_method.info.inputs),
output_id: api_method.info.output_id,
};
Ok(info)
}
}
impl frame_decode::runtime_apis::RuntimeApiEntryInfo for Metadata {
fn runtime_api_entries(&self) -> impl Iterator<Item = RuntimeApiEntry<'_>> {
self.runtime_api_traits().flat_map(|api_trait| {
let trait_name = api_trait.name();
let trait_iter = core::iter::once(RuntimeApiEntry::In(trait_name.into()));
let method_iter = api_trait
.methods()
.map(|method| RuntimeApiEntry::Name(method.name().into()));
trait_iter.chain(method_iter)
})
}
}
impl frame_decode::view_functions::ViewFunctionTypeInfo for Metadata {
type TypeId = u32;
fn view_function_info(
&self,
pallet_name: &str,
function_name: &str,
) -> Result<ViewFunctionInfo<'_, Self::TypeId>, ViewFunctionInfoError<'_>> {
let pallet = self.pallet_by_name(pallet_name).ok_or_else(|| {
ViewFunctionInfoError::PalletNotFound {
pallet_name: pallet_name.to_string(),
}
})?;
let function = pallet.view_function_by_name(function_name).ok_or_else(|| {
ViewFunctionInfoError::FunctionNotFound {
pallet_name: Cow::Borrowed(pallet.name()),
function_name: function_name.to_string(),
}
})?;
let info = ViewFunctionInfo {
inputs: Cow::Borrowed(&function.inner.info.inputs),
output_id: function.inner.info.output_id,
query_id: *function.query_id(),
};
Ok(info)
}
}
impl frame_decode::view_functions::ViewFunctionEntryInfo for Metadata {
fn view_function_entries(&self) -> impl Iterator<Item = ViewFunctionEntry<'_>> {
self.pallets().flat_map(|pallet| {
let pallet_name = pallet.name();
let pallet_iter = core::iter::once(ViewFunctionEntry::In(pallet_name.into()));
let fn_iter = pallet
.view_functions()
.map(|function| ViewFunctionEntry::Name(function.name().into()));
pallet_iter.chain(fn_iter)
})
}
}
impl frame_decode::constants::ConstantTypeInfo for Metadata {
type TypeId = u32;
fn constant_info(
&self,
pallet_name: &str,
constant_name: &str,
) -> Result<ConstantInfo<'_, Self::TypeId>, ConstantInfoError<'_>> {
let pallet =
self.pallet_by_name(pallet_name)
.ok_or_else(|| ConstantInfoError::PalletNotFound {
pallet_name: pallet_name.to_string(),
})?;
let constant = pallet.constant_by_name(constant_name).ok_or_else(|| {
ConstantInfoError::ConstantNotFound {
pallet_name: Cow::Borrowed(pallet.name()),
constant_name: constant_name.to_string(),
}
})?;
let info = ConstantInfo {
bytes: &constant.value,
type_id: constant.ty,
};
Ok(info)
}
}
impl frame_decode::constants::ConstantEntryInfo for Metadata {
fn constant_entries(&self) -> impl Iterator<Item = ConstantEntry<'_>> {
self.pallets().flat_map(|pallet| {
let pallet_name = pallet.name();
let pallet_iter = core::iter::once(ConstantEntry::In(pallet_name.into()));
let constant_iter = pallet
.constants()
.map(|constant| ConstantEntry::Name(constant.name().into()));
pallet_iter.chain(constant_iter)
})
}
}
impl frame_decode::custom_values::CustomValueTypeInfo for Metadata {
type TypeId = u32;
fn custom_value_info(
&self,
name: &str,
) -> Result<CustomValueInfo<'_, Self::TypeId>, CustomValueInfoError> {
let custom_value = self
.custom()
.get(name)
.ok_or_else(|| CustomValueInfoError {
not_found: name.to_string(),
})?;
let info = CustomValueInfo {
bytes: custom_value.data,
type_id: custom_value.type_id,
};
Ok(info)
}
}
impl frame_decode::custom_values::CustomValueEntryInfo for Metadata {
fn custom_values(&self) -> impl Iterator<Item = CustomValue<'_>> {
self.custom.map.keys().map(|name| CustomValue {
name: Cow::Borrowed(name),
})
}
}
impl Metadata {
pub fn arc(self) -> ArcMetadata {
Arc::new(self)
}
pub fn decode_from(bytes: &[u8]) -> Result<Self, codec::Error> {
let metadata = decode_runtime_metadata(bytes)?;
from_runtime_metadata(metadata)
}
pub fn from_v16(
metadata: frame_metadata::v16::RuntimeMetadataV16,
) -> Result<Self, TryFromError> {
metadata.try_into()
}
pub fn from_v15(
metadata: frame_metadata::v15::RuntimeMetadataV15,
) -> Result<Self, TryFromError> {
metadata.try_into()
}
pub fn from_v14(
metadata: frame_metadata::v14::RuntimeMetadataV14,
) -> Result<Self, TryFromError> {
metadata.try_into()
}
#[cfg(feature = "legacy")]
pub fn from_v13(
metadata: &frame_metadata::v13::RuntimeMetadataV13,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v13(metadata, types, from::legacy::Opts::compat())
}
#[cfg(feature = "legacy")]
pub fn from_v12(
metadata: &frame_metadata::v12::RuntimeMetadataV12,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v12(metadata, types, from::legacy::Opts::compat())
}
#[cfg(feature = "legacy")]
pub fn from_v11(
metadata: &frame_metadata::v11::RuntimeMetadataV11,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v11(metadata, types, from::legacy::Opts::compat())
}
#[cfg(feature = "legacy")]
pub fn from_v10(
metadata: &frame_metadata::v10::RuntimeMetadataV10,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v10(metadata, types, from::legacy::Opts::compat())
}
#[cfg(feature = "legacy")]
pub fn from_v9(
metadata: &frame_metadata::v9::RuntimeMetadataV9,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v9(metadata, types, from::legacy::Opts::compat())
}
#[cfg(feature = "legacy")]
pub fn from_v8(
metadata: &frame_metadata::v8::RuntimeMetadataV8,
types: &scale_info_legacy::TypeRegistrySet<'_>,
) -> Result<Self, LegacyFromError> {
from::legacy::from_v8(metadata, types, from::legacy::Opts::compat())
}
pub fn types(&self) -> &PortableRegistry {
&self.types
}
pub fn types_mut(&mut self) -> &mut PortableRegistry {
&mut self.types
}
pub fn dispatch_error_ty(&self) -> Option<u32> {
self.dispatch_error_ty
}
pub fn extrinsic(&self) -> &ExtrinsicMetadata {
&self.extrinsic
}
pub fn outer_enums(&self) -> OuterEnumsMetadata {
self.outer_enums
}
pub fn pallets(&self) -> impl ExactSizeIterator<Item = PalletMetadata<'_>> {
self.pallets.values().iter().map(|inner| PalletMetadata {
inner,
types: self.types(),
})
}
pub fn pallet_by_call_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
let inner = self
.pallets_by_call_index
.get(&variant_index)
.and_then(|i| self.pallets.get_by_index(*i))?;
Some(PalletMetadata {
inner,
types: self.types(),
})
}
pub fn pallet_by_event_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
let inner = self
.pallets_by_event_index
.get(&variant_index)
.and_then(|i| self.pallets.get_by_index(*i))?;
Some(PalletMetadata {
inner,
types: self.types(),
})
}
pub fn pallet_by_error_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
let inner = self
.pallets_by_error_index
.get(&variant_index)
.and_then(|i| self.pallets.get_by_index(*i))?;
Some(PalletMetadata {
inner,
types: self.types(),
})
}
pub fn pallet_by_name(&self, pallet_name: &str) -> Option<PalletMetadata<'_>> {
let inner = self.pallets.get_by_key(pallet_name)?;
Some(PalletMetadata {
inner,
types: self.types(),
})
}
pub fn runtime_api_traits(&self) -> impl ExactSizeIterator<Item = RuntimeApiMetadata<'_>> {
self.apis.values().iter().map(|inner| RuntimeApiMetadata {
inner,
types: self.types(),
})
}
pub fn runtime_api_trait_by_name(&'_ self, name: &str) -> Option<RuntimeApiMetadata<'_>> {
let inner = self.apis.get_by_key(name)?;
Some(RuntimeApiMetadata {
inner,
types: self.types(),
})
}
pub fn custom(&self) -> CustomMetadata<'_> {
CustomMetadata {
types: self.types(),
inner: &self.custom,
}
}
pub fn hasher(&self) -> MetadataHasher<'_> {
MetadataHasher::new(self)
}
pub fn type_hash(&self, id: u32) -> Option<[u8; HASH_LEN]> {
self.types.resolve(id)?;
Some(crate::utils::validation::get_type_hash(&self.types, id))
}
}
#[derive(Debug, Clone, Copy)]
pub struct PalletMetadata<'a> {
inner: &'a PalletMetadataInner,
types: &'a PortableRegistry,
}
impl<'a> PalletMetadata<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
pub fn call_index(&self) -> u8 {
self.inner.call_index
}
pub fn event_index(&self) -> u8 {
self.inner.event_index
}
pub fn error_index(&self) -> u8 {
self.inner.error_index
}
pub fn docs(&self) -> &'a [String] {
&self.inner.docs
}
pub fn call_ty_id(&self) -> Option<u32> {
self.inner.call_ty
}
pub fn event_ty_id(&self) -> Option<u32> {
self.inner.event_ty
}
pub fn error_ty_id(&self) -> Option<u32> {
self.inner.error_ty
}
pub fn storage(&self) -> Option<&'a StorageMetadata> {
self.inner.storage.as_ref()
}
pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
VariantIndex::get(self.inner.event_ty, self.types)
}
pub fn event_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
self.inner.event_variant_index.lookup_by_index(
variant_index,
self.inner.event_ty,
self.types,
)
}
pub fn has_view_functions(&self) -> bool {
!self.inner.view_functions.is_empty()
}
pub fn view_functions(
&self,
) -> impl ExactSizeIterator<Item = ViewFunctionMetadata<'a>> + use<'a> {
self.inner
.view_functions
.values()
.iter()
.map(|vf: &'a _| ViewFunctionMetadata {
inner: vf,
types: self.types,
})
}
pub fn view_function_by_name(&self, name: &str) -> Option<ViewFunctionMetadata<'a>> {
self.inner
.view_functions
.get_by_key(name)
.map(|vf: &'a _| ViewFunctionMetadata {
inner: vf,
types: self.types,
})
}
pub fn associated_types(&self) -> impl ExactSizeIterator<Item = (&'a str, u32)> + use<'a> {
self.inner
.associated_types
.iter()
.map(|(name, ty)| (&**name, *ty))
}
pub fn associated_type_id(&self, name: &str) -> Option<u32> {
self.inner.associated_types.get(name).copied()
}
pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
VariantIndex::get(self.inner.call_ty, self.types)
}
pub fn call_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
self.inner
.call_variant_index
.lookup_by_index(variant_index, self.inner.call_ty, self.types)
}
pub fn call_variant_by_name(&self, call_name: &str) -> Option<&'a Variant<PortableForm>> {
self.inner
.call_variant_index
.lookup_by_name(call_name, self.inner.call_ty, self.types)
}
pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
VariantIndex::get(self.inner.error_ty, self.types)
}
pub fn error_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
self.inner.error_variant_index.lookup_by_index(
variant_index,
self.inner.error_ty,
self.types,
)
}
pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
self.inner.constants.get_by_key(name)
}
pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> + use<'a> {
self.inner.constants.values().iter()
}
pub fn storage_hash(&self, entry_name: &str) -> Option<[u8; HASH_LEN]> {
crate::utils::validation::get_storage_hash(self, entry_name)
}
pub fn constant_hash(&self, constant_name: &str) -> Option<[u8; HASH_LEN]> {
crate::utils::validation::get_constant_hash(self, constant_name)
}
pub fn call_hash(&self, call_name: &str) -> Option<[u8; HASH_LEN]> {
crate::utils::validation::get_call_hash(self, call_name)
}
pub fn hash(&self) -> [u8; HASH_LEN] {
crate::utils::validation::get_pallet_hash(*self)
}
}
#[derive(Debug, Clone)]
struct PalletMetadataInner {
name: String,
call_index: u8,
event_index: u8,
error_index: u8,
storage: Option<StorageMetadata>,
call_ty: Option<u32>,
call_variant_index: VariantIndex,
event_ty: Option<u32>,
event_variant_index: VariantIndex,
error_ty: Option<u32>,
error_variant_index: VariantIndex,
constants: OrderedMap<String, ConstantMetadata>,
view_functions: OrderedMap<String, ViewFunctionMetadataInner>,
associated_types: BTreeMap<String, u32>,
docs: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct StorageMetadata {
prefix: String,
entries: OrderedMap<String, StorageEntryMetadata>,
}
impl StorageMetadata {
pub fn prefix(&self) -> &str {
&self.prefix
}
pub fn entries(&self) -> &[StorageEntryMetadata] {
self.entries.values()
}
pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
self.entries.get_by_key(name)
}
}
#[derive(Debug, Clone)]
pub struct StorageEntryMetadata {
name: String,
info: StorageInfo<'static, u32>,
docs: Vec<String>,
}
impl StorageEntryMetadata {
pub fn name(&self) -> &str {
&self.name
}
pub fn keys(&self) -> impl ExactSizeIterator<Item = &StorageKeyInfo<u32>> {
let keys = &*self.info.keys;
keys.iter()
}
pub fn value_ty(&self) -> u32 {
self.info.value_id
}
pub fn default_value(&self) -> Option<&[u8]> {
self.info.default_value.as_deref()
}
pub fn docs(&self) -> &[String] {
&self.docs
}
}
#[derive(Debug, Clone)]
pub struct ConstantMetadata {
name: String,
ty: u32,
value: Vec<u8>,
docs: Vec<String>,
}
impl ConstantMetadata {
pub fn name(&self) -> &str {
&self.name
}
pub fn ty(&self) -> u32 {
self.ty
}
pub fn value(&self) -> &[u8] {
&self.value
}
pub fn docs(&self) -> &[String] {
&self.docs
}
}
#[derive(Debug, Clone)]
pub struct ExtrinsicMetadata {
address_ty: u32,
signature_ty: u32,
supported_versions: Vec<u8>,
transaction_extensions: Vec<TransactionExtensionMetadataInner>,
transaction_extensions_by_version: BTreeMap<u8, Vec<u32>>,
}
impl ExtrinsicMetadata {
pub fn supported_versions(&self) -> &[u8] {
&self.supported_versions
}
pub fn transaction_extensions_by_version(
&self,
version: u8,
) -> Option<impl Iterator<Item = TransactionExtensionMetadata<'_>>> {
let extension_indexes = self.transaction_extensions_by_version.get(&version)?;
let iter = extension_indexes.iter().map(|index| {
let tx_metadata = self
.transaction_extensions
.get(*index as usize)
.expect("transaction extension should exist if index is in transaction_extensions_by_version");
TransactionExtensionMetadata {
identifier: &tx_metadata.identifier,
extra_ty: tx_metadata.extra_ty,
additional_ty: tx_metadata.additional_ty,
}
});
Some(iter)
}
pub fn transaction_extension_version_to_use_for_encoding(&self) -> u8 {
*self
.transaction_extensions_by_version
.keys()
.max()
.expect("At least one version of transaction extensions is expected")
}
pub fn transaction_extensions_to_use_for_encoding(
&self,
) -> impl Iterator<Item = TransactionExtensionMetadata<'_>> {
let encoding_version = self.transaction_extension_version_to_use_for_encoding();
self.transaction_extensions_by_version(encoding_version)
.unwrap()
}
pub fn transaction_extension_version_to_use_for_decoding(&self) -> u8 {
*self
.transaction_extensions_by_version
.keys()
.max()
.expect("At least one version of transaction extensions is expected")
}
}
#[derive(Debug, Clone)]
pub struct TransactionExtensionMetadata<'a> {
identifier: &'a str,
extra_ty: u32,
additional_ty: u32,
}
#[derive(Debug, Clone)]
struct TransactionExtensionMetadataInner {
identifier: String,
extra_ty: u32,
additional_ty: u32,
}
impl<'a> TransactionExtensionMetadata<'a> {
pub fn identifier(&self) -> &'a str {
self.identifier
}
pub fn extra_ty(&self) -> u32 {
self.extra_ty
}
pub fn additional_ty(&self) -> u32 {
self.additional_ty
}
}
#[derive(Debug, Clone, Copy)]
pub struct OuterEnumsMetadata {
call_enum_ty: u32,
event_enum_ty: u32,
error_enum_ty: u32,
}
impl OuterEnumsMetadata {
pub fn call_enum_ty(&self) -> u32 {
self.call_enum_ty
}
pub fn event_enum_ty(&self) -> u32 {
self.event_enum_ty
}
pub fn error_enum_ty(&self) -> u32 {
self.error_enum_ty
}
}
#[derive(Debug, Clone, Copy)]
pub struct RuntimeApiMetadata<'a> {
inner: &'a RuntimeApiMetadataInner,
types: &'a PortableRegistry,
}
impl<'a> RuntimeApiMetadata<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
pub fn docs(&self) -> &[String] {
&self.inner.docs
}
pub fn methods(&self) -> impl ExactSizeIterator<Item = RuntimeApiMethodMetadata<'a>> + use<'a> {
self.inner
.methods
.values()
.iter()
.map(|item| RuntimeApiMethodMetadata {
trait_name: &self.inner.name,
inner: item,
types: self.types,
})
}
pub fn method_by_name(&self, name: &str) -> Option<RuntimeApiMethodMetadata<'a>> {
self.inner
.methods
.get_by_key(name)
.map(|item| RuntimeApiMethodMetadata {
trait_name: &self.inner.name,
inner: item,
types: self.types,
})
}
pub fn hash(&self) -> [u8; HASH_LEN] {
crate::utils::validation::get_runtime_apis_hash(*self)
}
}
#[derive(Debug, Clone)]
struct RuntimeApiMetadataInner {
name: String,
methods: OrderedMap<String, RuntimeApiMethodMetadataInner>,
docs: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct RuntimeApiMethodMetadata<'a> {
trait_name: &'a str,
inner: &'a RuntimeApiMethodMetadataInner,
types: &'a PortableRegistry,
}
impl<'a> RuntimeApiMethodMetadata<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
pub fn docs(&self) -> &[String] {
&self.inner.docs
}
pub fn inputs(
&self,
) -> impl ExactSizeIterator<Item = &'a RuntimeApiInput<'static, u32>> + use<'a> {
let inputs = &*self.inner.info.inputs;
inputs.iter()
}
pub fn output_ty(&self) -> u32 {
self.inner.info.output_id
}
pub fn hash(&self) -> [u8; HASH_LEN] {
crate::utils::validation::get_runtime_api_hash(self)
}
}
#[derive(Debug, Clone)]
struct RuntimeApiMethodMetadataInner {
name: String,
info: RuntimeApiInfo<'static, u32>,
docs: Vec<String>,
}
#[derive(Debug, Clone, Copy)]
pub struct ViewFunctionMetadata<'a> {
inner: &'a ViewFunctionMetadataInner,
types: &'a PortableRegistry,
}
impl<'a> ViewFunctionMetadata<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
pub fn query_id(&self) -> &'a [u8; 32] {
&self.inner.info.query_id
}
pub fn docs(&self) -> &'a [String] {
&self.inner.docs
}
pub fn inputs(
&self,
) -> impl ExactSizeIterator<Item = &'a ViewFunctionInput<'static, u32>> + use<'a> {
let inputs = &*self.inner.info.inputs;
inputs.iter()
}
pub fn output_ty(&self) -> u32 {
self.inner.info.output_id
}
pub fn hash(&self) -> [u8; HASH_LEN] {
crate::utils::validation::get_view_function_hash(self)
}
}
#[derive(Debug, Clone)]
struct ViewFunctionMetadataInner {
name: String,
info: ViewFunctionInfo<'static, u32>,
docs: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct MethodParamMetadata {
pub name: String,
pub ty: u32,
}
#[derive(Debug, Clone)]
pub struct CustomMetadata<'a> {
types: &'a PortableRegistry,
inner: &'a CustomMetadataInner,
}
impl<'a> CustomMetadata<'a> {
pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
self.inner
.map
.get_key_value(name)
.map(|(name, e)| CustomValueMetadata {
types: self.types,
type_id: e.ty.id,
data: &e.value,
name,
})
}
pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata<'a>> + use<'a> {
self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
types: self.types,
type_id: e.ty.id,
data: &e.value,
name: name.as_ref(),
})
}
pub fn types(&self) -> &PortableRegistry {
self.types
}
}
pub struct CustomValueMetadata<'a> {
types: &'a PortableRegistry,
type_id: u32,
data: &'a [u8],
name: &'a str,
}
impl<'a> CustomValueMetadata<'a> {
pub fn types(&self) -> &PortableRegistry {
self.types
}
pub fn bytes(&self) -> &'a [u8] {
self.data
}
pub fn type_id(&self) -> u32 {
self.type_id
}
pub fn name(&self) -> &str {
self.name
}
pub fn hash(&self) -> [u8; HASH_LEN] {
get_custom_value_hash(self)
}
}
impl codec::Decode for Metadata {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
from_runtime_metadata(metadata.1)
}
}
pub fn decode_runtime_metadata(
input: &[u8],
) -> Result<frame_metadata::RuntimeMetadata, codec::Error> {
use codec::Decode;
let err = match frame_metadata::RuntimeMetadataPrefixed::decode(&mut &*input) {
Ok(md) => return Ok(md.1),
Err(e) => e,
};
if let Ok(md) = frame_metadata::RuntimeMetadata::decode(&mut &*input) {
return Ok(md);
}
if let Ok(len) = codec::Compact::<u64>::decode(&mut &*input) {
if input.len() == len.0 as usize {
return decode_runtime_metadata(input);
}
}
Err(err)
}
fn from_runtime_metadata(
metadata: frame_metadata::RuntimeMetadata,
) -> Result<Metadata, codec::Error> {
let metadata = match metadata {
frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
frame_metadata::RuntimeMetadata::V16(md) => md.try_into(),
_ => {
let reason = alloc::format!(
"RuntimeMetadata version {} cannot be decoded from",
metadata.version()
);
let e: codec::Error = "Metadata::decode failed: Cannot try_into() to Metadata: unsupported metadata version".into();
return Err(e.chain(reason));
}
};
metadata.map_err(|reason: TryFromError| {
let e: codec::Error = "Metadata::decode failed: Cannot try_into() to Metadata".into();
e.chain(reason.to_string())
})
}