1use crate::std::{borrow::ToOwned, string::String, vec::Vec};
3
4#[cfg(not(feature = "std"))]
5use core::any::TypeId;
6#[cfg(all(not(feature = "std"), any(feature = "merkle-lean", test)))]
7use core::marker::PhantomData;
8
9#[cfg(feature = "std")]
10use std::any::TypeId;
11#[cfg(all(feature = "std", any(feature = "merkle-lean", test)))]
12use std::marker::PhantomData;
13
14use external_memory_tools::{AddressableBuffer, ExternalMemory};
15
16#[cfg(any(feature = "proof-gen", test))]
17use merkle_cbt_lean::Hasher;
18
19#[cfg(any(feature = "merkle-lean", test))]
20use merkle_cbt_lean::Leaf;
21
22use parity_scale_codec::{Decode, Encode};
23
24use scale_info::{
25 form::PortableForm, interner::UntrackedSymbol, Field, Path, PortableType, Type, TypeDef,
26 TypeDefBitSequence, TypeDefPrimitive, TypeDefVariant, Variant,
27};
28
29#[cfg(any(feature = "proof-gen", test))]
30use substrate_parser::ShortSpecs;
31use substrate_parser::{
32 cards::Info,
33 compacts::get_compact,
34 decoding_sci::{decode_type_def_primitive, pick_variant, BitVecPositions, ResolvedTy, Ty},
35 error::{ParserError, RegistryError, SignableError},
36 propagated::{Checker, Propagated, SpecialtySet},
37 special_indicators::{Hint, SpecialtyTypeHinted, ENUM_INDEX_ENCODED_LEN},
38 traits::{AsMetadata, ResolveType, SignedExtensionMetadata, SpecNameVersion},
39 MarkedData,
40};
41
42use crate::error::{MetaCutError, RegistryCutError};
43
44#[cfg(any(feature = "proof-gen", test))]
45use crate::traits::{Blake3Hasher, HashableMetadata, HashableRegistry, MerkleProofMetadata};
46
47#[cfg(any(feature = "merkle-lean", test))]
48use crate::traits::LEN;
49
50#[derive(Debug)]
58pub struct DraftRegistry {
59 pub types: Vec<DraftRegistryEntry>,
60}
61
62#[derive(Debug)]
64pub struct DraftRegistryEntry {
65 pub id: u32,
66 pub entry_details: EntryDetails,
67}
68
69#[derive(Debug)]
72pub enum EntryDetails {
73 Regular {
74 ty: Type<PortableForm>,
75 },
76 ReduceableEnum {
77 path: Path<PortableForm>,
78 variants: Vec<Variant<PortableForm>>,
79 },
80}
81
82#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq)]
96pub struct ShortRegistry {
97 pub types: Vec<PortableType>,
98}
99
100#[derive(Debug, PartialEq)]
109pub struct LeavesRegistry {
110 pub types: Vec<PortableType>,
111}
112
113impl DraftRegistry {
114 pub fn new() -> Self {
116 Self { types: Vec::new() }
117 }
118
119 pub fn finalize_to_short(&self) -> ShortRegistry {
126 let mut short_registry = ShortRegistry { types: Vec::new() };
127 for draft_entry in self.types.iter() {
128 let id = draft_entry.id;
129 let ty = match &draft_entry.entry_details {
130 EntryDetails::Regular { ty } => ty.to_owned(),
131 EntryDetails::ReduceableEnum { path, variants } => Type {
132 path: path.to_owned(),
133 type_params: Vec::new(),
134 type_def: TypeDef::Variant(TypeDefVariant {
135 variants: variants.to_owned(),
136 }),
137 docs: Vec::new(),
138 },
139 };
140 short_registry.types.push(PortableType { id, ty })
141 }
142 for entry in short_registry.types.iter_mut() {
143 if let TypeDef::Variant(ref mut variants_entry) = entry.ty.type_def {
144 variants_entry
145 .variants
146 .sort_by(|a, b| a.index.cmp(&b.index))
147 }
148 }
149 short_registry.types.sort_by(|a, b| a.id.cmp(&b.id));
150 short_registry
151 }
152
153 pub fn into_leaves(&self) -> LeavesRegistry {
163 let mut leaves = LeavesRegistry { types: Vec::new() };
164 for draft_entry in self.types.iter() {
165 let id = draft_entry.id;
166 match &draft_entry.entry_details {
167 EntryDetails::Regular { ty } => leaves.types.push(PortableType {
168 id,
169 ty: ty.to_owned(),
170 }),
171 EntryDetails::ReduceableEnum { path, variants } => {
172 for variant in variants.iter() {
173 let ty = Type {
174 path: path.to_owned(),
175 type_params: Vec::new(),
176 type_def: TypeDef::Variant(TypeDefVariant {
177 variants: vec![variant.to_owned()],
178 }),
179 docs: Vec::new(),
180 };
181 leaves.types.push(PortableType { id, ty })
182 }
183 }
184 };
185 }
186 leaves.types.sort_by(|a, b| {
187 if a.id == b.id {
188 if let TypeDef::Variant(variants_a) = &a.ty.type_def {
189 if let TypeDef::Variant(variants_b) = &b.ty.type_def {
190 variants_a.variants[0]
191 .index
192 .cmp(&variants_b.variants[0].index)
193 } else {
194 unreachable!("only variants have more than one entry")
195 }
196 } else {
197 unreachable!("only variants have more than one entry")
198 }
199 } else {
200 a.id.cmp(&b.id)
201 }
202 });
203 leaves
204 }
205}
206
207impl Default for DraftRegistry {
208 fn default() -> Self {
209 Self::new()
210 }
211}
212
213pub(crate) fn add_ty_as_regular(
215 draft_registry: &mut DraftRegistry,
216 mut ty: Type<PortableForm>,
217 id: u32,
218) -> Result<(), RegistryCutError> {
219 for draft_registry_entry in draft_registry.types.iter() {
220 if draft_registry_entry.id == id {
221 match draft_registry_entry.entry_details {
222 EntryDetails::Regular { ty: ref known_ty } => {
223 if known_ty == &ty {
224 return Ok(());
225 } else {
226 return Err(RegistryCutError::IndexTwice { id });
227 }
228 }
229 EntryDetails::ReduceableEnum {
230 path: _,
231 variants: _,
232 } => return Err(RegistryCutError::IndexTwice { id }),
233 }
234 }
235 }
236
237 if let TypeDef::Composite(ref mut type_def_composite) = ty.type_def {
241 for field in type_def_composite.fields.iter_mut() {
242 field.docs.clear();
243 }
244 }
245
246 ty.docs.clear();
248 let entry_details = EntryDetails::Regular { ty };
249 let draft_registry_entry = DraftRegistryEntry { id, entry_details };
250 draft_registry.types.push(draft_registry_entry);
251 Ok(())
252}
253
254pub(crate) fn add_as_enum(
256 draft_registry: &mut DraftRegistry,
257 path: &Path<PortableForm>,
258 mut variant: Variant<PortableForm>,
259 id: u32,
260) -> Result<(), RegistryCutError> {
261 for draft_registry_entry in draft_registry.types.iter_mut() {
262 if draft_registry_entry.id == id {
263 match draft_registry_entry.entry_details {
264 EntryDetails::Regular { ty: _ } => {
265 return Err(RegistryCutError::IndexTwice { id });
266 }
267 EntryDetails::ReduceableEnum {
268 path: ref known_path,
269 ref mut variants,
270 } => {
271 if known_path == path {
272 variant.docs.clear();
274
275 for field in variant.fields.iter_mut() {
277 field.docs.clear();
278 }
279
280 if !variants.contains(&variant) {
281 variants.push(variant)
282 }
283 return Ok(());
284 } else {
285 return Err(RegistryCutError::IndexTwice { id });
286 }
287 }
288 }
289 }
290 }
291
292 variant.docs.clear();
294
295 for field in variant.fields.iter_mut() {
297 field.docs.clear();
298 }
299
300 let variants = vec![variant];
301 let entry_details = EntryDetails::ReduceableEnum {
302 path: path.to_owned(),
303 variants,
304 };
305 let draft_registry_entry = DraftRegistryEntry { id, entry_details };
306 draft_registry.types.push(draft_registry_entry);
307 Ok(())
308}
309
310pub fn pass_call<B, E, M>(
313 marked_data: &MarkedData<B, E, M>,
314 ext_memory: &mut E,
315 full_metadata: &M,
316 draft_registry: &mut DraftRegistry,
317) -> Result<(), MetaCutError<E, M>>
318where
319 B: AddressableBuffer<E>,
320 E: ExternalMemory,
321 M: AsMetadata<E>,
322{
323 let data = marked_data.data_no_extensions();
324 let mut position = marked_data.call_start();
325
326 pass_call_unmarked(
327 &data,
328 &mut position,
329 ext_memory,
330 full_metadata,
331 draft_registry,
332 )?;
333 if position != marked_data.extensions_start() {
334 Err(MetaCutError::Signable(SignableError::SomeDataNotUsedCall {
335 from: position,
336 to: marked_data.extensions_start(),
337 }))
338 } else {
339 Ok(())
340 }
341}
342
343pub fn pass_call_unmarked<B, E, M>(
346 data: &B,
347 position: &mut usize,
348 ext_memory: &mut E,
349 full_metadata: &M,
350 draft_registry: &mut DraftRegistry,
351) -> Result<(), MetaCutError<E, M>>
352where
353 B: AddressableBuffer<E>,
354 E: ExternalMemory,
355 M: AsMetadata<E>,
356{
357 let call_ty = full_metadata
358 .call_ty()
359 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?;
360
361 pass_type::<B, E, M>(
362 &Ty::Symbol(&call_ty),
363 data,
364 ext_memory,
365 position,
366 &full_metadata.types(),
367 Propagated::new(),
368 draft_registry,
369 )
370}
371
372pub fn pass_extensions<B, E, M>(
375 marked_data: &MarkedData<B, E, M>,
376 ext_memory: &mut E,
377 full_metadata: &M,
378 draft_registry: &mut DraftRegistry,
379) -> Result<(), MetaCutError<E, M>>
380where
381 B: AddressableBuffer<E>,
382 E: ExternalMemory,
383 M: AsMetadata<E>,
384{
385 let mut position = marked_data.extensions_start();
386 let data = marked_data.data();
387
388 pass_extensions_unmarked(
389 data,
390 &mut position,
391 ext_memory,
392 full_metadata,
393 draft_registry,
394 )
395}
396
397pub fn pass_extensions_unmarked<B, E, M>(
400 data: &B,
401 position: &mut usize,
402 ext_memory: &mut E,
403 full_metadata: &M,
404 draft_registry: &mut DraftRegistry,
405) -> Result<(), MetaCutError<E, M>>
406where
407 B: AddressableBuffer<E>,
408 E: ExternalMemory,
409 M: AsMetadata<E>,
410{
411 let full_metadata_types = full_metadata.types();
412 let signed_extensions = full_metadata
413 .signed_extensions()
414 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?;
415 for signed_extensions_metadata in signed_extensions.iter() {
416 pass_type::<B, E, M>(
417 &Ty::Symbol(&signed_extensions_metadata.ty),
418 data,
419 ext_memory,
420 position,
421 &full_metadata_types,
422 Propagated::from_ext_meta(signed_extensions_metadata),
423 draft_registry,
424 )?;
425 }
426 for signed_extensions_metadata in signed_extensions.iter() {
427 pass_type::<B, E, M>(
428 &Ty::Symbol(&signed_extensions_metadata.additional_signed),
429 data,
430 ext_memory,
431 position,
432 &full_metadata_types,
433 Propagated::from_ext_meta(signed_extensions_metadata),
434 draft_registry,
435 )?;
436 }
437 if *position != data.total_len() {
439 Err(MetaCutError::Signable(
440 SignableError::SomeDataNotUsedExtensions { from: *position },
441 ))
442 } else {
443 Ok(())
444 }
445}
446
447#[cfg(any(feature = "merkle-lean", test))]
452#[repr(C)]
453#[derive(Debug, Decode, Encode, Eq, PartialEq)]
454pub struct ShortMetadata<L, E>
455where
456 L: Leaf<LEN, E>,
457 E: ExternalMemory,
458{
459 pub short_registry: ShortRegistry,
460 pub indices: Vec<u32>,
461 pub lemmas: Vec<L>,
462 pub metadata_descriptor: MetadataDescriptor,
463 ext_memory_type: PhantomData<E>,
464}
465
466#[repr(C)]
469#[non_exhaustive]
470#[derive(Debug, Decode, Encode, Eq, PartialEq)]
471pub enum MetadataDescriptor {
472 V0,
473 V1 {
474 call_ty: UntrackedSymbol<TypeId>,
475 signed_extensions: Vec<SignedExtensionMetadata>,
476 spec_name_version: SpecNameVersion,
477 base58prefix: u16,
478 decimals: u8,
479 unit: String,
480 },
481}
482
483#[cfg(any(feature = "proof-gen", test))]
488pub fn cut_metadata<B, E, L, M>(
489 data: &B,
490 ext_memory: &mut E,
491 full_metadata: &M,
492 short_specs: &ShortSpecs,
493) -> Result<ShortMetadata<L, E>, MetaCutError<E, M>>
494where
495 B: AddressableBuffer<E>,
496 E: ExternalMemory,
497 L: Leaf<LEN, E>,
498 M: HashableMetadata<E>,
499 <M as AsMetadata<E>>::TypeRegistry: HashableRegistry<E>,
500{
501 let mut draft_registry = DraftRegistry::new();
502
503 let marked_data =
504 MarkedData::<B, E, M>::mark(data, ext_memory).map_err(MetaCutError::Signable)?;
505 pass_call::<B, E, M>(&marked_data, ext_memory, full_metadata, &mut draft_registry)?;
506 pass_extensions::<B, E, M>(&marked_data, ext_memory, full_metadata, &mut draft_registry)?;
507
508 let short_registry = draft_registry.finalize_to_short();
509
510 let leaves_registry_short =
511 <ShortRegistry as HashableRegistry<E>>::merkle_leaves_source(&short_registry)
512 .map_err(MetaCutError::Registry)?;
513 let leaves_registry_long = full_metadata
514 .types()
515 .merkle_leaves_source()
516 .map_err(MetaCutError::Registry)?;
517
518 let leaves_short: Vec<[u8; LEN]> = leaves_registry_short
519 .types
520 .iter()
521 .map(|entry| Blake3Hasher::make(&entry.encode()))
522 .collect();
523 let leaves_long: Vec<[u8; LEN]> = leaves_registry_long
524 .types
525 .iter()
526 .map(|entry| Blake3Hasher::make(&entry.encode()))
527 .collect();
528
529 let proof = MerkleProofMetadata::for_leaves_subset(leaves_long, &leaves_short, ext_memory)
530 .map_err(MetaCutError::TreeCalculateProof)?;
531
532 let metadata_descriptor = MetadataDescriptor::V1 {
533 call_ty: full_metadata
534 .call_ty()
535 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
536 signed_extensions: full_metadata
537 .signed_extensions()
538 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
539 spec_name_version: full_metadata
540 .spec_name_version()
541 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
542 base58prefix: short_specs.base58prefix,
543 decimals: short_specs.decimals,
544 unit: short_specs.unit.to_owned(),
545 };
546
547 Ok(ShortMetadata {
548 short_registry,
549 indices: proof.indices(),
550 lemmas: proof.lemmas,
551 metadata_descriptor,
552 ext_memory_type: PhantomData,
553 })
554}
555
556#[cfg(any(feature = "proof-gen", test))]
561pub fn cut_metadata_transaction_unmarked<B, E, L, M>(
562 data: &B,
563 ext_memory: &mut E,
564 full_metadata: &M,
565 short_specs: &ShortSpecs,
566) -> Result<ShortMetadata<L, E>, MetaCutError<E, M>>
567where
568 B: AddressableBuffer<E>,
569 E: ExternalMemory,
570 L: Leaf<LEN, E>,
571 M: HashableMetadata<E>,
572 <M as AsMetadata<E>>::TypeRegistry: HashableRegistry<E>,
573{
574 let mut draft_registry = DraftRegistry::new();
575
576 let mut position = 0;
577 pass_call_unmarked::<B, E, M>(
578 data,
579 &mut position,
580 ext_memory,
581 full_metadata,
582 &mut draft_registry,
583 )?;
584 pass_extensions_unmarked::<B, E, M>(
585 data,
586 &mut position,
587 ext_memory,
588 full_metadata,
589 &mut draft_registry,
590 )?;
591
592 let short_registry = draft_registry.finalize_to_short();
593
594 let leaves_registry_short =
595 <ShortRegistry as HashableRegistry<E>>::merkle_leaves_source(&short_registry)
596 .map_err(MetaCutError::Registry)?;
597 let leaves_registry_long = full_metadata
598 .types()
599 .merkle_leaves_source()
600 .map_err(MetaCutError::Registry)?;
601
602 let leaves_short: Vec<[u8; LEN]> = leaves_registry_short
603 .types
604 .iter()
605 .map(|entry| Blake3Hasher::make(&entry.encode()))
606 .collect();
607 let leaves_long: Vec<[u8; LEN]> = leaves_registry_long
608 .types
609 .iter()
610 .map(|entry| Blake3Hasher::make(&entry.encode()))
611 .collect();
612
613 let proof = MerkleProofMetadata::for_leaves_subset(leaves_long, &leaves_short, ext_memory)
614 .map_err(MetaCutError::TreeCalculateProof)?;
615
616 let metadata_descriptor = MetadataDescriptor::V1 {
617 call_ty: full_metadata
618 .call_ty()
619 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
620 signed_extensions: full_metadata
621 .signed_extensions()
622 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
623 spec_name_version: full_metadata
624 .spec_name_version()
625 .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
626 base58prefix: short_specs.base58prefix,
627 decimals: short_specs.decimals,
628 unit: short_specs.unit.to_owned(),
629 };
630
631 Ok(ShortMetadata {
632 short_registry,
633 indices: proof.indices(),
634 lemmas: proof.lemmas,
635 metadata_descriptor,
636 ext_memory_type: PhantomData,
637 })
638}
639
640pub fn pass_type<B, E, M>(
642 ty_input: &Ty,
643 data: &B,
644 ext_memory: &mut E,
645 position: &mut usize,
646 registry: &M::TypeRegistry,
647 mut propagated: Propagated,
648 draft_registry: &mut DraftRegistry,
649) -> Result<(), MetaCutError<E, M>>
650where
651 B: AddressableBuffer<E>,
652 E: ExternalMemory,
653 M: AsMetadata<E>,
654{
655 let (ty, id) = match ty_input {
656 Ty::Resolved(resolved_ty) => (resolved_ty.ty.to_owned(), resolved_ty.id),
657 Ty::Symbol(ty_symbol) => (
658 registry.resolve_ty(ty_symbol.id, ext_memory).map_err(|e| {
659 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
660 })?,
661 ty_symbol.id,
662 ),
663 };
664
665 let info_ty = Info::from_ty(&ty);
666 propagated.add_info(&info_ty);
667
668 match &ty.type_def {
669 TypeDef::Composite(x) => {
670 pass_fields::<B, E, M>(
671 &x.fields,
672 data,
673 ext_memory,
674 position,
675 registry,
676 propagated.checker,
677 draft_registry,
678 )?;
679 add_ty_as_regular(draft_registry, ty.to_owned(), id).map_err(MetaCutError::Registry)
680 }
681 TypeDef::Variant(x) => {
682 propagated.reject_compact().map_err(|e| {
683 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
684 })?;
685 if !x.variants.is_empty() {
686 pass_variant::<B, E, M>(
687 &x.variants,
688 data,
689 ext_memory,
690 position,
691 registry,
692 draft_registry,
693 &info_ty.path,
694 id,
695 )
696 } else {
697 add_ty_as_regular(draft_registry, ty.to_owned(), id).map_err(MetaCutError::Registry)
698 }
699 }
700 TypeDef::Sequence(x) => {
701 let number_of_elements = get_compact::<u32, B, E>(data, ext_memory, position)
702 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(e)))?;
703 propagated.checker.drop_cycle_check();
704 pass_elements_set::<B, E, M>(
705 &x.type_param,
706 number_of_elements,
707 data,
708 ext_memory,
709 position,
710 registry,
711 propagated,
712 draft_registry,
713 )?;
714 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
715 }
716 TypeDef::Array(x) => {
717 pass_elements_set::<B, E, M>(
718 &x.type_param,
719 x.len,
720 data,
721 ext_memory,
722 position,
723 registry,
724 propagated,
725 draft_registry,
726 )?;
727 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
728 }
729 TypeDef::Tuple(x) => {
730 if x.fields.len() > 1 {
731 propagated.reject_compact().map_err(|e| {
732 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
733 })?;
734 propagated.forget_hint();
735 }
736 for inner_ty_symbol in x.fields.iter() {
737 let id = inner_ty_symbol.id;
738 let ty = registry.resolve_ty(id, ext_memory).map_err(|e| {
739 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
740 })?;
741 pass_type::<B, E, M>(
742 &Ty::Resolved(ResolvedTy {
743 ty: ty.to_owned(),
744 id,
745 }),
746 data,
747 ext_memory,
748 position,
749 registry,
750 Propagated::for_ty(&propagated.checker, &ty, id).map_err(|e| {
751 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
752 })?,
753 draft_registry,
754 )?;
755 }
756 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
757 }
758 TypeDef::Primitive(x) => {
759 decode_type_def_primitive::<B, E>(
760 x,
761 data,
762 ext_memory,
763 position,
764 propagated.checker.specialty_set,
765 )
766 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(e)))?;
767 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
768 }
769 TypeDef::Compact(x) => {
770 propagated.reject_compact().map_err(|e| {
771 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
772 })?;
773 propagated.checker.specialty_set.compact_at = Some(id);
774 propagated.checker.check_id(x.type_param.id).map_err(|e| {
775 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
776 })?;
777 pass_type::<B, E, M>(
778 &Ty::Symbol(&x.type_param),
779 data,
780 ext_memory,
781 position,
782 registry,
783 propagated,
784 draft_registry,
785 )?;
786 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
787 }
788 TypeDef::BitSequence(x) => {
789 propagated.reject_compact().map_err(|e| {
790 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
791 })?;
792 pass_type_def_bit_sequence::<B, E, M>(
793 x,
794 id,
795 data,
796 ext_memory,
797 position,
798 registry,
799 draft_registry,
800 )?;
801 add_ty_as_regular(draft_registry, ty, id).map_err(MetaCutError::Registry)
802 }
803 }
804}
805
806fn pass_fields<B, E, M>(
808 fields: &[Field<PortableForm>],
809 data: &B,
810 ext_memory: &mut E,
811 position: &mut usize,
812 registry: &M::TypeRegistry,
813 mut checker: Checker,
814 draft_registry: &mut DraftRegistry,
815) -> Result<(), MetaCutError<E, M>>
816where
817 B: AddressableBuffer<E>,
818 E: ExternalMemory,
819 M: AsMetadata<E>,
820{
821 if fields.len() > 1 {
822 checker.reject_compact().map_err(|e| {
826 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
827 })?;
828
829 checker.forget_hint();
832 }
833 for field in fields.iter() {
834 pass_type::<B, E, M>(
835 &Ty::Symbol(&field.ty),
836 data,
837 ext_memory,
838 position,
839 registry,
840 Propagated::for_field(&checker, field).map_err(|e| {
841 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
842 })?,
843 draft_registry,
844 )?;
845 }
846 Ok(())
847}
848
849#[allow(clippy::too_many_arguments)]
852fn pass_elements_set<B, E, M>(
853 element: &UntrackedSymbol<TypeId>,
854 number_of_elements: u32,
855 data: &B,
856 ext_memory: &mut E,
857 position: &mut usize,
858 registry: &M::TypeRegistry,
859 propagated: Propagated,
860 draft_registry: &mut DraftRegistry,
861) -> Result<(), MetaCutError<E, M>>
862where
863 B: AddressableBuffer<E>,
864 E: ExternalMemory,
865 M: AsMetadata<E>,
866{
867 propagated
868 .reject_compact()
869 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e))))?;
870
871 let husked = husk_type_no_info::<E, M>(
872 element,
873 registry,
874 ext_memory,
875 propagated.checker,
876 draft_registry,
877 )?;
878
879 for _i in 0..number_of_elements {
880 pass_type::<B, E, M>(
881 &Ty::Resolved(ResolvedTy {
882 ty: husked.ty.to_owned(),
883 id: husked.id,
884 }),
885 data,
886 ext_memory,
887 position,
888 registry,
889 Propagated::with_checker(husked.checker.clone()),
890 draft_registry,
891 )?;
892 }
893 Ok(())
894}
895
896#[allow(clippy::too_many_arguments)]
898fn pass_variant<B, E, M>(
899 variants: &[Variant<PortableForm>],
900 data: &B,
901 ext_memory: &mut E,
902 position: &mut usize,
903 registry: &M::TypeRegistry,
904 draft_registry: &mut DraftRegistry,
905 path: &Path<PortableForm>,
906 enum_ty_id: u32,
907) -> Result<(), MetaCutError<E, M>>
908where
909 B: AddressableBuffer<E>,
910 E: ExternalMemory,
911 M: AsMetadata<E>,
912{
913 let found_variant = pick_variant::<B, E>(variants, data, ext_memory, *position)
914 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(e)))?;
915
916 *position += ENUM_INDEX_ENCODED_LEN;
917
918 pass_fields::<B, E, M>(
919 &found_variant.fields,
920 data,
921 ext_memory,
922 position,
923 registry,
924 Checker::new(),
925 draft_registry,
926 )?;
927
928 add_as_enum(draft_registry, path, found_variant.to_owned(), enum_ty_id)
929 .map_err(MetaCutError::Registry)
930}
931
932fn pass_type_def_bit_sequence<B, E, M>(
934 bit_ty: &TypeDefBitSequence<PortableForm>,
935 id: u32,
936 data: &B,
937 ext_memory: &mut E,
938 position: &mut usize,
939 registry: &M::TypeRegistry,
940 draft_registry: &mut DraftRegistry,
941) -> Result<(), MetaCutError<E, M>>
942where
943 B: AddressableBuffer<E>,
944 E: ExternalMemory,
945 M: AsMetadata<E>,
946{
947 let bitorder_type = registry
949 .resolve_ty(bit_ty.bit_order_type.id, ext_memory)
950 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e))))?;
951 add_ty_as_regular(draft_registry, bitorder_type, bit_ty.bit_order_type.id)
952 .map_err(MetaCutError::Registry)?;
953
954 let bitstore_type = registry
956 .resolve_ty(bit_ty.bit_store_type.id, ext_memory)
957 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e))))?;
958
959 match bitstore_type.type_def {
960 TypeDef::Primitive(TypeDefPrimitive::U8) => {
961 pass_bitvec_decode::<u8, B, E>(data, ext_memory, position)
962 }
963 TypeDef::Primitive(TypeDefPrimitive::U16) => {
964 pass_bitvec_decode::<u16, B, E>(data, ext_memory, position)
965 }
966 TypeDef::Primitive(TypeDefPrimitive::U32) => {
967 pass_bitvec_decode::<u32, B, E>(data, ext_memory, position)
968 }
969 TypeDef::Primitive(TypeDefPrimitive::U64) => {
970 pass_bitvec_decode::<u64, B, E>(data, ext_memory, position)
971 }
972 _ => Err(ParserError::Registry(RegistryError::NotBitStoreType { id })),
973 }
974 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(e)))?;
975
976 add_ty_as_regular(draft_registry, bitstore_type, bit_ty.bit_store_type.id)
977 .map_err(MetaCutError::Registry)
978}
979
980fn pass_bitvec_decode<'a, T, B, E>(
982 data: &B,
983 ext_memory: &'a mut E,
984 position: &'a mut usize,
985) -> Result<(), ParserError<E>>
986where
987 B: AddressableBuffer<E>,
988 E: ExternalMemory,
989{
990 let bitvec_positions = BitVecPositions::new::<T, B, E>(data, ext_memory, *position)?;
991 *position = bitvec_positions.bitvec_end;
992 Ok(())
993}
994
995struct HuskedTypeNoInfo {
1006 checker: Checker,
1007 ty: Type<PortableForm>,
1008 id: u32,
1009}
1010
1011fn husk_type_no_info<E, M>(
1015 entry_symbol: &UntrackedSymbol<TypeId>,
1016 registry: &M::TypeRegistry,
1017 ext_memory: &mut E,
1018 mut checker: Checker,
1019 draft_registry: &mut DraftRegistry,
1020) -> Result<HuskedTypeNoInfo, MetaCutError<E, M>>
1021where
1022 E: ExternalMemory,
1023 M: AsMetadata<E>,
1024{
1025 let entry_symbol_id = entry_symbol.id;
1026 checker
1027 .check_id(entry_symbol_id)
1028 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e))))?;
1029 checker.specialty_set = SpecialtySet {
1030 compact_at: None,
1031 hint: Hint::None,
1032 };
1033
1034 let mut ty = registry
1035 .resolve_ty(entry_symbol_id, ext_memory)
1036 .map_err(|e| MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e))))?;
1037 let mut id = entry_symbol_id;
1038
1039 while let SpecialtyTypeHinted::None = SpecialtyTypeHinted::from_type(&ty) {
1040 let type_def = ty.type_def.to_owned();
1041 match type_def {
1042 TypeDef::Composite(x) => {
1043 if x.fields.len() == 1 {
1044 add_ty_as_regular(draft_registry, ty.to_owned(), id)
1045 .map_err(MetaCutError::Registry)?;
1046 id = x.fields[0].ty.id;
1047 checker.check_id(id).map_err(|e| {
1048 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
1049 })?;
1050 ty = registry.resolve_ty(id, ext_memory).map_err(|e| {
1051 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
1052 })?;
1053 if let Hint::None = checker.specialty_set.hint {
1054 checker.specialty_set.hint = Hint::from_field(&x.fields[0])
1055 }
1056 } else {
1057 break;
1058 }
1059 }
1060 TypeDef::Compact(x) => {
1061 add_ty_as_regular(draft_registry, ty.to_owned(), id)
1062 .map_err(MetaCutError::Registry)?;
1063 checker.reject_compact().map_err(|e| {
1064 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
1065 })?;
1066 checker.specialty_set.compact_at = Some(id);
1067 id = x.type_param.id;
1068 checker.check_id(id).map_err(|e| {
1069 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
1070 })?;
1071 ty = registry.resolve_ty(id, ext_memory).map_err(|e| {
1072 MetaCutError::Signable(SignableError::Parsing(ParserError::Registry(e)))
1073 })?;
1074 }
1075 _ => break,
1076 }
1077 }
1078
1079 Ok(HuskedTypeNoInfo { checker, ty, id })
1080}
1081
1082#[cfg(test)]
1083mod tests {
1084 use super::*;
1085 use scale_info::{Path, PortableRegistry};
1086
1087 use crate::std::string::ToString;
1088
1089 #[test]
1090 fn sort_draft_registry() {
1091 let mut draft_registry = DraftRegistry::new();
1092 add_as_enum(
1093 &mut draft_registry,
1094 &Path::<PortableForm> {
1095 segments: vec!["test".to_string(), "Path".to_string()],
1096 },
1097 Variant::<PortableForm> {
1098 name: "OtherVariant".to_string(),
1099 fields: Vec::new(),
1100 index: 3u8,
1101 docs: Vec::new(),
1102 },
1103 144,
1104 )
1105 .unwrap();
1106 add_as_enum(
1107 &mut draft_registry,
1108 &Path::<PortableForm> {
1109 segments: vec!["test".to_string(), "Path".to_string()],
1110 },
1111 Variant::<PortableForm> {
1112 name: "SomeVariant".to_string(),
1113 fields: Vec::new(),
1114 index: 1u8,
1115 docs: Vec::new(),
1116 },
1117 144,
1118 )
1119 .unwrap();
1120 add_as_enum(
1121 &mut draft_registry,
1122 &Path::<PortableForm> {
1123 segments: vec!["test".to_string(), "Path".to_string()],
1124 },
1125 Variant::<PortableForm> {
1126 name: "ThirdVariant".to_string(),
1127 fields: Vec::new(),
1128 index: 7u8,
1129 docs: Vec::new(),
1130 },
1131 144,
1132 )
1133 .unwrap();
1134
1135 let to_short = draft_registry.finalize_to_short();
1136 assert_eq!(
1137 to_short,
1138 ShortRegistry {
1139 types: vec![PortableType {
1140 id: 144,
1141 ty: Type {
1142 path: Path {
1143 segments: vec!["test".to_string(), "Path".to_string()]
1144 },
1145 type_params: Vec::new(),
1146 type_def: TypeDef::Variant(TypeDefVariant {
1147 variants: vec![
1148 Variant {
1149 name: "SomeVariant".to_string(),
1150 fields: Vec::new(),
1151 index: 1,
1152 docs: Vec::new()
1153 },
1154 Variant {
1155 name: "OtherVariant".to_string(),
1156 fields: Vec::new(),
1157 index: 3,
1158 docs: Vec::new()
1159 },
1160 Variant {
1161 name: "ThirdVariant".to_string(),
1162 fields: Vec::new(),
1163 index: 7,
1164 docs: Vec::new()
1165 }
1166 ]
1167 }),
1168 docs: Vec::new()
1169 }
1170 }]
1171 }
1172 );
1173
1174 let leaves = draft_registry.into_leaves();
1175 assert_eq!(
1176 leaves,
1177 LeavesRegistry {
1178 types: vec![
1179 PortableType {
1180 id: 144,
1181 ty: Type {
1182 path: Path {
1183 segments: vec!["test".to_string(), "Path".to_string()]
1184 },
1185 type_params: Vec::new(),
1186 type_def: TypeDef::Variant(TypeDefVariant {
1187 variants: vec![Variant {
1188 name: "SomeVariant".to_string(),
1189 fields: Vec::new(),
1190 index: 1,
1191 docs: Vec::new()
1192 }]
1193 }),
1194 docs: Vec::new()
1195 }
1196 },
1197 PortableType {
1198 id: 144,
1199 ty: Type {
1200 path: Path {
1201 segments: vec!["test".to_string(), "Path".to_string()]
1202 },
1203 type_params: Vec::new(),
1204 type_def: TypeDef::Variant(TypeDefVariant {
1205 variants: vec![Variant {
1206 name: "OtherVariant".to_string(),
1207 fields: Vec::new(),
1208 index: 3,
1209 docs: Vec::new()
1210 }]
1211 }),
1212 docs: Vec::new()
1213 }
1214 },
1215 PortableType {
1216 id: 144,
1217 ty: Type {
1218 path: Path {
1219 segments: vec!["test".to_string(), "Path".to_string()]
1220 },
1221 type_params: Vec::new(),
1222 type_def: TypeDef::Variant(TypeDefVariant {
1223 variants: vec![Variant {
1224 name: "ThirdVariant".to_string(),
1225 fields: Vec::new(),
1226 index: 7,
1227 docs: Vec::new()
1228 }]
1229 }),
1230 docs: Vec::new()
1231 }
1232 }
1233 ]
1234 }
1235 );
1236 }
1237
1238 #[test]
1239 fn keep_empty_enums_portable() {
1240 let portable_registry = PortableRegistry {
1241 types: vec![PortableType {
1242 id: 0,
1243 ty: Type {
1244 path: Path {
1245 segments: vec!["test".to_string(), "Path".to_string()],
1246 },
1247 type_params: Vec::new(),
1248 type_def: TypeDef::Variant(TypeDefVariant { variants: vec![] }),
1249 docs: vec![
1250 "important information".to_string(),
1251 "danger ahead".to_string(),
1252 ],
1253 },
1254 }],
1255 };
1256 let leaves_registry =
1257 <PortableRegistry as HashableRegistry<()>>::merkle_leaves_source(&portable_registry)
1258 .unwrap();
1259 assert_eq!(leaves_registry.types.len(), 1,);
1260 }
1261
1262 #[test]
1263 fn keep_empty_enums_short() {
1264 let short_registry = ShortRegistry {
1265 types: vec![PortableType {
1266 id: 15,
1267 ty: Type {
1268 path: Path {
1269 segments: vec!["test".to_string(), "Path".to_string()],
1270 },
1271 type_params: Vec::new(),
1272 type_def: TypeDef::Variant(TypeDefVariant { variants: vec![] }),
1273 docs: vec![
1274 "important information".to_string(),
1275 "danger ahead".to_string(),
1276 ],
1277 },
1278 }],
1279 };
1280 let leaves_registry =
1281 <ShortRegistry as HashableRegistry<()>>::merkle_leaves_source(&short_registry).unwrap();
1282 assert_eq!(leaves_registry.types.len(), 1,);
1283 }
1284}