1#![deny(missing_docs)]
25#![cfg_attr(not(feature = "std"), no_std)]
26
27extern crate alloc;
28
29mod methods;
30mod utils;
31
32pub mod extrinsics {
33 pub use crate::methods::extrinsic_decoder::{
39 Extrinsic, ExtrinsicDecodeError, ExtrinsicExtensions, ExtrinsicOwned, ExtrinsicSignature,
40 ExtrinsicType, NamedArg, decode_extrinsic,
41 };
42 pub use crate::methods::extrinsic_type_info::{
43 ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
44 ExtrinsicSignatureInfo, ExtrinsicTypeInfo,
45 };
46}
47
48pub mod storage {
49 pub use crate::methods::storage_decoder::{
60 StorageKey, StorageKeyDecodeError, StorageKeyPart, StorageKeyPartValue,
61 StorageKeyValueDecodeError, StorageValueDecodeError,
62 decode_default_storage_value_with_info, decode_storage_key, decode_storage_key_values,
63 decode_storage_key_with_info, decode_storage_value, decode_storage_value_with_info,
64 };
65 pub use crate::methods::storage_encoder::{
66 StorageKeyEncodeError, encode_storage_key, encode_storage_key_prefix,
67 encode_storage_key_suffix, encode_storage_key_suffix_to,
68 encode_storage_key_suffix_with_info_to, encode_storage_key_to,
69 encode_storage_key_with_info, encode_storage_key_with_info_to,
70 };
71 pub use crate::methods::storage_type_info::{
72 StorageEntry, StorageEntryInfo, StorageHasher, StorageInfo, StorageInfoError,
73 StorageKeyInfo, StorageTypeInfo,
74 };
75 pub use crate::utils::{
76 DecodableValues, EncodableValues, IntoDecodableValues, IntoEncodableValues,
77 };
78}
79
80pub mod constants {
81 pub use crate::methods::constant_decoder::{
90 ConstantDecodeError, decode_constant, decode_constant_with_info,
91 };
92 pub use crate::methods::constant_type_info::{
93 ConstantEntry, ConstantEntryInfo, ConstantInfo, ConstantInfoError, ConstantTypeInfo,
94 };
95}
96
97pub mod runtime_apis {
98 pub use crate::methods::runtime_api_decoder::{
108 RuntimeApiDecodeError, decode_runtime_api_response, decode_runtime_api_response_with_info,
109 };
110 pub use crate::methods::runtime_api_encoder::{
111 RuntimeApiInputsEncodeError, encode_runtime_api_inputs, encode_runtime_api_inputs_to,
112 encode_runtime_api_inputs_with_info_to, encode_runtime_api_name,
113 };
114 pub use crate::methods::runtime_api_type_info::{
115 RuntimeApiEntry, RuntimeApiEntryInfo, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
116 RuntimeApiTypeInfo,
117 };
118 pub use crate::utils::{EncodableValues, IntoEncodableValues};
119}
120
121pub mod view_functions {
122 pub use crate::methods::view_function_decoder::{
132 ViewFunctionDecodeError, decode_view_function_response,
133 decode_view_function_response_with_info,
134 };
135 pub use crate::methods::view_function_encoder::{
136 RUNTIME_API_NAME, ViewFunctionInputsEncodeError, encode_view_function_inputs,
137 encode_view_function_inputs_to, encode_view_function_inputs_with_info_to,
138 };
139 pub use crate::methods::view_function_type_info::{
140 ViewFunctionEntry, ViewFunctionEntryInfo, ViewFunctionInfo, ViewFunctionInfoError,
141 ViewFunctionInput, ViewFunctionTypeInfo,
142 };
143 pub use crate::utils::{EncodableValues, IntoEncodableValues};
144}
145
146pub mod custom_values {
147 pub use crate::methods::custom_value_decoder::{
156 CustomValueDecodeError, decode_custom_value, decode_custom_value_with_info,
157 };
158 pub use crate::methods::custom_value_type_info::{
159 CustomValue, CustomValueEntryInfo, CustomValueInfo, CustomValueInfoError,
160 CustomValueTypeInfo,
161 };
162}
163
164#[cfg(feature = "legacy-types")]
165pub mod legacy_types {
166 use alloc::boxed::Box;
169 type GenericError = Box<dyn core::error::Error + Send + Sync + 'static>;
170
171 pub fn from_bytes(bytes: &[u8]) -> Result<scale_info_legacy::ChainTypeRegistry, GenericError> {
173 let types = serde_yaml::from_slice(bytes)?;
174 Ok(types)
175 }
176
177 pub mod polkadot {
178 pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
182 let bytes = include_bytes!("../types/polkadot_relay_types.yaml");
185 serde_yaml::from_slice(bytes).expect("Polkadot RC types are valid YAML")
186 }
187 }
188
189 #[doc(hidden)]
191 pub mod kusama {
192 pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
196 let bytes = include_bytes!("../types/kusama_relay_types.yaml");
199 serde_yaml::from_slice(bytes).expect("Kusama RC types are valid YAML")
200 }
201
202 pub fn asset_hub() -> scale_info_legacy::ChainTypeRegistry {
204 let bytes = include_bytes!("../types/kusama_assethub_types.yaml");
207 serde_yaml::from_slice(bytes).expect("Kusama AssetHub types are valid YAML")
208 }
209 }
210}
211
212pub mod helpers {
213 pub use crate::methods::Entry;
222
223 pub use crate::utils::{
224 DecodableValues, DecodeErrorTrace, EncodableValues, IntoDecodableValues,
225 IntoEncodableValues, decode_with_error_tracing,
226 };
227 #[cfg(feature = "legacy")]
228 pub use crate::utils::{
229 ToTypeRegistry, type_registry_from_metadata, type_registry_from_metadata_any,
230 };
231
232 pub use scale_decode::visitor::decode_with_visitor;
236
237 pub use scale_decode;
239}
240
241#[cfg(test)]
242mod test {
243 use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
244 use crate::methods::runtime_api_type_info::RuntimeApiTypeInfo;
245 use crate::methods::storage_type_info::StorageTypeInfo;
246 use crate::methods::view_function_type_info::ViewFunctionTypeInfo;
247 use crate::utils::ToTypeRegistry;
248 use scale_info_legacy::type_registry::TypeRegistryResolveError;
249 use scale_info_legacy::{ChainTypeRegistry, LookupName};
250 use scale_type_resolver::Field;
251
252 #[test]
254 fn test_deserializing_legacy_types() {
255 let _ = crate::legacy_types::polkadot::relay_chain();
256 let _ = crate::legacy_types::kusama::relay_chain();
257 let _ = crate::legacy_types::kusama::asset_hub();
258 }
259
260 fn legacy_types() -> [(&'static str, ChainTypeRegistry); 3] {
261 [
262 ("Polkadot RC", crate::legacy_types::polkadot::relay_chain()),
263 ("Kusama RC", crate::legacy_types::kusama::relay_chain()),
264 ("Kusama AH", crate::legacy_types::kusama::asset_hub()),
265 ]
266 }
267
268 fn all_type_registry_sets(
269 registry: &scale_info_legacy::ChainTypeRegistry,
270 ) -> impl Iterator<Item = scale_info_legacy::TypeRegistrySet<'_>> {
271 let all_spec_versions = core::iter::once(u64::MAX)
272 .chain(registry.spec_version_ranges().map(|(low, _high)| low));
273 all_spec_versions.map(|version| registry.for_spec_version(version))
274 }
275
276 #[test]
277 fn test_legacy_types_have_sane_type_names() {
278 let builtins = &[
280 "u8", "u16", "u32", "u64", "u128", "u256", "i8", "i16", "i32", "i64", "i128", "i256",
281 "char", "bool", "str",
282 ];
283
284 for (chain, types) in legacy_types() {
285 for types in all_type_registry_sets(&types) {
286 for ty in types.keys() {
287 if let Some(path_and_name) = ty.name() {
288 let name = path_and_name.split("::").last().unwrap();
289
290 if builtins.contains(&name) {
291 continue;
292 }
293
294 if name.starts_with(|c: char| !c.is_uppercase() || !c.is_ascii_alphabetic())
295 {
296 panic!("{chain}: {ty} does not begin with an uppercase letter");
297 }
298 if name.contains(|c: char| !c.is_ascii_alphanumeric()) {
299 panic!("{chain}: {ty} contains a non-ascii-alphanumeric character");
300 }
301 }
302 }
303 }
304 }
305 }
306
307 #[test]
308 fn test_legacy_types_have_sane_field_names() {
309 fn assert_sane<'a>(
310 chain: &str,
311 ty: &LookupName,
312 fields: impl Iterator<Item = Field<'a, LookupName>>,
313 ) {
314 let field_names: Vec<_> = fields.map(|f| f.name).collect();
315
316 let all_fields_named = field_names.iter().all(|n| n.is_some());
317 let all_fields_unnamed = field_names.iter().all(|n| n.is_none());
318
319 if !(all_fields_named || all_fields_unnamed) {
320 panic!("{chain}: All fields must be named or unnamed, but aren't in '{ty}'");
321 }
322 if all_fields_named {
323 for name in field_names.into_iter().map(|n| n.unwrap()) {
324 let Some(fst) = name.chars().next() else {
325 panic!("{chain}: {ty} has a present but empty field name");
326 };
327 if !fst.is_ascii_alphabetic() {
328 panic!(
329 "{chain}: {ty} field name '{name}' is invalid (does not start with ascii letter)"
330 );
331 }
332 if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
333 panic!(
334 "{chain}: {ty} field name '{name}' is invalid (non-ascii-letter-or-number-or-underscore present in the name"
335 );
336 }
337 if name.contains(|c: char| c.is_uppercase()) {
338 panic!(
339 "{chain}: {ty} field name '{name}' contains uppercase. Field names should be lowercase only"
340 );
341 }
342 }
343 }
344 }
345
346 for (chain, types) in legacy_types() {
347 for types in all_type_registry_sets(&types) {
348 for ty in types.keys() {
349 let visitor = scale_type_resolver::visitor::new((), |_, _| ())
350 .visit_variant(|_ctx, _path, vars| {
351 for variant in vars {
352 assert_sane(chain, &ty, variant.fields);
353 }
354 })
355 .visit_composite(|_ctx, _path, fields| {
356 assert_sane(chain, &ty, fields);
357 });
358
359 if let Err(e) = types.resolve_type(ty.clone(), visitor) {
360 match e {
361 TypeRegistryResolveError::UnexpectedBitOrderType
362 | TypeRegistryResolveError::UnexpectedBitStoreType => {
363 }
365 e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
366 }
367 }
368 }
369 }
370 }
371 }
372
373 #[test]
374 fn test_legacy_types_have_sane_variant_names() {
375 fn assert_sane(chain: &str, ty: &LookupName, variant_name: &str) {
376 let Some(fst) = variant_name.chars().next() else {
377 panic!("{chain}: Enum {ty} has an empty variant");
378 };
379
380 if !fst.is_uppercase() {
381 panic!(
382 "{chain}: Enum {ty} variant name '{variant_name}' should start with an uppercase letter"
383 );
384 }
385 if !fst.is_ascii_alphabetic() {
386 panic!(
387 "{chain}: Enum {ty} variant name '{variant_name}' should start with an ASCII letter"
388 );
389 }
390 if !variant_name.chars().all(|c| c.is_ascii_alphanumeric()) {
391 panic!(
392 "{chain}: Enum {ty} variant name '{variant_name}' is invalid (non-ascii-letter-or-number present in the name"
393 );
394 }
395 }
396
397 for (chain, types) in legacy_types() {
398 for types in all_type_registry_sets(&types) {
399 for ty in types.keys() {
400 let visitor = scale_type_resolver::visitor::new((), |_, _| ()).visit_variant(
401 |_ctx, _path, vars| {
402 for variant in vars {
403 assert_sane(chain, &ty, variant.name);
404 }
405 },
406 );
407
408 if let Err(e) = types.resolve_type(ty.clone(), visitor) {
409 match e {
410 TypeRegistryResolveError::UnexpectedBitOrderType
411 | TypeRegistryResolveError::UnexpectedBitStoreType => {
412 }
414 e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
415 }
416 }
417 }
418 }
419 }
420 }
421
422 macro_rules! impls_trait {
423 ($type:ty, $trait:path) => {
424 const _: () = {
425 const fn assert_impl<T: $trait>() {}
426 assert_impl::<$type>();
427 };
428 };
429 }
430
431 #[rustfmt::skip]
435 const _: () = {
436 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ExtrinsicTypeInfo);
437 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ExtrinsicTypeInfo);
438 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ExtrinsicTypeInfo);
439 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ExtrinsicTypeInfo);
440 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ExtrinsicTypeInfo);
441 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ExtrinsicTypeInfo);
442 impls_trait!(frame_metadata::v14::RuntimeMetadataV14, ExtrinsicTypeInfo);
443 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, ExtrinsicTypeInfo);
444 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ExtrinsicTypeInfo);
445
446 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, StorageTypeInfo);
447 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, StorageTypeInfo);
448 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, StorageTypeInfo);
449 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, StorageTypeInfo);
450 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, StorageTypeInfo);
451 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, StorageTypeInfo);
452 impls_trait!(frame_metadata::v14::RuntimeMetadataV14, StorageTypeInfo);
453 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, StorageTypeInfo);
454 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, StorageTypeInfo);
455
456 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ViewFunctionTypeInfo);
460
461 impls_trait!(scale_info_legacy::TypeRegistry, RuntimeApiTypeInfo);
464 impls_trait!(scale_info_legacy::TypeRegistrySet, RuntimeApiTypeInfo);
465 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, RuntimeApiTypeInfo);
466 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, RuntimeApiTypeInfo);
467
468 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ToTypeRegistry);
470 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ToTypeRegistry);
471 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ToTypeRegistry);
472 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ToTypeRegistry);
473 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ToTypeRegistry);
474 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ToTypeRegistry);
475 };
476}