1#![cfg_attr(not(feature = "std"), no_std)]
21#![recursion_limit = "128"]
22
23use codec::{Decode, Encode, MaxEncodedLen};
24use frame_support::traits::reality::{AddOnlyPeopleTrait, PeopleTrait, PersonalId};
25use scale_info::TypeInfo;
26
27#[cfg(test)]
28mod mock;
29#[cfg(test)]
30mod tests;
31
32#[cfg(feature = "runtime-benchmarks")]
33mod benchmarking;
34pub mod weights;
35
36pub use pallet::*;
37pub use weights::WeightInfo;
38
39type MemberOf<T> = <<T as Config>::People as AddOnlyPeopleTrait>::Member;
40
41#[frame_support::pallet]
42pub mod pallet {
43 use super::*;
44 use frame_support::{pallet_prelude::*, Twox64Concat};
45 use frame_system::pallet_prelude::*;
46
47 #[pallet::pallet]
48 pub struct Pallet<T>(_);
49
50 #[pallet::config]
52 pub trait Config: frame_system::Config {
53 type WeightInfo: WeightInfo;
55
56 #[allow(deprecated)]
58 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
59
60 type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
63
64 type MaxPersonBatchSize: Get<u32>;
66
67 type People: PeopleTrait;
69 }
70
71 #[derive(
73 Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking,
74 )]
75 pub struct Record<Key> {
76 pub key: Key,
78 pub suspended: bool,
80 }
81
82 #[pallet::storage]
84 pub type ReservedIds<T: Config> = StorageMap<_, Blake2_128Concat, PersonalId, (), OptionQuery>;
85
86 #[pallet::storage]
88 pub type People<T: Config> =
89 StorageMap<_, Twox64Concat, PersonalId, Record<MemberOf<T>>, OptionQuery>;
90
91 #[pallet::event]
92 #[pallet::generate_deposit(pub(super) fn deposit_event)]
93 pub enum Event<T: Config> {
94 IdsReserved { count: u32 },
96 IdRenewed { id: PersonalId },
98 IdUnreserved { id: PersonalId },
100 PeopleRegistered { count: u32 },
102 PeopleSuspended { count: u32 },
104 PersonhoodResumed { id: PersonalId },
106 SuspensionsStarted,
108 SuspensionsEnded,
110 }
111
112 #[pallet::error]
113 pub enum Error<T> {
114 NotPerson,
116 NotSuspended,
118 NotReserved,
120 TooManyPeople,
122 }
123
124 #[pallet::call(weight = <T as Config>::WeightInfo)]
125 impl<T: Config> Pallet<T> {
126 #[pallet::weight(T::WeightInfo::reserve_ids(T::MaxPersonBatchSize::get()))]
128 #[pallet::call_index(0)]
129 pub fn reserve_ids(origin: OriginFor<T>, count: u32) -> DispatchResultWithPostInfo {
130 T::UpdateOrigin::ensure_origin_or_root(origin)?;
131 ensure!(count <= T::MaxPersonBatchSize::get(), Error::<T>::TooManyPeople);
132 for _ in 0..count {
133 let id = T::People::reserve_new_id();
134 ReservedIds::<T>::insert(id, ());
135 }
136 Self::deposit_event(Event::IdsReserved { count });
137 Ok(().into())
138 }
139
140 #[pallet::call_index(1)]
142 pub fn renew_id_reservation(
143 origin: OriginFor<T>,
144 id: PersonalId,
145 ) -> DispatchResultWithPostInfo {
146 T::UpdateOrigin::ensure_origin_or_root(origin)?;
147 T::People::renew_id_reservation(id)?;
148 ReservedIds::<T>::insert(id, ());
149
150 Self::deposit_event(Event::IdRenewed { id });
151 Ok(().into())
152 }
153
154 #[pallet::call_index(2)]
156 pub fn cancel_id_reservation(
157 origin: OriginFor<T>,
158 id: PersonalId,
159 ) -> DispatchResultWithPostInfo {
160 T::UpdateOrigin::ensure_origin_or_root(origin)?;
161 T::People::cancel_id_reservation(id)?;
162 ReservedIds::<T>::remove(id);
163
164 Self::deposit_event(Event::IdUnreserved { id });
165 Ok(().into())
166 }
167
168 #[pallet::weight(T::WeightInfo::recognize_personhood(T::MaxPersonBatchSize::get()))]
170 #[pallet::call_index(3)]
171 pub fn recognize_personhood(
172 origin: OriginFor<T>,
173 ids_and_keys: BoundedVec<(PersonalId, MemberOf<T>), T::MaxPersonBatchSize>,
174 ) -> DispatchResultWithPostInfo {
175 T::UpdateOrigin::ensure_origin_or_root(origin)?;
176 let count = ids_and_keys.len() as u32;
177 for (id, key) in ids_and_keys.into_iter() {
178 ReservedIds::<T>::take(id).ok_or(Error::<T>::NotReserved)?;
179 People::<T>::insert(id, Record { key: key.clone(), suspended: false });
180 T::People::recognize_personhood(id, Some(key))?;
181 }
182
183 Self::deposit_event(Event::PeopleRegistered { count });
184 Ok(().into())
185 }
186
187 #[pallet::weight(T::WeightInfo::suspend_personhood(T::MaxPersonBatchSize::get()))]
190 #[pallet::call_index(4)]
191 pub fn suspend_personhood(
192 origin: OriginFor<T>,
193 ids: BoundedVec<PersonalId, T::MaxPersonBatchSize>,
194 ) -> DispatchResultWithPostInfo {
195 T::UpdateOrigin::ensure_origin_or_root(origin)?;
196 T::People::suspend_personhood(&ids[..])?;
197 let count = ids.len() as u32;
198 for id in ids.into_iter() {
199 let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
200 record.suspended = true;
201 People::<T>::insert(id, record);
202 }
203
204 Self::deposit_event(Event::PeopleSuspended { count });
205 Ok(().into())
206 }
207
208 #[pallet::call_index(5)]
210 pub fn resume_personhood(
211 origin: OriginFor<T>,
212 id: PersonalId,
213 ) -> DispatchResultWithPostInfo {
214 T::UpdateOrigin::ensure_origin_or_root(origin)?;
215 let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
216 ensure!(record.suspended, Error::<T>::NotSuspended);
217 T::People::recognize_personhood(id, None)?;
218 record.suspended = false;
219 People::<T>::insert(id, record);
220
221 Self::deposit_event(Event::PersonhoodResumed { id });
222 Ok(().into())
223 }
224
225 #[pallet::call_index(6)]
228 pub fn start_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
229 T::UpdateOrigin::ensure_origin_or_root(origin)?;
230 T::People::start_people_set_mutation_session()?;
231 Self::deposit_event(Event::SuspensionsStarted);
232 Ok(().into())
233 }
234
235 #[pallet::call_index(7)]
240 pub fn end_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
241 T::UpdateOrigin::ensure_origin_or_root(origin)?;
242 T::People::end_people_set_mutation_session()?;
243 Self::deposit_event(Event::SuspensionsEnded);
244 Ok(().into())
245 }
246 }
247}