Skip to content

Commit

Permalink
move outer enums to their own module
Browse files Browse the repository at this point in the history
  • Loading branch information
tadeohepperle committed Dec 5, 2023
1 parent 84a9e77 commit e4d2af6
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 78 deletions.
2 changes: 1 addition & 1 deletion metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use scale_info::{form::PortableForm, PortableRegistry, Variant};
use std::collections::HashMap;
use std::sync::Arc;
use utils::variant_index::VariantIndex;
use utils::{ordered_map::OrderedMap, validation::OuterEnumHashes};
use utils::{ordered_map::OrderedMap, validation::outer_enum_hashes::OuterEnumHashes};

type ArcStr = Arc<str>;

Expand Down
81 changes: 4 additions & 77 deletions metadata/src/utils/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ use crate::{
CustomMetadata, CustomValueMetadata, ExtrinsicMetadata, Metadata, PalletMetadata,
RuntimeApiMetadata, RuntimeApiMethodMetadata, StorageEntryMetadata, StorageEntryType,
};
use outer_enum_hashes::OuterEnumHashes;
use scale_info::{form::PortableForm, Field, PortableRegistry, TypeDef, TypeDefVariant, Variant};
use std::collections::HashMap;

pub mod outer_enum_hashes;

// The number of bytes our `hash` function produces.
pub(crate) const HASH_LEN: usize = 32;
pub type Hash = [u8; HASH_LEN];
Expand Down Expand Up @@ -246,8 +249,7 @@ fn get_type_hash_recurse(
cache: &mut HashMap<u32, CachedHash>,
outer_enum_hashes: &OuterEnumHashes,
) -> Hash {
// If the type is part of `precomputed` hashes, return the precomputed hash instead:

// If the type is part of precomputed outer enum hashes, the respective hash is used instead:
if let Some(hash) = outer_enum_hashes.resolve(id) {
return hash;
}
Expand Down Expand Up @@ -308,81 +310,6 @@ fn get_extrinsic_hash(
bytes
}

/// Hash representations of the `frame_metadata::v15::OuterEnums`.
pub struct OuterEnumHashes {
call_hash: (u32, Hash),
error_hash: (u32, Hash),
event_hash: (u32, Hash),
}

impl OuterEnumHashes {
/// Constructs new `OuterEnumHashes` from metadata. If `only_these_variants` is set, the enums are stripped down to only these variants, before their hashes are calculated.
pub fn new(metadata: &Metadata, only_these_variants: Option<&[&str]>) -> Self {
fn get_enum_hash(
registry: &PortableRegistry,
id: u32,
only_these_variants: Option<&[&str]>,
) -> Hash {
let ty = registry
.types
.get(id as usize)
.expect("Metadata should contain enum type in registry");

if let TypeDef::Variant(variant) = &ty.ty.type_def {
get_type_def_variant_hash(
registry,
variant,
only_these_variants,
&mut HashMap::new(),
// ignored, because not computed yet...
&OuterEnumHashes::empty(),
)
} else {
get_type_hash(registry, id, &OuterEnumHashes::empty())
}
}
let enums = &metadata.outer_enums;

let call_hash = get_enum_hash(metadata.types(), enums.call_enum_ty, only_these_variants);
let event_hash = get_enum_hash(metadata.types(), enums.event_enum_ty, only_these_variants);
let error_hash = get_enum_hash(metadata.types(), enums.error_enum_ty, only_these_variants);

Self {
call_hash: (enums.call_enum_ty, call_hash),
error_hash: (enums.error_enum_ty, error_hash),
event_hash: (enums.event_enum_ty, event_hash),
}
}

/// Constructs empty `OuterEnumHashes` with type ids that are never a real type id.
/// Can be used as a placeholder when outer enum hashes are required but should be ignored.
pub fn empty() -> Self {
Self {
call_hash: (u32::MAX, [0; HASH_LEN]),
error_hash: (u32::MAX, [0; HASH_LEN]),
event_hash: (u32::MAX, [0; HASH_LEN]),
}
}

/// Returns a combined hash of the top level enums.
pub fn combined_hash(&self) -> Hash {
concat_and_hash3(&self.call_hash.1, &self.error_hash.1, &self.event_hash.1)
}

/// Checks if a type is one of the 3 top level enum types. If so, returns Some(hash).
///
/// This is useful, because top level enums are sometimes stripped down to only certain pallets.
/// The hashes of these stripped down types are stored in this struct.
pub fn resolve(&self, id: u32) -> Option<[u8; HASH_LEN]> {
match id {
e if e == self.error_hash.0 => Some(self.error_hash.1),
e if e == self.event_hash.0 => Some(self.event_hash.1),
e if e == self.call_hash.0 => Some(self.call_hash.1),
_ => None,
}
}
}

/// Get the hash corresponding to a single storage entry.
fn get_storage_entry_hash(
registry: &PortableRegistry,
Expand Down
87 changes: 87 additions & 0 deletions metadata/src/utils/validation/outer_enum_hashes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Hash representations of the `frame_metadata::v15::OuterEnums`.
use std::collections::HashMap;

use scale_info::{PortableRegistry, TypeDef};

use crate::{
utils::validation::{get_type_def_variant_hash, get_type_hash},
Metadata,
};

use super::{concat_and_hash3, Hash, HASH_LEN};

/// Hash representations of the `frame_metadata::v15::OuterEnums`.
pub struct OuterEnumHashes {
call_hash: (u32, Hash),
error_hash: (u32, Hash),
event_hash: (u32, Hash),
}

impl OuterEnumHashes {
/// Constructs new `OuterEnumHashes` from metadata. If `only_these_variants` is set, the enums are stripped down to only these variants, before their hashes are calculated.
pub fn new(metadata: &Metadata, only_these_variants: Option<&[&str]>) -> Self {
fn get_enum_hash(
registry: &PortableRegistry,
id: u32,
only_these_variants: Option<&[&str]>,
) -> Hash {
let ty = registry
.types
.get(id as usize)
.expect("Metadata should contain enum type in registry");

if let TypeDef::Variant(variant) = &ty.ty.type_def {
get_type_def_variant_hash(
registry,
variant,
only_these_variants,
&mut HashMap::new(),
// ignored, because not computed yet...
&OuterEnumHashes::empty(),
)
} else {
get_type_hash(registry, id, &OuterEnumHashes::empty())
}
}
let enums = &metadata.outer_enums;

let call_hash = get_enum_hash(metadata.types(), enums.call_enum_ty, only_these_variants);
let event_hash = get_enum_hash(metadata.types(), enums.event_enum_ty, only_these_variants);
let error_hash = get_enum_hash(metadata.types(), enums.error_enum_ty, only_these_variants);

Self {
call_hash: (enums.call_enum_ty, call_hash),
error_hash: (enums.error_enum_ty, error_hash),
event_hash: (enums.event_enum_ty, event_hash),
}
}

/// Constructs empty `OuterEnumHashes` with type ids that are never a real type id.
/// Can be used as a placeholder when outer enum hashes are required but should be ignored.
pub fn empty() -> Self {
Self {
call_hash: (u32::MAX, [0; HASH_LEN]),
error_hash: (u32::MAX, [0; HASH_LEN]),
event_hash: (u32::MAX, [0; HASH_LEN]),
}
}

/// Returns a combined hash of the top level enums.
pub fn combined_hash(&self) -> Hash {
concat_and_hash3(&self.call_hash.1, &self.error_hash.1, &self.event_hash.1)
}

/// Checks if a type is one of the 3 top level enum types. If so, returns Some(hash).
///
/// This is useful, because top level enums are sometimes stripped down to only certain pallets.
/// The hashes of these stripped down types are stored in this struct.
pub fn resolve(&self, id: u32) -> Option<[u8; HASH_LEN]> {
match id {
e if e == self.error_hash.0 => Some(self.error_hash.1),
e if e == self.event_hash.0 => Some(self.event_hash.1),
e if e == self.call_hash.0 => Some(self.call_hash.1),
_ => None,
}
}
}

0 comments on commit e4d2af6

Please sign in to comment.