referrerpolicy=no-referrer-when-downgrade

pallet_dummy_dim/
lib.rs

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