Skip to main content

metadata_shortener/
traits.rs

1//! Traits for digest generation.
2use crate::std::borrow::ToOwned;
3
4#[cfg(all(any(feature = "merkle-lean", test), not(feature = "std")))]
5use core::any::TypeId;
6#[cfg(all(any(feature = "merkle-lean", test), feature = "std"))]
7use std::any::TypeId;
8
9#[cfg(any(feature = "merkle-standard", feature = "merkle-lean", test))]
10use crate::std::vec::Vec;
11
12#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
13use external_memory_tools::AddressableBuffer;
14use external_memory_tools::ExternalMemory;
15
16#[cfg(any(feature = "merkle-standard", test))]
17use frame_metadata::v15::RuntimeMetadataV15;
18
19#[cfg(any(feature = "merkle-standard", test))]
20use merkle_cbt::{merkle_tree::Merge, CBMT};
21
22#[cfg(any(feature = "merkle-lean", test))]
23use merkle_cbt_lean::{Hasher, Leaf, MerkleProof};
24
25use parity_scale_codec::{Decode, Encode};
26
27#[cfg(any(feature = "merkle-lean", test))]
28use scale_info::interner::UntrackedSymbol;
29#[cfg(any(feature = "merkle-standard", test))]
30use scale_info::PortableType;
31use scale_info::{form::PortableForm, PortableRegistry, Type, TypeDef};
32
33#[cfg(any(feature = "merkle-lean", test))]
34use substrate_parser::traits::{SignedExtensionMetadata, SpecNameVersion};
35use substrate_parser::{error::RegistryError, traits::ResolveType};
36#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
37use substrate_parser::{
38    error::SignableError, parse_transaction, parse_transaction_unmarked, traits::AsMetadata,
39    ShortSpecs, TransactionParsed, TransactionUnmarkedParsed,
40};
41
42#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
43use crate::cutter::MetadataDescriptor;
44#[cfg(any(feature = "merkle-lean", test))]
45use crate::cutter::ShortMetadata;
46use crate::cutter::{add_as_enum, add_ty_as_regular, DraftRegistry, LeavesRegistry, ShortRegistry};
47
48#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
49use crate::error::MetaCutError;
50#[cfg(any(feature = "merkle-lean", test))]
51use crate::error::MetadataDescriptorError;
52use crate::error::RegistryCutError;
53
54/// Hash length used throughout this crate.
55pub const LEN: usize = 32;
56
57/// Hasher used throughout this crate. Specifies hash structure and merging.
58#[derive(Debug)]
59pub struct Blake3Hasher;
60
61#[cfg(any(feature = "merkle-lean", test))]
62impl Hasher<LEN> for Blake3Hasher {
63    fn make(bytes: &[u8]) -> [u8; LEN] {
64        blake3::hash(bytes).into()
65    }
66    fn merge(left: &[u8; LEN], right: &[u8; LEN]) -> [u8; LEN] {
67        blake3::hash(&[left.as_slice(), right.as_slice()].concat()).into()
68    }
69}
70
71/// [`MerkleProof`] for metadata.
72///
73/// Hash length is set to [`LEN`], [`Hasher`] is specified as [`Blake3Hasher`].
74#[cfg(any(feature = "merkle-lean", test))]
75pub type MerkleProofMetadata<L, E> = MerkleProof<LEN, L, E, Blake3Hasher>;
76
77/// Example Merkle tree leaf. Length is set to [`LEN`], value is available
78/// without external memory access.
79#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq)]
80pub struct Blake3Leaf([u8; LEN]);
81
82#[cfg(any(feature = "proof-gen", test))]
83impl<E: ExternalMemory> Leaf<LEN, E> for Blake3Leaf {
84    fn read(&self, _ext_memory: &mut E) -> Result<[u8; LEN], E::ExternalMemoryError> {
85        Ok(self.0)
86    }
87    fn write(value: [u8; LEN], _ext_memory: &mut E) -> Result<Self, E::ExternalMemoryError> {
88        Ok(Self(value))
89    }
90}
91
92#[cfg(any(feature = "merkle-standard", test))]
93impl Merge for Blake3Hasher {
94    type Item = [u8; LEN];
95    fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item {
96        blake3::hash(&[*left, *right].concat()).into()
97    }
98}
99
100/// Make blake3 hash for values implementing `Encode`.
101///
102/// Applied on individual [`PortableType`] in Merkle tree generation and on
103/// [`MetadataDescriptor`] in digest calculation.
104#[cfg(any(feature = "merkle-standard", test))]
105pub fn blake3_leaf<T: Encode>(value: &T) -> [u8; LEN] {
106    blake3::hash(value.encode().as_ref()).into()
107}
108
109/// [`AsMetadata`] with registry implementing [`HashableRegistry`].
110#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
111pub trait HashableMetadata<E: ExternalMemory>: AsMetadata<E>
112where
113    <Self as AsMetadata<E>>::TypeRegistry: HashableRegistry<E>,
114{
115    /// Calculate Merkle tree root hash for original complete types data.
116    ///
117    /// This root hash must be identical both for shortened and full metadata.
118    /// Note that for any shortened metadata in addition to known types data,
119    /// serialized Merkle proof data would be required.
120    fn types_merkle_root(&self, ext_memory: &mut E) -> Result<[u8; LEN], MetaCutError<E, Self>>;
121
122    /// Calculate full digest with additionally provided chain [`ShortSpecs`].
123    fn digest_with_short_specs(
124        &self,
125        short_specs: &ShortSpecs,
126        ext_memory: &mut E,
127    ) -> Result<[u8; LEN], MetaCutError<E, Self>> {
128        let types_merkle_root = self.types_merkle_root(ext_memory)?;
129        let metadata_descriptor = MetadataDescriptor::V1 {
130            call_ty: self
131                .call_ty()
132                .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
133            signed_extensions: self
134                .signed_extensions()
135                .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
136            spec_name_version: self
137                .spec_name_version()
138                .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
139            base58prefix: short_specs.base58prefix,
140            decimals: short_specs.decimals,
141            unit: short_specs.unit.to_owned(),
142        };
143        #[cfg(all(feature = "merkle-standard", not(test)))]
144        {
145            let metadata_descriptor_blake3 =
146                blake3_leaf::<MetadataDescriptor>(&metadata_descriptor);
147            Ok(<Blake3Hasher as Merge>::merge(
148                &types_merkle_root,
149                &metadata_descriptor_blake3,
150            ))
151        }
152        #[cfg(any(not(feature = "merkle-standard"), test))]
153        {
154            let metadata_descriptor_blake3 = Blake3Hasher::make(&metadata_descriptor.encode());
155            Ok(<Blake3Hasher as Hasher<LEN>>::merge(
156                &types_merkle_root,
157                &metadata_descriptor_blake3,
158            ))
159        }
160    }
161}
162
163/// [`HashableMetadata`] with in-built [`ShortSpecs`].
164#[cfg(any(feature = "merkle-lean", feature = "merkle-standard", test))]
165pub trait ExtendedMetadata<E: ExternalMemory>: HashableMetadata<E> + Sized
166where
167    <Self as AsMetadata<E>>::TypeRegistry: HashableRegistry<E>,
168{
169    /// Extract [`ShortSpecs`].
170    fn to_specs(&self) -> Result<ShortSpecs, <Self as AsMetadata<E>>::MetaStructureError>;
171
172    /// Calculate full digest.
173    fn digest(&self, ext_memory: &mut E) -> Result<[u8; LEN], MetaCutError<E, Self>> {
174        self.digest_with_short_specs(
175            &self
176                .to_specs()
177                .map_err(|e| MetaCutError::Signable(SignableError::MetaStructure(e)))?,
178            ext_memory,
179        )
180    }
181
182    /// Parse transaction (with call length compact prefix, standard form).
183    ///
184    /// Note that the chain genesis hash is not provided for
185    /// [`substrate_parser::parse_transaction`] here and genesis hash from
186    /// transaction is not checked to match that of the chain.
187    ///
188    /// Genesis hash is nonetheless a part of signed bytes (without the genesis
189    /// hash the extensions set is considered invalid by [`substrate_parser`]).
190    /// Metadata `spec_name` is contained in [`MetadataDescriptor`] and thus
191    /// participates in digest calculation.
192    fn parse_transaction<B>(
193        &self,
194        data: &B,
195        ext_memory: &mut E,
196    ) -> Result<TransactionParsed<E, Self>, SignableError<E, Self>>
197    where
198        B: AddressableBuffer<E>,
199    {
200        parse_transaction::<B, E, Self>(data, ext_memory, self, None)
201    }
202
203    /// Parse unmarked transaction (**no** call length compact prefix).
204    ///
205    /// Note that the chain genesis hash is not provided for
206    /// [`substrate_parser::parse_transaction_unmarked`] here and genesis hash
207    /// from transaction is not checked to match that of the chain.
208    ///
209    /// Genesis hash is nonetheless a part of signed bytes (without the genesis
210    /// hash the extensions set is considered invalid by [`substrate_parser`]).
211    /// Metadata `spec_name` is contained in [`MetadataDescriptor`] and thus
212    /// participates in digest calculation.
213    fn parse_transaction_unmarked<B>(
214        &self,
215        data: &B,
216        ext_memory: &mut E,
217    ) -> Result<TransactionUnmarkedParsed, SignableError<E, Self>>
218    where
219        B: AddressableBuffer<E>,
220    {
221        parse_transaction_unmarked::<B, E, Self>(data, ext_memory, self, None)
222    }
223}
224
225/// Types registry that could be transformed into deterministically sorted set
226/// of Merkle tree leaves.
227pub trait HashableRegistry<E: ExternalMemory>: ResolveType<E> {
228    /// Calculate Merkle tree leaves set.
229    ///
230    /// Each leave is calculated using a single type entry (for non-enums) or
231    /// using an enum entry with a single enum variant (for enums).
232    ///
233    /// Sorting is done pre-hashing, by type id and by enum variant index within
234    /// single id.
235    fn merkle_leaves_source(&self) -> Result<LeavesRegistry, RegistryCutError>;
236}
237
238/// Implement [`HashableRegistry`].
239macro_rules! impl_hashable_registry {
240    ($($ty: ty), *) => {
241        $(
242            impl<E: ExternalMemory> HashableRegistry<E> for $ty {
243                fn merkle_leaves_source(&self) -> Result<LeavesRegistry, RegistryCutError> {
244                    let mut draft_registry = DraftRegistry::new();
245                    for registry_entry in self.types.iter() {
246                        match registry_entry.ty.type_def {
247                                TypeDef::Variant(ref type_def_variant) => {
248                                    if !type_def_variant.variants.is_empty() {
249                                        for variant in type_def_variant.variants.iter() {
250                                            add_as_enum(
251                                                &mut draft_registry,
252                                                &registry_entry.ty.path,
253                                                variant.to_owned(),
254                                                registry_entry.id,
255                                            )?;
256                                        }
257                                    }
258                                    else {
259                                        add_ty_as_regular(
260                                            &mut draft_registry,
261                                            registry_entry.ty.to_owned(),
262                                            registry_entry.id,
263                                        )?;
264                                    }
265                                }
266                                _ => {
267                                    add_ty_as_regular(
268                                        &mut draft_registry,
269                                        registry_entry.ty.to_owned(),
270                                        registry_entry.id,
271                                    )?;
272                                }
273                        }
274                    }
275                    Ok(draft_registry.into_leaves())
276                }
277            }
278        )*
279    }
280}
281
282impl_hashable_registry!(PortableRegistry, ShortRegistry);
283
284impl<E: ExternalMemory> ResolveType<E> for ShortRegistry {
285    fn resolve_ty(
286        &self,
287        id: u32,
288        _ext_memory: &mut E,
289    ) -> Result<Type<PortableForm>, RegistryError> {
290        for short_registry_entry in self.types.iter() {
291            if short_registry_entry.id == id {
292                return Ok(short_registry_entry.ty.to_owned());
293            }
294        }
295        Err(RegistryError::TypeNotResolved { id })
296    }
297}
298
299#[cfg(any(feature = "merkle-lean", test))]
300impl<E, L> AsMetadata<E> for ShortMetadata<L, E>
301where
302    L: Leaf<LEN, E>,
303    E: ExternalMemory,
304{
305    type TypeRegistry = ShortRegistry;
306
307    type MetaStructureError = MetadataDescriptorError;
308
309    fn types(&self) -> Self::TypeRegistry {
310        self.short_registry.to_owned()
311    }
312
313    fn spec_name_version(&self) -> Result<SpecNameVersion, Self::MetaStructureError> {
314        match &self.metadata_descriptor {
315            MetadataDescriptor::V0 => Err(MetadataDescriptorError::DescriptorVersionIncompatible),
316            MetadataDescriptor::V1 {
317                call_ty: _,
318                signed_extensions: _,
319                spec_name_version,
320                base58prefix: _,
321                decimals: _,
322                unit: _,
323            } => Ok(spec_name_version.to_owned()),
324        }
325    }
326
327    fn call_ty(&self) -> Result<UntrackedSymbol<TypeId>, Self::MetaStructureError> {
328        match &self.metadata_descriptor {
329            MetadataDescriptor::V0 => Err(MetadataDescriptorError::DescriptorVersionIncompatible),
330            MetadataDescriptor::V1 {
331                call_ty,
332                signed_extensions: _,
333                spec_name_version: _,
334                base58prefix: _,
335                decimals: _,
336                unit: _,
337            } => Ok(*call_ty),
338        }
339    }
340
341    fn signed_extensions(&self) -> Result<Vec<SignedExtensionMetadata>, Self::MetaStructureError> {
342        match &self.metadata_descriptor {
343            MetadataDescriptor::V0 => Err(MetadataDescriptorError::DescriptorVersionIncompatible),
344            MetadataDescriptor::V1 {
345                call_ty: _,
346                signed_extensions,
347                spec_name_version: _,
348                base58prefix: _,
349                decimals: _,
350                unit: _,
351            } => Ok(signed_extensions.to_owned()),
352        }
353    }
354}
355
356#[cfg(any(feature = "merkle-lean", test))]
357impl<E, L> HashableMetadata<E> for ShortMetadata<L, E>
358where
359    L: Leaf<LEN, E>,
360    E: ExternalMemory,
361{
362    fn types_merkle_root(
363        &self,
364        ext_memory: &mut E,
365    ) -> Result<[u8; LEN], MetaCutError<E, ShortMetadata<L, E>>> {
366        let leaves_registry =
367            <ShortRegistry as HashableRegistry<E>>::merkle_leaves_source(&self.short_registry)
368                .map_err(MetaCutError::Registry)?;
369        let leaves: Vec<[u8; LEN]> = leaves_registry
370            .types
371            .iter()
372            .map(|entry| Blake3Hasher::make(&entry.encode()))
373            .collect();
374        let mut proof = MerkleProofMetadata::new_with_external_indices(
375            leaves,
376            self.indices.to_vec(),
377            self.lemmas.to_vec(),
378        )
379        .map_err(MetaCutError::TreeConstructProof)?;
380        proof
381            .calculate_root(ext_memory)
382            .map_err(MetaCutError::TreeCalculateRoot)
383    }
384}
385
386#[cfg(any(feature = "merkle-lean", test))]
387impl<E, L> ExtendedMetadata<E> for ShortMetadata<L, E>
388where
389    L: Leaf<LEN, E>,
390    E: ExternalMemory,
391{
392    fn to_specs(&self) -> Result<ShortSpecs, Self::MetaStructureError> {
393        match &self.metadata_descriptor {
394            MetadataDescriptor::V0 => Err(MetadataDescriptorError::DescriptorVersionIncompatible),
395            MetadataDescriptor::V1 {
396                call_ty: _,
397                signed_extensions: _,
398                spec_name_version: _,
399                base58prefix,
400                decimals,
401                unit,
402            } => Ok(ShortSpecs {
403                base58prefix: *base58prefix,
404                decimals: *decimals,
405                unit: unit.to_owned(),
406            }),
407        }
408    }
409}
410
411#[cfg(any(feature = "merkle-standard", test))]
412impl<E: ExternalMemory> HashableMetadata<E> for RuntimeMetadataV15 {
413    fn types_merkle_root(
414        &self,
415        _ext_memory: &mut E,
416    ) -> Result<[u8; LEN], MetaCutError<E, RuntimeMetadataV15>> {
417        let leaves_registry =
418            <PortableRegistry as HashableRegistry<E>>::merkle_leaves_source(&self.types)
419                .map_err(MetaCutError::Registry)?;
420        let leaves: Vec<[u8; LEN]> = leaves_registry
421            .types
422            .iter()
423            .map(blake3_leaf::<PortableType>)
424            .collect();
425        Ok(CBMT::<[u8; LEN], Blake3Hasher>::build_merkle_root(&leaves))
426    }
427}