substrate_constructor/
traits.rs

1use external_memory_tools::ExternalMemory;
2use frame_metadata::{
3    v14::{
4        PalletCallMetadata, PalletConstantMetadata, PalletErrorMetadata, PalletEventMetadata,
5        PalletMetadata as PalletMetadataV14, PalletStorageMetadata, RuntimeMetadataV14,
6    },
7    v15::{PalletMetadata as PalletMetadataV15, RuntimeMetadataV15},
8};
9use scale_info::form::PortableForm;
10use substrate_parser::{
11    cards::ParsedData,
12    decode_all_as_type,
13    error::{MetaStructureErrorV14, MetaVersionErrorPallets},
14    special_indicators::SpecialtyUnsignedInteger,
15    traits::{
16        version_constant_data_and_ty_v14, version_constant_data_and_ty_v15, AsCompleteMetadata,
17    },
18};
19
20use std::fmt::Debug;
21
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub enum Unsigned {
24    U8(u8),
25    U16(u16),
26    U32(u32),
27    U64(u64),
28    U128(u128),
29}
30
31pub trait AsPalletMetadata<E: ExternalMemory> {
32    fn name(&self) -> String;
33    fn storage(&self) -> Option<PalletStorageMetadata<PortableForm>>;
34    fn calls(&self) -> Option<PalletCallMetadata<PortableForm>>;
35    fn event(&self) -> Option<PalletEventMetadata<PortableForm>>;
36    fn constants(&self) -> Vec<PalletConstantMetadata<PortableForm>>;
37    fn error(&self) -> Option<PalletErrorMetadata<PortableForm>>;
38    fn index(&self) -> u8;
39}
40
41macro_rules! impl_as_pallet_metadata {
42    ($($ty:ty), *) => {
43        $(
44            impl <E: ExternalMemory> AsPalletMetadata<E> for $ty {
45                fn name(&self) -> String {
46                    self.name.to_owned()
47                }
48                fn storage(&self) -> Option<PalletStorageMetadata<PortableForm>> {
49                    self.storage.to_owned()
50                }
51                fn calls(&self) -> Option<PalletCallMetadata<PortableForm>> {
52                    self.calls.to_owned()
53                }
54                fn event(&self) -> Option<PalletEventMetadata<PortableForm>> {
55                    self.event.to_owned()
56                }
57                fn constants(&self) -> Vec<PalletConstantMetadata<PortableForm>> {
58                    self.constants.to_owned()
59                }
60                fn error(&self) -> Option<PalletErrorMetadata<PortableForm>> {
61                    self.error.to_owned()
62                }
63                fn index(&self) -> u8 {
64                    self.index
65                }
66            }
67        )*
68    }
69}
70
71impl_as_pallet_metadata!(
72    PalletMetadataV14<PortableForm>,
73    PalletMetadataV15<PortableForm>
74);
75
76pub trait AsFillMetadata<E: ExternalMemory>: AsCompleteMetadata<E> {
77    type PalletMetadata: AsPalletMetadata<E> + Clone + Debug;
78    fn pallets(&self) -> Vec<Self::PalletMetadata>;
79    fn defined_tx_version(&self) -> Option<Unsigned>;
80    fn spec_version(&self) -> Result<Unsigned, Self::MetaStructureError>;
81}
82
83// TODO spec_version as unsigned may go eventually into substrate_parser.
84
85macro_rules! impl_as_fill_metadata {
86    ($($ty:ty, $ty_pallet_metadata:ty, $func:ident, $err:expr), *) => {
87        $(
88            impl <E: ExternalMemory> AsFillMetadata<E> for $ty {
89                type PalletMetadata = $ty_pallet_metadata;
90                fn pallets(&self) -> Vec<Self::PalletMetadata> {
91                    self.pallets.to_owned()
92                }
93                fn defined_tx_version(&self) -> Option<Unsigned> {
94                    match $func(&self.pallets) {
95                        Ok((version_data, version_ty)) => {
96                            match decode_all_as_type::<&[u8], (), $ty>(
97                                &version_ty,
98                                &version_data.as_ref(),
99                                &mut (),
100                                &self.types,
101                            ) {
102                                Ok(extended_data) => tx_version(
103                                    extended_data.data,
104                                ),
105                                Err(_) => None,
106                            }
107                        },
108                        Err(_) => None,
109                    }
110                }
111                fn spec_version(&self) -> Result<Unsigned, Self::MetaStructureError> {
112                    let (version_data, version_ty) = $func(&self.pallets)?;
113                    match decode_all_as_type::<&[u8], (), $ty>(
114                        &version_ty,
115                        &version_data.as_ref(),
116                        &mut (),
117                        &self.types,
118                    ) {
119                        Ok(extended_data) => Ok(spec_version(
120                            extended_data.data,
121                        )?),
122                        Err(_) => Err($err),
123                    }
124                }
125            }
126        )*
127    }
128}
129
130impl_as_fill_metadata!(
131    RuntimeMetadataV14,
132    PalletMetadataV14<PortableForm>,
133    version_constant_data_and_ty_v14,
134    MetaStructureErrorV14::Version(MetaVersionErrorPallets::RuntimeVersionNotDecodeable)
135);
136impl_as_fill_metadata!(
137    RuntimeMetadataV15,
138    PalletMetadataV15<PortableForm>,
139    version_constant_data_and_ty_v15,
140    MetaVersionErrorPallets::RuntimeVersionNotDecodeable
141);
142
143/// Extract [`Unsigned`] `spec_version` from `Version` parsed data.
144fn spec_version(parsed_data: ParsedData) -> Result<Unsigned, MetaVersionErrorPallets> {
145    let mut spec_version = None;
146
147    if let ParsedData::Composite(fields) = parsed_data {
148        for field in fields.iter() {
149            match &field.data.data {
150                ParsedData::PrimitiveU8 {
151                    value,
152                    specialty: SpecialtyUnsignedInteger::SpecVersion,
153                } => {
154                    if spec_version.is_none() {
155                        spec_version = Some(Unsigned::U8(*value))
156                    } else {
157                        return Err(MetaVersionErrorPallets::SpecVersionIdentifierTwice);
158                    }
159                }
160                ParsedData::PrimitiveU16 {
161                    value,
162                    specialty: SpecialtyUnsignedInteger::SpecVersion,
163                } => {
164                    if spec_version.is_none() {
165                        spec_version = Some(Unsigned::U16(*value))
166                    } else {
167                        return Err(MetaVersionErrorPallets::SpecVersionIdentifierTwice);
168                    }
169                }
170                ParsedData::PrimitiveU32 {
171                    value,
172                    specialty: SpecialtyUnsignedInteger::SpecVersion,
173                } => {
174                    if spec_version.is_none() {
175                        spec_version = Some(Unsigned::U32(*value))
176                    } else {
177                        return Err(MetaVersionErrorPallets::SpecVersionIdentifierTwice);
178                    }
179                }
180                ParsedData::PrimitiveU64 {
181                    value,
182                    specialty: SpecialtyUnsignedInteger::SpecVersion,
183                } => {
184                    if spec_version.is_none() {
185                        spec_version = Some(Unsigned::U64(*value))
186                    } else {
187                        return Err(MetaVersionErrorPallets::SpecVersionIdentifierTwice);
188                    }
189                }
190                ParsedData::PrimitiveU128 {
191                    value,
192                    specialty: SpecialtyUnsignedInteger::SpecVersion,
193                } => {
194                    if spec_version.is_none() {
195                        spec_version = Some(Unsigned::U128(*value))
196                    } else {
197                        return Err(MetaVersionErrorPallets::SpecVersionIdentifierTwice);
198                    }
199                }
200                _ => (),
201            }
202        }
203    } else {
204        return Err(MetaVersionErrorPallets::UnexpectedRuntimeVersionFormat);
205    }
206    spec_version.ok_or(MetaVersionErrorPallets::NoSpecVersionIdentifier)
207}
208
209/// Extract [`Unsigned`] `tx_version` from `Version` parsed data.
210///
211/// It is not an error to not have `tx_version`.
212fn tx_version(parsed_data: ParsedData) -> Option<Unsigned> {
213    let mut tx_version = None;
214
215    if let ParsedData::Composite(fields) = parsed_data {
216        for field in fields.iter() {
217            match &field.data.data {
218                ParsedData::PrimitiveU8 {
219                    value,
220                    specialty: SpecialtyUnsignedInteger::TxVersion,
221                } => {
222                    if tx_version.is_none() {
223                        tx_version = Some(Unsigned::U8(*value))
224                    } else {
225                        return None;
226                    }
227                }
228                ParsedData::PrimitiveU16 {
229                    value,
230                    specialty: SpecialtyUnsignedInteger::TxVersion,
231                } => {
232                    if tx_version.is_none() {
233                        tx_version = Some(Unsigned::U16(*value))
234                    } else {
235                        return None;
236                    }
237                }
238                ParsedData::PrimitiveU32 {
239                    value,
240                    specialty: SpecialtyUnsignedInteger::TxVersion,
241                } => {
242                    if tx_version.is_none() {
243                        tx_version = Some(Unsigned::U32(*value))
244                    } else {
245                        return None;
246                    }
247                }
248                ParsedData::PrimitiveU64 {
249                    value,
250                    specialty: SpecialtyUnsignedInteger::TxVersion,
251                } => {
252                    if tx_version.is_none() {
253                        tx_version = Some(Unsigned::U64(*value))
254                    } else {
255                        return None;
256                    }
257                }
258                ParsedData::PrimitiveU128 {
259                    value,
260                    specialty: SpecialtyUnsignedInteger::TxVersion,
261                } => {
262                    if tx_version.is_none() {
263                        tx_version = Some(Unsigned::U128(*value))
264                    } else {
265                        return None;
266                    }
267                }
268                _ => (),
269            }
270        }
271    } else {
272        return None;
273    }
274    tx_version
275}