subxt_metadata/from/
v15.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, utils::ordered_map::OrderedMap,
12};
13use alloc::collections::BTreeMap;
14use alloc::vec;
15use alloc::vec::Vec;
16use frame_decode::runtime_apis::RuntimeApiTypeInfo;
17use frame_decode::storage::StorageTypeInfo;
18use frame_metadata::v15;
19use hashbrown::HashMap;
20use scale_info::form::PortableForm;
21
22impl TryFrom<v15::RuntimeMetadataV15> for Metadata {
23    type Error = TryFromError;
24    fn try_from(m: v15::RuntimeMetadataV15) -> Result<Self, TryFromError> {
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 constants = p.constants.iter().map(|c| {
56                let name = c.name.clone();
57                (name, from_constant_metadata(c.clone()))
58            });
59
60            let call_variant_index =
61                VariantIndex::build(p.calls.as_ref().map(|c| c.ty.id), &m.types);
62            let error_variant_index =
63                VariantIndex::build(p.error.as_ref().map(|e| e.ty.id), &m.types);
64            let event_variant_index =
65                VariantIndex::build(p.event.as_ref().map(|e| e.ty.id), &m.types);
66
67            pallets_by_index.insert(p.index, pos);
68            pallets.push_insert(
69                name.clone(),
70                PalletMetadataInner {
71                    name,
72                    call_index: p.index,
73                    event_index: p.index,
74                    error_index: p.index,
75                    storage,
76                    call_ty: p.calls.as_ref().map(|c| c.ty.id),
77                    call_variant_index,
78                    event_ty: p.event.as_ref().map(|e| e.ty.id),
79                    event_variant_index,
80                    error_ty: p.error.as_ref().map(|e| e.ty.id),
81                    error_variant_index,
82                    constants: constants.collect(),
83                    view_functions: Default::default(),
84                    associated_types: Default::default(),
85                    docs: p.docs.clone(),
86                },
87            );
88        }
89
90        let apis = m
91            .apis
92            .iter()
93            .map(|api| {
94                let trait_name = api.name.clone();
95                let methods = api
96                    .methods
97                    .iter()
98                    .map(|method| {
99                        let method_name = method.name.clone();
100                        let method_info = RuntimeApiMethodMetadataInner {
101                            info: m
102                                .runtime_api_info(&trait_name, &method.name)
103                                .map_err(|e| e.into_owned())?
104                                .into_owned(),
105                            name: method.name.clone(),
106                            docs: method.docs.clone(),
107                        };
108                        Ok((method_name, method_info))
109                    })
110                    .collect::<Result<_, TryFromError>>()?;
111
112                let runtime_api_metadata = RuntimeApiMetadataInner {
113                    name: trait_name.clone(),
114                    methods,
115                    docs: api.docs.clone(),
116                };
117                Ok((trait_name, runtime_api_metadata))
118            })
119            .collect::<Result<_, TryFromError>>()?;
120
121        let dispatch_error_ty = m
122            .types
123            .types
124            .iter()
125            .find(|ty| ty.ty.path.segments == ["sp_runtime", "DispatchError"])
126            .map(|ty| ty.id);
127
128        Ok(Metadata {
129            types: m.types,
130            pallets,
131            pallets_by_call_index: pallets_by_index.clone(),
132            pallets_by_error_index: pallets_by_index.clone(),
133            pallets_by_event_index: pallets_by_index,
134            extrinsic: from_extrinsic_metadata(m.extrinsic),
135            dispatch_error_ty,
136            apis,
137            outer_enums: OuterEnumsMetadata {
138                call_enum_ty: m.outer_enums.call_enum_ty.id,
139                event_enum_ty: m.outer_enums.event_enum_ty.id,
140                error_enum_ty: m.outer_enums.error_enum_ty.id,
141            },
142            custom: m.custom,
143        })
144    }
145}
146
147fn from_signed_extension_metadata(
148    value: v15::SignedExtensionMetadata<PortableForm>,
149) -> TransactionExtensionMetadataInner {
150    TransactionExtensionMetadataInner {
151        identifier: value.identifier,
152        extra_ty: value.ty.id,
153        additional_ty: value.additional_signed.id,
154    }
155}
156
157fn from_extrinsic_metadata(value: v15::ExtrinsicMetadata<PortableForm>) -> ExtrinsicMetadata {
158    let transaction_extensions: Vec<_> = value
159        .signed_extensions
160        .into_iter()
161        .map(from_signed_extension_metadata)
162        .collect();
163
164    let transaction_extension_indexes = (0..transaction_extensions.len() as u32).collect();
165
166    ExtrinsicMetadata {
167        supported_versions: vec![value.version],
168        transaction_extensions,
169        address_ty: value.address_ty.id,
170        signature_ty: value.signature_ty.id,
171        transaction_extensions_by_version: BTreeMap::from_iter([(
172            0,
173            transaction_extension_indexes,
174        )]),
175    }
176}
177
178fn from_constant_metadata(s: v15::PalletConstantMetadata<PortableForm>) -> ConstantMetadata {
179    ConstantMetadata {
180        name: s.name,
181        ty: s.ty.id,
182        value: s.value,
183        docs: s.docs,
184    }
185}