referrerpolicy=no-referrer-when-downgrade

frame_support/traits/
reality.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//! Traits concerned with modelling reality.
19
20use core::marker::PhantomData;
21
22use codec::{Decode, DecodeWithMemTracking, Encode, FullCodec, MaxEncodedLen};
23use frame_support::{CloneNoBound, EqNoBound, Parameter, PartialEqNoBound};
24use scale_info::TypeInfo;
25use sp_core::ConstU32;
26use sp_runtime::{traits::Member, BoundedVec, DispatchError, DispatchResult, RuntimeDebug};
27
28/// Identity of personhood.
29///
30/// This is a persistent identifier for every individual. Regardless of what else the individual
31/// changes within the system (such as identity documents, cryptographic keys, etc...) this does not
32/// change. As such, it should never be used in application code.
33pub type PersonalId = u64;
34
35/// Identifier for a specific application in which we may wish to track individual people.
36///
37/// NOTE: This MUST remain equivalent to the type `Context` in the crate `verifiable`.
38pub type Context = [u8; 32];
39
40/// Identifier for a specific individual within an application context.
41///
42/// NOTE: This MUST remain equivalent to the type `Alias` in the crate `verifiable`.
43pub type Alias = [u8; 32];
44
45/// The type we use to identify different rings.
46pub type RingIndex = u32;
47
48/// Data type for arbitrary information handled by the statement oracle.
49pub type Data = BoundedVec<u8, ConstU32<32>>;
50
51/// The maximum length of custom statement data.
52pub const MAX_STATEMENT_DATA_SIZE: u32 = 256;
53
54/// Data type for custom statement information handled by the statement oracle.
55pub type CustomStatement = BoundedVec<u8, ConstU32<MAX_STATEMENT_DATA_SIZE>>;
56
57/// The type used to represent the hash of the evidence used in statements by the statement oracle.
58pub type EvidenceHash = [u8; 32];
59
60/// Maximum length of the context passed in the oracle's judgements.
61pub const CONTEXT_SIZE: u32 = 64;
62
63/// The type used to represent the context of an oracle's judgement.
64pub type JudgementContext = BoundedVec<u8, ConstU32<CONTEXT_SIZE>>;
65
66/// The [`Alias`] type enriched with the originating [`Context`].
67#[derive(
68	Clone,
69	PartialEq,
70	Eq,
71	RuntimeDebug,
72	Encode,
73	Decode,
74	MaxEncodedLen,
75	TypeInfo,
76	DecodeWithMemTracking,
77)]
78pub struct ContextualAlias {
79	/// The alias of the person.
80	pub alias: Alias,
81	/// The context in which this alias was created.
82	pub context: Context,
83}
84
85/// Trait to recognize people and handle personal id.
86///
87/// `PersonalId` goes through multiple state: free, reserved, used; a used personal id can belong
88/// to a recognized person or a suspended person.
89pub trait AddOnlyPeopleTrait {
90	type Member: Parameter + MaxEncodedLen;
91	/// Reserve a new id for a future person. This id is not recognized, not reserved, and has
92	/// never been reserved in the past.
93	fn reserve_new_id() -> PersonalId;
94	/// Renew a reservation for a personal id. The id is not recognized, but has been reserved in
95	/// the past.
96	///
97	/// An error is returned if the id is used or wasn't reserved before.
98	fn renew_id_reservation(personal_id: PersonalId) -> Result<(), DispatchError>;
99	/// Cancel the reservation for a personal id
100	///
101	/// An error is returned if the id wasn't reserved in the first place.
102	fn cancel_id_reservation(personal_id: PersonalId) -> Result<(), DispatchError>;
103	/// Recognized a person.
104	///
105	/// The personal id must be reserved or the person must have already been recognized and
106	/// suspended in the past.
107	/// If recognizing a new person, a key must be provided. If resuming the personhood then no key
108	/// must be provided.
109	///
110	/// An error is returned if:
111	/// * `maybe_key` is some and the personal id was not reserved or is used by a recognized or
112	///   suspended person.
113	/// * `maybe_key` is none and the personal id was not recognized before.
114	fn recognize_personhood(
115		who: PersonalId,
116		maybe_key: Option<Self::Member>,
117	) -> Result<(), DispatchError>;
118	// All stuff for benchmarks.
119	#[cfg(feature = "runtime-benchmarks")]
120	type Secret;
121	#[cfg(feature = "runtime-benchmarks")]
122	fn mock_key(who: PersonalId) -> (Self::Member, Self::Secret);
123}
124
125/// Trait to recognize and suspend people.
126pub trait PeopleTrait: AddOnlyPeopleTrait {
127	/// Suspend a set of people. This operation must be called within a mutation session.
128	///
129	/// An error is returned if:
130	/// * a suspended personal id was already suspended.
131	/// * a personal id doesn't belong to any person.
132	fn suspend_personhood(suspensions: &[PersonalId]) -> DispatchResult;
133	/// Start a mutation session for setting people.
134	///
135	/// An error is returned if the mutation session can be started at the moment. It is expected
136	/// to become startable later.
137	fn start_people_set_mutation_session() -> DispatchResult;
138	/// End a mutation session for setting people.
139	///
140	/// An error is returned if there is no mutation session ongoing.
141	fn end_people_set_mutation_session() -> DispatchResult;
142}
143
144impl AddOnlyPeopleTrait for () {
145	type Member = ();
146	fn reserve_new_id() -> PersonalId {
147		0
148	}
149	fn renew_id_reservation(_: PersonalId) -> Result<(), DispatchError> {
150		Ok(())
151	}
152	fn cancel_id_reservation(_: PersonalId) -> Result<(), DispatchError> {
153		Ok(())
154	}
155	fn recognize_personhood(_: PersonalId, _: Option<Self::Member>) -> Result<(), DispatchError> {
156		Ok(())
157	}
158
159	#[cfg(feature = "runtime-benchmarks")]
160	type Secret = PersonalId;
161	#[cfg(feature = "runtime-benchmarks")]
162	fn mock_key(who: PersonalId) -> (Self::Member, Self::Secret) {
163		((), who)
164	}
165}
166
167impl PeopleTrait for () {
168	fn suspend_personhood(_: &[PersonalId]) -> DispatchResult {
169		Ok(())
170	}
171	fn start_people_set_mutation_session() -> DispatchResult {
172		Ok(())
173	}
174	fn end_people_set_mutation_session() -> DispatchResult {
175		Ok(())
176	}
177}
178
179/// Trait to get the total number of active members in a set.
180pub trait CountedMembers {
181	/// Returns the number of active members in the set.
182	fn active_count(&self) -> u32;
183}
184
185/// A legitimate verdict on a particular statement.
186#[derive(
187	Clone,
188	Copy,
189	PartialEq,
190	Eq,
191	RuntimeDebug,
192	Encode,
193	Decode,
194	MaxEncodedLen,
195	TypeInfo,
196	DecodeWithMemTracking,
197)]
198pub enum Truth {
199	/// The evidence can be taken as a clear indication that the statement is true. Doubt may still
200	/// remain but it should be unlikely (no more than 1 chance in 20) that this doubt would be
201	/// substantial enough to contravene the evidence.
202	True,
203	/// The evidence contradicts the statement.
204	False,
205}
206
207/// Judgement passed on the truth and validity of a statement.
208#[derive(
209	Clone,
210	Copy,
211	PartialEq,
212	Eq,
213	RuntimeDebug,
214	Encode,
215	Decode,
216	MaxEncodedLen,
217	TypeInfo,
218	DecodeWithMemTracking,
219)]
220pub enum Judgement {
221	/// A judgement on the truth of a statement.
222	Truth(Truth),
223	/// The evidence supplied probably (P > 50%) implies contempt for the system. Submitting
224	/// evidence which clearly appears to be manipulated or intentionally provides no indication of
225	/// truth for the statement would imply this outcome.
226	Contempt,
227}
228
229impl Judgement {
230	pub fn matches_intent(&self, j: Self) -> bool {
231		use self::Truth::*;
232		use Judgement::*;
233		matches!(
234			(self, j),
235			(Truth(True), Truth(True)) | (Truth(False), Truth(False)) | (Contempt, Contempt)
236		)
237	}
238}
239
240pub mod identity {
241	use super::*;
242
243	/// Social platforms that statement oracles support.
244	#[derive(
245		Clone,
246		PartialEq,
247		Eq,
248		RuntimeDebug,
249		Encode,
250		Decode,
251		MaxEncodedLen,
252		TypeInfo,
253		DecodeWithMemTracking,
254	)]
255	pub enum Social {
256		Twitter { username: Data },
257		Github { username: Data },
258	}
259
260	impl Social {
261		pub fn eq_platform(&self, other: &Social) -> bool {
262			matches!(
263				(&self, &other),
264				(Social::Twitter { .. }, Social::Twitter { .. }) |
265					(Social::Github { .. }, Social::Github { .. })
266			)
267		}
268	}
269}
270
271/// A statement upon which a [`StatementOracle`] can provide judgement.
272#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
273pub enum Statement {
274	/// Ask for whether evidence exists to confirm that a particular social credential on a
275	/// supported platform belongs to a person.
276	IdentityCredential { platform: identity::Social, evidence: Data },
277	/// Ask for whether a username meets certain standards.
278	///
279	/// It is up to the oracle to decide upon username validity,
280	/// but it may be assumed that a username is considered acceptable if it:
281	/// - contains no offensive, discriminatory, or inappropriate content,
282	/// - is visually distinct and readable in user interfaces,
283	/// - complies with other oracle guidelines.
284	UsernameValid { username: Data },
285	/// Ask for a custom statement to be judged. The responsibility of correctly interpreting the
286	/// encoded bytes falls on the [`StatementOracle`] implementation handling this. If no custom
287	/// statements are allowed, the implementation should reject this variant altogether.
288	Custom { id: u8, data: CustomStatement },
289}
290
291/// Describes the location within the runtime of a callback, along with other type information such
292/// as parameters passed into the callback.
293#[derive(
294	CloneNoBound, PartialEqNoBound, EqNoBound, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo,
295)]
296#[scale_info(skip_type_params(Params, RuntimeCall))]
297#[codec(mel_bound())]
298pub struct Callback<Params, RuntimeCall> {
299	pallet_index: u8,
300	call_index: u8,
301	phantom: PhantomData<(Params, RuntimeCall)>,
302}
303
304impl<Params: Encode, RuntimeCall: Decode> Callback<Params, RuntimeCall> {
305	pub const fn from_parts(pallet_index: u8, call_index: u8) -> Self {
306		Self { pallet_index, call_index, phantom: PhantomData }
307	}
308	pub fn curry(&self, args: Params) -> Result<RuntimeCall, codec::Error> {
309		(self.pallet_index, self.call_index, args).using_encoded(|mut d| Decode::decode(&mut d))
310	}
311}
312
313/// A provider of wondrous magic: give it a `Statement` and it will tell you if it's true, with
314/// some degree of resilience.
315///
316/// It's asynchronous, so you give it a callback in the form of a `RuntimeCall` stub.
317pub trait StatementOracle<RuntimeCall> {
318	/// A small piece of data which may be used to identify different ongoing judgements.
319	type Ticket: Member + FullCodec + TypeInfo + MaxEncodedLen + Default;
320
321	/// Judge a `statement` and get a Judgement.
322	///
323	/// We only care about the pallet/call index of `callback`; it must take exactly three
324	/// arguments:
325	///
326	/// - `Self::Ticket`: The ticket which was returned here to identify the judgement.
327	/// - `JudgementContext`: The value of `context` which was passed in to this call.
328	/// - `Judgement`: The judgement given by the oracle.
329	///
330	/// It is assumed that all costs associated with this oraclisation have already been paid for
331	/// or are absorbed by the system acting in its own interests.
332	fn judge_statement(
333		statement: Statement,
334		context: JudgementContext,
335		callback: Callback<(Self::Ticket, JudgementContext, Judgement), RuntimeCall>,
336	) -> Result<Self::Ticket, DispatchError>;
337}
338
339impl<C> StatementOracle<C> for () {
340	type Ticket = ();
341	fn judge_statement(
342		_: Statement,
343		_: JudgementContext,
344		_: Callback<(Self::Ticket, JudgementContext, Judgement), C>,
345	) -> Result<(), DispatchError> {
346		Err(DispatchError::Unavailable)
347	}
348}