#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod methods;
mod utils;
pub mod extrinsics {
pub use crate::methods::extrinsic_decoder::{
Extrinsic, ExtrinsicDecodeError, ExtrinsicExtensions, ExtrinsicOwned, ExtrinsicSignature,
ExtrinsicType, NamedArg, decode_extrinsic,
};
pub use crate::methods::extrinsic_encoder::{
ExtrinsicEncodeError, TransactionExtension, TransactionExtensionError,
TransactionExtensions, TransactionExtensionsError,
best_v5_general_transaction_extension_version, encode_call_data, encode_call_data_to,
encode_call_data_with_info, encode_call_data_with_info_to, encode_v4_signed,
encode_v4_signed_to, encode_v4_signed_with_info_to, encode_v4_signer_payload,
encode_v4_signer_payload_with_info, encode_v4_unsigned, encode_v4_unsigned_to,
encode_v4_unsigned_with_info_to, encode_v5_bare, encode_v5_bare_to,
encode_v5_bare_with_info_to, encode_v5_general, encode_v5_general_to,
encode_v5_general_with_info_to, encode_v5_signer_payload,
encode_v5_signer_payload_with_info,
};
pub use crate::methods::extrinsic_type_info::{
ExtrinsicCallInfo, ExtrinsicCallInfoArg, ExtrinsicExtensionInfo, ExtrinsicExtensionInfoArg,
ExtrinsicInfoError, ExtrinsicSignatureInfo, ExtrinsicTypeInfo,
};
}
pub mod storage {
pub use crate::methods::storage_decoder::{
StorageKey, StorageKeyDecodeError, StorageKeyPart, StorageKeyPartValue,
StorageKeyValueDecodeError, StorageValueDecodeError,
decode_default_storage_value_with_info, decode_storage_key, decode_storage_key_values,
decode_storage_key_with_info, decode_storage_value, decode_storage_value_with_info,
};
pub use crate::methods::storage_encoder::{
StorageKeyEncodeError, encode_storage_key, encode_storage_key_prefix,
encode_storage_key_suffix, encode_storage_key_suffix_to,
encode_storage_key_suffix_with_info_to, encode_storage_key_to,
encode_storage_key_with_info, encode_storage_key_with_info_to,
};
pub use crate::methods::storage_type_info::{
StorageEntry, StorageEntryInfo, StorageHasher, StorageInfo, StorageInfoError,
StorageKeyInfo, StorageTypeInfo,
};
pub use crate::utils::{
DecodableValues, EncodableValues, IntoDecodableValues, IntoEncodableValues,
};
}
pub mod constants {
pub use crate::methods::constant_decoder::{
ConstantDecodeError, decode_constant, decode_constant_with_info,
};
pub use crate::methods::constant_type_info::{
ConstantEntry, ConstantEntryInfo, ConstantInfo, ConstantInfoError, ConstantTypeInfo,
};
}
pub mod runtime_apis {
pub use crate::methods::runtime_api_decoder::{
RuntimeApiDecodeError, decode_runtime_api_response, decode_runtime_api_response_with_info,
};
pub use crate::methods::runtime_api_encoder::{
RuntimeApiInputsEncodeError, encode_runtime_api_inputs, encode_runtime_api_inputs_to,
encode_runtime_api_inputs_with_info_to, encode_runtime_api_name,
};
pub use crate::methods::runtime_api_type_info::{
RuntimeApiEntry, RuntimeApiEntryInfo, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
RuntimeApiTypeInfo,
};
pub use crate::utils::{EncodableValues, IntoEncodableValues};
}
pub mod view_functions {
pub use crate::methods::view_function_decoder::{
ViewFunctionDecodeError, decode_view_function_response,
decode_view_function_response_with_info,
};
pub use crate::methods::view_function_encoder::{
RUNTIME_API_NAME, ViewFunctionInputsEncodeError, encode_view_function_inputs,
encode_view_function_inputs_to, encode_view_function_inputs_with_info_to,
};
pub use crate::methods::view_function_type_info::{
ViewFunctionEntry, ViewFunctionEntryInfo, ViewFunctionInfo, ViewFunctionInfoError,
ViewFunctionInput, ViewFunctionTypeInfo,
};
pub use crate::utils::{EncodableValues, IntoEncodableValues};
}
pub mod custom_values {
pub use crate::methods::custom_value_decoder::{
CustomValueDecodeError, decode_custom_value, decode_custom_value_with_info,
};
pub use crate::methods::custom_value_type_info::{
CustomValue, CustomValueEntryInfo, CustomValueInfo, CustomValueInfoError,
CustomValueTypeInfo,
};
}
#[cfg(feature = "legacy-types")]
pub mod legacy_types {
use alloc::boxed::Box;
type GenericError = Box<dyn core::error::Error + Send + Sync + 'static>;
pub fn from_bytes(bytes: &[u8]) -> Result<scale_info_legacy::ChainTypeRegistry, GenericError> {
let types = serde_yaml::from_slice(bytes)?;
Ok(types)
}
pub mod polkadot {
pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
let bytes = include_bytes!("../types/polkadot_relay_types.yaml");
serde_yaml::from_slice(bytes).expect("Polkadot RC types are valid YAML")
}
}
pub mod kusama {
pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
let bytes = include_bytes!("../types/kusama_relay_types.yaml");
serde_yaml::from_slice(bytes).expect("Kusama RC types are valid YAML")
}
pub fn asset_hub() -> scale_info_legacy::ChainTypeRegistry {
let bytes = include_bytes!("../types/kusama_assethub_types.yaml");
serde_yaml::from_slice(bytes).expect("Kusama AssetHub types are valid YAML")
}
}
}
pub mod helpers {
pub use crate::methods::Entry;
pub use crate::utils::{
DecodableValues, DecodeErrorTrace, EncodableValues, IntoDecodableValues,
IntoEncodableValues, decode_with_error_tracing,
};
#[cfg(feature = "legacy")]
pub use crate::utils::{
ToTypeRegistry, type_registry_from_metadata, type_registry_from_metadata_any,
};
pub use scale_decode::visitor::decode_with_visitor;
pub use scale_decode;
}
#[cfg(test)]
mod test {
use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
use crate::methods::runtime_api_type_info::RuntimeApiTypeInfo;
use crate::methods::storage_type_info::StorageTypeInfo;
use crate::methods::view_function_type_info::ViewFunctionTypeInfo;
use crate::utils::ToTypeRegistry;
use scale_info_legacy::type_registry::TypeRegistryResolveError;
use scale_info_legacy::{ChainTypeRegistry, LookupName};
use scale_type_resolver::Field;
#[test]
fn test_deserializing_legacy_types() {
let _ = crate::legacy_types::polkadot::relay_chain();
let _ = crate::legacy_types::kusama::relay_chain();
let _ = crate::legacy_types::kusama::asset_hub();
}
fn legacy_types() -> [(&'static str, ChainTypeRegistry); 3] {
[
("Polkadot RC", crate::legacy_types::polkadot::relay_chain()),
("Kusama RC", crate::legacy_types::kusama::relay_chain()),
("Kusama AH", crate::legacy_types::kusama::asset_hub()),
]
}
fn all_type_registry_sets(
registry: &scale_info_legacy::ChainTypeRegistry,
) -> impl Iterator<Item = scale_info_legacy::TypeRegistrySet<'_>> {
let all_spec_versions = core::iter::once(u64::MAX)
.chain(registry.spec_version_ranges().map(|(low, _high)| low));
all_spec_versions.map(|version| registry.for_spec_version(version))
}
#[test]
fn test_legacy_types_have_sane_type_names() {
let builtins = &[
"u8", "u16", "u32", "u64", "u128", "u256", "i8", "i16", "i32", "i64", "i128", "i256",
"char", "bool", "str",
];
for (chain, types) in legacy_types() {
for types in all_type_registry_sets(&types) {
for ty in types.keys() {
if let Some(path_and_name) = ty.name() {
let name = path_and_name.split("::").last().unwrap();
if builtins.contains(&name) {
continue;
}
if name.starts_with(|c: char| !c.is_uppercase() || !c.is_ascii_alphabetic())
{
panic!("{chain}: {ty} does not begin with an uppercase letter");
}
if name.contains(|c: char| !c.is_ascii_alphanumeric()) {
panic!("{chain}: {ty} contains a non-ascii-alphanumeric character");
}
}
}
}
}
}
#[test]
fn test_legacy_types_have_sane_field_names() {
fn assert_sane<'a>(
chain: &str,
ty: &LookupName,
fields: impl Iterator<Item = Field<'a, LookupName>>,
) {
let field_names: Vec<_> = fields.map(|f| f.name).collect();
let all_fields_named = field_names.iter().all(|n| n.is_some());
let all_fields_unnamed = field_names.iter().all(|n| n.is_none());
if !(all_fields_named || all_fields_unnamed) {
panic!("{chain}: All fields must be named or unnamed, but aren't in '{ty}'");
}
if all_fields_named {
for name in field_names.into_iter().map(|n| n.unwrap()) {
let Some(fst) = name.chars().next() else {
panic!("{chain}: {ty} has a present but empty field name");
};
if !fst.is_ascii_alphabetic() {
panic!(
"{chain}: {ty} field name '{name}' is invalid (does not start with ascii letter)"
);
}
if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
panic!(
"{chain}: {ty} field name '{name}' is invalid (non-ascii-letter-or-number-or-underscore present in the name"
);
}
if name.contains(|c: char| c.is_uppercase()) {
panic!(
"{chain}: {ty} field name '{name}' contains uppercase. Field names should be lowercase only"
);
}
}
}
}
for (chain, types) in legacy_types() {
for types in all_type_registry_sets(&types) {
for ty in types.keys() {
let visitor = scale_type_resolver::visitor::new((), |_, _| ())
.visit_variant(|_ctx, _path, vars| {
for variant in vars {
assert_sane(chain, &ty, variant.fields);
}
})
.visit_composite(|_ctx, _path, fields| {
assert_sane(chain, &ty, fields);
});
if let Err(e) = types.resolve_type(ty.clone(), visitor) {
match e {
TypeRegistryResolveError::UnexpectedBitOrderType
| TypeRegistryResolveError::UnexpectedBitStoreType => {
}
e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
}
}
}
}
}
}
#[test]
fn test_legacy_types_have_sane_variant_names() {
fn assert_sane(chain: &str, ty: &LookupName, variant_name: &str) {
let Some(fst) = variant_name.chars().next() else {
panic!("{chain}: Enum {ty} has an empty variant");
};
if !fst.is_uppercase() {
panic!(
"{chain}: Enum {ty} variant name '{variant_name}' should start with an uppercase letter"
);
}
if !fst.is_ascii_alphabetic() {
panic!(
"{chain}: Enum {ty} variant name '{variant_name}' should start with an ASCII letter"
);
}
if !variant_name.chars().all(|c| c.is_ascii_alphanumeric()) {
panic!(
"{chain}: Enum {ty} variant name '{variant_name}' is invalid (non-ascii-letter-or-number present in the name"
);
}
}
for (chain, types) in legacy_types() {
for types in all_type_registry_sets(&types) {
for ty in types.keys() {
let visitor = scale_type_resolver::visitor::new((), |_, _| ()).visit_variant(
|_ctx, _path, vars| {
for variant in vars {
assert_sane(chain, &ty, variant.name);
}
},
);
if let Err(e) = types.resolve_type(ty.clone(), visitor) {
match e {
TypeRegistryResolveError::UnexpectedBitOrderType
| TypeRegistryResolveError::UnexpectedBitStoreType => {
}
e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
}
}
}
}
}
}
macro_rules! impls_trait {
($type:ty, $trait:path) => {
const _: () = {
const fn assert_impl<T: $trait>() {}
assert_impl::<$type>();
};
};
}
#[rustfmt::skip]
const _: () = {
impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v14::RuntimeMetadataV14, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v15::RuntimeMetadataV15, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ExtrinsicTypeInfo);
impls_trait!(frame_metadata::v8::RuntimeMetadataV8, StorageTypeInfo);
impls_trait!(frame_metadata::v9::RuntimeMetadataV9, StorageTypeInfo);
impls_trait!(frame_metadata::v10::RuntimeMetadataV10, StorageTypeInfo);
impls_trait!(frame_metadata::v11::RuntimeMetadataV11, StorageTypeInfo);
impls_trait!(frame_metadata::v12::RuntimeMetadataV12, StorageTypeInfo);
impls_trait!(frame_metadata::v13::RuntimeMetadataV13, StorageTypeInfo);
impls_trait!(frame_metadata::v14::RuntimeMetadataV14, StorageTypeInfo);
impls_trait!(frame_metadata::v15::RuntimeMetadataV15, StorageTypeInfo);
impls_trait!(frame_metadata::v16::RuntimeMetadataV16, StorageTypeInfo);
impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ViewFunctionTypeInfo);
impls_trait!(scale_info_legacy::TypeRegistry, RuntimeApiTypeInfo);
impls_trait!(scale_info_legacy::TypeRegistrySet, RuntimeApiTypeInfo);
impls_trait!(frame_metadata::v15::RuntimeMetadataV15, RuntimeApiTypeInfo);
impls_trait!(frame_metadata::v16::RuntimeMetadataV16, RuntimeApiTypeInfo);
impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ToTypeRegistry);
impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ToTypeRegistry);
impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ToTypeRegistry);
impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ToTypeRegistry);
impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ToTypeRegistry);
impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ToTypeRegistry);
};
}