mod keystore;
pub use keystore::*;
use std::{
fmt::{Display, Formatter, Result as FmtResult},
mem,
};
use parity_scale_codec::{Decode, Encode};
use crate::prelude::*;
pub trait Key
where
Self: Sized,
{
const ID: [u8; 4];
type Seed: Encode;
fn seed(self) -> Self::Seed;
fn to_key<const N: usize>(self) -> Result<[u8; N]> {
self.to_key_with_sub_seed(())
}
fn to_key_with_sub_seed<S, const N: usize>(self, sub_seed: S) -> Result<[u8; N]>
where
S: Encode,
{
let mut result = [0; N];
let seed = (self.seed(), sub_seed).encode();
if (Self::ID.len() + seed.len()) > N {
Err(error::Key::InvalidSubSeed)?;
}
Self::ID.iter().cloned().chain(seed).enumerate().for_each(|(i, v)| result[i] = v);
Ok(result)
}
}
macro_rules! impl_keys {
($(
#[doc=$doc:expr]
#[id=$id:expr]
$name:ident($ty:ty),
)+) => {
$(
#[doc=$doc]
#[derive(Debug)]
pub struct $name(pub $ty);
impl Key for $name {
type Seed = $ty;
const ID: [u8; 4] = $id;
fn seed(self) -> Self::Seed {
self.0
}
}
impl TryFrom<&[u8]> for $name {
type Error = Error;
fn try_from(key: &[u8]) -> Result<Self> {
let id_size = Self::ID.len();
let seed_size = mem::size_of::<$ty>();
if key.len() < id_size + seed_size {
Err(error::Key::InvalidKey)?;
}
let id = &key[..id_size];
let seed = &key[id_size..id_size + seed_size];
if id != Self::ID {
Err(error::Key::InvalidKey)?;
}
Ok(Self(<$ty>::decode(&mut &*seed).map_err(error::Generic::Codec)?))
}
}
)+
};
}
impl_keys! {
#[doc="Identifier of a pallet, aka `ModuleId`."]
#[id=*b"modl"]
PalletId([u8; 8]),
#[doc="Identifier of a parachain."]
#[id=*b"para"]
ParaId(u32),
#[doc="Identifier of a sibling chain."]
#[id=*b"sibl"]
SiblId(u32),
}
impl Display for PalletId {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "PalletId({})", String::from_utf8_lossy(&self.0))
}
}
impl Display for ParaId {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "ParaId({})", &self.0)
}
}
impl Display for SiblId {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "SiblId({})", &self.0)
}
}
#[test]
fn to_key_with_sub_seed_should_work() {
assert_eq!(
array_bytes::bytes2hex(
"0x",
PalletId(*b"py/cfund").to_key_with_sub_seed::<_, 32>(75_u32).unwrap()
),
"0x6d6f646c70792f6366756e644b00000000000000000000000000000000000000"
);
}