referrerpolicy=no-referrer-when-downgrade

pallet_identity/
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
18use super::*;
19use alloc::{vec, vec::Vec};
20use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
21use core::{fmt::Debug, iter::once, ops::Add};
22use frame_support::{
23	traits::{ConstU32, Get},
24	BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound,
25};
26use scale_info::{
27	build::{Fields, Variants},
28	Path, Type, TypeInfo,
29};
30use sp_runtime::{
31	traits::{Member, Zero},
32	RuntimeDebug,
33};
34
35/// An identifier for a single name registrar/identity verification service.
36pub type RegistrarIndex = u32;
37
38/// Either underlying data blob if it is at most 32 bytes, or a hash of it. If the data is greater
39/// than 32-bytes then it will be truncated when encoding.
40///
41/// Can also be `None`.
42#[derive(Clone, DecodeWithMemTracking, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)]
43pub enum Data {
44	/// No data here.
45	None,
46	/// The data is stored directly.
47	Raw(BoundedVec<u8, ConstU32<32>>),
48	/// Only the Blake2 hash of the data is stored. The preimage of the hash may be retrieved
49	/// through some hash-lookup service.
50	BlakeTwo256([u8; 32]),
51	/// Only the SHA2-256 hash of the data is stored. The preimage of the hash may be retrieved
52	/// through some hash-lookup service.
53	Sha256([u8; 32]),
54	/// Only the Keccak-256 hash of the data is stored. The preimage of the hash may be retrieved
55	/// through some hash-lookup service.
56	Keccak256([u8; 32]),
57	/// Only the SHA3-256 hash of the data is stored. The preimage of the hash may be retrieved
58	/// through some hash-lookup service.
59	ShaThree256([u8; 32]),
60}
61
62impl Data {
63	pub fn is_none(&self) -> bool {
64		self == &Data::None
65	}
66}
67
68impl Decode for Data {
69	fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
70		let b = input.read_byte()?;
71		Ok(match b {
72			0 => Data::None,
73			n @ 1..=33 => {
74				let mut r: BoundedVec<_, _> = vec![0u8; n as usize - 1]
75					.try_into()
76					.expect("bound checked in match arm condition; qed");
77				input.read(&mut r[..])?;
78				Data::Raw(r)
79			},
80			34 => Data::BlakeTwo256(<[u8; 32]>::decode(input)?),
81			35 => Data::Sha256(<[u8; 32]>::decode(input)?),
82			36 => Data::Keccak256(<[u8; 32]>::decode(input)?),
83			37 => Data::ShaThree256(<[u8; 32]>::decode(input)?),
84			_ => return Err(codec::Error::from("invalid leading byte")),
85		})
86	}
87}
88
89impl Encode for Data {
90	fn encode(&self) -> Vec<u8> {
91		match self {
92			Data::None => vec![0u8; 1],
93			Data::Raw(ref x) => {
94				let l = x.len().min(32);
95				let mut r = vec![l as u8 + 1; l + 1];
96				r[1..].copy_from_slice(&x[..l as usize]);
97				r
98			},
99			Data::BlakeTwo256(ref h) => once(34u8).chain(h.iter().cloned()).collect(),
100			Data::Sha256(ref h) => once(35u8).chain(h.iter().cloned()).collect(),
101			Data::Keccak256(ref h) => once(36u8).chain(h.iter().cloned()).collect(),
102			Data::ShaThree256(ref h) => once(37u8).chain(h.iter().cloned()).collect(),
103		}
104	}
105}
106impl codec::EncodeLike for Data {}
107
108/// Add a Raw variant with the given index and a fixed sized byte array
109macro_rules! data_raw_variants {
110    ($variants:ident, $(($index:literal, $size:literal)),* ) => {
111		$variants
112		$(
113			.variant(concat!("Raw", stringify!($size)), |v| v
114				.index($index)
115				.fields(Fields::unnamed().field(|f| f.ty::<[u8; $size]>()))
116			)
117		)*
118    }
119}
120
121impl TypeInfo for Data {
122	type Identity = Self;
123
124	fn type_info() -> Type {
125		let variants = Variants::new().variant("None", |v| v.index(0));
126
127		// create a variant for all sizes of Raw data from 0-32
128		let variants = data_raw_variants!(
129			variants,
130			(1, 0),
131			(2, 1),
132			(3, 2),
133			(4, 3),
134			(5, 4),
135			(6, 5),
136			(7, 6),
137			(8, 7),
138			(9, 8),
139			(10, 9),
140			(11, 10),
141			(12, 11),
142			(13, 12),
143			(14, 13),
144			(15, 14),
145			(16, 15),
146			(17, 16),
147			(18, 17),
148			(19, 18),
149			(20, 19),
150			(21, 20),
151			(22, 21),
152			(23, 22),
153			(24, 23),
154			(25, 24),
155			(26, 25),
156			(27, 26),
157			(28, 27),
158			(29, 28),
159			(30, 29),
160			(31, 30),
161			(32, 31),
162			(33, 32)
163		);
164
165		let variants = variants
166			.variant("BlakeTwo256", |v| {
167				v.index(34).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
168			})
169			.variant("Sha256", |v| {
170				v.index(35).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
171			})
172			.variant("Keccak256", |v| {
173				v.index(36).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
174			})
175			.variant("ShaThree256", |v| {
176				v.index(37).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
177			});
178
179		Type::builder().path(Path::new("Data", module_path!())).variant(variants)
180	}
181}
182
183impl Default for Data {
184	fn default() -> Self {
185		Self::None
186	}
187}
188
189/// An attestation of a registrar over how accurate some `IdentityInfo` is in describing an account.
190///
191/// NOTE: Registrars may pay little attention to some fields. Registrars may want to make clear
192/// which fields their attestation is relevant for by off-chain means.
193#[derive(
194	Copy,
195	Clone,
196	Encode,
197	Decode,
198	DecodeWithMemTracking,
199	Eq,
200	PartialEq,
201	RuntimeDebug,
202	MaxEncodedLen,
203	TypeInfo,
204)]
205pub enum Judgement<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
206{
207	/// The default value; no opinion is held.
208	Unknown,
209	/// No judgement is yet in place, but a deposit is reserved as payment for providing one.
210	FeePaid(Balance),
211	/// The data appears to be reasonably acceptable in terms of its accuracy, however no in depth
212	/// checks (such as in-person meetings or formal KYC) have been conducted.
213	Reasonable,
214	/// The target is known directly by the registrar and the registrar can fully attest to the
215	/// the data's accuracy.
216	KnownGood,
217	/// The data was once good but is currently out of date. There is no malicious intent in the
218	/// inaccuracy. This judgement can be removed through updating the data.
219	OutOfDate,
220	/// The data is imprecise or of sufficiently low-quality to be problematic. It is not
221	/// indicative of malicious intent. This judgement can be removed through updating the data.
222	LowQuality,
223	/// The data is erroneous. This may be indicative of malicious intent. This cannot be removed
224	/// except by the registrar.
225	Erroneous,
226}
227
228impl<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
229	Judgement<Balance>
230{
231	/// Returns `true` if this judgement is indicative of a deposit being currently held. This means
232	/// it should not be cleared or replaced except by an operation which utilizes the deposit.
233	pub(crate) fn has_deposit(&self) -> bool {
234		matches!(self, Judgement::FeePaid(_))
235	}
236
237	/// Returns `true` if this judgement is one that should not be generally be replaced outside
238	/// of specialized handlers. Examples include "malicious" judgements and deposit-holding
239	/// judgements.
240	pub(crate) fn is_sticky(&self) -> bool {
241		matches!(self, Judgement::FeePaid(_) | Judgement::Erroneous)
242	}
243}
244
245/// Information concerning the identity of the controller of an account.
246pub trait IdentityInformationProvider:
247	Encode + Decode + MaxEncodedLen + Clone + Debug + Eq + PartialEq + TypeInfo + Default
248{
249	/// Type capable of holding information on which identity fields are set.
250	type FieldsIdentifier: Member + Encode + Decode + MaxEncodedLen + TypeInfo + Default;
251
252	/// Check if an identity registered information for some given `fields`.
253	fn has_identity(&self, fields: Self::FieldsIdentifier) -> bool;
254
255	/// Create a basic instance of the identity information.
256	#[cfg(feature = "runtime-benchmarks")]
257	fn create_identity_info() -> Self;
258
259	/// The identity information representation for all identity fields enabled.
260	#[cfg(feature = "runtime-benchmarks")]
261	fn all_fields() -> Self::FieldsIdentifier;
262}
263
264/// Information on an identity along with judgements from registrars.
265///
266/// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a
267/// backwards compatible way through a specialized `Decode` impl.
268#[derive(
269	CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
270)]
271#[codec(mel_bound())]
272#[scale_info(skip_type_params(MaxJudgements))]
273pub struct Registration<
274	Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
275	MaxJudgements: Get<u32>,
276	IdentityInfo: IdentityInformationProvider,
277> {
278	/// Judgements from the registrars on this identity. Stored ordered by `RegistrarIndex`. There
279	/// may be only a single judgement from each registrar.
280	pub judgements: BoundedVec<(RegistrarIndex, Judgement<Balance>), MaxJudgements>,
281
282	/// Amount held on deposit for this information.
283	pub deposit: Balance,
284
285	/// Information on the identity.
286	pub info: IdentityInfo,
287}
288
289impl<
290		Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add,
291		MaxJudgements: Get<u32>,
292		IdentityInfo: IdentityInformationProvider,
293	> Registration<Balance, MaxJudgements, IdentityInfo>
294{
295	pub(crate) fn total_deposit(&self) -> Balance {
296		self.deposit +
297			self.judgements
298				.iter()
299				.map(|(_, ref j)| if let Judgement::FeePaid(fee) = j { *fee } else { Zero::zero() })
300				.fold(Zero::zero(), |a, i| a + i)
301	}
302}
303
304impl<
305		Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
306		MaxJudgements: Get<u32>,
307		IdentityInfo: IdentityInformationProvider,
308	> Decode for Registration<Balance, MaxJudgements, IdentityInfo>
309{
310	fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
311		let (judgements, deposit, info) = Decode::decode(&mut AppendZerosInput::new(input))?;
312		Ok(Self { judgements, deposit, info })
313	}
314}
315
316/// Information concerning a registrar.
317#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
318pub struct RegistrarInfo<
319	Balance: Encode + Decode + Clone + Debug + Eq + PartialEq,
320	AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq,
321	IdField: Encode + Decode + Clone + Debug + Default + Eq + PartialEq + TypeInfo + MaxEncodedLen,
322> {
323	/// The account of the registrar.
324	pub account: AccountId,
325
326	/// Amount required to be given to the registrar for them to provide judgement.
327	pub fee: Balance,
328
329	/// Relevant fields for this registrar. Registrar judgements are limited to attestations on
330	/// these fields.
331	pub fields: IdField,
332}
333
334/// The number of usernames that an authority may allocate.
335type Allocation = u32;
336/// A byte vec used to represent a username.
337pub(crate) type Suffix<T> = BoundedVec<u8, <T as Config>::MaxSuffixLength>;
338
339/// Properties of a username authority.
340#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
341pub struct AuthorityProperties<Account> {
342	/// The account of the authority.
343	pub account_id: Account,
344	/// The number of usernames remaining that this authority can grant.
345	pub allocation: Allocation,
346}
347
348/// A byte vec used to represent a username.
349pub(crate) type Username<T> = BoundedVec<u8, <T as Config>::MaxUsernameLength>;
350
351#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
352pub enum Provider<Balance> {
353	Allocation,
354	AuthorityDeposit(Balance),
355	System,
356}
357
358impl<Balance> Provider<Balance> {
359	pub fn new_with_allocation() -> Self {
360		Self::Allocation
361	}
362
363	pub fn new_with_deposit(deposit: Balance) -> Self {
364		Self::AuthorityDeposit(deposit)
365	}
366
367	#[allow(unused)]
368	pub fn new_permanent() -> Self {
369		Self::System
370	}
371}
372
373#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)]
374pub struct UsernameInformation<Account, Balance> {
375	pub owner: Account,
376	pub provider: Provider<Balance>,
377}
378
379#[cfg(test)]
380mod tests {
381	use super::*;
382
383	#[test]
384	fn manual_data_type_info() {
385		let mut registry = scale_info::Registry::new();
386		let type_id = registry.register_type(&scale_info::meta_type::<Data>());
387		let registry: scale_info::PortableRegistry = registry.into();
388		let type_info = registry.resolve(type_id.id).unwrap();
389
390		let check_type_info = |data: &Data| {
391			let variant_name = match data {
392				Data::None => "None".to_string(),
393				Data::BlakeTwo256(_) => "BlakeTwo256".to_string(),
394				Data::Sha256(_) => "Sha256".to_string(),
395				Data::Keccak256(_) => "Keccak256".to_string(),
396				Data::ShaThree256(_) => "ShaThree256".to_string(),
397				Data::Raw(bytes) => format!("Raw{}", bytes.len()),
398			};
399			if let scale_info::TypeDef::Variant(variant) = &type_info.type_def {
400				let variant = variant
401					.variants
402					.iter()
403					.find(|v| v.name == variant_name)
404					.expect(&format!("Expected to find variant {}", variant_name));
405
406				let field_arr_len = variant
407					.fields
408					.first()
409					.and_then(|f| registry.resolve(f.ty.id))
410					.map(|ty| {
411						if let scale_info::TypeDef::Array(arr) = &ty.type_def {
412							arr.len
413						} else {
414							panic!("Should be an array type")
415						}
416					})
417					.unwrap_or(0);
418
419				let encoded = data.encode();
420				assert_eq!(encoded[0], variant.index);
421				assert_eq!(encoded.len() as u32 - 1, field_arr_len);
422			} else {
423				panic!("Should be a variant type")
424			};
425		};
426
427		let mut data = vec![
428			Data::None,
429			Data::BlakeTwo256(Default::default()),
430			Data::Sha256(Default::default()),
431			Data::Keccak256(Default::default()),
432			Data::ShaThree256(Default::default()),
433		];
434
435		// A Raw instance for all possible sizes of the Raw data
436		for n in 0..32 {
437			data.push(Data::Raw(vec![0u8; n as usize].try_into().unwrap()))
438		}
439
440		for d in data.iter() {
441			check_type_info(d);
442		}
443	}
444}