1use super::TryFromError;
6
7use crate::utils::variant_index::VariantIndex;
8use crate::{
9 ConstantMetadata, ExtrinsicMetadata, Metadata, OuterEnumsMetadata, PalletMetadataInner,
10 RuntimeApiMetadataInner, RuntimeApiMethodMetadataInner, StorageEntryMetadata, StorageMetadata,
11 TransactionExtensionMetadataInner, ViewFunctionMetadataInner, utils::ordered_map::OrderedMap,
12};
13use frame_decode::runtime_apis::RuntimeApiTypeInfo;
14use frame_decode::storage::StorageTypeInfo;
15use frame_decode::view_functions::ViewFunctionTypeInfo;
16use frame_metadata::{v15, v16};
17use hashbrown::HashMap;
18use scale_info::form::PortableForm;
19
20impl TryFrom<v16::RuntimeMetadataV16> for Metadata {
21 type Error = TryFromError;
22 fn try_from(m: v16::RuntimeMetadataV16) -> Result<Self, TryFromError> {
23 let types = &m.types;
24
25 let mut pallets = OrderedMap::new();
26 let mut pallets_by_index = HashMap::new();
27 for (pos, p) in m.pallets.iter().enumerate() {
28 let name = p.name.clone();
29
30 let storage = match &p.storage {
31 None => None,
32 Some(s) => Some(StorageMetadata {
33 prefix: s.prefix.clone(),
34 entries: s
35 .entries
36 .iter()
37 .map(|s| {
38 let entry_name = s.name.clone();
39 let storage_info = m
40 .storage_info(&name, &entry_name)
41 .map_err(|e| e.into_owned())?
42 .into_owned();
43 let storage_entry = StorageEntryMetadata {
44 name: entry_name.clone(),
45 info: storage_info,
46 docs: s.docs.clone(),
47 };
48
49 Ok::<_, TryFromError>((entry_name, storage_entry))
50 })
51 .collect::<Result<_, TryFromError>>()?,
52 }),
53 };
54
55 let view_functions = p
56 .view_functions
57 .iter()
58 .map(|vf| {
59 let view_function_metadata = ViewFunctionMetadataInner {
60 name: vf.name.clone(),
61 info: m
62 .view_function_info(&name, &vf.name)
63 .map_err(|e| e.into_owned())?
64 .into_owned(),
65 docs: vf.docs.clone(),
66 };
67 Ok((vf.name.clone(), view_function_metadata))
68 })
69 .collect::<Result<_, TryFromError>>()?;
70
71 let constants = p.constants.iter().map(|c| {
72 let name = c.name.clone();
73 (name, from_constant_metadata(c.clone()))
74 });
75
76 let call_variant_index = VariantIndex::build(p.calls.as_ref().map(|c| c.ty.id), types);
77 let error_variant_index = VariantIndex::build(p.error.as_ref().map(|e| e.ty.id), types);
78 let event_variant_index = VariantIndex::build(p.event.as_ref().map(|e| e.ty.id), types);
79
80 let associated_types = p
81 .associated_types
82 .iter()
83 .map(|t| (t.name.clone(), t.ty.id))
84 .collect();
85
86 pallets_by_index.insert(p.index, pos);
87 pallets.push_insert(
88 name.clone(),
89 PalletMetadataInner {
90 name,
91 call_index: p.index,
92 event_index: p.index,
93 error_index: p.index,
94 storage,
95 call_ty: p.calls.as_ref().map(|c| c.ty.id),
96 call_variant_index,
97 event_ty: p.event.as_ref().map(|e| e.ty.id),
98 event_variant_index,
99 error_ty: p.error.as_ref().map(|e| e.ty.id),
100 error_variant_index,
101 constants: constants.collect(),
102 view_functions,
103 associated_types,
104 docs: p.docs.clone(),
105 },
106 );
107 }
108
109 let apis = m
110 .apis
111 .iter()
112 .map(|api| {
113 let trait_name = api.name.clone();
114 let methods = api
115 .methods
116 .iter()
117 .map(|method| {
118 let method_name = method.name.clone();
119 let method_info = RuntimeApiMethodMetadataInner {
120 info: m
121 .runtime_api_info(&trait_name, &method.name)
122 .map_err(|e| e.into_owned())?
123 .into_owned(),
124 name: method.name.clone(),
125 docs: method.docs.clone(),
126 };
127 Ok((method_name, method_info))
128 })
129 .collect::<Result<_, TryFromError>>()?;
130
131 let runtime_api_metadata = RuntimeApiMetadataInner {
132 name: trait_name.clone(),
133 methods,
134 docs: api.docs.clone(),
135 };
136 Ok((trait_name, runtime_api_metadata))
137 })
138 .collect::<Result<_, TryFromError>>()?;
139
140 let custom_map = m
141 .custom
142 .map
143 .into_iter()
144 .map(|(key, val)| {
145 let custom_val = v15::CustomValueMetadata {
146 ty: val.ty,
147 value: val.value,
148 };
149 (key, custom_val)
150 })
151 .collect();
152
153 let dispatch_error_ty = types
154 .types
155 .iter()
156 .find(|ty| ty.ty.path.segments == ["sp_runtime", "DispatchError"])
157 .map(|ty| ty.id);
158
159 Ok(Metadata {
160 types: m.types,
161 pallets,
162 pallets_by_call_index: pallets_by_index.clone(),
163 pallets_by_error_index: pallets_by_index.clone(),
164 pallets_by_event_index: pallets_by_index,
165 extrinsic: from_extrinsic_metadata(m.extrinsic),
166 dispatch_error_ty,
167 apis,
168 outer_enums: OuterEnumsMetadata {
169 call_enum_ty: m.outer_enums.call_enum_ty.id,
170 event_enum_ty: m.outer_enums.event_enum_ty.id,
171 error_enum_ty: m.outer_enums.error_enum_ty.id,
172 },
173 custom: v15::CustomMetadata { map: custom_map },
174 })
175 }
176}
177
178fn from_transaction_extension_metadata(
179 value: v16::TransactionExtensionMetadata<PortableForm>,
180) -> TransactionExtensionMetadataInner {
181 TransactionExtensionMetadataInner {
182 identifier: value.identifier,
183 extra_ty: value.ty.id,
184 additional_ty: value.implicit.id,
185 }
186}
187
188fn from_extrinsic_metadata(value: v16::ExtrinsicMetadata<PortableForm>) -> ExtrinsicMetadata {
189 ExtrinsicMetadata {
190 supported_versions: value.versions,
191 transaction_extensions_by_version: value
192 .transaction_extensions_by_version
193 .into_iter()
194 .map(|(version, idxs)| (version, idxs.into_iter().map(|idx| idx.0).collect()))
195 .collect(),
196 transaction_extensions: value
197 .transaction_extensions
198 .into_iter()
199 .map(from_transaction_extension_metadata)
200 .collect(),
201 address_ty: value.address_ty.id,
202 signature_ty: value.signature_ty.id,
203 }
204}
205
206fn from_constant_metadata(s: v16::PalletConstantMetadata<PortableForm>) -> ConstantMetadata {
207 ConstantMetadata {
208 name: s.name,
209 ty: s.ty.id,
210 value: s.value,
211 docs: s.docs,
212 }
213}