use crate::prelude::*;
use core::{borrow::Borrow, slice};
use codec::Decode;
#[cfg(any(feature = "v12", feature = "v13"))]
use frame_metadata::decode_different::DecodeDifferent;
use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
#[cfg(feature = "v12")]
pub use v12::*;
#[cfg(feature = "v13")]
pub use v13::*;
#[cfg(feature = "v14")]
pub use v14::*;
use crate::hasher::hash;
#[cfg(feature = "v12")]
mod v12 {
use frame_metadata::v12::*;
pub type Metadata = RuntimeMetadataV12;
pub type PalletMeta = ModuleMetadata;
pub type StorageMeta = StorageMetadata;
pub type EntryMeta = StorageEntryMetadata;
pub type EntryType = StorageEntryType;
pub type Hasher = StorageHasher;
}
#[cfg(feature = "v13")]
mod v13 {
use frame_metadata::v13::*;
pub type Metadata = RuntimeMetadataV13;
pub type PalletMeta = ModuleMetadata;
pub type StorageMeta = StorageMetadata;
pub type EntryMeta = StorageEntryMetadata;
pub type EntryType = StorageEntryType;
pub type Hasher = StorageHasher;
}
#[cfg(feature = "v14")]
mod v14 {
use frame_metadata::v14::*;
use scale_info::form::PortableForm;
pub type Metadata = RuntimeMetadataV14;
pub type PalletMeta = PalletMetadata<PortableForm>;
pub type StorageMeta = PalletStorageMetadata<PortableForm>;
pub type EntryMeta = StorageEntryMetadata<PortableForm>;
pub type EntryType = StorageEntryType<PortableForm>;
pub type Hasher = StorageHasher;
}
pub fn meta_from_bytes(bytes: &mut &[u8]) -> core::result::Result<Metadata, codec::Error> {
let meta: RuntimeMetadataPrefixed = Decode::decode(bytes)?;
let meta = match meta.1 {
#[cfg(feature = "v12")]
RuntimeMetadata::V12(m) => m,
#[cfg(feature = "v13")]
RuntimeMetadata::V13(m) => m,
#[cfg(feature = "v14")]
RuntimeMetadata::V14(m) => m,
_ => unreachable!("Metadata version not supported"),
};
Ok(meta)
}
type EntryFor<'a, M> = <<<M as Meta<'a>>::Pallet as Pallet<'a>>::Storage as Storage<'a>>::Entry;
pub trait Meta<'a> {
type Pallet: Pallet<'a>;
fn pallets(&self) -> Pallets<Self::Pallet>;
fn pallet_by_name(&self, name: &str) -> Option<&Self::Pallet> {
self.pallets().find(|p| p.name() == name)
}
fn storage_entries(&'a self, pallet: &str) -> Option<Entries<EntryFor<Self>>> {
Some(self.pallet_by_name(pallet)?.storage()?.entries())
}
fn storage_entry(&'a self, pallet: &str, entry: &str) -> Option<&EntryFor<Self>> {
self.storage_entries(pallet)?.find(|e| e.name() == entry)
}
}
type Pallets<'a, P> = slice::Iter<'a, P>;
pub trait Pallet<'a> {
type Storage: Storage<'a>;
fn name(&self) -> &str;
fn storage(&self) -> Option<&Self::Storage>;
}
pub trait Storage<'a> {
type Entry: Entry + 'a;
fn module(&self) -> &str;
fn entries(&'a self) -> Entries<'a, Self::Entry>;
fn entry(&'a self, name: &str) -> Option<&'a Self::Entry> {
self.entries().find(|e| e.name() == name)
}
}
type Entries<'a, E> = slice::Iter<'a, E>;
pub trait Entry {
type Type: EntryTy;
fn name(&self) -> &str;
fn ty(&self) -> &Self::Type;
fn ty_id(&self) -> u32;
fn key(&self, pallet: &str, map_keys: &[&str]) -> Option<Vec<u8>> {
self.ty().key(pallet, self.name(), map_keys)
}
}
pub trait EntryTy {
fn key(&self, pallet: &str, item: &str, map_keys: &[&str]) -> Option<Vec<u8>>;
fn build_key<H>(
&self,
pallet: &str,
item: &str,
map_keys: &[&str],
hashers: &[H],
) -> Option<Vec<u8>>
where
H: Borrow<Hasher>,
{
let mut key = hash(&Hasher::Twox128, &pallet);
key.append(&mut hash(&Hasher::Twox128, &item));
if map_keys.len() != hashers.len() {
return None;
}
for (i, h) in hashers.iter().enumerate() {
let hasher = h.borrow();
if map_keys[i].is_empty() {
return None;
}
key.append(&mut hash(hasher, map_keys[i]))
}
Some(key)
}
}
impl<'a> Meta<'a> for Metadata {
type Pallet = PalletMeta;
#[cfg(not(feature = "v14"))]
fn pallets(&self) -> Pallets<Self::Pallet> {
self.modules.decoded().iter()
}
#[cfg(feature = "v14")]
fn pallets(&self) -> Pallets<Self::Pallet> {
self.pallets.iter()
}
}
impl<'a> Pallet<'a> for PalletMeta {
type Storage = StorageMeta;
fn storage(&self) -> Option<&Self::Storage> {
let storage = self.storage.as_ref();
#[cfg(not(feature = "v14"))]
let storage = storage.map(|s| s.decoded());
storage
}
fn name(&self) -> &str {
#[cfg(feature = "v14")]
let name = self.name.as_ref();
#[cfg(not(feature = "v14"))]
let name = self.name.decoded();
name
}
}
impl<'a> Storage<'a> for StorageMeta {
type Entry = EntryMeta;
fn module(&self) -> &str {
#[cfg(feature = "v14")]
let pref = self.prefix.as_ref();
#[cfg(not(feature = "v14"))]
let pref = self.prefix.decoded();
pref
}
fn entries(&'a self) -> Entries<Self::Entry> {
#[cfg(feature = "v14")]
let entries = self.entries.iter();
#[cfg(not(feature = "v14"))]
let entries = self.entries.decoded().iter();
entries
}
}
impl<'a> Entry for EntryMeta {
type Type = EntryType;
fn name(&self) -> &str {
#[cfg(feature = "v14")]
let name = self.name.as_ref();
#[cfg(not(feature = "v14"))]
let name = self.name.decoded();
name
}
fn ty(&self) -> &Self::Type {
&self.ty
}
fn ty_id(&self) -> u32 {
#[cfg(feature = "v14")]
match &self.ty {
EntryType::Plain(t) => t.id(),
EntryType::Map { value, .. } => value.id(),
}
#[cfg(not(feature = "v14"))]
0
}
}
impl EntryTy for EntryType {
fn key(&self, pallet: &str, item: &str, map_keys: &[&str]) -> Option<Vec<u8>> {
match self {
Self::Plain(ty) => {
log::debug!("Item Type: {:?}", ty);
self.build_key::<Hasher>(pallet, item, &[], &[])
}
#[cfg(any(feature = "v12", feature = "v13"))]
Self::Map {
hasher, key, value, ..
} => {
log::debug!("Item Type: {:?} => {:?}", key, value);
self.build_key(pallet, item, map_keys, &[hasher])
}
#[cfg(any(feature = "v12", feature = "v13"))]
Self::DoubleMap {
hasher,
key2_hasher,
key1,
key2,
value,
} => {
log::debug!("Item Type: ({:?}, {:?}) => {:?}", key1, key2, value);
self.build_key(pallet, item, map_keys, &[hasher, key2_hasher])
}
#[cfg(feature = "v13")]
Self::NMap {
hashers,
keys,
value,
} => {
log::debug!("Item Type: {:?} => {:?}", keys, value);
self.build_key(pallet, item, map_keys, hashers.decoded())
}
#[cfg(feature = "v14")]
Self::Map {
hashers,
key,
value,
} => {
log::debug!("Item Type: {:?} => {:?}", key, value);
self.build_key(pallet, item, map_keys, hashers)
}
}
}
}
#[cfg(any(feature = "v12", feature = "v13"))]
trait Decoded {
type Output;
fn decoded(&self) -> &Self::Output;
}
#[cfg(any(feature = "v12", feature = "v13"))]
impl<B, O> Decoded for DecodeDifferent<B, O> {
type Output = O;
fn decoded(&self) -> &Self::Output {
match self {
DecodeDifferent::Decoded(o) => o,
_ => unreachable!(),
}
}
}