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 decoding;
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    //! - See [`decode_extrinsic_legacy`] for a helper (and example) on decoding legacy extrinsics.
36    //!
37
38    use crate::utils::InfoAndResolver;
39    use scale_type_resolver::TypeResolver;
40
41    pub use crate::decoding::extrinsic_decoder::{
42        decode_extrinsic, Extrinsic, ExtrinsicDecodeError, ExtrinsicExtensions, ExtrinsicOwned,
43        ExtrinsicSignature, ExtrinsicType,
44    };
45    pub use crate::decoding::extrinsic_type_info::{
46        ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
47        ExtrinsicSignatureInfo, ExtrinsicTypeInfo,
48    };
49
50    /// Decode an extrinsic in a modern runtime (ie one exposing V14+ metadata).
51    ///
52    /// See [`decode_extrinsic`] for a more comprehensive example.
53    ///
54    /// # Example
55    ///
56    /// ```rust
57    /// use frame_decode::extrinsics::decode_extrinsic_current;
58    /// use frame_metadata::RuntimeMetadata;
59    /// use parity_scale_codec::Decode;
60    ///
61    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
62    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { panic!() };
63    ///
64    /// let extrinsics_bytes = std::fs::read("artifacts/exts_10000000_9180.json").unwrap();
65    /// let extrinsics_hex: Vec<String> = serde_json::from_slice(&extrinsics_bytes).unwrap();
66    ///
67    /// for ext_hex in extrinsics_hex {
68    ///     let ext_bytes = hex::decode(ext_hex.trim_start_matches("0x")).unwrap();
69    ///
70    ///     // Decode the extrinsic, returning information about it:
71    ///     let ext_info = decode_extrinsic_current(&mut &*ext_bytes, &metadata).unwrap();
72    ///
73    ///     // Now we can use this information to inspect the extrinsic and decode the
74    ///     // different values inside it (see the `decode_extrinsic` docs).
75    /// }
76    /// ```
77    pub fn decode_extrinsic_current<'info_and_resolver, T>(
78        cursor: &mut &[u8],
79        metadata: &'info_and_resolver T,
80    ) -> Result<
81        Extrinsic<'info_and_resolver, <T::Info as ExtrinsicTypeInfo>::TypeId>,
82        ExtrinsicDecodeError,
83    >
84    where
85        T: InfoAndResolver,
86        T::Info: ExtrinsicTypeInfo,
87        <T::Info as ExtrinsicTypeInfo>::TypeId: core::fmt::Debug + Clone,
88        T::Resolver:
89            scale_type_resolver::TypeResolver<TypeId = <T::Info as ExtrinsicTypeInfo>::TypeId>,
90    {
91        decode_extrinsic(cursor, metadata.info(), metadata.resolver())
92    }
93
94    /// Decode an extrinsic in a historic runtime (ie one prior to V14 metadata). This is basically
95    /// just an alias for [`decode_extrinsic`].
96    ///
97    /// To understand more about the historic types required to decode old blocks, see [`scale_info_legacy`].
98    ///
99    /// # Example
100    ///
101    /// ```rust
102    /// use frame_decode::extrinsics::decode_extrinsic_legacy;
103    /// use frame_metadata::RuntimeMetadata;
104    /// use parity_scale_codec::Decode;
105    /// use scale_info_legacy::ChainTypeRegistry;
106    ///
107    /// let metadata_bytes = std::fs::read("artifacts/metadata_5000000_30.scale").unwrap();
108    /// let RuntimeMetadata::V12(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { panic!() };
109    ///
110    /// let extrinsics_bytes = std::fs::read("artifacts/exts_5000000_30.json").unwrap();
111    /// let extrinsics_hex: Vec<String> = serde_json::from_slice(&extrinsics_bytes).unwrap();
112    ///
113    /// // For historic types, we also need to provide type definitions, since they aren't in the
114    /// // metadata. We use scale-info-legacy to do this, and have already defined types for the
115    /// // Polkadot relay chain, so let's load those in:
116    /// let historic_type_bytes = std::fs::read("types/polkadot_types.yaml").unwrap();
117    /// let historic_types: ChainTypeRegistry = serde_yaml::from_slice(&historic_type_bytes).unwrap();
118    ///
119    /// // We configure the loaded types for the spec version of the extrinsics we want to decode,
120    /// // because types can vary between different spec versions.
121    /// let mut historic_types_for_spec = historic_types.for_spec_version(30);
122    ///
123    /// // We also want to embelish these types with information from the metadata itself. This avoids
124    /// // needing to hardcode a load of type definitions that we can already construct from the metadata.
125    /// let types_from_metadata = frame_decode::helpers::type_registry_from_metadata(&metadata).unwrap();
126    /// historic_types_for_spec.prepend(types_from_metadata);
127    ///
128    /// for ext_hex in extrinsics_hex {
129    ///     let ext_bytes = hex::decode(ext_hex.trim_start_matches("0x")).unwrap();
130    ///
131    ///     // Decode the extrinsic, returning information about it:
132    ///     let ext_info = decode_extrinsic_legacy(&mut &*ext_bytes, &metadata, &historic_types_for_spec).unwrap();
133    ///
134    ///     // Now we can use this information to inspect the extrinsic and decode the
135    ///     // different values inside it (see the `decode_extrinsic` docs).
136    /// }
137    /// ```
138    pub fn decode_extrinsic_legacy<'info, Info, Resolver>(
139        cursor: &mut &[u8],
140        info: &'info Info,
141        type_resolver: &Resolver,
142    ) -> Result<Extrinsic<'info, Info::TypeId>, ExtrinsicDecodeError>
143    where
144        Info: ExtrinsicTypeInfo,
145        Info::TypeId: core::fmt::Debug + Clone,
146        Resolver: TypeResolver<TypeId = Info::TypeId>,
147    {
148        decode_extrinsic(cursor, info, type_resolver)
149    }
150}
151
152pub mod storage {
153    //! This module contains functions for decoding storage keys and values.
154    //!
155    //! - See [`decode_storage_key`] and [`decode_storage_value`] to decode storage keys or values
156    //!   from modern or historic runtimes.
157    //! - See [`decode_storage_key_current`] and [`decode_storage_value_current`] to decode modern
158    //!   storage keys and values.
159    //! - See [`decode_storage_key_legacy`] and [`decode_storage_value_legacy`] to decode historic
160    //!   storage keys and values (with examples).
161    //!
162
163    use crate::utils::InfoAndResolver;
164    use scale_decode::Visitor;
165    use scale_type_resolver::TypeResolver;
166
167    pub use crate::decoding::storage_type_info::{
168        StorageHasher, StorageInfo, StorageInfoError, StorageKeyInfo, StorageTypeInfo,
169    };
170
171    pub use crate::decoding::storage_decoder::{
172        decode_storage_key, decode_storage_value, StorageKey, StorageKeyDecodeError,
173        StorageKeyPart, StorageKeyPartValue, StorageValueDecodeError,
174    };
175
176    type TypeIdOf<T> = <<T as InfoAndResolver>::Info as StorageTypeInfo>::TypeId;
177
178    /// Decode a storage key in a modern runtime, returning information about it.
179    ///
180    /// This information can be used to identify and, where possible, decode the parts of the storage key.
181    ///
182    /// See [`decode_storage_key`] for a more complete example.
183    ///
184    /// # Example
185    ///
186    /// Here, we decode some storage keys from a block.
187    ///
188    /// ```rust
189    /// use frame_decode::storage::decode_storage_key_current;
190    /// use frame_decode::helpers::decode_with_visitor;
191    /// use frame_metadata::RuntimeMetadata;
192    /// use parity_scale_codec::Decode;
193    /// use scale_value::scale::ValueVisitor;
194    ///
195    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
196    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { return };
197    ///
198    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_10000000_9180_system_account.json").unwrap();
199    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
200    ///
201    /// for (key, _val) in storage_keyval_hex {
202    ///     let key_bytes = hex::decode(key.trim_start_matches("0x")).unwrap();
203    ///
204    ///     // Decode the storage key, returning information about it:
205    ///     let storage_info = decode_storage_key_current(
206    ///         "System",
207    ///         "Account",
208    ///         &mut &*key_bytes,
209    ///         &metadata,
210    ///     ).unwrap();
211    ///
212    ///     // See `decode_storage_key` for more.
213    /// }
214    /// ```
215    pub fn decode_storage_key_current<T>(
216        pallet_name: &str,
217        storage_entry: &str,
218        cursor: &mut &[u8],
219        metadata: &T,
220    ) -> Result<StorageKey<TypeIdOf<T>>, StorageKeyDecodeError<TypeIdOf<T>>>
221    where
222        T: InfoAndResolver,
223        T::Info: StorageTypeInfo,
224        TypeIdOf<T>: core::fmt::Debug + Clone,
225        T::Resolver: TypeResolver<TypeId = TypeIdOf<T>>,
226    {
227        decode_storage_key(
228            pallet_name,
229            storage_entry,
230            cursor,
231            metadata.info(),
232            metadata.resolver(),
233        )
234    }
235
236    /// Decode a storage key in a historic (pre-V14-metadata) runtime, returning information about it.
237    ///
238    /// This information can be used to identify and, where possible, decode the parts of the storage key.
239    ///
240    /// This is basically just an alias for [`decode_storage_key`]. See that for a more complete example.
241    ///
242    /// # Example
243    ///
244    /// Here, we decode some storage keys from a block.
245    ///
246    /// ```rust
247    /// use frame_decode::storage::decode_storage_key_legacy;
248    /// use frame_metadata::RuntimeMetadata;
249    /// use parity_scale_codec::Decode;
250    /// use scale_info_legacy::ChainTypeRegistry;
251    ///
252    /// let metadata_bytes = std::fs::read("artifacts/metadata_5000000_30.scale").unwrap();
253    /// let RuntimeMetadata::V12(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { panic!() };
254    ///  
255    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_5000000_30_staking_validators.json").unwrap();
256    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
257    ///
258    /// // For historic types, we also need to provide type definitions, since they aren't in the
259    /// // metadata. We use scale-info-legacy to do this, and have already defined types for the
260    /// // Polkadot relay chain, so let's load those in:
261    /// let historic_type_bytes = std::fs::read("types/polkadot_types.yaml").unwrap();
262    /// let historic_types: ChainTypeRegistry = serde_yaml::from_slice(&historic_type_bytes).unwrap();
263    ///
264    /// // We configure the loaded types for the spec version of the extrinsics we want to decode,
265    /// // because types can vary between different spec versions.
266    /// let mut historic_types_for_spec = historic_types.for_spec_version(30);
267    ///
268    /// // We also want to embelish these types with information from the metadata itself. This avoids
269    /// // needing to hardcode a load of type definitions that we can already construct from the metadata.
270    /// let types_from_metadata = frame_decode::helpers::type_registry_from_metadata(&metadata).unwrap();
271    /// historic_types_for_spec.prepend(types_from_metadata);
272    ///
273    /// for (key, _val) in storage_keyval_hex {
274    ///     let key_bytes = hex::decode(key.trim_start_matches("0x")).unwrap();
275    ///
276    ///     // Decode the storage key, returning information about it:
277    ///     let storage_info = decode_storage_key_legacy(
278    ///         "Staking",
279    ///         "Validators",
280    ///         &mut &*key_bytes,
281    ///         &metadata,
282    ///         &historic_types_for_spec
283    ///     ).unwrap();
284    ///
285    ///     // See `decode_storage_key` for more.
286    /// }
287    /// ```
288    #[cfg(feature = "legacy")]
289    pub fn decode_storage_key_legacy<Info, Resolver>(
290        pallet_name: &str,
291        storage_entry: &str,
292        cursor: &mut &[u8],
293        info: &Info,
294        type_resolver: &Resolver,
295    ) -> Result<StorageKey<Info::TypeId>, StorageKeyDecodeError<Info::TypeId>>
296    where
297        Info: StorageTypeInfo,
298        Info::TypeId: Clone + core::fmt::Debug,
299        Resolver: TypeResolver<TypeId = Info::TypeId>,
300    {
301        decode_storage_key(pallet_name, storage_entry, cursor, info, type_resolver)
302    }
303
304    /// Decode a storage value in a modern (V14-metadata-or-later) runtime.
305    ///
306    /// # Example
307    ///
308    /// Here, we decode some storage values from a block.
309    ///
310    /// ```rust
311    /// use frame_decode::storage::decode_storage_value_current;
312    /// use frame_decode::helpers::decode_with_visitor;
313    /// use frame_metadata::RuntimeMetadata;
314    /// use parity_scale_codec::Decode;
315    /// use scale_value::scale::ValueVisitor;
316    ///
317    /// let metadata_bytes = std::fs::read("artifacts/metadata_10000000_9180.scale").unwrap();
318    /// let RuntimeMetadata::V14(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { return };
319    ///
320    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_10000000_9180_system_account.json").unwrap();
321    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
322    ///
323    /// for (_key, val) in storage_keyval_hex {
324    ///     let value_bytes = hex::decode(val.trim_start_matches("0x")).unwrap();
325    ///
326    ///     // Decode the storage value, here into a scale_value::Value:
327    ///     let account_value = decode_storage_value_current(
328    ///         "System",
329    ///         "Account",
330    ///         &mut &*value_bytes,
331    ///         &metadata,
332    ///         ValueVisitor::new()
333    ///     ).unwrap();
334    /// }
335    /// ```
336    pub fn decode_storage_value_current<'scale, 'resolver, T, V>(
337        pallet_name: &str,
338        storage_entry: &str,
339        cursor: &mut &'scale [u8],
340        metadata: &'resolver T,
341        visitor: V,
342    ) -> Result<V::Value<'scale, 'resolver>, StorageValueDecodeError<TypeIdOf<T>>>
343    where
344        T: InfoAndResolver,
345        T::Info: StorageTypeInfo,
346        TypeIdOf<T>: core::fmt::Debug + Clone,
347        T::Resolver: scale_type_resolver::TypeResolver<TypeId = TypeIdOf<T>>,
348        V: Visitor<TypeResolver = T::Resolver>,
349        V::Error: core::fmt::Debug,
350    {
351        decode_storage_value(
352            pallet_name,
353            storage_entry,
354            cursor,
355            metadata.info(),
356            metadata.resolver(),
357            visitor,
358        )
359    }
360
361    /// Decode a storage value in a historic (pre-V14-metadata) runtime. This is basically
362    /// just an alias for [`decode_storage_value`].
363    ///
364    /// # Example
365    ///
366    /// Here, we decode some storage values from a block.
367    ///
368    /// ```rust
369    /// use frame_decode::storage::decode_storage_value_legacy;
370    /// use frame_metadata::RuntimeMetadata;
371    /// use parity_scale_codec::Decode;
372    /// use scale_info_legacy::ChainTypeRegistry;
373    /// use scale_value::scale::ValueVisitor;
374    ///
375    /// let metadata_bytes = std::fs::read("artifacts/metadata_5000000_30.scale").unwrap();
376    /// let RuntimeMetadata::V12(metadata) = RuntimeMetadata::decode(&mut &*metadata_bytes).unwrap() else { panic!() };
377    ///  
378    /// let storage_keyval_bytes = std::fs::read("artifacts/storage_5000000_30_staking_validators.json").unwrap();
379    /// let storage_keyval_hex: Vec<(String, String)> = serde_json::from_slice(&storage_keyval_bytes).unwrap();
380    ///
381    /// // For historic types, we also need to provide type definitions, since they aren't in the
382    /// // metadata. We use scale-info-legacy to do this, and have already defined types for the
383    /// // Polkadot relay chain, so let's load those in:
384    /// let historic_type_bytes = std::fs::read("types/polkadot_types.yaml").unwrap();
385    /// let historic_types: ChainTypeRegistry = serde_yaml::from_slice(&historic_type_bytes).unwrap();
386    ///
387    /// // We configure the loaded types for the spec version of the extrinsics we want to decode,
388    /// // because types can vary between different spec versions.
389    /// let mut historic_types_for_spec = historic_types.for_spec_version(30);
390    ///
391    /// // We also want to embelish these types with information from the metadata itself. This avoids
392    /// // needing to hardcode a load of type definitions that we can already construct from the metadata.
393    /// let types_from_metadata = frame_decode::helpers::type_registry_from_metadata(&metadata).unwrap();
394    /// historic_types_for_spec.prepend(types_from_metadata);
395    ///
396    /// for (_key, val) in storage_keyval_hex {
397    ///     let value_bytes = hex::decode(val.trim_start_matches("0x")).unwrap();
398    ///
399    ///     // Decode the storage value, here into a scale_value::Value:
400    ///     let account_value = decode_storage_value_legacy(
401    ///         "Staking",
402    ///         "Validators",
403    ///         &mut &*value_bytes,
404    ///         &metadata,
405    ///         &historic_types_for_spec,
406    ///         ValueVisitor::new()
407    ///     ).unwrap();
408    /// }
409    /// ```    
410    #[cfg(feature = "legacy")]
411    pub fn decode_storage_value_legacy<'scale, 'resolver, Info, Resolver, V>(
412        pallet_name: &str,
413        storage_entry: &str,
414        cursor: &mut &'scale [u8],
415        info: &Info,
416        type_resolver: &'resolver Resolver,
417        visitor: V,
418    ) -> Result<V::Value<'scale, 'resolver>, StorageValueDecodeError<Info::TypeId>>
419    where
420        Info: StorageTypeInfo,
421        Info::TypeId: Clone + core::fmt::Debug,
422        Resolver: TypeResolver<TypeId = Info::TypeId>,
423        V: scale_decode::Visitor<TypeResolver = Resolver>,
424        V::Error: core::fmt::Debug,
425    {
426        decode_storage_value(
427            pallet_name,
428            storage_entry,
429            cursor,
430            info,
431            type_resolver,
432            visitor,
433        )
434    }
435}
436
437pub mod helpers {
438    //! Helper functions and types to assist with decoding.
439    //!
440    //! - [`type_registry_from_metadata`] is expected to be used when decoding things from historic
441    //!   runtimes, adding the ability to decode some types from information in the metadata.
442    //! - [`decode_with_error_tracing`] is like [`decode_with_visitor`], but
443    //!   will use a tracing visitor (if the `error-tracing` feature is enabled) to provide more
444    //!   information in the event that decoding fails.
445    //! - [`list_storage_entries`] returns an iterator over all of the storage entries available in
446    //!   some metadata.
447    //!
448
449    pub use crate::utils::{decode_with_error_tracing, DecodeErrorTrace};
450    pub use crate::utils::{list_storage_entries, list_storage_entries_any, StorageEntry};
451    #[cfg(feature = "legacy")]
452    pub use crate::utils::{type_registry_from_metadata, type_registry_from_metadata_any};
453
454    /// An alias to [`scale_decode::visitor::decode_with_visitor`]. This can be used to decode the byte ranges
455    /// given back from functions like [`crate::extrinsics::decode_extrinsic_current`] or
456    /// [`crate::storage::decode_storage_key_current`].
457    ///
458    pub use scale_decode::visitor::decode_with_visitor;
459
460    /// An alias to the underlying [`scale-decode`] crate.
461    ///
462    pub use scale_decode;
463}