Skip to main content

concordium_contracts_common/
schema.rs

1//! Types related to contract schemas.
2//! These are optional annotations in modules that allow
3//! the users of smart contracts to interact with them in
4//! a way that is better than constructing raw bytes as parameters.
5
6use crate::{impls::*, traits::*, types::*};
7#[cfg(not(feature = "std"))]
8use alloc::boxed::Box;
9#[cfg(not(feature = "std"))]
10use alloc::{collections, string::String, vec::Vec};
11use collections::{BTreeMap, BTreeSet};
12#[cfg(not(feature = "std"))]
13use core::{
14    convert::{TryFrom, TryInto},
15    num::TryFromIntError,
16};
17#[cfg(feature = "derive-serde")]
18pub use impls::VersionedSchemaError;
19/// Contract schema related types
20#[cfg(feature = "std")]
21use std::{
22    collections,
23    convert::{TryFrom, TryInto},
24    num::TryFromIntError,
25};
26
27/// The `SchemaType` trait provides means to generate a schema for structures.
28/// Schemas are used to make structures human readable and to avoid dealing
29/// directly with bytes, such as the contract state or parameters for contract
30/// interaction.
31///
32/// Can be derived using `#[derive(SchemaType)]` for most cases of structs and
33/// enums.
34pub trait SchemaType {
35    fn get_type() -> crate::schema::Type;
36}
37
38/// Contains all the contract schemas for a smart contract module V0.
39///
40/// Older versions of smart contracts might have this embedded in the custom
41/// section labelled `concordium-schema-v1`.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct ModuleV0 {
44    pub contracts: BTreeMap<String, ContractV0>,
45}
46
47/// Contains all the contract schemas for a smart contract module V1.
48///
49/// Older versions of smart contracts might have this embedded in the custom
50/// section labelled `concordium-schema-v2`.
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct ModuleV1 {
53    pub contracts: BTreeMap<String, ContractV1>,
54}
55
56/// Contains all the contract schemas for a smart contract module V1 with a V2
57/// schema.
58#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct ModuleV2 {
60    pub contracts: BTreeMap<String, ContractV2>,
61}
62
63/// Contains all the contract schemas for a smart contract module V1 with a V3
64/// schema.
65#[cfg_attr(test, derive(arbitrary::Arbitrary))]
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct ModuleV3 {
68    pub contracts: BTreeMap<String, ContractV3>,
69}
70
71/// Represents the different schema versions.
72///
73/// The serialization of this type includes the versioning information. The
74/// serialization of this is always prefixed with two 255u8 in order to
75/// distinguish this versioned schema from the unversioned.
76///
77/// When embedded into a smart contract module, name the custom section
78/// `concordium-schema`.
79#[derive(Debug, Clone)]
80pub enum VersionedModuleSchema {
81    /// Version 0 schema, only supported by V0 smart contracts.
82    V0(ModuleV0),
83    /// Version 1 schema, only supported by V1 smart contracts.
84    V1(ModuleV1),
85    /// Version 2 schema, only supported by V1 smart contracts.
86    V2(ModuleV2),
87    /// Version 3 schema, only supported by V1 smart contracts.
88    V3(ModuleV3),
89}
90
91/// Describes all the schemas of a V0 smart contract.
92/// The [`Default`] instance produces an empty schema.
93#[derive(Debug, Default, Clone, PartialEq, Eq)]
94pub struct ContractV0 {
95    pub state:   Option<Type>,
96    pub init:    Option<Type>,
97    pub receive: BTreeMap<String, Type>,
98}
99
100/// Describes all the schemas of a V1 smart contract.
101#[derive(Debug, Default, Clone, PartialEq, Eq)]
102/// The [`Default`] instance produces an empty schema.
103pub struct ContractV1 {
104    pub init:    Option<FunctionV1>,
105    pub receive: BTreeMap<String, FunctionV1>,
106}
107
108/// Describes all the schemas of a V1 smart contract with a V2 schema.
109#[derive(Debug, Default, Clone, PartialEq, Eq)]
110/// The [`Default`] instance produces an empty schema.
111pub struct ContractV2 {
112    pub init:    Option<FunctionV2>,
113    pub receive: BTreeMap<String, FunctionV2>,
114}
115
116/// Describes all the schemas of a V1 smart contract with a V3 schema.
117#[cfg_attr(test, derive(arbitrary::Arbitrary))]
118#[derive(Debug, Default, Clone, PartialEq, Eq)]
119/// The [`Default`] instance produces an empty schema.
120pub struct ContractV3 {
121    pub init:    Option<FunctionV2>,
122    pub receive: BTreeMap<String, FunctionV2>,
123    pub event:   Option<Type>,
124}
125
126impl ContractV3 {
127    /// Extract the event schema if it exists.
128    pub fn event(&self) -> Option<&Type> { self.event.as_ref() }
129}
130
131/// Describes the schema of an init or a receive function for V1 contracts with
132/// V1 schemas.
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub enum FunctionV1 {
135    Parameter(Type),
136    ReturnValue(Type),
137    Both {
138        parameter:    Type,
139        return_value: Type,
140    },
141}
142
143impl FunctionV1 {
144    /// Extract the parameter schema if it exists.
145    pub fn parameter(&self) -> Option<&Type> {
146        match self {
147            FunctionV1::Parameter(ty) => Some(ty),
148            FunctionV1::ReturnValue(_) => None,
149            FunctionV1::Both {
150                parameter,
151                ..
152            } => Some(parameter),
153        }
154    }
155
156    /// Extract the return value schema if it exists.
157    pub fn return_value(&self) -> Option<&Type> {
158        match self {
159            FunctionV1::Parameter(_) => None,
160            FunctionV1::ReturnValue(rv) => Some(rv),
161            FunctionV1::Both {
162                return_value,
163                ..
164            } => Some(return_value),
165        }
166    }
167}
168
169/// Describes the schema of an init or a receive function for V1 contracts with
170/// V3 schemas. Differs from [`FunctionV1`] in that a schema for the error can
171/// be included.
172#[cfg_attr(test, derive(arbitrary::Arbitrary))]
173#[derive(Debug, Clone, PartialEq, Eq)]
174pub struct FunctionV2 {
175    pub parameter:    Option<Type>,
176    pub return_value: Option<Type>,
177    pub error:        Option<Type>,
178}
179
180impl FunctionV2 {
181    /// Extract the parameter schema if it exists.
182    pub fn parameter(&self) -> Option<&Type> { self.parameter.as_ref() }
183
184    /// Extract the return value schema if it exists.
185    pub fn return_value(&self) -> Option<&Type> { self.return_value.as_ref() }
186
187    /// Extract the error schema if it exists.
188    pub fn error(&self) -> Option<&Type> { self.error.as_ref() }
189}
190
191/// Schema for the fields of a struct or some enum variant.
192#[derive(Debug, Clone, PartialEq, Eq)]
193#[cfg_attr(test, derive(arbitrary::Arbitrary))]
194pub enum Fields {
195    /// Named fields, e.g., `struct Foo {x: u64, y: u32}`.
196    Named(Vec<(String, Type)>),
197    /// Unnamed fields, e.g., `struct Foo(u64, u32)`
198    Unnamed(Vec<Type>),
199    /// No fields. Note that this is distinct from an empty set of named or
200    /// unnamed fields. That is, in Rust there is a (albeit trivial) difference
201    /// between `struct Foo {}`, `struct Foo`, and `struct Foo()`, all of which
202    /// are valid, but will have different representations.
203    None,
204}
205
206/// Type of the variable used to encode the length of Sets, List, Maps
207#[derive(Debug, Copy, Clone, PartialEq, Eq)]
208#[cfg_attr(test, derive(arbitrary::Arbitrary))]
209pub enum SizeLength {
210    U8,
211    U16,
212    U32,
213    U64,
214}
215
216/// Schema type used to describe the different types in a smart contract, their
217/// serialization and how to represent the types in JSON.
218#[derive(Debug, Clone, PartialEq, Eq)]
219#[cfg_attr(test, derive(arbitrary::Arbitrary))]
220pub enum Type {
221    /// A type with no serialization.
222    Unit,
223    /// Boolean. Serialized as a byte, where the value 0 is false and 1 is true.
224    Bool,
225    /// Unsigned 8-bit integer.
226    U8,
227    /// Unsigned 16-bit integer. Serialized as little endian.
228    U16,
229    /// Unsigned 32-bit integer. Serialized as little endian.
230    U32,
231    /// Unsigned 64-bit integer. Serialized as little endian.
232    U64,
233    /// Unsigned 128-bit integer. Serialized as little endian.
234    U128,
235    /// Signed 8-bit integer. Serialized as little endian.
236    I8,
237    /// Signed 16-bit integer. Serialized as little endian.
238    I16,
239    /// Signed 32-bit integer. Serialized as little endian.
240    I32,
241    /// Signed 64-bit integer. Serialized as little endian.
242    I64,
243    /// Signed 128-bit integer. Serialized as little endian.
244    I128,
245    /// An amount of CCD. Serialized as 64-bit unsigned integer little endian.
246    Amount,
247    /// An account address.
248    AccountAddress,
249    /// A contract address.
250    ContractAddress,
251    /// A timestamp. Represented as milliseconds since Unix epoch. Serialized as
252    /// a 64-bit unsigned integer little endian.
253    Timestamp,
254    /// A duration of milliseconds, cannot be negative. Serialized as a 64-bit
255    /// unsigned integer little endian.
256    Duration,
257    /// A pair.
258    Pair(Box<Type>, Box<Type>),
259    /// A list. It is serialized with the length first followed by the list
260    /// items.
261    List(SizeLength, Box<Type>),
262    /// A Set. It is serialized with the length first followed by the list
263    /// items.
264    Set(SizeLength, Box<Type>),
265    /// A Map. It is serialized with the length first followed by key-value
266    /// pairs of the entries.
267    Map(SizeLength, Box<Type>, Box<Type>),
268    /// A fixed sized list.
269    Array(u32, Box<Type>),
270    /// A structure type with fields.
271    Struct(Fields),
272    /// A sum type.
273    Enum(Vec<(String, Fields)>),
274    /// A UTF8 String. It is serialized with the length first followed by the
275    /// encoding of the string.
276    String(SizeLength),
277    /// A smart contract name. It is serialized with the length first followed
278    /// by the ASCII encoding of the name.
279    ContractName(SizeLength),
280    /// A smart contract receive function name. It is serialized with the length
281    /// first followed by the ASCII encoding of the name.
282    ReceiveName(SizeLength),
283    /// An unsigned integer encoded using LEB128 with the addition of a
284    /// constraint on the maximum number of bytes to use for an encoding.
285    ULeb128(u32),
286    /// A signed integer encoded using LEB128 with the addition of a constraint
287    /// on the maximum number of bytes to use for an encoding.
288    ILeb128(u32),
289    /// A list of bytes. It is serialized with the length first followed by the
290    /// bytes.
291    ByteList(SizeLength),
292    /// A fixed sized list of bytes.
293    ByteArray(u32),
294    /// An enum with a tag.
295    TaggedEnum(BTreeMap<u8, (String, Fields)>),
296}
297
298impl Type {
299    #[doc(hidden)]
300    /// Sets the size_length of schema types, with variable size otherwise
301    /// it is a noop. Used when deriving SchemaType.
302    pub fn set_size_length(self, size_len: SizeLength) -> Type {
303        match self {
304            Type::List(_, ty) => Type::List(size_len, ty),
305            Type::Set(_, ty) => Type::Set(size_len, ty),
306            Type::Map(_, key_ty, val_ty) => Type::Map(size_len, key_ty, val_ty),
307            Type::String(_) => Type::String(size_len),
308            Type::ByteList(_) => Type::ByteList(size_len),
309            t => t,
310        }
311    }
312}
313
314impl SchemaType for () {
315    fn get_type() -> Type { Type::Unit }
316}
317impl SchemaType for bool {
318    fn get_type() -> Type { Type::Bool }
319}
320impl SchemaType for u8 {
321    fn get_type() -> Type { Type::U8 }
322}
323impl SchemaType for u16 {
324    fn get_type() -> Type { Type::U16 }
325}
326impl SchemaType for u32 {
327    fn get_type() -> Type { Type::U32 }
328}
329impl SchemaType for u64 {
330    fn get_type() -> Type { Type::U64 }
331}
332impl SchemaType for u128 {
333    fn get_type() -> Type { Type::U128 }
334}
335impl SchemaType for i8 {
336    fn get_type() -> Type { Type::I8 }
337}
338impl SchemaType for i16 {
339    fn get_type() -> Type { Type::I16 }
340}
341impl SchemaType for i32 {
342    fn get_type() -> Type { Type::I32 }
343}
344impl SchemaType for i64 {
345    fn get_type() -> Type { Type::I64 }
346}
347impl SchemaType for i128 {
348    fn get_type() -> Type { Type::I128 }
349}
350impl SchemaType for Amount {
351    fn get_type() -> Type { Type::Amount }
352}
353impl SchemaType for ModuleReference {
354    fn get_type() -> Type { Type::ByteArray(32) }
355}
356impl SchemaType for AccountAddress {
357    fn get_type() -> Type { Type::AccountAddress }
358}
359impl SchemaType for ContractAddress {
360    fn get_type() -> Type { Type::ContractAddress }
361}
362impl SchemaType for Address {
363    fn get_type() -> Type {
364        Type::Enum(Vec::from([
365            (String::from("Account"), Fields::Unnamed(Vec::from([Type::AccountAddress]))),
366            (String::from("Contract"), Fields::Unnamed(Vec::from([Type::ContractAddress]))),
367        ]))
368    }
369}
370impl SchemaType for Timestamp {
371    fn get_type() -> Type { Type::Timestamp }
372}
373impl SchemaType for Duration {
374    fn get_type() -> Type { Type::Duration }
375}
376impl<T: SchemaType> SchemaType for Option<T> {
377    fn get_type() -> Type {
378        Type::Enum(Vec::from([
379            (String::from("None"), Fields::None),
380            (String::from("Some"), Fields::Unnamed(Vec::from([T::get_type()]))),
381        ]))
382    }
383}
384impl<L: SchemaType, R: SchemaType> SchemaType for (L, R) {
385    fn get_type() -> Type { Type::Pair(Box::new(L::get_type()), Box::new(R::get_type())) }
386}
387impl<T: SchemaType> SchemaType for Vec<T> {
388    fn get_type() -> Type { Type::List(SizeLength::U32, Box::new(T::get_type())) }
389}
390impl<T: SchemaType> SchemaType for BTreeSet<T> {
391    fn get_type() -> Type { Type::Set(SizeLength::U32, Box::new(T::get_type())) }
392}
393impl<K: SchemaType, V: SchemaType> SchemaType for BTreeMap<K, V> {
394    fn get_type() -> Type {
395        Type::Map(SizeLength::U32, Box::new(K::get_type()), Box::new(V::get_type()))
396    }
397}
398impl<T: SchemaType> SchemaType for HashSet<T> {
399    fn get_type() -> Type { Type::Set(SizeLength::U32, Box::new(T::get_type())) }
400}
401impl<K: SchemaType, V: SchemaType> SchemaType for HashMap<K, V> {
402    fn get_type() -> Type {
403        Type::Map(SizeLength::U32, Box::new(K::get_type()), Box::new(V::get_type()))
404    }
405}
406impl SchemaType for [u8] {
407    fn get_type() -> Type { Type::ByteList(SizeLength::U32) }
408}
409
410impl SchemaType for String {
411    fn get_type() -> Type { Type::String(SizeLength::U32) }
412}
413
414impl SchemaType for &str {
415    fn get_type() -> Type { String::get_type() }
416}
417
418impl SchemaType for OwnedContractName {
419    fn get_type() -> Type { Type::ContractName(SizeLength::U16) }
420}
421
422impl SchemaType for OwnedReceiveName {
423    fn get_type() -> Type { Type::ReceiveName(SizeLength::U16) }
424}
425
426impl SchemaType for OwnedEntrypointName {
427    fn get_type() -> Type { Type::String(SizeLength::U16) }
428}
429
430impl SchemaType for OwnedParameter {
431    fn get_type() -> Type { Type::ByteList(SizeLength::U16) }
432}
433
434impl<A: SchemaType, const N: usize> SchemaType for [A; N] {
435    fn get_type() -> Type { Type::Array(N.try_into().unwrap(), Box::new(A::get_type())) }
436}
437
438impl<Kind> SchemaType for NonZeroThresholdU8<Kind> {
439    // This is not entirely ideal since it won't check if the threshold is 0, but
440    // at present we do not have a type that is better suited.
441    fn get_type() -> Type { u8::get_type() }
442}
443
444impl Serial for Fields {
445    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
446        match self {
447            Fields::Named(fields) => {
448                out.write_u8(0)?;
449                fields.serial(out)?;
450            }
451            Fields::Unnamed(fields) => {
452                out.write_u8(1)?;
453                fields.serial(out)?;
454            }
455            Fields::None => {
456                out.write_u8(2)?;
457            }
458        }
459        Ok(())
460    }
461}
462
463impl Deserial for Fields {
464    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
465        let idx = source.read_u8()?;
466        match idx {
467            0 => Ok(Fields::Named(source.get()?)),
468            1 => Ok(Fields::Unnamed(source.get()?)),
469            2 => Ok(Fields::None),
470            _ => Err(ParseError::default()),
471        }
472    }
473}
474
475impl Serial for ModuleV0 {
476    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
477        self.contracts.serial(out)?;
478        Ok(())
479    }
480}
481
482impl Serial for ModuleV1 {
483    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
484        self.contracts.serial(out)?;
485        Ok(())
486    }
487}
488
489impl Serial for ModuleV2 {
490    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
491        self.contracts.serial(out)?;
492        Ok(())
493    }
494}
495
496impl Serial for ModuleV3 {
497    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
498        self.contracts.serial(out)?;
499        Ok(())
500    }
501}
502
503impl Serial for VersionedModuleSchema {
504    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
505        // Prefix for versioned module schema, used to distinquish from the unversioned.
506        out.write_u16(u16::MAX)?;
507        match self {
508            VersionedModuleSchema::V0(module) => {
509                out.write_u8(0)?;
510                module.serial(out)?;
511            }
512            VersionedModuleSchema::V1(module) => {
513                out.write_u8(1)?;
514                module.serial(out)?;
515            }
516            VersionedModuleSchema::V2(module) => {
517                out.write_u8(2)?;
518                module.serial(out)?;
519            }
520            VersionedModuleSchema::V3(module) => {
521                out.write_u8(3)?;
522                module.serial(out)?;
523            }
524        }
525        Ok(())
526    }
527}
528
529impl Deserial for ModuleV0 {
530    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
531        let len: u32 = source.get()?;
532        let contracts = deserial_map_no_length_no_order_check(source, len as usize)?;
533        Ok(ModuleV0 {
534            contracts,
535        })
536    }
537}
538
539impl Deserial for ModuleV1 {
540    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
541        let len: u32 = source.get()?;
542        let contracts = deserial_map_no_length_no_order_check(source, len as usize)?;
543        Ok(ModuleV1 {
544            contracts,
545        })
546    }
547}
548
549impl Deserial for ModuleV2 {
550    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
551        let len: u32 = source.get()?;
552        let contracts = deserial_map_no_length_no_order_check(source, len as usize)?;
553        Ok(ModuleV2 {
554            contracts,
555        })
556    }
557}
558
559impl Deserial for ModuleV3 {
560    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
561        let len: u32 = source.get()?;
562        let contracts = deserial_map_no_length_no_order_check(source, len as usize)?;
563        Ok(ModuleV3 {
564            contracts,
565        })
566    }
567}
568
569impl Deserial for VersionedModuleSchema {
570    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
571        // First we ensure the prefix is correct.
572        let prefix = source.read_u16()?;
573        if prefix != u16::MAX {
574            return Err(ParseError {});
575        }
576        let version = source.read_u8()?;
577        match version {
578            0 => {
579                let module = source.get()?;
580                Ok(VersionedModuleSchema::V0(module))
581            }
582            1 => {
583                let module = source.get()?;
584                Ok(VersionedModuleSchema::V1(module))
585            }
586            2 => {
587                let module = source.get()?;
588                Ok(VersionedModuleSchema::V2(module))
589            }
590            3 => {
591                let module = source.get()?;
592                Ok(VersionedModuleSchema::V3(module))
593            }
594            _ => Err(ParseError {}),
595        }
596    }
597}
598
599impl Serial for ContractV0 {
600    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
601        self.state.serial(out)?;
602        self.init.serial(out)?;
603        self.receive.serial(out)?;
604        Ok(())
605    }
606}
607
608impl Serial for ContractV1 {
609    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
610        self.init.serial(out)?;
611        self.receive.serial(out)?;
612        Ok(())
613    }
614}
615
616impl Serial for ContractV2 {
617    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
618        self.init.serial(out)?;
619        self.receive.serial(out)?;
620        Ok(())
621    }
622}
623
624impl Serial for ContractV3 {
625    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
626        self.init.serial(out)?;
627        self.receive.serial(out)?;
628        self.event.serial(out)?;
629        Ok(())
630    }
631}
632
633impl Deserial for ContractV0 {
634    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
635        let state = source.get()?;
636        let init = source.get()?;
637        let len: u32 = source.get()?;
638        let receive = deserial_map_no_length_no_order_check(source, len as usize)?;
639        Ok(ContractV0 {
640            state,
641            init,
642            receive,
643        })
644    }
645}
646
647impl Deserial for ContractV1 {
648    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
649        let init = source.get()?;
650        let len: u32 = source.get()?;
651        let receive = deserial_map_no_length_no_order_check(source, len as usize)?;
652        Ok(ContractV1 {
653            init,
654            receive,
655        })
656    }
657}
658
659impl Deserial for ContractV2 {
660    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
661        let init = source.get()?;
662        let len: u32 = source.get()?;
663        let receive = deserial_map_no_length_no_order_check(source, len as usize)?;
664        Ok(ContractV2 {
665            init,
666            receive,
667        })
668    }
669}
670
671impl Deserial for ContractV3 {
672    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
673        let init = source.get()?;
674        let len: u32 = source.get()?;
675        let receive = deserial_map_no_length_no_order_check(source, len as usize)?;
676        let event = source.get()?;
677        Ok(ContractV3 {
678            init,
679            receive,
680            event,
681        })
682    }
683}
684
685impl Serial for FunctionV1 {
686    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
687        match self {
688            FunctionV1::Parameter(parameter) => {
689                out.write_u8(0)?;
690                parameter.serial(out)
691            }
692            FunctionV1::ReturnValue(return_value) => {
693                out.write_u8(1)?;
694                return_value.serial(out)
695            }
696            FunctionV1::Both {
697                parameter,
698                return_value,
699            } => {
700                out.write_u8(2)?;
701                parameter.serial(out)?;
702                return_value.serial(out)
703            }
704        }
705    }
706}
707
708impl Deserial for FunctionV1 {
709    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
710        let idx = source.read_u8()?;
711        match idx {
712            0 => Ok(FunctionV1::Parameter(source.get()?)),
713            1 => Ok(FunctionV1::ReturnValue(source.get()?)),
714            2 => Ok(FunctionV1::Both {
715                parameter:    source.get()?,
716                return_value: source.get()?,
717            }),
718            _ => Err(ParseError::default()),
719        }
720    }
721}
722
723impl Serial for FunctionV2 {
724    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
725        let parameter = self.parameter.is_some();
726        let return_value = self.return_value.is_some();
727        let error = self.error.is_some();
728        let tag: u8 = match (parameter, return_value, error) {
729            // parameter
730            (true, false, false) => 0,
731            // return_value
732            (false, true, false) => 1,
733            // parameter + return_value
734            (true, true, false) => 2,
735            // error
736            (false, false, true) => 3,
737            // parameter + error
738            (true, false, true) => 4,
739            // return_value + error
740            (false, true, true) => 5,
741            // parameter + return_value + error
742            (true, true, true) => 6,
743            // no schema
744            (false, false, false) => 7,
745        };
746        out.write_u8(tag)?;
747        if let Some(p) = self.parameter.as_ref() {
748            p.serial(out)?;
749        }
750        if let Some(rv) = self.return_value.as_ref() {
751            rv.serial(out)?;
752        }
753        if let Some(err) = self.error.as_ref() {
754            err.serial(out)?;
755        }
756        Ok(())
757    }
758}
759
760impl Deserial for FunctionV2 {
761    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
762        let idx = source.read_u8()?;
763        let mut r = FunctionV2 {
764            parameter:    None,
765            return_value: None,
766            error:        None,
767        };
768        if idx > 7 {
769            return Err(ParseError::default());
770        }
771        if matches!(idx, 0 | 2 | 4 | 6) {
772            let _ = r.parameter.insert(source.get()?);
773        }
774        if matches!(idx, 1 | 2 | 5 | 6) {
775            let _ = r.return_value.insert(source.get()?);
776        }
777        if matches!(idx, 3..=6) {
778            let _ = r.error.insert(source.get()?);
779        }
780        Ok(r)
781    }
782}
783
784impl Serial for SizeLength {
785    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
786        match self {
787            SizeLength::U8 => out.write_u8(0)?,
788            SizeLength::U16 => out.write_u8(1)?,
789            SizeLength::U32 => out.write_u8(2)?,
790            SizeLength::U64 => out.write_u8(3)?,
791        }
792        Ok(())
793    }
794}
795
796impl Deserial for SizeLength {
797    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
798        let idx = source.read_u8()?;
799        match idx {
800            0 => Ok(SizeLength::U8),
801            1 => Ok(SizeLength::U16),
802            2 => Ok(SizeLength::U32),
803            3 => Ok(SizeLength::U64),
804            _ => Err(ParseError::default()),
805        }
806    }
807}
808
809impl Serial for Type {
810    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
811        match self {
812            Type::Unit => out.write_u8(0),
813            Type::Bool => out.write_u8(1),
814            Type::U8 => out.write_u8(2),
815            Type::U16 => out.write_u8(3),
816            Type::U32 => out.write_u8(4),
817            Type::U64 => out.write_u8(5),
818            Type::I8 => out.write_u8(6),
819            Type::I16 => out.write_u8(7),
820            Type::I32 => out.write_u8(8),
821            Type::I64 => out.write_u8(9),
822            Type::Amount => out.write_u8(10),
823            Type::AccountAddress => out.write_u8(11),
824            Type::ContractAddress => out.write_u8(12),
825            Type::Timestamp => out.write_u8(13),
826            Type::Duration => out.write_u8(14),
827            Type::Pair(left, right) => {
828                out.write_u8(15)?;
829                left.serial(out)?;
830                right.serial(out)
831            }
832            Type::List(len_size, ty) => {
833                out.write_u8(16)?;
834                len_size.serial(out)?;
835                ty.serial(out)
836            }
837            Type::Set(len_size, ty) => {
838                out.write_u8(17)?;
839                len_size.serial(out)?;
840                ty.serial(out)
841            }
842            Type::Map(len_size, key, value) => {
843                out.write_u8(18)?;
844                len_size.serial(out)?;
845                key.serial(out)?;
846                value.serial(out)
847            }
848            Type::Array(len, ty) => {
849                out.write_u8(19)?;
850                len.serial(out)?;
851                ty.serial(out)
852            }
853            Type::Struct(fields) => {
854                out.write_u8(20)?;
855                fields.serial(out)
856            }
857            Type::Enum(fields) => {
858                out.write_u8(21)?;
859                fields.serial(out)
860            }
861            Type::String(len) => {
862                out.write_u8(22)?;
863                len.serial(out)
864            }
865            Type::U128 => out.write_u8(23),
866            Type::I128 => out.write_u8(24),
867            Type::ContractName(len_size) => {
868                out.write_u8(25)?;
869                len_size.serial(out)
870            }
871            Type::ReceiveName(len_size) => {
872                out.write_u8(26)?;
873                len_size.serial(out)
874            }
875            Type::ULeb128(constraint) => {
876                out.write_u8(27)?;
877                constraint.serial(out)
878            }
879            Type::ILeb128(constraint) => {
880                out.write_u8(28)?;
881                constraint.serial(out)
882            }
883            Type::ByteList(len_size) => {
884                out.write_u8(29)?;
885                len_size.serial(out)
886            }
887            Type::ByteArray(len) => {
888                out.write_u8(30)?;
889                len.serial(out)
890            }
891            Type::TaggedEnum(fields) => {
892                out.write_u8(31)?;
893                fields.serial(out)
894            }
895        }
896    }
897}
898
899impl Deserial for Type {
900    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
901        let idx = source.read_u8()?;
902        match idx {
903            0 => Ok(Type::Unit),
904            1 => Ok(Type::Bool),
905            2 => Ok(Type::U8),
906            3 => Ok(Type::U16),
907            4 => Ok(Type::U32),
908            5 => Ok(Type::U64),
909            6 => Ok(Type::I8),
910            7 => Ok(Type::I16),
911            8 => Ok(Type::I32),
912            9 => Ok(Type::I64),
913            10 => Ok(Type::Amount),
914            11 => Ok(Type::AccountAddress),
915            12 => Ok(Type::ContractAddress),
916            13 => Ok(Type::Timestamp),
917            14 => Ok(Type::Duration),
918            15 => {
919                let left = Type::deserial(source)?;
920                let right = Type::deserial(source)?;
921                Ok(Type::Pair(Box::new(left), Box::new(right)))
922            }
923            16 => {
924                let len_size = SizeLength::deserial(source)?;
925                let ty = Type::deserial(source)?;
926                Ok(Type::List(len_size, Box::new(ty)))
927            }
928            17 => {
929                let len_size = SizeLength::deserial(source)?;
930                let ty = Type::deserial(source)?;
931                Ok(Type::Set(len_size, Box::new(ty)))
932            }
933            18 => {
934                let len_size = SizeLength::deserial(source)?;
935                let key = Type::deserial(source)?;
936                let value = Type::deserial(source)?;
937                Ok(Type::Map(len_size, Box::new(key), Box::new(value)))
938            }
939            19 => {
940                let len = u32::deserial(source)?;
941                let ty = Type::deserial(source)?;
942                Ok(Type::Array(len, Box::new(ty)))
943            }
944            20 => {
945                let fields = source.get()?;
946                Ok(Type::Struct(fields))
947            }
948            21 => {
949                let variants = source.get()?;
950                Ok(Type::Enum(variants))
951            }
952            22 => {
953                let len_size = SizeLength::deserial(source)?;
954                Ok(Type::String(len_size))
955            }
956            23 => Ok(Type::U128),
957            24 => Ok(Type::I128),
958            25 => {
959                let len_size = SizeLength::deserial(source)?;
960                Ok(Type::ContractName(len_size))
961            }
962            26 => {
963                let len_size = SizeLength::deserial(source)?;
964                Ok(Type::ReceiveName(len_size))
965            }
966            27 => {
967                let constraint = u32::deserial(source)?;
968                Ok(Type::ULeb128(constraint))
969            }
970            28 => {
971                let constraint = u32::deserial(source)?;
972                Ok(Type::ILeb128(constraint))
973            }
974            29 => {
975                let len_size = SizeLength::deserial(source)?;
976                Ok(Type::ByteList(len_size))
977            }
978            30 => {
979                let len = u32::deserial(source)?;
980                Ok(Type::ByteArray(len))
981            }
982            31 => {
983                let variants = source.get()?;
984                Ok(Type::TaggedEnum(variants))
985            }
986
987            _ => Err(ParseError::default()),
988        }
989    }
990}
991
992impl From<TryFromIntError> for ParseError {
993    fn from(_: TryFromIntError) -> Self { ParseError::default() }
994}
995
996/// Try to convert the `len` to the provided size and serialize it.
997pub fn serial_length<W: Write>(
998    len: usize,
999    size_len: SizeLength,
1000    out: &mut W,
1001) -> Result<(), W::Err> {
1002    let to_w_err = |_| W::Err::default();
1003    match size_len {
1004        SizeLength::U8 => u8::try_from(len).map_err(to_w_err)?.serial(out)?,
1005        SizeLength::U16 => u16::try_from(len).map_err(to_w_err)?.serial(out)?,
1006        SizeLength::U32 => u32::try_from(len).map_err(to_w_err)?.serial(out)?,
1007        SizeLength::U64 => u64::try_from(len).map_err(to_w_err)?.serial(out)?,
1008    }
1009    Ok(())
1010}
1011
1012/// Deserialize a length of provided size.
1013pub fn deserial_length(source: &mut impl Read, size_len: SizeLength) -> ParseResult<usize> {
1014    let len: usize = match size_len {
1015        SizeLength::U8 => u8::deserial(source)?.into(),
1016        SizeLength::U16 => u16::deserial(source)?.into(),
1017        SizeLength::U32 => u32::deserial(source)?.try_into()?,
1018        SizeLength::U64 => u64::deserial(source)?.try_into()?,
1019    };
1020    Ok(len)
1021}
1022
1023// Versioned schema helpers
1024#[cfg(feature = "derive-serde")]
1025mod impls {
1026    use crate::{from_bytes, schema::*};
1027    use base64::{engine::general_purpose, Engine};
1028
1029    /// Useful for get_versioned_contract_schema(), but it's not currently used
1030    /// as input or output to any function, so it isn't public.
1031    enum VersionedContractSchema {
1032        V0(ContractV0),
1033        V1(ContractV1),
1034        V2(ContractV2),
1035        V3(ContractV3),
1036    }
1037
1038    #[derive(Debug, thiserror::Error, Clone, Copy)]
1039    pub enum VersionedSchemaError {
1040        #[error("Parse error")]
1041        ParseError,
1042        #[error("Missing Schema Version")]
1043        MissingSchemaVersion,
1044        #[error("Invalid Schema Version")]
1045        InvalidSchemaVersion,
1046        #[error("Unable to find contract schema in module schema")]
1047        NoContractInModule,
1048        #[error("Receive function schema not found in contract schema")]
1049        NoReceiveInContract,
1050        #[error("Init function schema not found in contract schema")]
1051        NoInitInContract,
1052        #[error("Receive function schema does not contain a parameter schema")]
1053        NoParamsInReceive,
1054        #[error("Init function schema does not contain a parameter schema")]
1055        NoParamsInInit,
1056        #[error("Receive function schema not found in contract schema")]
1057        NoErrorInReceive,
1058        #[error("Init function schema does not contain an error schema")]
1059        NoErrorInInit,
1060        #[error("Errors not supported for this module version")]
1061        ErrorNotSupported,
1062        #[error("Receive function schema has no return value schema")]
1063        NoReturnValueInReceive,
1064        #[error("Return values not supported for this module version")]
1065        ReturnValueNotSupported,
1066        #[error("Event schema not found in contract schema")]
1067        NoEventInContract,
1068        #[error("Events not supported for this module version")]
1069        EventNotSupported,
1070    }
1071
1072    impl From<ParseError> for VersionedSchemaError {
1073        fn from(_: ParseError) -> Self { VersionedSchemaError::ParseError }
1074    }
1075
1076    /// Unpacks a versioned contract schema from a versioned module schema
1077    fn get_versioned_contract_schema(
1078        versioned_module_schema: &VersionedModuleSchema,
1079        contract_name: &str,
1080    ) -> Result<VersionedContractSchema, VersionedSchemaError> {
1081        let versioned_contract_schema: VersionedContractSchema = match versioned_module_schema {
1082            VersionedModuleSchema::V0(module_schema) => {
1083                let contract_schema = module_schema
1084                    .contracts
1085                    .get(contract_name)
1086                    .ok_or(VersionedSchemaError::NoContractInModule)?
1087                    .clone();
1088                VersionedContractSchema::V0(contract_schema)
1089            }
1090            VersionedModuleSchema::V1(module_schema) => {
1091                let contract_schema = module_schema
1092                    .contracts
1093                    .get(contract_name)
1094                    .ok_or(VersionedSchemaError::NoContractInModule)?
1095                    .clone();
1096                VersionedContractSchema::V1(contract_schema)
1097            }
1098            VersionedModuleSchema::V2(module_schema) => {
1099                let contract_schema = module_schema
1100                    .contracts
1101                    .get(contract_name)
1102                    .ok_or(VersionedSchemaError::NoContractInModule)?
1103                    .clone();
1104                VersionedContractSchema::V2(contract_schema)
1105            }
1106            VersionedModuleSchema::V3(module_schema) => {
1107                let contract_schema = module_schema
1108                    .contracts
1109                    .get(contract_name)
1110                    .ok_or(VersionedSchemaError::NoContractInModule)?
1111                    .clone();
1112                VersionedContractSchema::V3(contract_schema)
1113            }
1114        };
1115
1116        Ok(versioned_contract_schema)
1117    }
1118
1119    impl VersionedModuleSchema {
1120        /// Get a versioned module schema. First reads header to see if the
1121        /// version can be discerned, otherwise tries using provided
1122        /// schema_version.
1123        pub fn new(
1124            schema_bytes: &[u8],
1125            schema_version: &Option<u8>,
1126        ) -> Result<Self, VersionedSchemaError> {
1127            let versioned_module_schema = match from_bytes::<VersionedModuleSchema>(schema_bytes) {
1128                Ok(versioned) => versioned,
1129                Err(_) => match schema_version {
1130                    Some(0) => VersionedModuleSchema::V0(from_bytes(schema_bytes)?),
1131                    Some(1) => VersionedModuleSchema::V1(from_bytes(schema_bytes)?),
1132                    Some(2) => VersionedModuleSchema::V2(from_bytes(schema_bytes)?),
1133                    Some(3) => VersionedModuleSchema::V3(from_bytes(schema_bytes)?),
1134                    Some(_) => return Err(VersionedSchemaError::InvalidSchemaVersion),
1135                    None => return Err(VersionedSchemaError::MissingSchemaVersion),
1136                },
1137            };
1138            Ok(versioned_module_schema)
1139        }
1140
1141        /// Get a versioned module schema from a base64 string.
1142        pub fn from_base64_str(s: &str) -> Result<Self, VersionedSchemaError> {
1143            let bytes: Vec<u8> = general_purpose::STANDARD_NO_PAD
1144                .decode(s)
1145                .map_err(|_| VersionedSchemaError::ParseError)?;
1146            let mut cursor = Cursor::new(bytes);
1147            let schema = VersionedModuleSchema::deserial(&mut cursor)?;
1148            Ok(schema)
1149        }
1150
1151        /// Returns a receive function's parameter schema from a versioned
1152        /// module schema
1153        pub fn get_receive_param_schema(
1154            &self,
1155            contract_name: &str,
1156            function_name: &str,
1157        ) -> Result<Type, VersionedSchemaError> {
1158            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1159            let param_schema = match versioned_contract_schema {
1160                VersionedContractSchema::V0(contract_schema) => contract_schema
1161                    .receive
1162                    .get(function_name)
1163                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1164                    .clone(),
1165                VersionedContractSchema::V1(contract_schema) => contract_schema
1166                    .receive
1167                    .get(function_name)
1168                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1169                    .parameter()
1170                    .ok_or(VersionedSchemaError::NoParamsInReceive)?
1171                    .clone(),
1172                VersionedContractSchema::V2(contract_schema) => contract_schema
1173                    .receive
1174                    .get(function_name)
1175                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1176                    .parameter()
1177                    .ok_or(VersionedSchemaError::NoParamsInReceive)?
1178                    .clone(),
1179                VersionedContractSchema::V3(contract_schema) => contract_schema
1180                    .receive
1181                    .get(function_name)
1182                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1183                    .parameter()
1184                    .ok_or(VersionedSchemaError::NoParamsInReceive)?
1185                    .clone(),
1186            };
1187            Ok(param_schema)
1188        }
1189
1190        /// Returns an init function's parameter schema from a versioned module
1191        /// schema
1192        pub fn get_init_param_schema(
1193            &self,
1194            contract_name: &str,
1195        ) -> Result<Type, VersionedSchemaError> {
1196            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1197            let param_schema = match versioned_contract_schema {
1198                VersionedContractSchema::V0(contract_schema) => contract_schema
1199                    .init
1200                    .as_ref()
1201                    .ok_or(VersionedSchemaError::NoInitInContract)?
1202                    .clone(),
1203                VersionedContractSchema::V1(contract_schema) => contract_schema
1204                    .init
1205                    .as_ref()
1206                    .ok_or(VersionedSchemaError::NoInitInContract)?
1207                    .parameter()
1208                    .ok_or(VersionedSchemaError::NoParamsInInit)?
1209                    .clone(),
1210                VersionedContractSchema::V2(contract_schema) => contract_schema
1211                    .init
1212                    .as_ref()
1213                    .ok_or(VersionedSchemaError::NoInitInContract)?
1214                    .parameter()
1215                    .ok_or(VersionedSchemaError::NoParamsInInit)?
1216                    .clone(),
1217                VersionedContractSchema::V3(contract_schema) => contract_schema
1218                    .init
1219                    .as_ref()
1220                    .ok_or(VersionedSchemaError::NoInitInContract)?
1221                    .parameter()
1222                    .ok_or(VersionedSchemaError::NoParamsInInit)?
1223                    .clone(),
1224            };
1225            Ok(param_schema)
1226        }
1227
1228        // Returns an event schema from a versioned module schema
1229        pub fn get_event_schema(&self, contract_name: &str) -> Result<Type, VersionedSchemaError> {
1230            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1231
1232            match versioned_contract_schema {
1233                VersionedContractSchema::V0(_) => Err(VersionedSchemaError::EventNotSupported)?,
1234                VersionedContractSchema::V1(_) => Err(VersionedSchemaError::EventNotSupported)?,
1235                VersionedContractSchema::V2(_) => Err(VersionedSchemaError::EventNotSupported)?,
1236                VersionedContractSchema::V3(contract_schema) => {
1237                    contract_schema.event.ok_or(VersionedSchemaError::NoEventInContract)
1238                }
1239            }
1240        }
1241
1242        /// Returns a receive function's error schema from a versioned module
1243        /// schema
1244        pub fn get_receive_error_schema(
1245            &self,
1246            contract_name: &str,
1247            function_name: &str,
1248        ) -> Result<Type, VersionedSchemaError> {
1249            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1250            let param_schema = match versioned_contract_schema {
1251                VersionedContractSchema::V0(_) => {
1252                    return Err(VersionedSchemaError::ErrorNotSupported)
1253                }
1254                VersionedContractSchema::V1(_) => {
1255                    return Err(VersionedSchemaError::ErrorNotSupported)
1256                }
1257                VersionedContractSchema::V2(contract_schema) => contract_schema
1258                    .receive
1259                    .get(function_name)
1260                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1261                    .error()
1262                    .ok_or(VersionedSchemaError::NoErrorInReceive)?
1263                    .clone(),
1264                VersionedContractSchema::V3(contract_schema) => contract_schema
1265                    .receive
1266                    .get(function_name)
1267                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1268                    .error()
1269                    .ok_or(VersionedSchemaError::NoErrorInReceive)?
1270                    .clone(),
1271            };
1272            Ok(param_schema)
1273        }
1274
1275        /// Returns an init function's error schema from a versioned module
1276        /// schema
1277        pub fn get_init_error_schema(
1278            &self,
1279            contract_name: &str,
1280        ) -> Result<Type, VersionedSchemaError> {
1281            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1282            let param_schema = match versioned_contract_schema {
1283                VersionedContractSchema::V0(_) => {
1284                    return Err(VersionedSchemaError::ErrorNotSupported)
1285                }
1286                VersionedContractSchema::V1(_) => {
1287                    return Err(VersionedSchemaError::ErrorNotSupported)
1288                }
1289                VersionedContractSchema::V2(contract_schema) => contract_schema
1290                    .init
1291                    .as_ref()
1292                    .ok_or(VersionedSchemaError::NoInitInContract)?
1293                    .error()
1294                    .ok_or(VersionedSchemaError::NoErrorInInit)?
1295                    .clone(),
1296                VersionedContractSchema::V3(contract_schema) => contract_schema
1297                    .init
1298                    .as_ref()
1299                    .ok_or(VersionedSchemaError::NoInitInContract)?
1300                    .error()
1301                    .ok_or(VersionedSchemaError::NoErrorInInit)?
1302                    .clone(),
1303            };
1304            Ok(param_schema)
1305        }
1306
1307        /// Returns the return value schema from a versioned module schema.
1308        pub fn get_receive_return_value_schema(
1309            &self,
1310            contract_name: &str,
1311            function_name: &str,
1312        ) -> Result<Type, VersionedSchemaError> {
1313            let versioned_contract_schema = get_versioned_contract_schema(self, contract_name)?;
1314            let return_value_schema = match versioned_contract_schema {
1315                VersionedContractSchema::V0(_) => {
1316                    return Err(VersionedSchemaError::ReturnValueNotSupported)
1317                }
1318                VersionedContractSchema::V1(contract_schema) => contract_schema
1319                    .receive
1320                    .get(function_name)
1321                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1322                    .return_value()
1323                    .ok_or(VersionedSchemaError::NoReturnValueInReceive)?
1324                    .clone(),
1325                VersionedContractSchema::V2(contract_schema) => contract_schema
1326                    .receive
1327                    .get(function_name)
1328                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1329                    .return_value()
1330                    .ok_or(VersionedSchemaError::NoReturnValueInReceive)?
1331                    .clone(),
1332                VersionedContractSchema::V3(contract_schema) => contract_schema
1333                    .receive
1334                    .get(function_name)
1335                    .ok_or(VersionedSchemaError::NoReceiveInContract)?
1336                    .return_value()
1337                    .ok_or(VersionedSchemaError::NoReturnValueInReceive)?
1338                    .clone(),
1339            };
1340
1341            Ok(return_value_schema)
1342        }
1343    }
1344
1345    #[cfg(test)]
1346    mod tests {
1347        use super::*;
1348
1349        fn module_schema() -> VersionedModuleSchema {
1350            let module_bytes = hex::decode(
1351                "ffff02010000000c00000054657374436f6e7472616374010402030100000010000000726563656976655f66756e6374696f6e06060807",
1352            )
1353            .unwrap();
1354            VersionedModuleSchema::new(&module_bytes, &None).unwrap()
1355        }
1356
1357        #[test]
1358        fn test_getting_init_param_schema() {
1359            let extracted_type = module_schema().get_init_param_schema("TestContract").unwrap();
1360            assert_eq!(extracted_type, Type::U8)
1361        }
1362
1363        #[test]
1364        fn test_getting_get_event_schema() {
1365            let events = Type::Enum(vec![
1366                ("Foo".to_string(), Fields::None),
1367                ("Bar".to_string(), Fields::None),
1368            ]);
1369            let module_schema = VersionedModuleSchema::V3(ModuleV3 {
1370                contracts: BTreeMap::from([("TestContract".into(), ContractV3 {
1371                    init:    None,
1372                    receive: BTreeMap::new(),
1373                    event:   Some(events.clone()),
1374                })]),
1375            });
1376            let extracted_type = module_schema.get_event_schema("TestContract").unwrap();
1377            assert_eq!(extracted_type, events)
1378        }
1379
1380        #[test]
1381        fn test_getting_receive_param_schema() {
1382            let extracted_type = module_schema()
1383                .get_receive_param_schema("TestContract", "receive_function")
1384                .unwrap();
1385            assert_eq!(extracted_type, Type::I8)
1386        }
1387
1388        #[test]
1389        fn test_getting_init_error_schema() {
1390            let extracted_type = module_schema().get_init_error_schema("TestContract").unwrap();
1391            assert_eq!(extracted_type, Type::U16)
1392        }
1393
1394        #[test]
1395        fn test_getting_receive_error_schema() {
1396            let extracted_type = module_schema()
1397                .get_receive_error_schema("TestContract", "receive_function")
1398                .unwrap();
1399            assert_eq!(extracted_type, Type::I16)
1400        }
1401
1402        #[test]
1403        fn test_getting_receive_return_value_schema() {
1404            let extracted_type = module_schema()
1405                .get_receive_return_value_schema("TestContract", "receive_function")
1406                .unwrap();
1407            assert_eq!(extracted_type, Type::I32)
1408        }
1409    }
1410}
1411
1412#[cfg(test)]
1413mod tests {
1414    use super::*;
1415    use arbitrary::*;
1416
1417    #[test]
1418    fn test_schema_serial_deserial_is_id() {
1419        use rand::prelude::*;
1420        use rand_pcg::Pcg64;
1421
1422        let seed: u64 = random();
1423        let mut rng = Pcg64::seed_from_u64(seed);
1424        let mut data = [0u8; 100000];
1425        rng.fill_bytes(&mut data);
1426
1427        let mut unstructured = Unstructured::new(&data);
1428
1429        for _ in 0..10000 {
1430            let schema = Type::arbitrary(&mut unstructured).unwrap();
1431
1432            let res = from_bytes::<Type>(&to_bytes(&schema)).unwrap();
1433            assert_eq!(schema, res);
1434        }
1435    }
1436
1437    /// Serialize and then deserialize the input.
1438    fn serial_deserial<T: Serialize>(t: &T) -> ParseResult<T> { from_bytes::<T>(&to_bytes(t)) }
1439
1440    #[test]
1441    fn test_function_v1_serial_deserial_is_id() {
1442        let f1 = FunctionV1::Parameter(Type::String(SizeLength::U32));
1443        let f2 = FunctionV1::ReturnValue(Type::U128);
1444        let f3 = FunctionV1::Both {
1445            parameter:    Type::Set(SizeLength::U8, Box::new(Type::ByteArray(10))),
1446            return_value: Type::ILeb128(3),
1447        };
1448
1449        assert_eq!(serial_deserial(&f1), Ok(f1));
1450        assert_eq!(serial_deserial(&f2), Ok(f2));
1451        assert_eq!(serial_deserial(&f3), Ok(f3));
1452    }
1453
1454    #[test]
1455    fn test_function_v2_serial_deserial_is_id() {
1456        let f1 = FunctionV2 {
1457            parameter:    Some(Type::String(SizeLength::U32)),
1458            return_value: Some(Type::String(SizeLength::U32)),
1459            error:        Some(Type::String(SizeLength::U32)),
1460        };
1461
1462        assert_eq!(serial_deserial(&f1), Ok(f1));
1463    }
1464
1465    #[test]
1466    fn test_module_v0_serial_deserial_is_id() {
1467        let m = ModuleV0 {
1468            contracts: BTreeMap::from([("a".into(), ContractV0 {
1469                init:    Some(Type::U8),
1470                receive: BTreeMap::from([
1471                    ("b".into(), Type::String(SizeLength::U32)),
1472                    ("c".into(), Type::Bool),
1473                ]),
1474                state:   Some(Type::String(SizeLength::U64)),
1475            })]),
1476        };
1477
1478        assert_eq!(serial_deserial(&m), Ok(m));
1479    }
1480
1481    #[test]
1482    fn test_module_v1_serial_deserial_is_id() {
1483        let m = ModuleV1 {
1484            contracts: BTreeMap::from([("a".into(), ContractV1 {
1485                init:    Some(FunctionV1::Parameter(Type::U8)),
1486                receive: BTreeMap::from([
1487                    ("b".into(), FunctionV1::ReturnValue(Type::String(SizeLength::U32))),
1488                    ("c".into(), FunctionV1::Both {
1489                        parameter:    Type::U8,
1490                        return_value: Type::Bool,
1491                    }),
1492                ]),
1493            })]),
1494        };
1495
1496        assert_eq!(serial_deserial(&m), Ok(m));
1497    }
1498
1499    #[test]
1500    fn test_module_v2_serial_deserial_is_id() {
1501        let m = ModuleV2 {
1502            contracts: BTreeMap::from([("a".into(), ContractV2 {
1503                init:    Some(FunctionV2 {
1504                    parameter:    Some(Type::String(SizeLength::U32)),
1505                    return_value: Some(Type::String(SizeLength::U32)),
1506                    error:        Some(Type::String(SizeLength::U32)),
1507                }),
1508                receive: BTreeMap::from([
1509                    ("b".into(), FunctionV2 {
1510                        parameter:    Some(Type::String(SizeLength::U32)),
1511                        return_value: Some(Type::String(SizeLength::U32)),
1512                        error:        Some(Type::String(SizeLength::U32)),
1513                    }),
1514                    ("c".into(), FunctionV2 {
1515                        parameter:    Some(Type::String(SizeLength::U32)),
1516                        return_value: Some(Type::String(SizeLength::U32)),
1517                        error:        Some(Type::String(SizeLength::U32)),
1518                    }),
1519                ]),
1520            })]),
1521        };
1522
1523        assert_eq!(serial_deserial(&m), Ok(m));
1524    }
1525
1526    #[test]
1527    fn test_module_v3_schema_serial_deserial_is_id() {
1528        use rand::prelude::*;
1529        use rand_pcg::Pcg64;
1530
1531        let seed: u64 = random();
1532        let mut rng = Pcg64::seed_from_u64(seed);
1533        let mut data = [0u8; 100000];
1534        rng.fill_bytes(&mut data);
1535
1536        let mut unstructured = Unstructured::new(&data);
1537
1538        for _ in 0..10000 {
1539            let schema = ModuleV3::arbitrary(&mut unstructured).unwrap();
1540
1541            let res = from_bytes::<ModuleV3>(&to_bytes(&schema)).unwrap();
1542            assert_eq!(schema, res);
1543        }
1544    }
1545}