use super::*;
use alloc::{vec, vec::Vec};
use codec::{Decode, Encode, MaxEncodedLen};
use core::{fmt::Debug, iter::once, ops::Add};
use frame_support::{
traits::{ConstU32, Get},
BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound,
};
use scale_info::{
build::{Fields, Variants},
Path, Type, TypeInfo,
};
use sp_runtime::{
traits::{Member, Zero},
RuntimeDebug,
};
pub type RegistrarIndex = u32;
#[derive(Clone, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)]
pub enum Data {
None,
Raw(BoundedVec<u8, ConstU32<32>>),
BlakeTwo256([u8; 32]),
Sha256([u8; 32]),
Keccak256([u8; 32]),
ShaThree256([u8; 32]),
}
impl Data {
pub fn is_none(&self) -> bool {
self == &Data::None
}
}
impl Decode for Data {
fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
let b = input.read_byte()?;
Ok(match b {
0 => Data::None,
n @ 1..=33 => {
let mut r: BoundedVec<_, _> = vec![0u8; n as usize - 1]
.try_into()
.expect("bound checked in match arm condition; qed");
input.read(&mut r[..])?;
Data::Raw(r)
},
34 => Data::BlakeTwo256(<[u8; 32]>::decode(input)?),
35 => Data::Sha256(<[u8; 32]>::decode(input)?),
36 => Data::Keccak256(<[u8; 32]>::decode(input)?),
37 => Data::ShaThree256(<[u8; 32]>::decode(input)?),
_ => return Err(codec::Error::from("invalid leading byte")),
})
}
}
impl Encode for Data {
fn encode(&self) -> Vec<u8> {
match self {
Data::None => vec![0u8; 1],
Data::Raw(ref x) => {
let l = x.len().min(32);
let mut r = vec![l as u8 + 1; l + 1];
r[1..].copy_from_slice(&x[..l as usize]);
r
},
Data::BlakeTwo256(ref h) => once(34u8).chain(h.iter().cloned()).collect(),
Data::Sha256(ref h) => once(35u8).chain(h.iter().cloned()).collect(),
Data::Keccak256(ref h) => once(36u8).chain(h.iter().cloned()).collect(),
Data::ShaThree256(ref h) => once(37u8).chain(h.iter().cloned()).collect(),
}
}
}
impl codec::EncodeLike for Data {}
macro_rules! data_raw_variants {
($variants:ident, $(($index:literal, $size:literal)),* ) => {
$variants
$(
.variant(concat!("Raw", stringify!($size)), |v| v
.index($index)
.fields(Fields::unnamed().field(|f| f.ty::<[u8; $size]>()))
)
)*
}
}
impl TypeInfo for Data {
type Identity = Self;
fn type_info() -> Type {
let variants = Variants::new().variant("None", |v| v.index(0));
let variants = data_raw_variants!(
variants,
(1, 0),
(2, 1),
(3, 2),
(4, 3),
(5, 4),
(6, 5),
(7, 6),
(8, 7),
(9, 8),
(10, 9),
(11, 10),
(12, 11),
(13, 12),
(14, 13),
(15, 14),
(16, 15),
(17, 16),
(18, 17),
(19, 18),
(20, 19),
(21, 20),
(22, 21),
(23, 22),
(24, 23),
(25, 24),
(26, 25),
(27, 26),
(28, 27),
(29, 28),
(30, 29),
(31, 30),
(32, 31),
(33, 32)
);
let variants = variants
.variant("BlakeTwo256", |v| {
v.index(34).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
})
.variant("Sha256", |v| {
v.index(35).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
})
.variant("Keccak256", |v| {
v.index(36).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
})
.variant("ShaThree256", |v| {
v.index(37).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
});
Type::builder().path(Path::new("Data", module_path!())).variant(variants)
}
}
impl Default for Data {
fn default() -> Self {
Self::None
}
}
#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
pub enum Judgement<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
{
Unknown,
FeePaid(Balance),
Reasonable,
KnownGood,
OutOfDate,
LowQuality,
Erroneous,
}
impl<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
Judgement<Balance>
{
pub(crate) fn has_deposit(&self) -> bool {
matches!(self, Judgement::FeePaid(_))
}
pub(crate) fn is_sticky(&self) -> bool {
matches!(self, Judgement::FeePaid(_) | Judgement::Erroneous)
}
}
pub trait IdentityInformationProvider:
Encode + Decode + MaxEncodedLen + Clone + Debug + Eq + PartialEq + TypeInfo + Default
{
type FieldsIdentifier: Member + Encode + Decode + MaxEncodedLen + TypeInfo + Default;
fn has_identity(&self, fields: Self::FieldsIdentifier) -> bool;
#[cfg(feature = "runtime-benchmarks")]
fn create_identity_info() -> Self;
#[cfg(feature = "runtime-benchmarks")]
fn all_fields() -> Self::FieldsIdentifier;
}
#[derive(
CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
)]
#[codec(mel_bound())]
#[scale_info(skip_type_params(MaxJudgements))]
pub struct Registration<
Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
MaxJudgements: Get<u32>,
IdentityInfo: IdentityInformationProvider,
> {
pub judgements: BoundedVec<(RegistrarIndex, Judgement<Balance>), MaxJudgements>,
pub deposit: Balance,
pub info: IdentityInfo,
}
impl<
Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add,
MaxJudgements: Get<u32>,
IdentityInfo: IdentityInformationProvider,
> Registration<Balance, MaxJudgements, IdentityInfo>
{
pub(crate) fn total_deposit(&self) -> Balance {
self.deposit +
self.judgements
.iter()
.map(|(_, ref j)| if let Judgement::FeePaid(fee) = j { *fee } else { Zero::zero() })
.fold(Zero::zero(), |a, i| a + i)
}
}
impl<
Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
MaxJudgements: Get<u32>,
IdentityInfo: IdentityInformationProvider,
> Decode for Registration<Balance, MaxJudgements, IdentityInfo>
{
fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
let (judgements, deposit, info) = Decode::decode(&mut AppendZerosInput::new(input))?;
Ok(Self { judgements, deposit, info })
}
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
pub struct RegistrarInfo<
Balance: Encode + Decode + Clone + Debug + Eq + PartialEq,
AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq,
IdField: Encode + Decode + Clone + Debug + Default + Eq + PartialEq + TypeInfo + MaxEncodedLen,
> {
pub account: AccountId,
pub fee: Balance,
pub fields: IdField,
}
type Allocation = u32;
pub(crate) type Suffix<T> = BoundedVec<u8, <T as Config>::MaxSuffixLength>;
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
pub struct AuthorityProperties<Account> {
pub account_id: Account,
pub allocation: Allocation,
}
pub(crate) type Username<T> = BoundedVec<u8, <T as Config>::MaxUsernameLength>;
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
pub enum Provider<Balance> {
Allocation,
AuthorityDeposit(Balance),
System,
}
impl<Balance> Provider<Balance> {
pub fn new_with_allocation() -> Self {
Self::Allocation
}
pub fn new_with_deposit(deposit: Balance) -> Self {
Self::AuthorityDeposit(deposit)
}
#[allow(unused)]
pub fn new_permanent() -> Self {
Self::System
}
}
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
pub struct UsernameInformation<Account, Balance> {
pub owner: Account,
pub provider: Provider<Balance>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn manual_data_type_info() {
let mut registry = scale_info::Registry::new();
let type_id = registry.register_type(&scale_info::meta_type::<Data>());
let registry: scale_info::PortableRegistry = registry.into();
let type_info = registry.resolve(type_id.id).unwrap();
let check_type_info = |data: &Data| {
let variant_name = match data {
Data::None => "None".to_string(),
Data::BlakeTwo256(_) => "BlakeTwo256".to_string(),
Data::Sha256(_) => "Sha256".to_string(),
Data::Keccak256(_) => "Keccak256".to_string(),
Data::ShaThree256(_) => "ShaThree256".to_string(),
Data::Raw(bytes) => format!("Raw{}", bytes.len()),
};
if let scale_info::TypeDef::Variant(variant) = &type_info.type_def {
let variant = variant
.variants
.iter()
.find(|v| v.name == variant_name)
.expect(&format!("Expected to find variant {}", variant_name));
let field_arr_len = variant
.fields
.first()
.and_then(|f| registry.resolve(f.ty.id))
.map(|ty| {
if let scale_info::TypeDef::Array(arr) = &ty.type_def {
arr.len
} else {
panic!("Should be an array type")
}
})
.unwrap_or(0);
let encoded = data.encode();
assert_eq!(encoded[0], variant.index);
assert_eq!(encoded.len() as u32 - 1, field_arr_len);
} else {
panic!("Should be a variant type")
};
};
let mut data = vec![
Data::None,
Data::BlakeTwo256(Default::default()),
Data::Sha256(Default::default()),
Data::Keccak256(Default::default()),
Data::ShaThree256(Default::default()),
];
for n in 0..32 {
data.push(Data::Raw(vec![0u8; n as usize].try_into().unwrap()))
}
for d in data.iter() {
check_type_info(d);
}
}
}