#![cfg_attr(not(feature = "std"), no_std)]
#![recursion_limit = "128"]
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::traits::reality::{AddOnlyPeopleTrait, PeopleTrait, PersonalId};
use scale_info::TypeInfo;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use pallet::*;
pub use weights::WeightInfo;
type MemberOf<T> = <<T as Config>::People as AddOnlyPeopleTrait>::Member;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::{pallet_prelude::*, Twox64Concat};
use frame_system::pallet_prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type WeightInfo: WeightInfo;
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type MaxPersonBatchSize: Get<u32>;
type People: PeopleTrait;
}
#[derive(
Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking,
)]
pub struct Record<Key> {
pub key: Key,
pub suspended: bool,
}
#[pallet::storage]
pub type ReservedIds<T: Config> = StorageMap<_, Blake2_128Concat, PersonalId, (), OptionQuery>;
#[pallet::storage]
pub type People<T: Config> =
StorageMap<_, Twox64Concat, PersonalId, Record<MemberOf<T>>, OptionQuery>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
IdsReserved { count: u32 },
IdRenewed { id: PersonalId },
IdUnreserved { id: PersonalId },
PeopleRegistered { count: u32 },
PeopleSuspended { count: u32 },
PersonhoodResumed { id: PersonalId },
SuspensionsStarted,
SuspensionsEnded,
}
#[pallet::error]
pub enum Error<T> {
NotPerson,
NotSuspended,
NotReserved,
TooManyPeople,
}
#[pallet::call(weight = <T as Config>::WeightInfo)]
impl<T: Config> Pallet<T> {
#[pallet::weight(T::WeightInfo::reserve_ids(T::MaxPersonBatchSize::get()))]
#[pallet::call_index(0)]
pub fn reserve_ids(origin: OriginFor<T>, count: u32) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
ensure!(count <= T::MaxPersonBatchSize::get(), Error::<T>::TooManyPeople);
for _ in 0..count {
let id = T::People::reserve_new_id();
ReservedIds::<T>::insert(id, ());
}
Self::deposit_event(Event::IdsReserved { count });
Ok(().into())
}
#[pallet::call_index(1)]
pub fn renew_id_reservation(
origin: OriginFor<T>,
id: PersonalId,
) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
T::People::renew_id_reservation(id)?;
ReservedIds::<T>::insert(id, ());
Self::deposit_event(Event::IdRenewed { id });
Ok(().into())
}
#[pallet::call_index(2)]
pub fn cancel_id_reservation(
origin: OriginFor<T>,
id: PersonalId,
) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
T::People::cancel_id_reservation(id)?;
ReservedIds::<T>::remove(id);
Self::deposit_event(Event::IdUnreserved { id });
Ok(().into())
}
#[pallet::weight(T::WeightInfo::recognize_personhood(T::MaxPersonBatchSize::get()))]
#[pallet::call_index(3)]
pub fn recognize_personhood(
origin: OriginFor<T>,
ids_and_keys: BoundedVec<(PersonalId, MemberOf<T>), T::MaxPersonBatchSize>,
) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
let count = ids_and_keys.len() as u32;
for (id, key) in ids_and_keys.into_iter() {
ReservedIds::<T>::take(id).ok_or(Error::<T>::NotReserved)?;
People::<T>::insert(id, Record { key: key.clone(), suspended: false });
T::People::recognize_personhood(id, Some(key))?;
}
Self::deposit_event(Event::PeopleRegistered { count });
Ok(().into())
}
#[pallet::weight(T::WeightInfo::suspend_personhood(T::MaxPersonBatchSize::get()))]
#[pallet::call_index(4)]
pub fn suspend_personhood(
origin: OriginFor<T>,
ids: BoundedVec<PersonalId, T::MaxPersonBatchSize>,
) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
T::People::suspend_personhood(&ids[..])?;
let count = ids.len() as u32;
for id in ids.into_iter() {
let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
record.suspended = true;
People::<T>::insert(id, record);
}
Self::deposit_event(Event::PeopleSuspended { count });
Ok(().into())
}
#[pallet::call_index(5)]
pub fn resume_personhood(
origin: OriginFor<T>,
id: PersonalId,
) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
ensure!(record.suspended, Error::<T>::NotSuspended);
T::People::recognize_personhood(id, None)?;
record.suspended = false;
People::<T>::insert(id, record);
Self::deposit_event(Event::PersonhoodResumed { id });
Ok(().into())
}
#[pallet::call_index(6)]
pub fn start_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
T::People::start_people_set_mutation_session()?;
Self::deposit_event(Event::SuspensionsStarted);
Ok(().into())
}
#[pallet::call_index(7)]
pub fn end_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
T::People::end_people_set_mutation_session()?;
Self::deposit_event(Event::SuspensionsEnded);
Ok(().into())
}
}
}