referrerpolicy=no-referrer-when-downgrade

pallet_people/
types.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//! Types for Proof-of-Personhood system.
19
20#![allow(clippy::result_unit_err)]
21
22use super::*;
23use frame_support::{pallet_prelude::*, DefaultNoBound};
24
25pub type RevisionIndex = u32;
26pub type PageIndex = u32;
27pub type KeyCount = u64;
28
29pub type MemberOf<T> = <<T as Config>::Crypto as GenerateVerifiable>::Member;
30pub type MembersOf<T> = <<T as Config>::Crypto as GenerateVerifiable>::Members;
31pub type IntermediateOf<T> = <<T as Config>::Crypto as GenerateVerifiable>::Intermediate;
32pub type SecretOf<T> = <<T as Config>::Crypto as GenerateVerifiable>::Secret;
33pub type SignatureOf<T> = <<T as Config>::Crypto as GenerateVerifiable>::Signature;
34pub type ChunksOf<T> = BoundedVec<
35	<<T as Config>::Crypto as GenerateVerifiable>::StaticChunk,
36	<T as Config>::ChunkPageSize,
37>;
38
39/// The overarching state of all people rings regarding the actions that are currently allowed to be
40/// performed on them.
41#[derive(
42	Clone,
43	PartialEq,
44	Eq,
45	RuntimeDebug,
46	Encode,
47	Decode,
48	MaxEncodedLen,
49	TypeInfo,
50	DecodeWithMemTracking,
51)]
52pub enum RingMembersState {
53	/// The rings can accept new people sequentially if the maximum capacity has not been reached
54	/// yet. Ring building is permitted in this state by building the ring roots on top of
55	/// previously computed roots. In case a ring suffered mutations that invalidated a previous
56	/// ring root through the removal of an included member, the existing ring root will be removed
57	/// and ring building will start from scratch.
58	AppendOnly,
59	/// A semaphore counting the number of entities making changes to the ring members list which
60	/// require the entire ring to be rebuilt. Whenever a DIM would want to suspend
61	/// people, it would first need to increment this counter and then start submitting the
62	/// suspended indices. After all indices are registered, the counter is decremented. Ring
63	/// merges are allowed only when no entity is allowed to suspend keys and the counter is 0.
64	Mutating(u8),
65	/// After mutations to the member set, any pending key migrations are enacted before the new
66	/// ring roots will be built in order to reflect the latest changes in state.
67	KeyMigration,
68}
69
70impl Default for RingMembersState {
71	fn default() -> Self {
72		Self::AppendOnly
73	}
74}
75
76impl RingMembersState {
77	/// Returns whether the state allows only incremental additions to rings and their roots.
78	pub fn append_only(&self) -> bool {
79		matches!(self, Self::AppendOnly)
80	}
81
82	/// Returns whether the state allows mutating the member set of rings.
83	pub fn mutating(&self) -> bool {
84		matches!(self, Self::Mutating(_))
85	}
86
87	/// Returns whether the state allows the pending key migrations to be enacted.
88	pub fn key_migration(&self) -> bool {
89		matches!(self, Self::KeyMigration)
90	}
91
92	/// Move to a mutation state.
93	pub fn start_mutation_session(self) -> Result<Self, ()> {
94		match self {
95			Self::AppendOnly => Ok(Self::Mutating(1)),
96			Self::Mutating(n) => Ok(Self::Mutating(n.checked_add(1).ok_or(())?)),
97			Self::KeyMigration => Err(()),
98		}
99	}
100
101	/// Move out of a mutation state.
102	pub fn end_mutation_session(self) -> Result<Self, ()> {
103		match self {
104			Self::AppendOnly => Err(()),
105			Self::Mutating(1) => Ok(Self::KeyMigration),
106			Self::Mutating(n) => Ok(Self::Mutating(n.saturating_sub(1))),
107			Self::KeyMigration => Err(()),
108		}
109	}
110
111	/// Move out of a key migration state.
112	pub fn end_key_migration(self) -> Result<Self, ()> {
113		match self {
114			Self::KeyMigration => Ok(Self::AppendOnly),
115			_ => Err(()),
116		}
117	}
118}
119
120/// A contextual alias [`ContextualAlias`] used in a specific ring revision.
121///
122/// The revision can be used to tell in the future if an alias may have been suspended.
123/// For instance, if a person is suspended, then ring will get revised, the revised alias with the
124/// old revision shows that the alias may not be owned by a valid person anymore.
125#[derive(
126	Clone,
127	PartialEq,
128	Eq,
129	RuntimeDebug,
130	Encode,
131	Decode,
132	MaxEncodedLen,
133	TypeInfo,
134	DecodeWithMemTracking,
135)]
136pub struct RevisedContextualAlias {
137	pub revision: RevisionIndex,
138	pub ring: RingIndex,
139	pub ca: ContextualAlias,
140}
141
142/// An alias [`Alias`] used in a specific ring revision.
143///
144/// The revision can be used to tell in the future if an alias may have been suspended.
145/// For instance, if a person is suspended, then ring will get revised, the revised alias with the
146/// old revision shows that the alias may not be owned by a valid person anymore.
147#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
148pub struct RevisedAlias {
149	pub revision: RevisionIndex,
150	pub ring: RingIndex,
151	pub alias: Alias,
152}
153
154#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
155#[scale_info(skip_type_params(T))]
156pub struct RingRoot<T: Config> {
157	/// The ring root for the current ring.
158	pub root: MembersOf<T>,
159	/// The revision index of the ring.
160	pub revision: RevisionIndex,
161	/// An intermediate value if the ring is not full.
162	pub intermediate: IntermediateOf<T>,
163}
164
165#[derive(
166	PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, DefaultNoBound,
167)]
168#[scale_info(skip_type_params(T))]
169/// Information about the current key inclusion status in a ring.
170pub struct RingStatus {
171	/// The number of keys in the ring.
172	pub total: u32,
173	/// The number of keys that have already been baked in.
174	pub included: u32,
175}
176
177/// The state of a person's key within the pallet along with its position in relevant structures.
178///
179/// Differentiates between individuals included in a ring, those being onboarded and the suspended
180/// ones. For those already included, provides ring index and position in it. For those being
181/// onboarded, provides queue page index and position in the queue.
182#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
183pub enum RingPosition {
184	/// Coordinates within the onboarding queue for a person that doesn't belong to a ring yet.
185	Onboarding { queue_page: PageIndex },
186	/// Coordinates within the rings for a person that was registered.
187	Included { ring_index: RingIndex, ring_position: u32, scheduled_for_removal: bool },
188	/// The person is suspended and isn't part of any ring or onboarding queue page.
189	Suspended,
190}
191
192impl RingPosition {
193	/// Returns whether the person is suspended and has no position.
194	pub fn suspended(&self) -> bool {
195		matches!(self, Self::Suspended)
196	}
197
198	/// Returns whether the person is included in a ring and is scheduled for removal.
199	pub fn scheduled_for_removal(&self) -> bool {
200		match &self {
201			Self::Included { scheduled_for_removal, .. } => *scheduled_for_removal,
202			_ => false,
203		}
204	}
205
206	/// Returns the index of the ring if this person is included.
207	pub fn ring_index(&self) -> Option<RingIndex> {
208		match &self {
209			Self::Included { ring_index, .. } => Some(*ring_index),
210			_ => None,
211		}
212	}
213}
214
215/// Record of personhood.
216#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
217pub struct PersonRecord<Member, AccountId> {
218	// The key used for the person.
219	pub key: Member,
220	// The position identifier of the key.
221	pub position: RingPosition,
222	/// An optional privileged account that can send transaction on the behalf of the person.
223	pub account: Option<AccountId>,
224}
225
226/// Describes the action to take after checking the first two pages of the onboarding queue for a
227/// potential merge.
228#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
229#[scale_info(skip_type_params(T))]
230pub(crate) enum QueueMergeAction<T: Config> {
231	Merge {
232		initial_head: PageIndex,
233		new_head: PageIndex,
234		first_key_page: BoundedVec<MemberOf<T>, T::OnboardingQueuePageSize>,
235		second_key_page: BoundedVec<MemberOf<T>, T::OnboardingQueuePageSize>,
236	},
237	NoAction,
238}