1use super::TryFromError;
6use crate::Metadata;
7use alloc::borrow::ToOwned;
8use alloc::string::String;
9use alloc::vec;
10use alloc::vec::Vec;
11use core::fmt::Write;
12use frame_metadata::{v14, v15};
13use scale_info::TypeDef;
14
15impl TryFrom<v14::RuntimeMetadataV14> for Metadata {
16 type Error = TryFromError;
17 fn try_from(value: v14::RuntimeMetadataV14) -> Result<Self, Self::Error> {
18 v14_to_v15(value)?.try_into()
20 }
21}
22
23impl From<Metadata> for v14::RuntimeMetadataV14 {
24 fn from(val: Metadata) -> Self {
25 let v15 = val.into();
26 v15_to_v14(v15)
27 }
28}
29
30fn v15_to_v14(mut metadata: v15::RuntimeMetadataV15) -> v14::RuntimeMetadataV14 {
31 let types = &mut metadata.types;
32
33 let extrinsic_type = scale_info::Type {
35 path: scale_info::Path {
36 segments: vec![
37 "primitives".to_owned(),
38 "runtime".to_owned(),
39 "generic".to_owned(),
40 "UncheckedExtrinsic".to_owned(),
41 ],
42 },
43 type_params: vec![
44 scale_info::TypeParameter::<scale_info::form::PortableForm> {
45 name: "Address".to_owned(),
46 ty: Some(metadata.extrinsic.address_ty),
47 },
48 scale_info::TypeParameter::<scale_info::form::PortableForm> {
49 name: "Call".to_owned(),
50 ty: Some(metadata.extrinsic.call_ty),
51 },
52 scale_info::TypeParameter::<scale_info::form::PortableForm> {
53 name: "Signature".to_owned(),
54 ty: Some(metadata.extrinsic.signature_ty),
55 },
56 scale_info::TypeParameter::<scale_info::form::PortableForm> {
57 name: "Extra".to_owned(),
58 ty: Some(metadata.extrinsic.extra_ty),
59 },
60 ],
61 type_def: scale_info::TypeDef::Composite(scale_info::TypeDefComposite { fields: vec![] }),
62 docs: vec![],
63 };
64 let extrinsic_type_id = types.types.len() as u32;
65
66 types.types.push(scale_info::PortableType {
67 id: extrinsic_type_id,
68 ty: extrinsic_type,
69 });
70
71 v14::RuntimeMetadataV14 {
72 types: metadata.types,
73 pallets: metadata
74 .pallets
75 .into_iter()
76 .map(|pallet| frame_metadata::v14::PalletMetadata {
77 name: pallet.name,
78 storage: pallet
79 .storage
80 .map(|storage| frame_metadata::v14::PalletStorageMetadata {
81 prefix: storage.prefix,
82 entries: storage
83 .entries
84 .into_iter()
85 .map(|entry| {
86 let modifier = match entry.modifier {
87 frame_metadata::v15::StorageEntryModifier::Optional => {
88 frame_metadata::v14::StorageEntryModifier::Optional
89 }
90 frame_metadata::v15::StorageEntryModifier::Default => {
91 frame_metadata::v14::StorageEntryModifier::Default
92 }
93 };
94
95 let ty = match entry.ty {
96 frame_metadata::v15::StorageEntryType::Plain(ty) => {
97 frame_metadata::v14::StorageEntryType::Plain(ty)
98 },
99 frame_metadata::v15::StorageEntryType::Map {
100 hashers,
101 key,
102 value,
103 } => frame_metadata::v14::StorageEntryType::Map {
104 hashers: hashers.into_iter().map(|hasher| match hasher {
105 frame_metadata::v15::StorageHasher::Blake2_128 => frame_metadata::v14::StorageHasher::Blake2_128,
106 frame_metadata::v15::StorageHasher::Blake2_256 => frame_metadata::v14::StorageHasher::Blake2_256,
107 frame_metadata::v15::StorageHasher::Blake2_128Concat => frame_metadata::v14::StorageHasher::Blake2_128Concat ,
108 frame_metadata::v15::StorageHasher::Twox128 => frame_metadata::v14::StorageHasher::Twox128,
109 frame_metadata::v15::StorageHasher::Twox256 => frame_metadata::v14::StorageHasher::Twox256,
110 frame_metadata::v15::StorageHasher::Twox64Concat => frame_metadata::v14::StorageHasher::Twox64Concat,
111 frame_metadata::v15::StorageHasher::Identity=> frame_metadata::v14::StorageHasher::Identity,
112 }).collect(),
113 key,
114 value,
115 },
116 };
117
118 frame_metadata::v14::StorageEntryMetadata {
119 name: entry.name,
120 modifier,
121 ty,
122 default: entry.default,
123 docs: entry.docs,
124 }
125 })
126 .collect(),
127 }),
128 calls: pallet.calls.map(|calls| frame_metadata::v14::PalletCallMetadata { ty: calls.ty } ),
129 event: pallet.event.map(|event| frame_metadata::v14::PalletEventMetadata { ty: event.ty } ),
130 constants: pallet.constants.into_iter().map(|constant| frame_metadata::v14::PalletConstantMetadata {
131 name: constant.name,
132 ty: constant.ty,
133 value: constant.value,
134 docs: constant.docs,
135 } ).collect(),
136 error: pallet.error.map(|error| frame_metadata::v14::PalletErrorMetadata { ty: error.ty } ),
137 index: pallet.index,
138 })
139 .collect(),
140 extrinsic: frame_metadata::v14::ExtrinsicMetadata {
141 ty: extrinsic_type_id.into(),
142 version: metadata.extrinsic.version,
143 signed_extensions: metadata.extrinsic.signed_extensions.into_iter().map(|ext| {
144 frame_metadata::v14::SignedExtensionMetadata {
145 identifier: ext.identifier,
146 ty: ext.ty,
147 additional_signed: ext.additional_signed,
148 }
149 }).collect()
150 },
151 ty: metadata.ty,
152 }
153}
154
155fn v14_to_v15(
156 mut metadata: v14::RuntimeMetadataV14,
157) -> Result<v15::RuntimeMetadataV15, TryFromError> {
158 let extrinsic_parts = ExtrinsicPartTypeIds::new(&metadata)?;
160
161 let outer_enums = generate_outer_enums(&mut metadata)?;
162
163 Ok(v15::RuntimeMetadataV15 {
164 types: metadata.types,
165 pallets: metadata
166 .pallets
167 .into_iter()
168 .map(|pallet| frame_metadata::v15::PalletMetadata {
169 name: pallet.name,
170 storage: pallet
171 .storage
172 .map(|storage| frame_metadata::v15::PalletStorageMetadata {
173 prefix: storage.prefix,
174 entries: storage
175 .entries
176 .into_iter()
177 .map(|entry| {
178 let modifier = match entry.modifier {
179 frame_metadata::v14::StorageEntryModifier::Optional => {
180 frame_metadata::v15::StorageEntryModifier::Optional
181 }
182 frame_metadata::v14::StorageEntryModifier::Default => {
183 frame_metadata::v15::StorageEntryModifier::Default
184 }
185 };
186
187 let ty = match entry.ty {
188 frame_metadata::v14::StorageEntryType::Plain(ty) => {
189 frame_metadata::v15::StorageEntryType::Plain(ty)
190 },
191 frame_metadata::v14::StorageEntryType::Map {
192 hashers,
193 key,
194 value,
195 } => frame_metadata::v15::StorageEntryType::Map {
196 hashers: hashers.into_iter().map(|hasher| match hasher {
197 frame_metadata::v14::StorageHasher::Blake2_128 => frame_metadata::v15::StorageHasher::Blake2_128,
198 frame_metadata::v14::StorageHasher::Blake2_256 => frame_metadata::v15::StorageHasher::Blake2_256,
199 frame_metadata::v14::StorageHasher::Blake2_128Concat => frame_metadata::v15::StorageHasher::Blake2_128Concat ,
200 frame_metadata::v14::StorageHasher::Twox128 => frame_metadata::v15::StorageHasher::Twox128,
201 frame_metadata::v14::StorageHasher::Twox256 => frame_metadata::v15::StorageHasher::Twox256,
202 frame_metadata::v14::StorageHasher::Twox64Concat => frame_metadata::v15::StorageHasher::Twox64Concat,
203 frame_metadata::v14::StorageHasher::Identity=> frame_metadata::v15::StorageHasher::Identity,
204 }).collect(),
205 key,
206 value,
207 },
208 };
209
210 frame_metadata::v15::StorageEntryMetadata {
211 name: entry.name,
212 modifier,
213 ty,
214 default: entry.default,
215 docs: entry.docs,
216 }
217 })
218 .collect(),
219 }),
220 calls: pallet.calls.map(|calls| frame_metadata::v15::PalletCallMetadata { ty: calls.ty } ),
221 event: pallet.event.map(|event| frame_metadata::v15::PalletEventMetadata { ty: event.ty } ),
222 constants: pallet.constants.into_iter().map(|constant| frame_metadata::v15::PalletConstantMetadata {
223 name: constant.name,
224 ty: constant.ty,
225 value: constant.value,
226 docs: constant.docs,
227 } ).collect(),
228 error: pallet.error.map(|error| frame_metadata::v15::PalletErrorMetadata { ty: error.ty } ),
229 index: pallet.index,
230 docs: Default::default(),
231 })
232 .collect(),
233 extrinsic: frame_metadata::v15::ExtrinsicMetadata {
234 version: metadata.extrinsic.version,
235 signed_extensions: metadata.extrinsic.signed_extensions.into_iter().map(|ext| {
236 frame_metadata::v15::SignedExtensionMetadata {
237 identifier: ext.identifier,
238 ty: ext.ty,
239 additional_signed: ext.additional_signed,
240 }
241 }).collect(),
242 address_ty: extrinsic_parts.address.into(),
243 call_ty: extrinsic_parts.call.into(),
244 signature_ty: extrinsic_parts.signature.into(),
245 extra_ty: extrinsic_parts.extra.into(),
246 },
247 ty: metadata.ty,
248 apis: Default::default(),
249 outer_enums,
250 custom: v15::CustomMetadata {
251 map: Default::default(),
252 },
253 })
254}
255
256struct ExtrinsicPartTypeIds {
260 address: u32,
261 call: u32,
262 signature: u32,
263 extra: u32,
264}
265
266impl ExtrinsicPartTypeIds {
267 fn new(metadata: &v14::RuntimeMetadataV14) -> Result<Self, TryFromError> {
269 const ADDRESS: &str = "Address";
270 const CALL: &str = "Call";
271 const SIGNATURE: &str = "Signature";
272 const EXTRA: &str = "Extra";
273
274 let extrinsic_id = metadata.extrinsic.ty.id;
275 let Some(extrinsic_ty) = metadata.types.resolve(extrinsic_id) else {
276 return Err(TryFromError::TypeNotFound(extrinsic_id));
277 };
278
279 let find_param = |name: &'static str| -> Option<u32> {
280 extrinsic_ty
281 .type_params
282 .iter()
283 .find(|param| param.name.as_str() == name)
284 .and_then(|param| param.ty.as_ref())
285 .map(|ty| ty.id)
286 };
287
288 let Some(address) = find_param(ADDRESS) else {
289 return Err(TryFromError::TypeNameNotFound(ADDRESS.into()));
290 };
291 let Some(call) = find_param(CALL) else {
292 return Err(TryFromError::TypeNameNotFound(CALL.into()));
293 };
294 let Some(signature) = find_param(SIGNATURE) else {
295 return Err(TryFromError::TypeNameNotFound(SIGNATURE.into()));
296 };
297 let Some(extra) = find_param(EXTRA) else {
298 return Err(TryFromError::TypeNameNotFound(EXTRA.into()));
299 };
300
301 Ok(ExtrinsicPartTypeIds {
302 address,
303 call,
304 signature,
305 extra,
306 })
307 }
308}
309
310fn generate_outer_enums(
311 metadata: &mut v14::RuntimeMetadataV14,
312) -> Result<v15::OuterEnums<scale_info::form::PortableForm>, TryFromError> {
313 let find_type = |name: &str| {
314 metadata.types.types.iter().find_map(|ty| {
315 let ident = ty.ty.path.ident()?;
316
317 if ident != name {
318 return None;
319 }
320
321 let TypeDef::Variant(_) = &ty.ty.type_def else {
322 return None;
323 };
324
325 Some((ty.id, ty.ty.path.segments.clone()))
326 })
327 };
328
329 let Some((call_enum, mut call_path)) = find_type("RuntimeCall") else {
330 return Err(TryFromError::TypeNameNotFound("RuntimeCall".into()));
331 };
332
333 let Some((event_enum, _)) = find_type("RuntimeEvent") else {
334 return Err(TryFromError::TypeNameNotFound("RuntimeEvent".into()));
335 };
336
337 let error_enum = if let Some((error_enum, _)) = find_type("RuntimeError") {
338 error_enum
339 } else {
340 let Some(last) = call_path.last_mut() else {
341 return Err(TryFromError::InvalidTypePath("RuntimeCall".into()));
342 };
343 "RuntimeError".clone_into(last);
344 generate_outer_error_enum_type(metadata, call_path)
345 };
346
347 Ok(v15::OuterEnums {
348 call_enum_ty: call_enum.into(),
349 event_enum_ty: event_enum.into(),
350 error_enum_ty: error_enum.into(),
351 })
352}
353
354fn generate_outer_error_enum_type(
358 metadata: &mut v14::RuntimeMetadataV14,
359 path_segments: Vec<String>,
360) -> u32 {
361 let variants: Vec<_> = metadata
362 .pallets
363 .iter()
364 .filter_map(|pallet| {
365 let error = pallet.error.as_ref()?;
366
367 let mut path = String::new();
370 write!(path, "{}Error", pallet.name).expect("Cannot panic, qed;");
371 let ty = error.ty.id.into();
372
373 Some(scale_info::Variant {
374 name: pallet.name.clone(),
375 fields: vec![scale_info::Field {
376 name: None,
377 ty,
378 type_name: Some(path),
379 docs: vec![],
380 }],
381 index: pallet.index,
382 docs: vec![],
383 })
384 })
385 .collect();
386
387 let enum_type = scale_info::Type {
388 path: scale_info::Path {
389 segments: path_segments,
390 },
391 type_params: vec![],
392 type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant { variants }),
393 docs: vec![],
394 };
395
396 let enum_type_id = metadata.types.types.len() as u32;
397
398 metadata.types.types.push(scale_info::PortableType {
399 id: enum_type_id,
400 ty: enum_type,
401 });
402
403 enum_type_id
404}
405
406#[cfg(test)]
407mod tests {
408 use super::*;
409 use codec::Decode;
410 use frame_metadata::{
411 v14::ExtrinsicMetadata, v15::RuntimeMetadataV15, RuntimeMetadata, RuntimeMetadataPrefixed,
412 };
413 use scale_info::{meta_type, IntoPortable, TypeDef, TypeInfo};
414 use std::{fs, marker::PhantomData, path::Path};
415
416 fn load_v15_metadata() -> RuntimeMetadataV15 {
417 let bytes = fs::read(Path::new("../artifacts/polkadot_metadata_full.scale"))
418 .expect("Cannot read metadata blob");
419 let meta: RuntimeMetadataPrefixed =
420 Decode::decode(&mut &*bytes).expect("Cannot decode scale metadata");
421
422 match meta.1 {
423 RuntimeMetadata::V15(v15) => v15,
424 _ => panic!("Unsupported metadata version {:?}", meta.1),
425 }
426 }
427
428 #[test]
429 fn test_extrinsic_id_generation() {
430 let v15 = load_v15_metadata();
431 let v14 = v15_to_v14(v15.clone());
432
433 let ext_ty = v14.types.resolve(v14.extrinsic.ty.id).unwrap();
434 let addr_id = ext_ty
435 .type_params
436 .iter()
437 .find_map(|ty| {
438 if ty.name == "Address" {
439 Some(ty.ty.unwrap().id)
440 } else {
441 None
442 }
443 })
444 .unwrap();
445 let call_id = ext_ty
446 .type_params
447 .iter()
448 .find_map(|ty| {
449 if ty.name == "Call" {
450 Some(ty.ty.unwrap().id)
451 } else {
452 None
453 }
454 })
455 .unwrap();
456 let extra_id = ext_ty
457 .type_params
458 .iter()
459 .find_map(|ty| {
460 if ty.name == "Extra" {
461 Some(ty.ty.unwrap().id)
462 } else {
463 None
464 }
465 })
466 .unwrap();
467 let signature_id = ext_ty
468 .type_params
469 .iter()
470 .find_map(|ty| {
471 if ty.name == "Signature" {
472 Some(ty.ty.unwrap().id)
473 } else {
474 None
475 }
476 })
477 .unwrap();
478
479 assert_eq!(v15.extrinsic.address_ty.id, addr_id);
481 assert_eq!(v15.extrinsic.call_ty.id, call_id);
482 assert_eq!(v15.extrinsic.extra_ty.id, extra_id);
483 assert_eq!(v15.extrinsic.signature_ty.id, signature_id);
484
485 let v15_addr = v15.types.resolve(v15.extrinsic.address_ty.id).unwrap();
486 let v14_addr = v14.types.resolve(addr_id).unwrap();
487 assert_eq!(v15_addr, v14_addr);
488
489 let v15_call = v15.types.resolve(v15.extrinsic.call_ty.id).unwrap();
490 let v14_call = v14.types.resolve(call_id).unwrap();
491 assert_eq!(v15_call, v14_call);
492
493 let v15_extra = v15.types.resolve(v15.extrinsic.extra_ty.id).unwrap();
494 let v14_extra = v14.types.resolve(extra_id).unwrap();
495 assert_eq!(v15_extra, v14_extra);
496
497 let v15_sign = v15.types.resolve(v15.extrinsic.signature_ty.id).unwrap();
498 let v14_sign = v14.types.resolve(signature_id).unwrap();
499 assert_eq!(v15_sign, v14_sign);
500
501 let converted_v15 = v14_to_v15(v14).unwrap();
503
504 let v15_addr = v15.types.resolve(v15.extrinsic.address_ty.id).unwrap();
505 let converted_v15_addr = converted_v15
506 .types
507 .resolve(converted_v15.extrinsic.address_ty.id)
508 .unwrap();
509 assert_eq!(v15_addr, converted_v15_addr);
510
511 let v15_call = v15.types.resolve(v15.extrinsic.call_ty.id).unwrap();
512 let converted_v15_call = converted_v15
513 .types
514 .resolve(converted_v15.extrinsic.call_ty.id)
515 .unwrap();
516 assert_eq!(v15_call, converted_v15_call);
517
518 let v15_extra = v15.types.resolve(v15.extrinsic.extra_ty.id).unwrap();
519 let converted_v15_extra = converted_v15
520 .types
521 .resolve(converted_v15.extrinsic.extra_ty.id)
522 .unwrap();
523 assert_eq!(v15_extra, converted_v15_extra);
524
525 let v15_sign = v15.types.resolve(v15.extrinsic.signature_ty.id).unwrap();
526 let converted_v15_sign = converted_v15
527 .types
528 .resolve(converted_v15.extrinsic.signature_ty.id)
529 .unwrap();
530 assert_eq!(v15_sign, converted_v15_sign);
531 }
532
533 #[test]
534 fn test_outer_enums_generation() {
535 let v15 = load_v15_metadata();
536 let v14 = v15_to_v14(v15.clone());
537
538 let converted_v15 = v14_to_v15(v14).unwrap();
540
541 let v15_call = v15.types.resolve(v15.outer_enums.call_enum_ty.id).unwrap();
543 let converted_v15_call = converted_v15
544 .types
545 .resolve(converted_v15.outer_enums.call_enum_ty.id)
546 .unwrap();
547 assert_eq!(v15_call, converted_v15_call);
548
549 let v15_event = v15.types.resolve(v15.outer_enums.event_enum_ty.id).unwrap();
550 let converted_v15_event = converted_v15
551 .types
552 .resolve(converted_v15.outer_enums.event_enum_ty.id)
553 .unwrap();
554 assert_eq!(v15_event, converted_v15_event);
555
556 let v15_error = v15.types.resolve(v15.outer_enums.error_enum_ty.id).unwrap();
557 let converted_v15_error = converted_v15
558 .types
559 .resolve(converted_v15.outer_enums.error_enum_ty.id)
560 .unwrap();
561
562 assert_eq!(v15_error.path, converted_v15_error.path);
564
565 let TypeDef::Variant(v15_variant) = &v15_error.type_def else {
566 panic!("V15 error must be a variant");
567 };
568
569 let TypeDef::Variant(converted_v15_variant) = &converted_v15_error.type_def else {
570 panic!("Converted V15 error must be a variant");
571 };
572
573 assert_eq!(
574 v15_variant.variants.len(),
575 converted_v15_variant.variants.len()
576 );
577
578 for (v15_var, converted_v15_var) in v15_variant
579 .variants
580 .iter()
581 .zip(converted_v15_variant.variants.iter())
582 {
583 assert_eq!(v15_var.name, converted_v15_var.name);
585 assert_eq!(v15_var.fields.len(), converted_v15_var.fields.len());
586
587 for (v15_field, converted_v15_field) in
589 v15_var.fields.iter().zip(converted_v15_var.fields.iter())
590 {
591 assert_eq!(v15_field.ty.id, converted_v15_field.ty.id);
592
593 let ty = v15.types.resolve(v15_field.ty.id).unwrap();
594 let converted_ty = converted_v15
595 .types
596 .resolve(converted_v15_field.ty.id)
597 .unwrap();
598 assert_eq!(ty, converted_ty);
599 }
600 }
601 }
602
603 #[test]
604 fn test_missing_extrinsic_types() {
605 #[derive(TypeInfo)]
606 struct Runtime;
607
608 let generate_metadata = |extrinsic_ty| {
609 let mut registry = scale_info::Registry::new();
610
611 let ty = registry.register_type(&meta_type::<Runtime>());
612
613 let extrinsic = ExtrinsicMetadata {
614 ty: extrinsic_ty,
615 version: 0,
616 signed_extensions: vec![],
617 }
618 .into_portable(&mut registry);
619
620 v14::RuntimeMetadataV14 {
621 types: registry.into(),
622 pallets: Vec::new(),
623 extrinsic,
624 ty,
625 }
626 };
627
628 let metadata = generate_metadata(meta_type::<()>());
629 let err = v14_to_v15(metadata).unwrap_err();
630 assert_eq!(err, TryFromError::TypeNameNotFound("Address".into()));
631
632 #[derive(TypeInfo)]
633 struct ExtrinsicNoCall<Address, Signature, Extra> {
634 _phantom: PhantomData<(Address, Signature, Extra)>,
635 }
636 let metadata = generate_metadata(meta_type::<ExtrinsicNoCall<(), (), ()>>());
637 let err = v14_to_v15(metadata).unwrap_err();
638 assert_eq!(err, TryFromError::TypeNameNotFound("Call".into()));
639
640 #[derive(TypeInfo)]
641 struct ExtrinsicNoSign<Call, Address, Extra> {
642 _phantom: PhantomData<(Call, Address, Extra)>,
643 }
644 let metadata = generate_metadata(meta_type::<ExtrinsicNoSign<(), (), ()>>());
645 let err = v14_to_v15(metadata).unwrap_err();
646 assert_eq!(err, TryFromError::TypeNameNotFound("Signature".into()));
647
648 #[derive(TypeInfo)]
649 struct ExtrinsicNoExtra<Call, Address, Signature> {
650 _phantom: PhantomData<(Call, Address, Signature)>,
651 }
652 let metadata = generate_metadata(meta_type::<ExtrinsicNoExtra<(), (), ()>>());
653 let err = v14_to_v15(metadata).unwrap_err();
654 assert_eq!(err, TryFromError::TypeNameNotFound("Extra".into()));
655 }
656
657 #[test]
658 fn test_missing_outer_enum_types() {
659 #[derive(TypeInfo)]
660 struct Runtime;
661
662 #[derive(TypeInfo)]
663 enum RuntimeCall {}
664 #[derive(TypeInfo)]
665 enum RuntimeEvent {}
666
667 #[allow(unused)]
668 #[derive(TypeInfo)]
669 struct ExtrinsicType<Address, Call, Signature, Extra> {
670 pub signature: Option<(Address, Signature, Extra)>,
671 pub function: Call,
672 }
673
674 {
676 let mut registry = scale_info::Registry::new();
677 let ty = registry.register_type(&meta_type::<Runtime>());
678 registry.register_type(&meta_type::<RuntimeEvent>());
679
680 let extrinsic = ExtrinsicMetadata {
681 ty: meta_type::<ExtrinsicType<(), (), (), ()>>(),
682 version: 0,
683 signed_extensions: vec![],
684 }
685 .into_portable(&mut registry);
686
687 let metadata = v14::RuntimeMetadataV14 {
688 types: registry.into(),
689 pallets: Vec::new(),
690 extrinsic,
691 ty,
692 };
693
694 let err = v14_to_v15(metadata).unwrap_err();
695 assert_eq!(err, TryFromError::TypeNameNotFound("RuntimeCall".into()));
696 }
697
698 {
700 let mut registry = scale_info::Registry::new();
701 let ty = registry.register_type(&meta_type::<Runtime>());
702 registry.register_type(&meta_type::<RuntimeCall>());
703
704 let extrinsic = ExtrinsicMetadata {
705 ty: meta_type::<ExtrinsicType<(), (), (), ()>>(),
706 version: 0,
707 signed_extensions: vec![],
708 }
709 .into_portable(&mut registry);
710
711 let metadata = v14::RuntimeMetadataV14 {
712 types: registry.into(),
713 pallets: Vec::new(),
714 extrinsic,
715 ty,
716 };
717
718 let err = v14_to_v15(metadata).unwrap_err();
719 assert_eq!(err, TryFromError::TypeNameNotFound("RuntimeEvent".into()));
720 }
721 }
722}