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