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}