config: Handle hasher and header

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
Alexandru Vasile
2024-05-08 08:34:52 +00:00
parent a1434a9764
commit 609b701d4d
4 changed files with 125 additions and 8 deletions
+104 -4
View File
@@ -3,9 +3,10 @@
// see LICENSE for license details.
use heck::ToSnakeCase as _;
use scale_info::{TypeDef, TypeDefComposite};
use scale_typegen::typegen::ir::ToTokensWithSettings;
use scale_typegen::TypeGenerator;
use std::collections::HashSet;
use std::{any::Any, collections::HashSet};
use subxt_metadata::{CustomValueMetadata, Metadata};
use proc_macro2::TokenStream as TokenStream2;
@@ -20,14 +21,113 @@ pub fn generate_custom_values(
let mut fn_names_taken = HashSet::new();
let custom = metadata.custom();
let custom_types = custom.iter().map(|custom| {
let name = format_ident!("{}", custom.name());
let name_str = custom.name();
let Ok(ty) = type_gen.resolve_type_path(custom.type_id()) else {
let name = format_ident!("{}", name_str);
let Ok(ty_path) = type_gen.resolve_type_path(custom.type_id()) else {
return quote! {};
};
let ty = ty.to_token_stream(type_gen.settings());
let ty = ty_path.to_token_stream(type_gen.settings());
let mut maybe_impl = None;
let mut extra = None;
if name_str == "Hashing" {
// Extract hasher name
let ty_path_str = ty.to_string();
if ty_path_str.contains("BlakeTwo256") {
maybe_impl = Some(quote! {
impl #crate_path::config::Hasher for #ty {
type Output = #crate_path::utils::H256;
fn hash(s: &[u8]) -> Self::Output {
let mut bytes = Vec::new();
#crate_path::storage::utils::hash_bytes(s, #crate_path::storage::utils::StorageHasher::Blake2_256, &mut bytes);
let arr: [u8; 32] = bytes.try_into().expect("Invalid hashing output provided");
arr.into()
}
}
});
}
}
if name_str == "Header" {
// Extract header number from the provided type.
let Ok(ty_res) = type_gen.resolve_type(custom.type_id()) else {
return quote! {};
};
let TypeDef::Composite(composite) = &ty_res.type_def else {
return quote! {};
};
// Sanity check for the number type.
let number_ty = composite.fields.iter().find_map(
|field| if let Some(n) = &field.name {
if n == "number" {
Some(field.ty.id)
} else {
None
}
} else {
None
}
);
if let Some(num) = number_ty {
let Ok(ty_path) = type_gen.resolve_type_path(num) else {
return quote! {};
};
if !ty_path.is_compact() {
let ty = ty_path.to_token_stream(type_gen.settings());
extra = Some(quote! {
pub type HeaderNumber = #ty;
});
} else {
// Ty is compact.
let Ok(ty_res) = type_gen.resolve_type(num) else {
return quote! {};
};
let TypeDef::Compact(compact) = &ty_res.type_def else {
return quote! {};
};
let compact_ty_id = compact.type_param.id;
let Ok(ty_path) = type_gen.resolve_type_path(compact_ty_id) else {
return quote! {};
};
let ty = ty_path.to_token_stream(type_gen.settings());
extra = Some(quote! {
pub type HeaderNumber = #ty;
});
}
maybe_impl = Some(quote! {
impl #crate_path::config::Header for #ty {
type Number = HeaderNumber;
type Hasher = Hashing;
// If we got to this point, the `number` field exists on the header
// structure.
fn number(&self) -> Self::Number {
self.number
}
}
});
}
}
quote! {
pub type #name = #ty;
#maybe_impl
#extra
}
});
+1 -1
View File
@@ -42,7 +42,7 @@
//! ```
mod storage_key;
mod utils;
pub mod utils;
pub mod address;
+2 -1
View File
@@ -11,7 +11,8 @@ use crate::error::{Error, MetadataError};
use crate::metadata::Metadata;
use alloc::borrow::ToOwned;
use alloc::vec::Vec;
use subxt_metadata::{PalletMetadata, StorageEntryMetadata, StorageHasher};
pub use subxt_metadata::StorageHasher;
use subxt_metadata::{PalletMetadata, StorageEntryMetadata};
/// Return the root of a given [`Address`]: hash the pallet name and entry name
/// and append those bytes to the output.
+18 -2
View File
@@ -1,5 +1,6 @@
#![allow(missing_docs)]
use subxt::{OnlineClient, SubstrateConfig};
use subxt_core::config::substrate::SubstrateHeader;
use subxt_core::config::{Config, DefaultExtrinsicParams};
use subxt_signer::sr25519::dev;
@@ -20,10 +21,25 @@ impl Config for MetadataConfig {
// Present in metadata but this PoC needs to add
// fn specific per name of type to impl the hashing fn.
type Hasher = <SubstrateConfig as Config>::Hasher;
// type Hasher = <SubstrateConfig as Config>::Hasher;
//
// TODO: Eventually extend this to a DynamicHasher object instead.
// Similar logic already exists for StorageHasher.
type Hasher = polkadot::custom_types::Hashing;
// Present in metadata but this PoC needs to impl the header
// trait to make use of this.
type Header = <SubstrateConfig as Config>::Header;
// type Header = <SubstrateConfig as Config>::Header;
// The metadata header type must implement `Deserialize`, which
// must be manually implemented for the Digest logs of the header.
// An alternative is to extract the header number and use the
// generated hasher to expose the same information, this is not
// as robust and codgen can be used instead.
// type Header = polkadot::custom_types::Header;
type Header =
SubstrateHeader<polkadot::custom_types::HeaderNumber, polkadot::custom_types::Hashing>;
// Same story, present in md but needs subxt::tx::Signer<T>.
// type Signature = polkadot::custom_types::Signature;
type Signature = <SubstrateConfig as Config>::Signature;