Skip to main content

pezpallet_dummy_dim/
lib.rs

1// This file is part of Bizinikiwi.
2
3// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! A simple interface to interact with a Proof-of-Personhood system.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21#![recursion_limit = "128"]
22
23use codec::{Decode, Encode, MaxEncodedLen};
24use pezframe_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 pezpallet::*;
37pub use weights::WeightInfo;
38
39type MemberOf<T> = <<T as Config>::People as AddOnlyPeopleTrait>::Member;
40
41#[pezframe_support::pezpallet]
42pub mod pezpallet {
43	use super::*;
44	use pezframe_support::{pezpallet_prelude::*, Twox64Concat};
45	use pezframe_system::pezpallet_prelude::*;
46
47	#[pezpallet::pezpallet]
48	pub struct Pezpallet<T>(_);
49
50	/// The configuration of the pezpallet dummy DIM.
51	#[pezpallet::config]
52	pub trait Config: pezframe_system::Config {
53		/// Weight information for extrinsics in this pezpallet.
54		type WeightInfo: WeightInfo;
55
56		/// The runtime event type.
57		#[allow(deprecated)]
58		type RuntimeEvent: From<Event<Self>>
59			+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
60
61		/// The origin which may command personhood updates through this pezpallet. Root can always
62		/// do this.
63		type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
64
65		/// The maximum number of people supported in a single operation.
66		type MaxPersonBatchSize: Get<u32>;
67
68		/// Who to tell when we recognise personhood.
69		type People: PeopleTrait;
70	}
71
72	/// The record of recognized people.
73	#[derive(
74		Clone,
75		PartialEq,
76		Eq,
77		RuntimeDebug,
78		Encode,
79		Decode,
80		MaxEncodedLen,
81		TypeInfo,
82		DecodeWithMemTracking,
83	)]
84	pub struct Record<Key> {
85		/// The key of the person.
86		pub key: Key,
87		/// Flag describing the suspension status.
88		pub suspended: bool,
89	}
90
91	/// The personal IDs that are reserved by unproven people.
92	#[pezpallet::storage]
93	pub type ReservedIds<T: Config> = StorageMap<_, Blake2_128Concat, PersonalId, (), OptionQuery>;
94
95	/// The people we track along with their records.
96	#[pezpallet::storage]
97	pub type People<T: Config> =
98		StorageMap<_, Twox64Concat, PersonalId, Record<MemberOf<T>>, OptionQuery>;
99
100	#[pezpallet::event]
101	#[pezpallet::generate_deposit(pub(super) fn deposit_event)]
102	pub enum Event<T: Config> {
103		/// A number of IDs was reserved.
104		IdsReserved { count: u32 },
105		/// An ID was renewed.
106		IdRenewed { id: PersonalId },
107		/// A reserved ID was removed.
108		IdUnreserved { id: PersonalId },
109		/// Register multiple people.
110		PeopleRegistered { count: u32 },
111		/// Suspend a number of people.
112		PeopleSuspended { count: u32 },
113		/// Someone's personhood was resumed.
114		PersonhoodResumed { id: PersonalId },
115		/// The pezpallet enabled suspensions.
116		SuspensionsStarted,
117		/// The pezpallet disabled suspensions.
118		SuspensionsEnded,
119	}
120
121	#[pezpallet::error]
122	pub enum Error<T> {
123		/// The personal ID does not belong to a recognized person.
124		NotPerson,
125		/// The personal ID does not belong to a suspended person.
126		NotSuspended,
127		/// The personal ID is not reserved and awaiting recognition.
128		NotReserved,
129		/// The operation does not support this many people.
130		TooManyPeople,
131	}
132
133	#[pezpallet::call(weight = <T as Config>::WeightInfo)]
134	impl<T: Config> Pezpallet<T> {
135		/// Reserve a number of personal IDs.
136		#[pezpallet::weight(T::WeightInfo::reserve_ids(T::MaxPersonBatchSize::get()))]
137		#[pezpallet::call_index(0)]
138		pub fn reserve_ids(origin: OriginFor<T>, count: u32) -> DispatchResultWithPostInfo {
139			T::UpdateOrigin::ensure_origin_or_root(origin)?;
140			ensure!(count <= T::MaxPersonBatchSize::get(), Error::<T>::TooManyPeople);
141			for _ in 0..count {
142				let id = T::People::reserve_new_id();
143				ReservedIds::<T>::insert(id, ());
144			}
145			Self::deposit_event(Event::IdsReserved { count });
146			Ok(().into())
147		}
148
149		/// Renew a personal ID. The ID must not be in use.
150		#[pezpallet::call_index(1)]
151		pub fn renew_id_reservation(
152			origin: OriginFor<T>,
153			id: PersonalId,
154		) -> DispatchResultWithPostInfo {
155			T::UpdateOrigin::ensure_origin_or_root(origin)?;
156			T::People::renew_id_reservation(id)?;
157			ReservedIds::<T>::insert(id, ());
158
159			Self::deposit_event(Event::IdRenewed { id });
160			Ok(().into())
161		}
162
163		/// Cancel a personal ID reservation.
164		#[pezpallet::call_index(2)]
165		pub fn cancel_id_reservation(
166			origin: OriginFor<T>,
167			id: PersonalId,
168		) -> DispatchResultWithPostInfo {
169			T::UpdateOrigin::ensure_origin_or_root(origin)?;
170			T::People::cancel_id_reservation(id)?;
171			ReservedIds::<T>::remove(id);
172
173			Self::deposit_event(Event::IdUnreserved { id });
174			Ok(().into())
175		}
176
177		/// Grant personhood for a list of candidates that have reserved personal IDs.
178		#[pezpallet::weight(T::WeightInfo::recognize_personhood(T::MaxPersonBatchSize::get()))]
179		#[pezpallet::call_index(3)]
180		pub fn recognize_personhood(
181			origin: OriginFor<T>,
182			ids_and_keys: BoundedVec<(PersonalId, MemberOf<T>), T::MaxPersonBatchSize>,
183		) -> DispatchResultWithPostInfo {
184			T::UpdateOrigin::ensure_origin_or_root(origin)?;
185			let count = ids_and_keys.len() as u32;
186			for (id, key) in ids_and_keys.into_iter() {
187				ReservedIds::<T>::take(id).ok_or(Error::<T>::NotReserved)?;
188				People::<T>::insert(id, Record { key: key.clone(), suspended: false });
189				T::People::recognize_personhood(id, Some(key))?;
190			}
191
192			Self::deposit_event(Event::PeopleRegistered { count });
193			Ok(().into())
194		}
195
196		/// Suspend the personhood of a list of recognized people. The people must not currently be
197		/// suspended.
198		#[pezpallet::weight(T::WeightInfo::suspend_personhood(T::MaxPersonBatchSize::get()))]
199		#[pezpallet::call_index(4)]
200		pub fn suspend_personhood(
201			origin: OriginFor<T>,
202			ids: BoundedVec<PersonalId, T::MaxPersonBatchSize>,
203		) -> DispatchResultWithPostInfo {
204			T::UpdateOrigin::ensure_origin_or_root(origin)?;
205			T::People::suspend_personhood(&ids[..])?;
206			let count = ids.len() as u32;
207			for id in ids.into_iter() {
208				let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
209				record.suspended = true;
210				People::<T>::insert(id, record);
211			}
212
213			Self::deposit_event(Event::PeopleSuspended { count });
214			Ok(().into())
215		}
216
217		/// Resume someone's personhood. The person must currently be suspended.
218		#[pezpallet::call_index(5)]
219		pub fn resume_personhood(
220			origin: OriginFor<T>,
221			id: PersonalId,
222		) -> DispatchResultWithPostInfo {
223			T::UpdateOrigin::ensure_origin_or_root(origin)?;
224			let mut record = People::<T>::get(id).ok_or(Error::<T>::NotPerson)?;
225			ensure!(record.suspended, Error::<T>::NotSuspended);
226			T::People::recognize_personhood(id, None)?;
227			record.suspended = false;
228			People::<T>::insert(id, record);
229
230			Self::deposit_event(Event::PersonhoodResumed { id });
231			Ok(().into())
232		}
233
234		/// Start a mutation session in the underlying `People` interface. This call does not check
235		/// whether a mutation session is already ongoing and can start new sessions.
236		#[pezpallet::call_index(6)]
237		pub fn start_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
238			T::UpdateOrigin::ensure_origin_or_root(origin)?;
239			T::People::start_people_set_mutation_session()?;
240			Self::deposit_event(Event::SuspensionsStarted);
241			Ok(().into())
242		}
243
244		/// End a mutation session in the underlying `People` interface. This call can end multiple
245		/// mutation sessions, even ones not started by this pezpallet.
246		///
247		/// This call will fail if no mutation session is ongoing.
248		#[pezpallet::call_index(7)]
249		pub fn end_mutation_session(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
250			T::UpdateOrigin::ensure_origin_or_root(origin)?;
251			T::People::end_people_set_mutation_session()?;
252			Self::deposit_event(Event::SuspensionsEnded);
253			Ok(().into())
254		}
255	}
256}