subxt_metadata/from/
v16.rs

1// Copyright 2019-2025 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use 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}