frame_decode/
lib.rs

1// Copyright (C) 2022-2023 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-value crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Decode extrinsics and storage values from substrate based networks which expose `frame-metadata::RuntimeMetadata`
17//! like Polkadot.
18//!
19//! - See [`extrinsics`] for decoding Extrinsics.
20//! - See [`storage`] for decoding storage keys and values.
21//!
22#![deny(missing_docs)]
23#![cfg_attr(not(feature = "std"), no_std)]
24
25extern crate alloc;
26
27mod methods;
28mod utils;
29
30pub mod extrinsics {
31    //! This module contains functions for decoding extrinsics.
32    //!
33    //! - See [`decode_extrinsic`] for a general function to decode modern or historic extrinsics.
34    //! - See [`decode_extrinsic_current`] for a helper to decode modern extrinsics.
35    //!
36
37    use crate::utils::InfoAndResolver;
38
39    pub use crate::methods::extrinsic_decoder::{
40        decode_extrinsic, Extrinsic, ExtrinsicDecodeError, ExtrinsicExtensions, ExtrinsicOwned,
41        ExtrinsicSignature, ExtrinsicType, NamedArg,
42    };
43    pub use crate::methods::extrinsic_type_info::{
44        ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
45        ExtrinsicSignatureInfo, ExtrinsicTypeInfo,
46    };
47
48    /// Decode an extrinsic in a modern runtime (ie one exposing V14+ metadata).
49    ///
50    /// See [`decode_extrinsic`] for a more comprehensive example.
51    ///
52    /// # Example
53    ///
54    /// ```rust
55    /// use frame_decode::extrinsics::decode_extrinsic_current;
56    /// use frame_metadata::RuntimeMetadata;
57    /// use parity_scale_codec::Decode;
58    ///
59    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
60    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { panic!() };
61    ///
62    /// let extrinsics_bytes = std::fs::read("artifacts/exts_10000000_9180.json").unwrap();
63    /// let extrinsics_hex: Vec<String> = serde_json::from_slice(&extrinsics_bytes).unwrap();
64    ///
65    /// for ext_hex in extrinsics_hex {
66    ///     let ext_bytes = hex::decode(ext_hex.trim_start_matches("0x")).unwrap();
67    ///
68    ///     // Decode the extrinsic, returning information about it:
69    ///     let ext_info = decode_extrinsic_current(&mut &*ext_bytes, &metadata).unwrap();
70    ///
71    ///     // Now we can use this information to inspect the extrinsic and decode the
72    ///     // different values inside it (see the `decode_extrinsic` docs).
73    /// }
74    /// ```
75    pub fn decode_extrinsic_current<'info_and_resolver, T>(
76        cursor: &mut &[u8],
77        metadata: &'info_and_resolver T,
78    ) -> Result<
79        Extrinsic<'info_and_resolver, <T::Info as ExtrinsicTypeInfo>::TypeId>,
80        ExtrinsicDecodeError,
81    >
82    where
83        T: InfoAndResolver,
84        T::Info: ExtrinsicTypeInfo,
85        <T::Info as ExtrinsicTypeInfo>::TypeId: core::fmt::Debug + Clone,
86        T::Resolver:
87            scale_type_resolver::TypeResolver<TypeId = <T::Info as ExtrinsicTypeInfo>::TypeId>,
88    {
89        decode_extrinsic(cursor, metadata.info(), metadata.resolver())
90    }
91}
92
93pub mod storage {
94    //! This module contains functions for decoding storage keys and values.
95    //!
96    //! - See [`decode_storage_key`] and [`decode_storage_value`] to decode storage keys or values
97    //!   from modern or historic runtimes.
98    //! - See [`decode_storage_key_current`] and [`decode_storage_value_current`] to decode modern
99    //!   storage keys and values.
100    //! - See [`encode_prefix`] to encode storage prefixes, and [`encode_storage_key`] to encode
101    //!   storage keys.
102
103    use crate::utils::InfoAndResolver;
104    use scale_decode::Visitor;
105    use scale_type_resolver::TypeResolver;
106
107    pub use crate::methods::storage_type_info::{
108        StorageHasher, StorageInfo, StorageInfoError, StorageKeyInfo, StorageTypeInfo,
109    };
110
111    pub use crate::methods::storage_decoder::{
112        decode_storage_key, decode_storage_key_with_info, decode_storage_value,
113        decode_storage_value_with_info, StorageKey, StorageKeyDecodeError, StorageKeyPart,
114        StorageKeyPartValue, StorageValueDecodeError,
115    };
116    pub use crate::methods::storage_encoder::{
117        encode_prefix, encode_storage_key, encode_storage_key_to, encode_storage_key_with_info_to,
118        IntoStorageKeys, StorageKeyEncodeError, StorageKeys,
119    };
120
121    type TypeIdOf<T> = <<T as InfoAndResolver>::Info as StorageTypeInfo>::TypeId;
122
123    /// Decode a storage key in a modern runtime, returning information about it.
124    ///
125    /// This information can be used to identify and, where possible, decode the parts of the storage key.
126    ///
127    /// See [`decode_storage_key`] for a more complete example.
128    ///
129    /// # Example
130    ///
131    /// Here, we decode some storage keys from a block.
132    ///
133    /// ```rust
134    /// use frame_decode::storage::decode_storage_key_current;
135    /// use frame_decode::helpers::decode_with_visitor;
136    /// use frame_metadata::RuntimeMetadata;
137    /// use parity_scale_codec::Decode;
138    /// use scale_value::scale::ValueVisitor;
139    ///
140    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
141    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { return };
142    ///
143    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_10000000_9180_system_account.json").unwrap();
144    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
145    ///
146    /// for (key, _val) in storage_keyval_hex {
147    ///     let key_bytes = hex::decode(key.trim_start_matches("0x")).unwrap();
148    ///
149    ///     // Decode the storage key, returning information about it:
150    ///     let storage_info = decode_storage_key_current(
151    ///         "System",
152    ///         "Account",
153    ///         &mut &*key_bytes,
154    ///         &metadata,
155    ///     ).unwrap();
156    ///
157    ///     // See `decode_storage_key` for more.
158    /// }
159    /// ```
160    pub fn decode_storage_key_current<T>(
161        pallet_name: &str,
162        storage_entry: &str,
163        cursor: &mut &[u8],
164        metadata: &T,
165    ) -> Result<StorageKey<TypeIdOf<T>>, StorageKeyDecodeError<TypeIdOf<T>>>
166    where
167        T: InfoAndResolver,
168        T::Info: StorageTypeInfo,
169        TypeIdOf<T>: core::fmt::Debug + Clone,
170        T::Resolver: TypeResolver<TypeId = TypeIdOf<T>>,
171    {
172        decode_storage_key(
173            pallet_name,
174            storage_entry,
175            cursor,
176            metadata.info(),
177            metadata.resolver(),
178        )
179    }
180
181    /// Decode a storage value in a modern (V14-metadata-or-later) runtime.
182    ///
183    /// # Example
184    ///
185    /// Here, we decode some storage values from a block.
186    ///
187    /// ```rust
188    /// use frame_decode::storage::decode_storage_value_current;
189    /// use frame_decode::helpers::decode_with_visitor;
190    /// use frame_metadata::RuntimeMetadata;
191    /// use parity_scale_codec::Decode;
192    /// use scale_value::scale::ValueVisitor;
193    ///
194    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
195    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { return };
196    ///
197    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_10000000_9180_system_account.json").unwrap();
198    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
199    ///
200    /// for (_key, val) in storage_keyval_hex {
201    ///     let value_bytes = hex::decode(val.trim_start_matches("0x")).unwrap();
202    ///
203    ///     // Decode the storage value, here into a scale_value::Value:
204    ///     let account_value = decode_storage_value_current(
205    ///         "System",
206    ///         "Account",
207    ///         &mut &*value_bytes,
208    ///         &metadata,
209    ///         ValueVisitor::new()
210    ///     ).unwrap();
211    /// }
212    /// ```
213    pub fn decode_storage_value_current<'scale, 'resolver, T, V>(
214        pallet_name: &str,
215        storage_entry: &str,
216        cursor: &mut &'scale [u8],
217        metadata: &'resolver T,
218        visitor: V,
219    ) -> Result<V::Value<'scale, 'resolver>, StorageValueDecodeError<TypeIdOf<T>>>
220    where
221        T: InfoAndResolver,
222        T::Info: StorageTypeInfo,
223        TypeIdOf<T>: core::fmt::Debug + Clone,
224        T::Resolver: scale_type_resolver::TypeResolver<TypeId = TypeIdOf<T>>,
225        V: Visitor<TypeResolver = T::Resolver>,
226        V::Error: core::fmt::Debug,
227    {
228        decode_storage_value(
229            pallet_name,
230            storage_entry,
231            cursor,
232            metadata.info(),
233            metadata.resolver(),
234            visitor,
235        )
236    }
237}
238
239#[cfg(feature = "legacy-types")]
240pub mod legacy_types {
241    //! This module contains legacy types that can be used to decode pre-V14 blocks and storage.
242
243    pub mod polkadot {
244        //! Legacy types for Polkadot chains.
245
246        /// Legacy types for the Polkadot Relay Chain.
247        pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry {
248            // This is a convenience function to load the Polkadot relay chain types.
249            // It is used in the examples in this crate.
250            let bytes = include_bytes!("../types/polkadot_types.yaml");
251            serde_yaml::from_slice(bytes).expect("Polkadot types are valid YAML")
252        }
253    }
254}
255
256pub mod helpers {
257    //! Helper functions and types to assist with decoding.
258    //!
259    //! - [`type_registry_from_metadata`] is expected to be used when decoding things from historic
260    //!   runtimes, adding the ability to decode some types from information in the metadata.
261    //! - [`decode_with_error_tracing`] is like [`decode_with_visitor`], but
262    //!   will use a tracing visitor (if the `error-tracing` feature is enabled) to provide more
263    //!   information in the event that decoding fails.
264    //! - [`list_storage_entries`] returns an iterator over all of the storage entries available in
265    //!   some metadata.
266    //!
267
268    pub use crate::utils::{decode_with_error_tracing, DecodeErrorTrace};
269    pub use crate::utils::{list_storage_entries, list_storage_entries_any, StorageEntry};
270    #[cfg(feature = "legacy")]
271    pub use crate::utils::{type_registry_from_metadata, type_registry_from_metadata_any};
272
273    /// An alias to [`scale_decode::visitor::decode_with_visitor`]. This can be used to decode the byte ranges
274    /// given back from functions like [`crate::extrinsics::decode_extrinsic_current`] or
275    /// [`crate::storage::decode_storage_key_current`].
276    ///
277    pub use scale_decode::visitor::decode_with_visitor;
278
279    /// An alias to the underlying [`scale-decode`] crate.
280    ///
281    pub use scale_decode;
282}
283
284#[cfg(test)]
285mod test {
286    use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
287    use crate::methods::storage_type_info::StorageTypeInfo;
288    use crate::utils::{InfoAndResolver, ToStorageEntriesList, ToTypeRegistry};
289
290    // This will panic if there is any issue decoding the legacy types we provide.
291    #[test]
292    fn test_deserializing_legacy_types() {
293        let _ = crate::legacy_types::polkadot::relay_chain();
294    }
295
296    macro_rules! impls_trait {
297        ($type:ty, $trait:path) => {
298            const _: () = {
299                const fn assert_impl<T: $trait>() {}
300                assert_impl::<$type>();
301            };
302        };
303    }
304
305    // Just a sanity check that all of the metadata versions we expect implement
306    // all of the key traits. Makes it harder to miss something when adding a new metadata
307    // version; just add it below and implement the traits until everything compiles.
308    #[rustfmt::skip]
309    const _: () = {
310        impls_trait!(frame_metadata::v14::RuntimeMetadataV14, InfoAndResolver);
311        impls_trait!(frame_metadata::v15::RuntimeMetadataV15, InfoAndResolver);
312        impls_trait!(frame_metadata::v16::RuntimeMetadataV16, InfoAndResolver);
313
314        impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ExtrinsicTypeInfo);
315        impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ExtrinsicTypeInfo);
316        impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ExtrinsicTypeInfo);
317        impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ExtrinsicTypeInfo);
318        impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ExtrinsicTypeInfo);
319        impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ExtrinsicTypeInfo);
320        impls_trait!(frame_metadata::v14::RuntimeMetadataV14, ExtrinsicTypeInfo);
321        impls_trait!(frame_metadata::v15::RuntimeMetadataV15, ExtrinsicTypeInfo);
322        impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ExtrinsicTypeInfo);
323
324        impls_trait!(frame_metadata::v8::RuntimeMetadataV8, StorageTypeInfo);
325        impls_trait!(frame_metadata::v9::RuntimeMetadataV9, StorageTypeInfo);
326        impls_trait!(frame_metadata::v10::RuntimeMetadataV10, StorageTypeInfo);
327        impls_trait!(frame_metadata::v11::RuntimeMetadataV11, StorageTypeInfo);
328        impls_trait!(frame_metadata::v12::RuntimeMetadataV12, StorageTypeInfo);
329        impls_trait!(frame_metadata::v13::RuntimeMetadataV13, StorageTypeInfo);
330        impls_trait!(frame_metadata::v14::RuntimeMetadataV14, StorageTypeInfo);
331        impls_trait!(frame_metadata::v15::RuntimeMetadataV15, StorageTypeInfo);
332        impls_trait!(frame_metadata::v16::RuntimeMetadataV16, StorageTypeInfo);
333
334        impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ToStorageEntriesList);
335        impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ToStorageEntriesList);
336        impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ToStorageEntriesList);
337        impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ToStorageEntriesList);
338        impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ToStorageEntriesList);
339        impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ToStorageEntriesList);
340        impls_trait!(frame_metadata::v14::RuntimeMetadataV14, ToStorageEntriesList);
341        impls_trait!(frame_metadata::v15::RuntimeMetadataV15, ToStorageEntriesList);
342        impls_trait!(frame_metadata::v16::RuntimeMetadataV16, ToStorageEntriesList);
343
344        // This is a legacy trait and so only legacy metadata versions implement it:
345        impls_trait!(frame_metadata::v8::RuntimeMetadataV8, ToTypeRegistry);
346        impls_trait!(frame_metadata::v9::RuntimeMetadataV9, ToTypeRegistry);
347        impls_trait!(frame_metadata::v10::RuntimeMetadataV10, ToTypeRegistry);
348        impls_trait!(frame_metadata::v11::RuntimeMetadataV11, ToTypeRegistry);
349        impls_trait!(frame_metadata::v12::RuntimeMetadataV12, ToTypeRegistry);
350        impls_trait!(frame_metadata::v13::RuntimeMetadataV13, ToTypeRegistry);
351    };
352}