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_encoder::{
43 ExtrinsicEncodeError, TransactionExtension, TransactionExtensionError,
44 TransactionExtensions, TransactionExtensionsError,
45 best_v5_general_transaction_extension_version, encode_call_data, encode_call_data_to,
46 encode_call_data_with_info, encode_call_data_with_info_to, encode_v4_signed,
47 encode_v4_signed_to, encode_v4_signed_with_info_to, encode_v4_signer_payload,
48 encode_v4_signer_payload_with_info, encode_v4_unsigned, encode_v4_unsigned_to,
49 encode_v4_unsigned_with_info_to, encode_v5_bare, encode_v5_bare_to,
50 encode_v5_bare_with_info_to, encode_v5_general, encode_v5_general_to,
51 encode_v5_general_with_info_to, encode_v5_signer_payload,
52 encode_v5_signer_payload_with_info,
53 };
54 pub use crate::methods::extrinsic_type_info::{
55 ExtrinsicCallInfo, ExtrinsicCallInfoArg, ExtrinsicExtensionInfo, ExtrinsicExtensionInfoArg,
56 ExtrinsicInfoError, ExtrinsicSignatureInfo, ExtrinsicTypeInfo,
57 };
58}
59
60pub mod storage {
61 pub use crate::methods::storage_decoder::{
72 StorageKey, StorageKeyDecodeError, StorageKeyPart, StorageKeyPartValue,
73 StorageKeyValueDecodeError, StorageValueDecodeError,
74 decode_default_storage_value_with_info, decode_storage_key, decode_storage_key_values,
75 decode_storage_key_with_info, decode_storage_value, decode_storage_value_with_info,
76 };
77 pub use crate::methods::storage_encoder::{
78 StorageKeyEncodeError, encode_storage_key, encode_storage_key_prefix,
79 encode_storage_key_suffix, encode_storage_key_suffix_to,
80 encode_storage_key_suffix_with_info_to, encode_storage_key_to,
81 encode_storage_key_with_info, encode_storage_key_with_info_to,
82 };
83 pub use crate::methods::storage_type_info::{
84 StorageEntry, StorageEntryInfo, StorageHasher, StorageInfo, StorageInfoError,
85 StorageKeyInfo, StorageTypeInfo,
86 };
87 pub use crate::utils::{
88 DecodableValues, EncodableValues, IntoDecodableValues, IntoEncodableValues,
89 };
90}
91
92pub mod constants {
93 pub use crate::methods::constant_decoder::{
102 ConstantDecodeError, decode_constant, decode_constant_with_info,
103 };
104 pub use crate::methods::constant_type_info::{
105 ConstantEntry, ConstantEntryInfo, ConstantInfo, ConstantInfoError, ConstantTypeInfo,
106 };
107}
108
109pub mod runtime_apis {
110 pub use crate::methods::runtime_api_decoder::{
120 RuntimeApiDecodeError, decode_runtime_api_response, decode_runtime_api_response_with_info,
121 };
122 pub use crate::methods::runtime_api_encoder::{
123 RuntimeApiInputsEncodeError, encode_runtime_api_inputs, encode_runtime_api_inputs_to,
124 encode_runtime_api_inputs_with_info_to, encode_runtime_api_name,
125 };
126 pub use crate::methods::runtime_api_type_info::{
127 RuntimeApiEntry, RuntimeApiEntryInfo, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
128 RuntimeApiTypeInfo,
129 };
130 pub use crate::utils::{EncodableValues, IntoEncodableValues};
131}
132
133pub mod view_functions {
134 pub use crate::methods::view_function_decoder::{
144 ViewFunctionDecodeError, decode_view_function_response,
145 decode_view_function_response_with_info,
146 };
147 pub use crate::methods::view_function_encoder::{
148 RUNTIME_API_NAME, ViewFunctionInputsEncodeError, encode_view_function_inputs,
149 encode_view_function_inputs_to, encode_view_function_inputs_with_info_to,
150 };
151 pub use crate::methods::view_function_type_info::{
152 ViewFunctionEntry, ViewFunctionEntryInfo, ViewFunctionInfo, ViewFunctionInfoError,
153 ViewFunctionInput, ViewFunctionTypeInfo,
154 };
155 pub use crate::utils::{EncodableValues, IntoEncodableValues};
156}
157
158pub mod custom_values {
159 pub use crate::methods::custom_value_decoder::{
168 CustomValueDecodeError, decode_custom_value, decode_custom_value_with_info,
169 };
170 pub use crate::methods::custom_value_type_info::{
171 CustomValue, CustomValueEntryInfo, CustomValueInfo, CustomValueInfoError,
172 CustomValueTypeInfo,
173 };
174}
175
176#[cfg(feature = "legacy-types")]
177pub mod legacy_types {
178 use alloc::boxed::Box;
181 type GenericError = Box<dyn core::error::Error + Send + Sync + 'static>;
182
183 pub fn from_bytes(bytes: &[u8]) -> Result<scale_info_legacy::ChainTypeRegistry, GenericError> {
185 let types = serde_yaml::from_slice(bytes)?;
186 Ok(types)
187 }
188
189 pub mod polkadot {
190 pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
194 let bytes = include_bytes!("../types/polkadot_relay_types.yaml");
197 serde_yaml::from_slice(bytes).expect("Polkadot RC types are valid YAML")
198 }
199 }
200
201 pub mod kusama {
202 pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
206 let bytes = include_bytes!("../types/kusama_relay_types.yaml");
209 serde_yaml::from_slice(bytes).expect("Kusama RC types are valid YAML")
210 }
211
212 pub fn asset_hub() -> scale_info_legacy::ChainTypeRegistry {
214 let bytes = include_bytes!("../types/kusama_assethub_types.yaml");
217 serde_yaml::from_slice(bytes).expect("Kusama AssetHub types are valid YAML")
218 }
219 }
220}
221
222pub mod helpers {
223 pub use crate::methods::Entry;
232
233 pub use crate::utils::{
234 DecodableValues, DecodeErrorTrace, EncodableValues, IntoDecodableValues,
235 IntoEncodableValues, decode_with_error_tracing,
236 };
237 #[cfg(feature = "legacy")]
238 pub use crate::utils::{
239 ToTypeRegistry, type_registry_from_metadata, type_registry_from_metadata_any,
240 };
241
242 pub use scale_decode::visitor::decode_with_visitor;
246
247 pub use scale_decode;
249}
250
251#[cfg(test)]
252mod test {
253 use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
254 use crate::methods::runtime_api_type_info::RuntimeApiTypeInfo;
255 use crate::methods::storage_type_info::StorageTypeInfo;
256 use crate::methods::view_function_type_info::ViewFunctionTypeInfo;
257 use crate::utils::ToTypeRegistry;
258 use scale_info_legacy::type_registry::TypeRegistryResolveError;
259 use scale_info_legacy::{ChainTypeRegistry, LookupName};
260 use scale_type_resolver::Field;
261
262 #[test]
264 fn test_deserializing_legacy_types() {
265 let _ = crate::legacy_types::polkadot::relay_chain();
266 let _ = crate::legacy_types::kusama::relay_chain();
267 let _ = crate::legacy_types::kusama::asset_hub();
268 }
269
270 fn legacy_types() -> [(&'static str, ChainTypeRegistry); 3] {
271 [
272 ("Polkadot RC", crate::legacy_types::polkadot::relay_chain()),
273 ("Kusama RC", crate::legacy_types::kusama::relay_chain()),
274 ("Kusama AH", crate::legacy_types::kusama::asset_hub()),
275 ]
276 }
277
278 fn all_type_registry_sets(
279 registry: &scale_info_legacy::ChainTypeRegistry,
280 ) -> impl Iterator<Item = scale_info_legacy::TypeRegistrySet<'_>> {
281 let all_spec_versions = core::iter::once(u64::MAX)
282 .chain(registry.spec_version_ranges().map(|(low, _high)| low));
283 all_spec_versions.map(|version| registry.for_spec_version(version))
284 }
285
286 #[test]
287 fn test_legacy_types_have_sane_type_names() {
288 let builtins = &[
290 "u8", "u16", "u32", "u64", "u128", "u256", "i8", "i16", "i32", "i64", "i128", "i256",
291 "char", "bool", "str",
292 ];
293
294 for (chain, types) in legacy_types() {
295 for types in all_type_registry_sets(&types) {
296 for ty in types.keys() {
297 if let Some(path_and_name) = ty.name() {
298 let name = path_and_name.split("::").last().unwrap();
299
300 if builtins.contains(&name) {
301 continue;
302 }
303
304 if name.starts_with(|c: char| !c.is_uppercase() || !c.is_ascii_alphabetic())
305 {
306 panic!("{chain}: {ty} does not begin with an uppercase letter");
307 }
308 if name.contains(|c: char| !c.is_ascii_alphanumeric()) {
309 panic!("{chain}: {ty} contains a non-ascii-alphanumeric character");
310 }
311 }
312 }
313 }
314 }
315 }
316
317 #[test]
318 fn test_legacy_types_have_sane_field_names() {
319 fn assert_sane<'a>(
320 chain: &str,
321 ty: &LookupName,
322 fields: impl Iterator<Item = Field<'a, LookupName>>,
323 ) {
324 let field_names: Vec<_> = fields.map(|f| f.name).collect();
325
326 let all_fields_named = field_names.iter().all(|n| n.is_some());
327 let all_fields_unnamed = field_names.iter().all(|n| n.is_none());
328
329 if !(all_fields_named || all_fields_unnamed) {
330 panic!("{chain}: All fields must be named or unnamed, but aren't in '{ty}'");
331 }
332 if all_fields_named {
333 for name in field_names.into_iter().map(|n| n.unwrap()) {
334 let Some(fst) = name.chars().next() else {
335 panic!("{chain}: {ty} has a present but empty field name");
336 };
337 if !fst.is_ascii_alphabetic() {
338 panic!(
339 "{chain}: {ty} field name '{name}' is invalid (does not start with ascii letter)"
340 );
341 }
342 if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
343 panic!(
344 "{chain}: {ty} field name '{name}' is invalid (non-ascii-letter-or-number-or-underscore present in the name"
345 );
346 }
347 if name.contains(|c: char| c.is_uppercase()) {
348 panic!(
349 "{chain}: {ty} field name '{name}' contains uppercase. Field names should be lowercase only"
350 );
351 }
352 }
353 }
354 }
355
356 for (chain, types) in legacy_types() {
357 for types in all_type_registry_sets(&types) {
358 for ty in types.keys() {
359 let visitor = scale_type_resolver::visitor::new((), |_, _| ())
360 .visit_variant(|_ctx, _path, vars| {
361 for variant in vars {
362 assert_sane(chain, &ty, variant.fields);
363 }
364 })
365 .visit_composite(|_ctx, _path, fields| {
366 assert_sane(chain, &ty, fields);
367 });
368
369 if let Err(e) = types.resolve_type(ty.clone(), visitor) {
370 match e {
371 TypeRegistryResolveError::UnexpectedBitOrderType
372 | TypeRegistryResolveError::UnexpectedBitStoreType => {
373 }
375 e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
376 }
377 }
378 }
379 }
380 }
381 }
382
383 #[test]
384 fn test_legacy_types_have_sane_variant_names() {
385 fn assert_sane(chain: &str, ty: &LookupName, variant_name: &str) {
386 let Some(fst) = variant_name.chars().next() else {
387 panic!("{chain}: Enum {ty} has an empty variant");
388 };
389
390 if !fst.is_uppercase() {
391 panic!(
392 "{chain}: Enum {ty} variant name '{variant_name}' should start with an uppercase letter"
393 );
394 }
395 if !fst.is_ascii_alphabetic() {
396 panic!(
397 "{chain}: Enum {ty} variant name '{variant_name}' should start with an ASCII letter"
398 );
399 }
400 if !variant_name.chars().all(|c| c.is_ascii_alphanumeric()) {
401 panic!(
402 "{chain}: Enum {ty} variant name '{variant_name}' is invalid (non-ascii-letter-or-number present in the name"
403 );
404 }
405 }
406
407 for (chain, types) in legacy_types() {
408 for types in all_type_registry_sets(&types) {
409 for ty in types.keys() {
410 let visitor = scale_type_resolver::visitor::new((), |_, _| ()).visit_variant(
411 |_ctx, _path, vars| {
412 for variant in vars {
413 assert_sane(chain, &ty, variant.name);
414 }
415 },
416 );
417
418 if let Err(e) = types.resolve_type(ty.clone(), visitor) {
419 match e {
420 TypeRegistryResolveError::UnexpectedBitOrderType
421 | TypeRegistryResolveError::UnexpectedBitStoreType => {
422 }
424 e => panic!("{chain}: Cannot resolve type '{ty}': {e}"),
425 }
426 }
427 }
428 }
429 }
430 }
431
432 macro_rules! impls_trait {
433 ($type:ty, $trait:path) => {
434 const _: () = {
435 const fn assert_impl<T: $trait>() {}
436 assert_impl::<$type>();
437 };
438 };
439 }
440
441 #[rustfmt::skip]
445 const _: () = {
446 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ExtrinsicTypeInfo);
447 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ExtrinsicTypeInfo);
448 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ExtrinsicTypeInfo);
449 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ExtrinsicTypeInfo);
450 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ExtrinsicTypeInfo);
451 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ExtrinsicTypeInfo);
452 impls_trait!(frame_metadata::v14::RuntimeMetadataV14, ExtrinsicTypeInfo);
453 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, ExtrinsicTypeInfo);
454 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ExtrinsicTypeInfo);
455
456 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, StorageTypeInfo);
457 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, StorageTypeInfo);
458 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, StorageTypeInfo);
459 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, StorageTypeInfo);
460 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, StorageTypeInfo);
461 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, StorageTypeInfo);
462 impls_trait!(frame_metadata::v14::RuntimeMetadataV14, StorageTypeInfo);
463 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, StorageTypeInfo);
464 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, StorageTypeInfo);
465
466 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ViewFunctionTypeInfo);
470
471 impls_trait!(scale_info_legacy::TypeRegistry, RuntimeApiTypeInfo);
474 impls_trait!(scale_info_legacy::TypeRegistrySet, RuntimeApiTypeInfo);
475 impls_trait!(frame_metadata::v15::RuntimeMetadataV15, RuntimeApiTypeInfo);
476 impls_trait!(frame_metadata::v16::RuntimeMetadataV16, RuntimeApiTypeInfo);
477
478 impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ToTypeRegistry);
480 impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ToTypeRegistry);
481 impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ToTypeRegistry);
482 impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ToTypeRegistry);
483 impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ToTypeRegistry);
484 impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ToTypeRegistry);
485 };
486}