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