difftreelog
feat(identity) fork + publicize private fields
in: master
14 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4026,7 +4026,7 @@
"pallet-elections-phragmen",
"pallet-fast-unstake",
"pallet-grandpa",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36)",
"pallet-im-online",
"pallet-indices",
"pallet-membership",
@@ -5322,7 +5322,7 @@
"pallet-evm-transaction-payment",
"pallet-foreign-assets",
"pallet-fungible",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev",
"pallet-inflation",
"pallet-maintenance",
"pallet-nonfungible",
@@ -5777,7 +5777,7 @@
[[package]]
name = "pallet-collator-selection"
-version = "3.0.0"
+version = "4.0.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@@ -5885,6 +5885,7 @@
"frame-support",
"frame-system",
"pallet-evm",
+ "pallet-identity 4.0.0-dev",
"parity-scale-codec 3.2.1",
"scale-info",
"sp-core",
@@ -6184,6 +6185,23 @@
[[package]]
name = "pallet-identity"
version = "4.0.0-dev"
+dependencies = [
+ "enumflags2",
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "parity-scale-codec 3.2.1",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-identity"
+version = "4.0.0-dev"
source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51"
dependencies = [
"enumflags2",
@@ -8137,7 +8155,7 @@
"pallet-elections-phragmen",
"pallet-fast-unstake",
"pallet-grandpa",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36)",
"pallet-im-online",
"pallet-indices",
"pallet-membership",
@@ -8912,7 +8930,7 @@
"pallet-evm-transaction-payment",
"pallet-foreign-assets",
"pallet-fungible",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev",
"pallet-inflation",
"pallet-maintenance",
"pallet-nonfungible",
@@ -9353,7 +9371,7 @@
"pallet-democracy",
"pallet-elections-phragmen",
"pallet-grandpa",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36)",
"pallet-im-online",
"pallet-indices",
"pallet-membership",
@@ -13144,7 +13162,7 @@
"pallet-evm-transaction-payment",
"pallet-foreign-assets",
"pallet-fungible",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev",
"pallet-inflation",
"pallet-maintenance",
"pallet-nonfungible",
@@ -13789,7 +13807,7 @@
"pallet-elections-phragmen",
"pallet-fast-unstake",
"pallet-grandpa",
- "pallet-identity",
+ "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36)",
"pallet-im-online",
"pallet-indices",
"pallet-membership",
pallets/collator-selection/Cargo.tomldiffbeforeafterboth--- a/pallets/collator-selection/Cargo.toml
+++ b/pallets/collator-selection/Cargo.toml
@@ -1,8 +1,8 @@
[package]
name = "pallet-collator-selection"
-version = "3.0.0"
+version = "4.0.0"
description = "Simple staking pallet with a fixed stake."
-authors = ["Unique Network <support@uniquenetwork.io>"]
+authors = ["Parity Technologies <admin@parity.io>", "Unique Network <support@uniquenetwork.io>"]
edition = "2021"
homepage = "https://unique.network"
repository = "https://github.com/UniqueNetwork/unique-chain"
pallets/data-management/Cargo.tomldiffbeforeafterboth--- a/pallets/data-management/Cargo.toml
+++ b/pallets/data-management/Cargo.toml
@@ -16,6 +16,7 @@
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+pallet-identity = { default-features = false, path = "../identity" }
pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
pallets/data-management/src/lib.rsdiffbeforeafterboth--- a/pallets/data-management/src/lib.rs
+++ b/pallets/data-management/src/lib.rs
@@ -34,9 +34,10 @@
use sp_std::vec::Vec;
use super::weights::WeightInfo;
use pallet_evm::{PrecompileHandle, Pallet as PalletEvm};
+ use pallet_identity::Registration;
#[pallet::config]
- pub trait Config: frame_system::Config + pallet_evm::Config {
+ pub trait Config: frame_system::Config + pallet_evm::Config + pallet_identity::Config {
/// Weights
type WeightInfo: WeightInfo;
/// The overarching event type.
@@ -149,6 +150,23 @@
}
Ok(())
}
+
+ /// Insert or remove identities.
+ #[pallet::call_index(5)]
+ #[pallet::weight(<SelfWeightOf<T>>::insert_events(identities.len() as u32))] // todo:collator weight
+ pub fn insert_identities(
+ origin: OriginFor<T>,
+ identities: Vec<(
+ T::AccountId,
+ Option<Registration<pallet_identity::BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>>,
+ )>,
+ ) -> DispatchResult {
+ ensure_root(origin)?;
+ for identity in identities {
+ <pallet_identity::IdentityOf<T>>::set(identity.0, identity.1);
+ }
+ Ok(())
+ }
}
/// Implements [`pallet_evm::OnMethodCall`], which reserves accounts with pending migration
pallets/identity/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/Cargo.toml
@@ -0,0 +1,47 @@
+[package]
+name = "pallet-identity"
+version = "4.0.0-dev"
+authors = ["Parity Technologies <admin@parity.io>", "Unique Network <support@uniquenetwork.io>"]
+edition = "2021"
+license = "Apache-2.0"
+homepage = "https://substrate.io"
+repository = "https://github.com/paritytech/substrate/"
+description = "FRAME identity management pallet"
+readme = "README.md"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] }
+enumflags2 = { version = "0.7.4" }
+scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
+frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-io = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-runtime = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-std = { version = "5.0.0", default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+
+[dev-dependencies]
+pallet-balances = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-core = { version = "7.0.0", git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+
+[features]
+default = ["std"]
+std = [
+ "codec/std",
+ "frame-benchmarking?/std",
+ "frame-support/std",
+ "frame-system/std",
+ "scale-info/std",
+ "sp-io/std",
+ "sp-runtime/std",
+ "sp-std/std",
+]
+runtime-benchmarks = [
+ "frame-benchmarking/runtime-benchmarks",
+ "frame-support/runtime-benchmarks",
+ "frame-system/runtime-benchmarks",
+]
+try-runtime = ["frame-support/try-runtime"]
pallets/identity/README.mddiffbeforeafterboth1# Identity Module23- [`identity::Config`](https://docs.rs/pallet-identity/latest/pallet_identity/trait.Config.html)4- [`Call`](https://docs.rs/pallet-identity/latest/pallet_identity/enum.Call.html)56## Overview78A federated naming system, allowing for multiple registrars to be added from a specified origin.9Registrars can set a fee to provide identity-verification service. Anyone can put forth a10proposed identity for a fixed deposit and ask for review by any number of registrars (paying11each of their fees). Registrar judgements are given as an `enum`, allowing for sophisticated,12multi-tier opinions.1314Some judgements are identified as *sticky*, which means they cannot be removed except by15complete removal of the identity, or by the registrar. Judgements are allowed to represent a16portion of funds that have been reserved for the registrar.1718A super-user can remove accounts and in doing so, slash the deposit.1920All accounts may also have a limited number of sub-accounts which may be specified by the owner;21by definition, these have equivalent ownership and each has an individual name.2223The number of registrars should be limited, and the deposit made sufficiently large, to ensure24no state-bloat attack is viable.2526## Interface2728### Dispatchable Functions2930#### For general users31* `set_identity` - Set the associated identity of an account; a small deposit is reserved if not32 already taken.33* `clear_identity` - Remove an account's associated identity; the deposit is returned.34* `request_judgement` - Request a judgement from a registrar, paying a fee.35* `cancel_request` - Cancel the previous request for a judgement.3637#### For general users with sub-identities38* `set_subs` - Set the sub-accounts of an identity.39* `add_sub` - Add a sub-identity to an identity.40* `remove_sub` - Remove a sub-identity of an identity.41* `rename_sub` - Rename a sub-identity of an identity.42* `quit_sub` - Remove a sub-identity of an identity (called by the sub-identity).4344#### For registrars45* `set_fee` - Set the fee required to be paid for a judgement to be given by the registrar.46* `set_fields` - Set the fields that a registrar cares about in their judgements.47* `provide_judgement` - Provide a judgement to an identity.4849#### For super-users50* `add_registrar` - Add a new registrar to the system.51* `kill_identity` - Forcibly remove the associated identity; the deposit is lost.5253[`Call`]: ./enum.Call.html54[`Config`]: ./trait.Config.html5556License: Apache-2.0pallets/identity/src/benchmarking.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/src/benchmarking.rs
@@ -0,0 +1,462 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// Original license:
+// This file is part of Substrate.
+
+// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Identity pallet benchmarking.
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+
+use crate::Pallet as Identity;
+use frame_benchmarking::{account, benchmarks, whitelisted_caller};
+use frame_support::{
+ ensure,
+ traits::{EnsureOrigin, Get},
+};
+use frame_system::RawOrigin;
+use sp_runtime::traits::Bounded;
+
+const SEED: u32 = 0;
+
+fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
+ frame_system::Pallet::<T>::assert_last_event(generic_event.into());
+}
+
+// Adds `r` registrars to the Identity Pallet. These registrars will have set fees and fields.
+fn add_registrars<T: Config>(r: u32) -> Result<(), &'static str> {
+ for i in 0..r {
+ let registrar: T::AccountId = account("registrar", i, SEED);
+ let registrar_lookup = T::Lookup::unlookup(registrar.clone());
+ let _ = T::Currency::make_free_balance_be(®istrar, BalanceOf::<T>::max_value());
+ let registrar_origin = T::RegistrarOrigin::successful_origin();
+ Identity::<T>::add_registrar(registrar_origin, registrar_lookup)?;
+ Identity::<T>::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?;
+ let fields =
+ IdentityFields(
+ IdentityField::Display |
+ IdentityField::Legal | IdentityField::Web |
+ IdentityField::Riot | IdentityField::Email |
+ IdentityField::PgpFingerprint |
+ IdentityField::Image | IdentityField::Twitter,
+ );
+ Identity::<T>::set_fields(RawOrigin::Signed(registrar.clone()).into(), i, fields)?;
+ }
+
+ assert_eq!(Registrars::<T>::get().len(), r as usize);
+ Ok(())
+}
+
+// Create `s` sub-accounts for the identity of `who` and return them.
+// Each will have 32 bytes of raw data added to it.
+fn create_sub_accounts<T: Config>(
+ who: &T::AccountId,
+ s: u32,
+) -> Result<Vec<(T::AccountId, Data)>, &'static str> {
+ let mut subs = Vec::new();
+ let who_origin = RawOrigin::Signed(who.clone());
+ let data = Data::Raw(vec![0; 32].try_into().unwrap());
+
+ for i in 0..s {
+ let sub_account = account("sub", i, SEED);
+ subs.push((sub_account, data.clone()));
+ }
+
+ // Set identity so `set_subs` does not fail.
+ if IdentityOf::<T>::get(who).is_none() {
+ let _ = T::Currency::make_free_balance_be(who, BalanceOf::<T>::max_value() / 2u32.into());
+ let info = create_identity_info::<T>(1);
+ Identity::<T>::set_identity(who_origin.into(), Box::new(info))?;
+ }
+
+ Ok(subs)
+}
+
+// Adds `s` sub-accounts to the identity of `who`. Each will have 32 bytes of raw data added to it.
+// This additionally returns the vector of sub-accounts so it can be modified if needed.
+fn add_sub_accounts<T: Config>(
+ who: &T::AccountId,
+ s: u32,
+) -> Result<Vec<(T::AccountId, Data)>, &'static str> {
+ let who_origin = RawOrigin::Signed(who.clone());
+ let subs = create_sub_accounts::<T>(who, s)?;
+
+ Identity::<T>::set_subs(who_origin.into(), subs.clone())?;
+
+ Ok(subs)
+}
+
+// This creates an `IdentityInfo` object with `num_fields` extra fields.
+// All data is pre-populated with some arbitrary bytes.
+fn create_identity_info<T: Config>(num_fields: u32) -> IdentityInfo<T::MaxAdditionalFields> {
+ let data = Data::Raw(vec![0; 32].try_into().unwrap());
+
+ IdentityInfo {
+ additional: vec![(data.clone(), data.clone()); num_fields as usize].try_into().unwrap(),
+ display: data.clone(),
+ legal: data.clone(),
+ web: data.clone(),
+ riot: data.clone(),
+ email: data.clone(),
+ pgp_fingerprint: Some([0; 20]),
+ image: data.clone(),
+ twitter: data,
+ }
+}
+
+benchmarks! {
+ add_registrar {
+ let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::<T>(r)?;
+ ensure!(Registrars::<T>::get().len() as u32 == r, "Registrars not set up correctly.");
+ let origin = T::RegistrarOrigin::successful_origin();
+ let account = T::Lookup::unlookup(account("registrar", r + 1, SEED));
+ }: _<T::RuntimeOrigin>(origin, account)
+ verify {
+ ensure!(Registrars::<T>::get().len() as u32 == r + 1, "Registrars not added.");
+ }
+
+ set_identity {
+ let r in 1 .. T::MaxRegistrars::get() => add_registrars::<T>(r)?;
+ let x in 0 .. T::MaxAdditionalFields::get();
+ let caller = {
+ // The target user
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_lookup = T::Lookup::unlookup(caller.clone());
+ let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into();
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ // Add an initial identity
+ let initial_info = create_identity_info::<T>(1);
+ Identity::<T>::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?;
+
+ // User requests judgement from all the registrars, and they approve
+ for i in 0..r {
+ let registrar: T::AccountId = account("registrar", i, SEED);
+ let registrar_lookup = T::Lookup::unlookup(registrar.clone());
+ let balance_to_use = T::Currency::minimum_balance() * 10u32.into();
+ let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use);
+
+ Identity::<T>::request_judgement(caller_origin.clone(), i, 10u32.into())?;
+ Identity::<T>::provide_judgement(
+ RawOrigin::Signed(registrar).into(),
+ i,
+ caller_lookup.clone(),
+ Judgement::Reasonable,
+ T::Hashing::hash_of(&initial_info),
+ )?;
+ }
+ caller
+ };
+ }: _(RawOrigin::Signed(caller.clone()), Box::new(create_identity_info::<T>(x)))
+ verify {
+ assert_last_event::<T>(Event::<T>::IdentitySet { who: caller }.into());
+ }
+
+ // We need to split `set_subs` into two benchmarks to accurately isolate the potential
+ // writes caused by new or old sub accounts. The actual weight should simply be
+ // the sum of these two weights.
+ set_subs_new {
+ let caller: T::AccountId = whitelisted_caller();
+ // Create a new subs vec with s sub accounts
+ let s in 0 .. T::MaxSubAccounts::get() => ();
+ let subs = create_sub_accounts::<T>(&caller, s)?;
+ ensure!(SubsOf::<T>::get(&caller).1.len() == 0, "Caller already has subs");
+ }: set_subs(RawOrigin::Signed(caller.clone()), subs)
+ verify {
+ ensure!(SubsOf::<T>::get(&caller).1.len() as u32 == s, "Subs not added");
+ }
+
+ set_subs_old {
+ let caller: T::AccountId = whitelisted_caller();
+ // Give them p many previous sub accounts.
+ let p in 0 .. T::MaxSubAccounts::get() => {
+ let _ = add_sub_accounts::<T>(&caller, p)?;
+ };
+ // Remove all subs.
+ let subs = create_sub_accounts::<T>(&caller, 0)?;
+ ensure!(
+ SubsOf::<T>::get(&caller).1.len() as u32 == p,
+ "Caller does have subs",
+ );
+ }: set_subs(RawOrigin::Signed(caller.clone()), subs)
+ verify {
+ ensure!(SubsOf::<T>::get(&caller).1.len() == 0, "Subs not removed");
+ }
+
+ clear_identity {
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller.clone()));
+ let caller_lookup = <T::Lookup as StaticLookup>::unlookup(caller.clone());
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() => add_registrars::<T>(r)?;
+ let s in 0 .. T::MaxSubAccounts::get() => {
+ // Give them s many sub accounts
+ let caller: T::AccountId = whitelisted_caller();
+ let _ = add_sub_accounts::<T>(&caller, s)?;
+ };
+ let x in 0 .. T::MaxAdditionalFields::get();
+
+ // Create their main identity with x additional fields
+ let info = create_identity_info::<T>(x);
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller.clone()));
+ Identity::<T>::set_identity(caller_origin.clone(), Box::new(info.clone()))?;
+
+ // User requests judgement from all the registrars, and they approve
+ for i in 0..r {
+ let registrar: T::AccountId = account("registrar", i, SEED);
+ let balance_to_use = T::Currency::minimum_balance() * 10u32.into();
+ let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use);
+
+ Identity::<T>::request_judgement(caller_origin.clone(), i, 10u32.into())?;
+ Identity::<T>::provide_judgement(
+ RawOrigin::Signed(registrar).into(),
+ i,
+ caller_lookup.clone(),
+ Judgement::Reasonable,
+ T::Hashing::hash_of(&info),
+ )?;
+ }
+ ensure!(IdentityOf::<T>::contains_key(&caller), "Identity does not exist.");
+ }: _(RawOrigin::Signed(caller.clone()))
+ verify {
+ ensure!(!IdentityOf::<T>::contains_key(&caller), "Identity not cleared.");
+ }
+
+ request_judgement {
+ let caller: T::AccountId = whitelisted_caller();
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() => add_registrars::<T>(r)?;
+ let x in 0 .. T::MaxAdditionalFields::get() => {
+ // Create their main identity with x additional fields
+ let info = create_identity_info::<T>(x);
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller));
+ Identity::<T>::set_identity(caller_origin, Box::new(info))?;
+ };
+ }: _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into())
+ verify {
+ assert_last_event::<T>(Event::<T>::JudgementRequested { who: caller, registrar_index: r-1 }.into());
+ }
+
+ cancel_request {
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller.clone()));
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() => add_registrars::<T>(r)?;
+ let x in 0 .. T::MaxAdditionalFields::get() => {
+ // Create their main identity with x additional fields
+ let info = create_identity_info::<T>(x);
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller));
+ Identity::<T>::set_identity(caller_origin, Box::new(info))?;
+ };
+
+ Identity::<T>::request_judgement(caller_origin, r - 1, 10u32.into())?;
+ }: _(RawOrigin::Signed(caller.clone()), r - 1)
+ verify {
+ assert_last_event::<T>(Event::<T>::JudgementUnrequested { who: caller, registrar_index: r-1 }.into());
+ }
+
+ set_fee {
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_lookup = T::Lookup::unlookup(caller.clone());
+
+ let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::<T>(r)?;
+
+ let registrar_origin = T::RegistrarOrigin::successful_origin();
+ Identity::<T>::add_registrar(registrar_origin, caller_lookup)?;
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set.");
+ }: _(RawOrigin::Signed(caller), r, 100u32.into())
+ verify {
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().fee == 100u32.into(), "Fee not changed.");
+ }
+
+ set_account_id {
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_lookup = T::Lookup::unlookup(caller.clone());
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::<T>(r)?;
+
+ let registrar_origin = T::RegistrarOrigin::successful_origin();
+ Identity::<T>::add_registrar(registrar_origin, caller_lookup)?;
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set.");
+ let new_account = T::Lookup::unlookup(account("new", 0, SEED));
+ }: _(RawOrigin::Signed(caller), r, new_account)
+ verify {
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().account == account("new", 0, SEED), "id not changed.");
+ }
+
+ set_fields {
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_lookup = T::Lookup::unlookup(caller.clone());
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::<T>(r)?;
+
+ let registrar_origin = T::RegistrarOrigin::successful_origin();
+ Identity::<T>::add_registrar(registrar_origin, caller_lookup)?;
+ let fields = IdentityFields(
+ IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot
+ | IdentityField::Email | IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter
+ );
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().fields == Default::default(), "fields already set.");
+ }: _(RawOrigin::Signed(caller), r, fields)
+ verify {
+ let registrars = Registrars::<T>::get();
+ ensure!(registrars[r as usize].as_ref().unwrap().fields != Default::default(), "fields not set.");
+ }
+
+ provide_judgement {
+ // The user
+ let user: T::AccountId = account("user", r, SEED);
+ let user_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(user.clone()));
+ let user_lookup = <T::Lookup as StaticLookup>::unlookup(user.clone());
+ let _ = T::Currency::make_free_balance_be(&user, BalanceOf::<T>::max_value());
+
+ let caller: T::AccountId = whitelisted_caller();
+ let caller_lookup = T::Lookup::unlookup(caller.clone());
+ let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
+
+ let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::<T>(r)?;
+ let x in 0 .. T::MaxAdditionalFields::get();
+
+ let info = create_identity_info::<T>(x);
+ let info_hash = T::Hashing::hash_of(&info);
+ Identity::<T>::set_identity(user_origin.clone(), Box::new(info))?;
+
+ let registrar_origin = T::RegistrarOrigin::successful_origin();
+ Identity::<T>::add_registrar(registrar_origin, caller_lookup)?;
+ Identity::<T>::request_judgement(user_origin, r, 10u32.into())?;
+ }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash)
+ verify {
+ assert_last_event::<T>(Event::<T>::JudgementGiven { target: user, registrar_index: r }.into())
+ }
+
+ kill_identity {
+ let r in 1 .. T::MaxRegistrars::get() => add_registrars::<T>(r)?;
+ let s in 0 .. T::MaxSubAccounts::get();
+ let x in 0 .. T::MaxAdditionalFields::get();
+
+ let target: T::AccountId = account("target", 0, SEED);
+ let target_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(target.clone()).into();
+ let target_lookup = T::Lookup::unlookup(target.clone());
+ let _ = T::Currency::make_free_balance_be(&target, BalanceOf::<T>::max_value());
+
+ let info = create_identity_info::<T>(x);
+ Identity::<T>::set_identity(target_origin.clone(), Box::new(info.clone()))?;
+ let _ = add_sub_accounts::<T>(&target, s)?;
+
+ // User requests judgement from all the registrars, and they approve
+ for i in 0..r {
+ let registrar: T::AccountId = account("registrar", i, SEED);
+ let balance_to_use = T::Currency::minimum_balance() * 10u32.into();
+ let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use);
+
+ Identity::<T>::request_judgement(target_origin.clone(), i, 10u32.into())?;
+ Identity::<T>::provide_judgement(
+ RawOrigin::Signed(registrar).into(),
+ i,
+ target_lookup.clone(),
+ Judgement::Reasonable,
+ T::Hashing::hash_of(&info),
+ )?;
+ }
+ ensure!(IdentityOf::<T>::contains_key(&target), "Identity not set");
+ let origin = T::ForceOrigin::successful_origin();
+ }: _<T::RuntimeOrigin>(origin, target_lookup)
+ verify {
+ ensure!(!IdentityOf::<T>::contains_key(&target), "Identity not removed");
+ }
+
+ add_sub {
+ let s in 0 .. T::MaxSubAccounts::get() - 1;
+
+ let caller: T::AccountId = whitelisted_caller();
+ let _ = add_sub_accounts::<T>(&caller, s)?;
+ let sub = account("new_sub", 0, SEED);
+ let data = Data::Raw(vec![0; 32].try_into().unwrap());
+ ensure!(SubsOf::<T>::get(&caller).1.len() as u32 == s, "Subs not set.");
+ }: _(RawOrigin::Signed(caller.clone()), T::Lookup::unlookup(sub), data)
+ verify {
+ ensure!(SubsOf::<T>::get(&caller).1.len() as u32 == s + 1, "Subs not added.");
+ }
+
+ rename_sub {
+ let s in 1 .. T::MaxSubAccounts::get();
+
+ let caller: T::AccountId = whitelisted_caller();
+ let (sub, _) = add_sub_accounts::<T>(&caller, s)?.remove(0);
+ let data = Data::Raw(vec![1; 32].try_into().unwrap());
+ ensure!(SuperOf::<T>::get(&sub).unwrap().1 != data, "data already set");
+ }: _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone()), data.clone())
+ verify {
+ ensure!(SuperOf::<T>::get(&sub).unwrap().1 == data, "data not set");
+ }
+
+ remove_sub {
+ let s in 1 .. T::MaxSubAccounts::get();
+
+ let caller: T::AccountId = whitelisted_caller();
+ let (sub, _) = add_sub_accounts::<T>(&caller, s)?.remove(0);
+ ensure!(SuperOf::<T>::contains_key(&sub), "Sub doesn't exists");
+ }: _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone()))
+ verify {
+ ensure!(!SuperOf::<T>::contains_key(&sub), "Sub not removed");
+ }
+
+ quit_sub {
+ let s in 0 .. T::MaxSubAccounts::get() - 1;
+
+ let caller: T::AccountId = whitelisted_caller();
+ let sup = account("super", 0, SEED);
+ let _ = add_sub_accounts::<T>(&sup, s)?;
+ let sup_origin = RawOrigin::Signed(sup).into();
+ Identity::<T>::add_sub(sup_origin, T::Lookup::unlookup(caller.clone()), Data::Raw(vec![0; 32].try_into().unwrap()))?;
+ ensure!(SuperOf::<T>::contains_key(&caller), "Sub doesn't exists");
+ }: _(RawOrigin::Signed(caller.clone()))
+ verify {
+ ensure!(!SuperOf::<T>::contains_key(&caller), "Sub not removed");
+ }
+
+ impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test);
+}
pallets/identity/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/src/lib.rs
@@ -0,0 +1,1030 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// Original license:
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! # Identity Pallet
+//!
+//! - [`Config`]
+//! - [`Call`]
+//!
+//! ## Overview
+//!
+//! A federated naming system, allowing for multiple registrars to be added from a specified origin.
+//! Registrars can set a fee to provide identity-verification service. Anyone can put forth a
+//! proposed identity for a fixed deposit and ask for review by any number of registrars (paying
+//! each of their fees). Registrar judgements are given as an `enum`, allowing for sophisticated,
+//! multi-tier opinions.
+//!
+//! Some judgements are identified as *sticky*, which means they cannot be removed except by
+//! complete removal of the identity, or by the registrar. Judgements are allowed to represent a
+//! portion of funds that have been reserved for the registrar.
+//!
+//! A super-user can remove accounts and in doing so, slash the deposit.
+//!
+//! All accounts may also have a limited number of sub-accounts which may be specified by the owner;
+//! by definition, these have equivalent ownership and each has an individual name.
+//!
+//! The number of registrars should be limited, and the deposit made sufficiently large, to ensure
+//! no state-bloat attack is viable.
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+//! #### For general users
+//! * `set_identity` - Set the associated identity of an account; a small deposit is reserved if not
+//! already taken.
+//! * `clear_identity` - Remove an account's associated identity; the deposit is returned.
+//! * `request_judgement` - Request a judgement from a registrar, paying a fee.
+//! * `cancel_request` - Cancel the previous request for a judgement.
+//!
+//! #### For general users with sub-identities
+//! * `set_subs` - Set the sub-accounts of an identity.
+//! * `add_sub` - Add a sub-identity to an identity.
+//! * `remove_sub` - Remove a sub-identity of an identity.
+//! * `rename_sub` - Rename a sub-identity of an identity.
+//! * `quit_sub` - Remove a sub-identity of an identity (called by the sub-identity).
+//!
+//! #### For registrars
+//! * `set_fee` - Set the fee required to be paid for a judgement to be given by the registrar.
+//! * `set_fields` - Set the fields that a registrar cares about in their judgements.
+//! * `provide_judgement` - Provide a judgement to an identity.
+//!
+//! #### For super-users
+//! * `add_registrar` - Add a new registrar to the system.
+//! * `kill_identity` - Forcibly remove the associated identity; the deposit is lost.
+//!
+//! [`Call`]: ./enum.Call.html
+//! [`Config`]: ./trait.Config.html
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+mod benchmarking;
+#[cfg(test)]
+mod tests;
+mod types;
+pub mod weights;
+
+use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency};
+use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero};
+use sp_std::prelude::*;
+pub use weights::WeightInfo;
+
+pub use pallet::*;
+pub use types::{
+ Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo,
+ Registration,
+};
+
+pub type BalanceOf<T> =
+ <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
+type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
+ <T as frame_system::Config>::AccountId,
+>>::NegativeImbalance;
+type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
+
+#[frame_support::pallet]
+pub mod pallet {
+ use super::*;
+ use frame_support::pallet_prelude::*;
+ use frame_system::pallet_prelude::*;
+
+ #[pallet::config]
+ pub trait Config: frame_system::Config {
+ /// The overarching event type.
+ type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+ /// The currency trait.
+ type Currency: ReservableCurrency<Self::AccountId>;
+
+ /// The amount held on deposit for a registered identity
+ #[pallet::constant]
+ type BasicDeposit: Get<BalanceOf<Self>>;
+
+ /// The amount held on deposit per additional field for a registered identity.
+ #[pallet::constant]
+ type FieldDeposit: Get<BalanceOf<Self>>;
+
+ /// The amount held on deposit for a registered subaccount. This should account for the fact
+ /// that one storage item's value will increase by the size of an account ID, and there will
+ /// be another trie item whose value is the size of an account ID plus 32 bytes.
+ #[pallet::constant]
+ type SubAccountDeposit: Get<BalanceOf<Self>>;
+
+ /// The maximum number of sub-accounts allowed per identified account.
+ #[pallet::constant]
+ type MaxSubAccounts: Get<u32>;
+
+ /// Maximum number of additional fields that may be stored in an ID. Needed to bound the I/O
+ /// required to access an identity, but can be pretty high.
+ #[pallet::constant]
+ type MaxAdditionalFields: Get<u32>;
+
+ /// Maxmimum number of registrars allowed in the system. Needed to bound the complexity
+ /// of, e.g., updating judgements.
+ #[pallet::constant]
+ type MaxRegistrars: Get<u32>;
+
+ /// What to do with slashed funds.
+ type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;
+
+ /// The origin which may forcibly set or remove a name. Root can always do this.
+ type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
+
+ /// The origin which may add or remove registrars. Root can always do this.
+ type RegistrarOrigin: EnsureOrigin<Self::RuntimeOrigin>;
+
+ /// Weight information for extrinsics in this pallet.
+ type WeightInfo: WeightInfo;
+ }
+
+ #[pallet::pallet]
+ #[pallet::generate_store(pub(super) trait Store)]
+ pub struct Pallet<T>(_);
+
+ /// Information that is pertinent to identify the entity behind an account.
+ ///
+ /// TWOX-NOTE: OK ― `AccountId` is a secure hash.
+ #[pallet::storage]
+ #[pallet::getter(fn identity)]
+ pub type IdentityOf<T: Config> = StorageMap<
+ _,
+ Twox64Concat,
+ T::AccountId,
+ Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,
+ OptionQuery,
+ >;
+
+ /// The super-identity of an alternative "sub" identity together with its name, within that
+ /// context. If the account is not some other account's sub-identity, then just `None`.
+ #[pallet::storage]
+ #[pallet::getter(fn super_of)]
+ pub(super) type SuperOf<T: Config> =
+ StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>;
+
+ /// Alternative "sub" identities of this account.
+ ///
+ /// The first item is the deposit, the second is a vector of the accounts.
+ ///
+ /// TWOX-NOTE: OK ― `AccountId` is a secure hash.
+ #[pallet::storage]
+ #[pallet::getter(fn subs_of)]
+ pub(super) type SubsOf<T: Config> = StorageMap<
+ _,
+ Twox64Concat,
+ T::AccountId,
+ (BalanceOf<T>, BoundedVec<T::AccountId, T::MaxSubAccounts>),
+ ValueQuery,
+ >;
+
+ /// The set of registrars. Not expected to get very big as can only be added through a
+ /// special origin (likely a council motion).
+ ///
+ /// The index into this can be cast to `RegistrarIndex` to get a valid value.
+ #[pallet::storage]
+ #[pallet::getter(fn registrars)]
+ pub(super) type Registrars<T: Config> = StorageValue<
+ _,
+ BoundedVec<Option<RegistrarInfo<BalanceOf<T>, T::AccountId>>, T::MaxRegistrars>,
+ ValueQuery,
+ >;
+
+ #[pallet::error]
+ pub enum Error<T> {
+ /// Too many subs-accounts.
+ TooManySubAccounts,
+ /// Account isn't found.
+ NotFound,
+ /// Account isn't named.
+ NotNamed,
+ /// Empty index.
+ EmptyIndex,
+ /// Fee is changed.
+ FeeChanged,
+ /// No identity found.
+ NoIdentity,
+ /// Sticky judgement.
+ StickyJudgement,
+ /// Judgement given.
+ JudgementGiven,
+ /// Invalid judgement.
+ InvalidJudgement,
+ /// The index is invalid.
+ InvalidIndex,
+ /// The target is invalid.
+ InvalidTarget,
+ /// Too many additional fields.
+ TooManyFields,
+ /// Maximum amount of registrars reached. Cannot add any more.
+ TooManyRegistrars,
+ /// Account ID is already named.
+ AlreadyClaimed,
+ /// Sender is not a sub-account.
+ NotSub,
+ /// Sub-account isn't owned by sender.
+ NotOwned,
+ /// The provided judgement was for a different identity.
+ JudgementForDifferentIdentity,
+ /// Error that occurs when there is an issue paying for judgement.
+ JudgementPaymentFailed,
+ }
+
+ #[pallet::event]
+ #[pallet::generate_deposit(pub(super) fn deposit_event)]
+ pub enum Event<T: Config> {
+ /// A name was set or reset (which will remove all judgements).
+ IdentitySet { who: T::AccountId },
+ /// A name was cleared, and the given balance returned.
+ IdentityCleared { who: T::AccountId, deposit: BalanceOf<T> },
+ /// A name was removed and the given balance slashed.
+ IdentityKilled { who: T::AccountId, deposit: BalanceOf<T> },
+ /// A judgement was asked from a registrar.
+ JudgementRequested { who: T::AccountId, registrar_index: RegistrarIndex },
+ /// A judgement request was retracted.
+ JudgementUnrequested { who: T::AccountId, registrar_index: RegistrarIndex },
+ /// A judgement was given by a registrar.
+ JudgementGiven { target: T::AccountId, registrar_index: RegistrarIndex },
+ /// A registrar was added.
+ RegistrarAdded { registrar_index: RegistrarIndex },
+ /// A sub-identity was added to an identity and the deposit paid.
+ SubIdentityAdded { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf<T> },
+ /// A sub-identity was removed from an identity and the deposit freed.
+ SubIdentityRemoved { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf<T> },
+ /// A sub-identity was cleared, and the given deposit repatriated from the
+ /// main identity account to the sub-identity account.
+ SubIdentityRevoked { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf<T> },
+ }
+
+ #[pallet::call]
+ /// Identity pallet declaration.
+ impl<T: Config> Pallet<T> {
+ /// Add a registrar to the system.
+ ///
+ /// The dispatch origin for this call must be `T::RegistrarOrigin`.
+ ///
+ /// - `account`: the account of the registrar.
+ ///
+ /// Emits `RegistrarAdded` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R)` where `R` registrar-count (governance-bounded and code-bounded).
+ /// - One storage mutation (codec `O(R)`).
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(0)]
+ #[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]
+ pub fn add_registrar(
+ origin: OriginFor<T>,
+ account: AccountIdLookupOf<T>,
+ ) -> DispatchResultWithPostInfo {
+ T::RegistrarOrigin::ensure_origin(origin)?;
+ let account = T::Lookup::lookup(account)?;
+
+ let (i, registrar_count) = <Registrars<T>>::try_mutate(
+ |registrars| -> Result<(RegistrarIndex, usize), DispatchError> {
+ registrars
+ .try_push(Some(RegistrarInfo {
+ account,
+ fee: Zero::zero(),
+ fields: Default::default(),
+ }))
+ .map_err(|_| Error::<T>::TooManyRegistrars)?;
+ Ok(((registrars.len() - 1) as RegistrarIndex, registrars.len()))
+ },
+ )?;
+
+ Self::deposit_event(Event::RegistrarAdded { registrar_index: i });
+
+ Ok(Some(T::WeightInfo::add_registrar(registrar_count as u32)).into())
+ }
+
+ /// Set an account's identity information and reserve the appropriate deposit.
+ ///
+ /// If the account already has identity information, the deposit is taken as part payment
+ /// for the new deposit.
+ ///
+ /// The dispatch origin for this call must be _Signed_.
+ ///
+ /// - `info`: The identity information.
+ ///
+ /// Emits `IdentitySet` if successful.
+ ///
+ /// # <weight>
+ /// - `O(X + X' + R)`
+ /// - where `X` additional-field-count (deposit-bounded and code-bounded)
+ /// - where `R` judgements-count (registrar-count-bounded)
+ /// - One balance reserve operation.
+ /// - One storage mutation (codec-read `O(X' + R)`, codec-write `O(X + R)`).
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(1)]
+ #[pallet::weight( T::WeightInfo::set_identity(
+ T::MaxRegistrars::get(), // R
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn set_identity(
+ origin: OriginFor<T>,
+ info: Box<IdentityInfo<T::MaxAdditionalFields>>,
+ ) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+ let extra_fields = info.additional.len() as u32;
+ ensure!(extra_fields <= T::MaxAdditionalFields::get(), Error::<T>::TooManyFields);
+ let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();
+
+ let mut id = match <IdentityOf<T>>::get(&sender) {
+ Some(mut id) => {
+ // Only keep non-positive judgements.
+ id.judgements.retain(|j| j.1.is_sticky());
+ id.info = *info;
+ id
+ },
+ None => Registration {
+ info: *info,
+ judgements: BoundedVec::default(),
+ deposit: Zero::zero(),
+ },
+ };
+
+ let old_deposit = id.deposit;
+ id.deposit = T::BasicDeposit::get() + fd;
+ if id.deposit > old_deposit {
+ T::Currency::reserve(&sender, id.deposit - old_deposit)?;
+ }
+ if old_deposit > id.deposit {
+ let err_amount = T::Currency::unreserve(&sender, old_deposit - id.deposit);
+ debug_assert!(err_amount.is_zero());
+ }
+
+ let judgements = id.judgements.len();
+ <IdentityOf<T>>::insert(&sender, id);
+ Self::deposit_event(Event::IdentitySet { who: sender });
+
+ Ok(Some(T::WeightInfo::set_identity(
+ judgements as u32, // R
+ extra_fields, // X
+ ))
+ .into())
+ }
+
+ /// Set the sub-accounts of the sender.
+ ///
+ /// Payment: Any aggregate balance reserved by previous `set_subs` calls will be returned
+ /// and an amount `SubAccountDeposit` will be reserved for each item in `subs`.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// identity.
+ ///
+ /// - `subs`: The identity's (new) sub-accounts.
+ ///
+ /// # <weight>
+ /// - `O(P + S)`
+ /// - where `P` old-subs-count (hard- and deposit-bounded).
+ /// - where `S` subs-count (hard- and deposit-bounded).
+ /// - At most one balance operations.
+ /// - DB:
+ /// - `P + S` storage mutations (codec complexity `O(1)`)
+ /// - One storage read (codec complexity `O(P)`).
+ /// - One storage write (codec complexity `O(S)`).
+ /// - One storage-exists (`IdentityOf::contains_key`).
+ /// # </weight>
+ // TODO: This whole extrinsic screams "not optimized". For example we could
+ // filter any overlap between new and old subs, and avoid reading/writing
+ // to those values... We could also ideally avoid needing to write to
+ // N storage items for N sub accounts. Right now the weight on this function
+ // is a large overestimate due to the fact that it could potentially write
+ // to 2 x T::MaxSubAccounts::get().
+ #[pallet::call_index(2)]
+ #[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get()) // P: Assume max sub accounts removed.
+ .saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32)) // S: Assume all subs are new.
+ )]
+ pub fn set_subs(
+ origin: OriginFor<T>,
+ subs: Vec<(T::AccountId, Data)>,
+ ) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+ ensure!(<IdentityOf<T>>::contains_key(&sender), Error::<T>::NotFound);
+ ensure!(
+ subs.len() <= T::MaxSubAccounts::get() as usize,
+ Error::<T>::TooManySubAccounts
+ );
+
+ let (old_deposit, old_ids) = <SubsOf<T>>::get(&sender);
+ let new_deposit = T::SubAccountDeposit::get() * <BalanceOf<T>>::from(subs.len() as u32);
+
+ let not_other_sub =
+ subs.iter().filter_map(|i| SuperOf::<T>::get(&i.0)).all(|i| i.0 == sender);
+ ensure!(not_other_sub, Error::<T>::AlreadyClaimed);
+
+ if old_deposit < new_deposit {
+ T::Currency::reserve(&sender, new_deposit - old_deposit)?;
+ } else if old_deposit > new_deposit {
+ let err_amount = T::Currency::unreserve(&sender, old_deposit - new_deposit);
+ debug_assert!(err_amount.is_zero());
+ }
+ // do nothing if they're equal.
+
+ for s in old_ids.iter() {
+ <SuperOf<T>>::remove(s);
+ }
+ let mut ids = BoundedVec::<T::AccountId, T::MaxSubAccounts>::default();
+ for (id, name) in subs {
+ <SuperOf<T>>::insert(&id, (sender.clone(), name));
+ ids.try_push(id).expect("subs length is less than T::MaxSubAccounts; qed");
+ }
+ let new_subs = ids.len();
+
+ if ids.is_empty() {
+ <SubsOf<T>>::remove(&sender);
+ } else {
+ <SubsOf<T>>::insert(&sender, (new_deposit, ids));
+ }
+
+ Ok(Some(
+ T::WeightInfo::set_subs_old(old_ids.len() as u32) // P: Real number of old accounts removed.
+ // S: New subs added
+ .saturating_add(T::WeightInfo::set_subs_new(new_subs as u32)),
+ )
+ .into())
+ }
+
+ /// Clear an account's identity info and all sub-accounts and return all deposits.
+ ///
+ /// Payment: All reserved balances on the account are returned.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// identity.
+ ///
+ /// Emits `IdentityCleared` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R + S + X)`
+ /// - where `R` registrar-count (governance-bounded).
+ /// - where `S` subs-count (hard- and deposit-bounded).
+ /// - where `X` additional-field-count (deposit-bounded and code-bounded).
+ /// - One balance-unreserve operation.
+ /// - `2` storage reads and `S + 2` storage deletions.
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(3)]
+ #[pallet::weight(T::WeightInfo::clear_identity(
+ T::MaxRegistrars::get(), // R
+ T::MaxSubAccounts::get(), // S
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+
+ let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&sender);
+ let id = <IdentityOf<T>>::take(&sender).ok_or(Error::<T>::NotNamed)?;
+ let deposit = id.total_deposit() + subs_deposit;
+ for sub in sub_ids.iter() {
+ <SuperOf<T>>::remove(sub);
+ }
+
+ let err_amount = T::Currency::unreserve(&sender, deposit);
+ debug_assert!(err_amount.is_zero());
+
+ Self::deposit_event(Event::IdentityCleared { who: sender, deposit });
+
+ Ok(Some(T::WeightInfo::clear_identity(
+ id.judgements.len() as u32, // R
+ sub_ids.len() as u32, // S
+ id.info.additional.len() as u32, // X
+ ))
+ .into())
+ }
+
+ /// Request a judgement from a registrar.
+ ///
+ /// Payment: At most `max_fee` will be reserved for payment to the registrar if judgement
+ /// given.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a
+ /// registered identity.
+ ///
+ /// - `reg_index`: The index of the registrar whose judgement is requested.
+ /// - `max_fee`: The maximum fee that may be paid. This should just be auto-populated as:
+ ///
+ /// ```nocompile
+ /// Self::registrars().get(reg_index).unwrap().fee
+ /// ```
+ ///
+ /// Emits `JudgementRequested` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R + X)`.
+ /// - One balance-reserve operation.
+ /// - Storage: 1 read `O(R)`, 1 mutate `O(X + R)`.
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(4)]
+ #[pallet::weight(T::WeightInfo::request_judgement(
+ T::MaxRegistrars::get(), // R
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn request_judgement(
+ origin: OriginFor<T>,
+ #[pallet::compact] reg_index: RegistrarIndex,
+ #[pallet::compact] max_fee: BalanceOf<T>,
+ ) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+ let registrars = <Registrars<T>>::get();
+ let registrar = registrars
+ .get(reg_index as usize)
+ .and_then(Option::as_ref)
+ .ok_or(Error::<T>::EmptyIndex)?;
+ ensure!(max_fee >= registrar.fee, Error::<T>::FeeChanged);
+ let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;
+
+ let item = (reg_index, Judgement::FeePaid(registrar.fee));
+ match id.judgements.binary_search_by_key(®_index, |x| x.0) {
+ Ok(i) =>
+ if id.judgements[i].1.is_sticky() {
+ return Err(Error::<T>::StickyJudgement.into())
+ } else {
+ id.judgements[i] = item
+ },
+ Err(i) =>
+ id.judgements.try_insert(i, item).map_err(|_| Error::<T>::TooManyRegistrars)?,
+ }
+
+ T::Currency::reserve(&sender, registrar.fee)?;
+
+ let judgements = id.judgements.len();
+ let extra_fields = id.info.additional.len();
+ <IdentityOf<T>>::insert(&sender, id);
+
+ Self::deposit_event(Event::JudgementRequested {
+ who: sender,
+ registrar_index: reg_index,
+ });
+
+ Ok(Some(T::WeightInfo::request_judgement(judgements as u32, extra_fields as u32))
+ .into())
+ }
+
+ /// Cancel a previous request.
+ ///
+ /// Payment: A previously reserved deposit is returned on success.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a
+ /// registered identity.
+ ///
+ /// - `reg_index`: The index of the registrar whose judgement is no longer requested.
+ ///
+ /// Emits `JudgementUnrequested` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R + X)`.
+ /// - One balance-reserve operation.
+ /// - One storage mutation `O(R + X)`.
+ /// - One event
+ /// # </weight>
+ #[pallet::call_index(5)]
+ #[pallet::weight(T::WeightInfo::cancel_request(
+ T::MaxRegistrars::get(), // R
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn cancel_request(
+ origin: OriginFor<T>,
+ reg_index: RegistrarIndex,
+ ) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+ let mut id = <IdentityOf<T>>::get(&sender).ok_or(Error::<T>::NoIdentity)?;
+
+ let pos = id
+ .judgements
+ .binary_search_by_key(®_index, |x| x.0)
+ .map_err(|_| Error::<T>::NotFound)?;
+ let fee = if let Judgement::FeePaid(fee) = id.judgements.remove(pos).1 {
+ fee
+ } else {
+ return Err(Error::<T>::JudgementGiven.into())
+ };
+
+ let err_amount = T::Currency::unreserve(&sender, fee);
+ debug_assert!(err_amount.is_zero());
+ let judgements = id.judgements.len();
+ let extra_fields = id.info.additional.len();
+ <IdentityOf<T>>::insert(&sender, id);
+
+ Self::deposit_event(Event::JudgementUnrequested {
+ who: sender,
+ registrar_index: reg_index,
+ });
+
+ Ok(Some(T::WeightInfo::cancel_request(judgements as u32, extra_fields as u32)).into())
+ }
+
+ /// Set the fee required for a judgement to be requested from a registrar.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must be the account
+ /// of the registrar whose index is `index`.
+ ///
+ /// - `index`: the index of the registrar whose fee is to be set.
+ /// - `fee`: the new fee.
+ ///
+ /// # <weight>
+ /// - `O(R)`.
+ /// - One storage mutation `O(R)`.
+ /// - Benchmark: 7.315 + R * 0.329 µs (min squares analysis)
+ /// # </weight>
+ #[pallet::call_index(6)]
+ #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] // R
+ pub fn set_fee(
+ origin: OriginFor<T>,
+ #[pallet::compact] index: RegistrarIndex,
+ #[pallet::compact] fee: BalanceOf<T>,
+ ) -> DispatchResultWithPostInfo {
+ let who = ensure_signed(origin)?;
+
+ let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {
+ rs.get_mut(index as usize)
+ .and_then(|x| x.as_mut())
+ .and_then(|r| {
+ if r.account == who {
+ r.fee = fee;
+ Some(())
+ } else {
+ None
+ }
+ })
+ .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
+ Ok(rs.len())
+ })?;
+ Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) // R
+ }
+
+ /// Change the account associated with a registrar.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must be the account
+ /// of the registrar whose index is `index`.
+ ///
+ /// - `index`: the index of the registrar whose fee is to be set.
+ /// - `new`: the new account ID.
+ ///
+ /// # <weight>
+ /// - `O(R)`.
+ /// - One storage mutation `O(R)`.
+ /// - Benchmark: 8.823 + R * 0.32 µs (min squares analysis)
+ /// # </weight>
+ #[pallet::call_index(7)]
+ #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] // R
+ pub fn set_account_id(
+ origin: OriginFor<T>,
+ #[pallet::compact] index: RegistrarIndex,
+ new: AccountIdLookupOf<T>,
+ ) -> DispatchResultWithPostInfo {
+ let who = ensure_signed(origin)?;
+ let new = T::Lookup::lookup(new)?;
+
+ let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {
+ rs.get_mut(index as usize)
+ .and_then(|x| x.as_mut())
+ .and_then(|r| {
+ if r.account == who {
+ r.account = new;
+ Some(())
+ } else {
+ None
+ }
+ })
+ .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
+ Ok(rs.len())
+ })?;
+ Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) // R
+ }
+
+ /// Set the field information for a registrar.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must be the account
+ /// of the registrar whose index is `index`.
+ ///
+ /// - `index`: the index of the registrar whose fee is to be set.
+ /// - `fields`: the fields that the registrar concerns themselves with.
+ ///
+ /// # <weight>
+ /// - `O(R)`.
+ /// - One storage mutation `O(R)`.
+ /// - Benchmark: 7.464 + R * 0.325 µs (min squares analysis)
+ /// # </weight>
+ #[pallet::call_index(8)]
+ #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] // R
+ pub fn set_fields(
+ origin: OriginFor<T>,
+ #[pallet::compact] index: RegistrarIndex,
+ fields: IdentityFields,
+ ) -> DispatchResultWithPostInfo {
+ let who = ensure_signed(origin)?;
+
+ let registrars = <Registrars<T>>::mutate(|rs| -> Result<usize, DispatchError> {
+ rs.get_mut(index as usize)
+ .and_then(|x| x.as_mut())
+ .and_then(|r| {
+ if r.account == who {
+ r.fields = fields;
+ Some(())
+ } else {
+ None
+ }
+ })
+ .ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
+ Ok(rs.len())
+ })?;
+ Ok(Some(T::WeightInfo::set_fields(
+ registrars as u32, // R
+ ))
+ .into())
+ }
+
+ /// Provide a judgement for an account's identity.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must be the account
+ /// of the registrar whose index is `reg_index`.
+ ///
+ /// - `reg_index`: the index of the registrar whose judgement is being made.
+ /// - `target`: the account whose identity the judgement is upon. This must be an account
+ /// with a registered identity.
+ /// - `judgement`: the judgement of the registrar of index `reg_index` about `target`.
+ /// - `identity`: The hash of the [`IdentityInfo`] for that the judgement is provided.
+ ///
+ /// Emits `JudgementGiven` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R + X)`.
+ /// - One balance-transfer operation.
+ /// - Up to one account-lookup operation.
+ /// - Storage: 1 read `O(R)`, 1 mutate `O(R + X)`.
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(9)]
+ #[pallet::weight(T::WeightInfo::provide_judgement(
+ T::MaxRegistrars::get(), // R
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn provide_judgement(
+ origin: OriginFor<T>,
+ #[pallet::compact] reg_index: RegistrarIndex,
+ target: AccountIdLookupOf<T>,
+ judgement: Judgement<BalanceOf<T>>,
+ identity: T::Hash,
+ ) -> DispatchResultWithPostInfo {
+ let sender = ensure_signed(origin)?;
+ let target = T::Lookup::lookup(target)?;
+ ensure!(!judgement.has_deposit(), Error::<T>::InvalidJudgement);
+ <Registrars<T>>::get()
+ .get(reg_index as usize)
+ .and_then(Option::as_ref)
+ .filter(|r| r.account == sender)
+ .ok_or(Error::<T>::InvalidIndex)?;
+ let mut id = <IdentityOf<T>>::get(&target).ok_or(Error::<T>::InvalidTarget)?;
+
+ if T::Hashing::hash_of(&id.info) != identity {
+ return Err(Error::<T>::JudgementForDifferentIdentity.into())
+ }
+
+ let item = (reg_index, judgement);
+ match id.judgements.binary_search_by_key(®_index, |x| x.0) {
+ Ok(position) => {
+ if let Judgement::FeePaid(fee) = id.judgements[position].1 {
+ T::Currency::repatriate_reserved(
+ &target,
+ &sender,
+ fee,
+ BalanceStatus::Free,
+ )
+ .map_err(|_| Error::<T>::JudgementPaymentFailed)?;
+ }
+ id.judgements[position] = item
+ },
+ Err(position) => id
+ .judgements
+ .try_insert(position, item)
+ .map_err(|_| Error::<T>::TooManyRegistrars)?,
+ }
+
+ let judgements = id.judgements.len();
+ let extra_fields = id.info.additional.len();
+ <IdentityOf<T>>::insert(&target, id);
+ Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index });
+
+ Ok(Some(T::WeightInfo::provide_judgement(judgements as u32, extra_fields as u32))
+ .into())
+ }
+
+ /// Remove an account's identity and sub-account information and slash the deposits.
+ ///
+ /// Payment: Reserved balances from `set_subs` and `set_identity` are slashed and handled by
+ /// `Slash`. Verification request deposits are not returned; they should be cancelled
+ /// manually using `cancel_request`.
+ ///
+ /// The dispatch origin for this call must match `T::ForceOrigin`.
+ ///
+ /// - `target`: the account whose identity the judgement is upon. This must be an account
+ /// with a registered identity.
+ ///
+ /// Emits `IdentityKilled` if successful.
+ ///
+ /// # <weight>
+ /// - `O(R + S + X)`.
+ /// - One balance-reserve operation.
+ /// - `S + 2` storage mutations.
+ /// - One event.
+ /// # </weight>
+ #[pallet::call_index(10)]
+ #[pallet::weight(T::WeightInfo::kill_identity(
+ T::MaxRegistrars::get(), // R
+ T::MaxSubAccounts::get(), // S
+ T::MaxAdditionalFields::get(), // X
+ ))]
+ pub fn kill_identity(
+ origin: OriginFor<T>,
+ target: AccountIdLookupOf<T>,
+ ) -> DispatchResultWithPostInfo {
+ T::ForceOrigin::ensure_origin(origin)?;
+
+ // Figure out who we're meant to be clearing.
+ let target = T::Lookup::lookup(target)?;
+ // Grab their deposit (and check that they have one).
+ let (subs_deposit, sub_ids) = <SubsOf<T>>::take(&target);
+ let id = <IdentityOf<T>>::take(&target).ok_or(Error::<T>::NotNamed)?;
+ let deposit = id.total_deposit() + subs_deposit;
+ for sub in sub_ids.iter() {
+ <SuperOf<T>>::remove(sub);
+ }
+ // Slash their deposit from them.
+ T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0);
+
+ Self::deposit_event(Event::IdentityKilled { who: target, deposit });
+
+ Ok(Some(T::WeightInfo::kill_identity(
+ id.judgements.len() as u32, // R
+ sub_ids.len() as u32, // S
+ id.info.additional.len() as u32, // X
+ ))
+ .into())
+ }
+
+ /// Add the given account to the sender's subs.
+ ///
+ /// Payment: Balance reserved by a previous `set_subs` call for one sub will be repatriated
+ /// to the sender.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// sub identity of `sub`.
+ #[pallet::call_index(11)]
+ #[pallet::weight(T::WeightInfo::add_sub(T::MaxSubAccounts::get()))]
+ pub fn add_sub(
+ origin: OriginFor<T>,
+ sub: AccountIdLookupOf<T>,
+ data: Data,
+ ) -> DispatchResult {
+ let sender = ensure_signed(origin)?;
+ let sub = T::Lookup::lookup(sub)?;
+ ensure!(IdentityOf::<T>::contains_key(&sender), Error::<T>::NoIdentity);
+
+ // Check if it's already claimed as sub-identity.
+ ensure!(!SuperOf::<T>::contains_key(&sub), Error::<T>::AlreadyClaimed);
+
+ SubsOf::<T>::try_mutate(&sender, |(ref mut subs_deposit, ref mut sub_ids)| {
+ // Ensure there is space and that the deposit is paid.
+ ensure!(
+ sub_ids.len() < T::MaxSubAccounts::get() as usize,
+ Error::<T>::TooManySubAccounts
+ );
+ let deposit = T::SubAccountDeposit::get();
+ T::Currency::reserve(&sender, deposit)?;
+
+ SuperOf::<T>::insert(&sub, (sender.clone(), data));
+ sub_ids.try_push(sub.clone()).expect("sub ids length checked above; qed");
+ *subs_deposit = subs_deposit.saturating_add(deposit);
+
+ Self::deposit_event(Event::SubIdentityAdded { sub, main: sender.clone(), deposit });
+ Ok(())
+ })
+ }
+
+ /// Alter the associated name of the given sub-account.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// sub identity of `sub`.
+ #[pallet::call_index(12)]
+ #[pallet::weight(T::WeightInfo::rename_sub(T::MaxSubAccounts::get()))]
+ pub fn rename_sub(
+ origin: OriginFor<T>,
+ sub: AccountIdLookupOf<T>,
+ data: Data,
+ ) -> DispatchResult {
+ let sender = ensure_signed(origin)?;
+ let sub = T::Lookup::lookup(sub)?;
+ ensure!(IdentityOf::<T>::contains_key(&sender), Error::<T>::NoIdentity);
+ ensure!(SuperOf::<T>::get(&sub).map_or(false, |x| x.0 == sender), Error::<T>::NotOwned);
+ SuperOf::<T>::insert(&sub, (sender, data));
+ Ok(())
+ }
+
+ /// Remove the given account from the sender's subs.
+ ///
+ /// Payment: Balance reserved by a previous `set_subs` call for one sub will be repatriated
+ /// to the sender.
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// sub identity of `sub`.
+ #[pallet::call_index(13)]
+ #[pallet::weight(T::WeightInfo::remove_sub(T::MaxSubAccounts::get()))]
+ pub fn remove_sub(origin: OriginFor<T>, sub: AccountIdLookupOf<T>) -> DispatchResult {
+ let sender = ensure_signed(origin)?;
+ ensure!(IdentityOf::<T>::contains_key(&sender), Error::<T>::NoIdentity);
+ let sub = T::Lookup::lookup(sub)?;
+ let (sup, _) = SuperOf::<T>::get(&sub).ok_or(Error::<T>::NotSub)?;
+ ensure!(sup == sender, Error::<T>::NotOwned);
+ SuperOf::<T>::remove(&sub);
+ SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {
+ sub_ids.retain(|x| x != &sub);
+ let deposit = T::SubAccountDeposit::get().min(*subs_deposit);
+ *subs_deposit -= deposit;
+ let err_amount = T::Currency::unreserve(&sender, deposit);
+ debug_assert!(err_amount.is_zero());
+ Self::deposit_event(Event::SubIdentityRemoved { sub, main: sender, deposit });
+ });
+ Ok(())
+ }
+
+ /// Remove the sender as a sub-account.
+ ///
+ /// Payment: Balance reserved by a previous `set_subs` call for one sub will be repatriated
+ /// to the sender (*not* the original depositor).
+ ///
+ /// The dispatch origin for this call must be _Signed_ and the sender must have a registered
+ /// super-identity.
+ ///
+ /// NOTE: This should not normally be used, but is provided in the case that the non-
+ /// controller of an account is maliciously registered as a sub-account.
+ #[pallet::call_index(14)]
+ #[pallet::weight(T::WeightInfo::quit_sub(T::MaxSubAccounts::get()))]
+ pub fn quit_sub(origin: OriginFor<T>) -> DispatchResult {
+ let sender = ensure_signed(origin)?;
+ let (sup, _) = SuperOf::<T>::take(&sender).ok_or(Error::<T>::NotSub)?;
+ SubsOf::<T>::mutate(&sup, |(ref mut subs_deposit, ref mut sub_ids)| {
+ sub_ids.retain(|x| x != &sender);
+ let deposit = T::SubAccountDeposit::get().min(*subs_deposit);
+ *subs_deposit -= deposit;
+ let _ =
+ T::Currency::repatriate_reserved(&sup, &sender, deposit, BalanceStatus::Free);
+ Self::deposit_event(Event::SubIdentityRevoked {
+ sub: sender,
+ main: sup.clone(),
+ deposit,
+ });
+ });
+ Ok(())
+ }
+ }
+}
+
+impl<T: Config> Pallet<T> {
+ /// Get the subs of an account.
+ pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {
+ SubsOf::<T>::get(who)
+ .1
+ .into_iter()
+ .filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))
+ .collect()
+ }
+
+ /// Check if the account has corresponding identity information by the identity field.
+ pub fn has_identity(who: &T::AccountId, fields: u64) -> bool {
+ IdentityOf::<T>::get(who)
+ .map_or(false, |registration| (registration.info.fields().0.bits() & fields) == fields)
+ }
+}
pallets/identity/src/tests.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/src/tests.rs
@@ -0,0 +1,643 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// Original license:
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Tests for Identity Pallet
+
+use super::*;
+use crate as pallet_identity;
+
+use codec::{Decode, Encode};
+use frame_support::{
+ assert_noop, assert_ok, ord_parameter_types, parameter_types,
+ traits::{ConstU32, ConstU64, EitherOfDiverse},
+ BoundedVec,
+};
+use frame_system::{EnsureRoot, EnsureSignedBy};
+use sp_core::H256;
+use sp_runtime::{
+ testing::Header,
+ traits::{BadOrigin, BlakeTwo256, IdentityLookup},
+};
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
+type Block = frame_system::mocking::MockBlock<Test>;
+
+frame_support::construct_runtime!(
+ pub enum Test where
+ Block = Block,
+ NodeBlock = Block,
+ UncheckedExtrinsic = UncheckedExtrinsic,
+ {
+ System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+ Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
+ Identity: pallet_identity::{Pallet, Call, Storage, Event<T>},
+ }
+);
+
+parameter_types! {
+ pub BlockWeights: frame_system::limits::BlockWeights =
+ frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024));
+}
+impl frame_system::Config for Test {
+ type BaseCallFilter = frame_support::traits::Everything;
+ type BlockWeights = ();
+ type BlockLength = ();
+ type RuntimeOrigin = RuntimeOrigin;
+ type Index = u64;
+ type BlockNumber = u64;
+ type Hash = H256;
+ type RuntimeCall = RuntimeCall;
+ type Hashing = BlakeTwo256;
+ type AccountId = u64;
+ type Lookup = IdentityLookup<Self::AccountId>;
+ type Header = Header;
+ type RuntimeEvent = RuntimeEvent;
+ type BlockHashCount = ConstU64<250>;
+ type DbWeight = ();
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData<u64>;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type SS58Prefix = ();
+ type OnSetCode = ();
+ type MaxConsumers = ConstU32<16>;
+}
+
+impl pallet_balances::Config for Test {
+ type Balance = u64;
+ type RuntimeEvent = RuntimeEvent;
+ type DustRemoval = ();
+ type ExistentialDeposit = ConstU64<1>;
+ type AccountStore = System;
+ type MaxLocks = ();
+ type MaxReserves = ();
+ type ReserveIdentifier = [u8; 8];
+ type WeightInfo = ();
+}
+
+parameter_types! {
+ pub const MaxAdditionalFields: u32 = 2;
+ pub const MaxRegistrars: u32 = 20;
+}
+
+ord_parameter_types! {
+ pub const One: u64 = 1;
+ pub const Two: u64 = 2;
+}
+type EnsureOneOrRoot = EitherOfDiverse<EnsureRoot<u64>, EnsureSignedBy<One, u64>>;
+type EnsureTwoOrRoot = EitherOfDiverse<EnsureRoot<u64>, EnsureSignedBy<Two, u64>>;
+impl pallet_identity::Config for Test {
+ type RuntimeEvent = RuntimeEvent;
+ type Currency = Balances;
+ type Slashed = ();
+ type BasicDeposit = ConstU64<10>;
+ type FieldDeposit = ConstU64<10>;
+ type SubAccountDeposit = ConstU64<10>;
+ type MaxSubAccounts = ConstU32<2>;
+ type MaxAdditionalFields = MaxAdditionalFields;
+ type MaxRegistrars = MaxRegistrars;
+ type RegistrarOrigin = EnsureOneOrRoot;
+ type ForceOrigin = EnsureTwoOrRoot;
+ type WeightInfo = ();
+}
+
+pub fn new_test_ext() -> sp_io::TestExternalities {
+ let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
+ pallet_balances::GenesisConfig::<Test> {
+ balances: vec![(1, 10), (2, 10), (3, 10), (10, 100), (20, 100), (30, 100)],
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+ t.into()
+}
+
+fn ten() -> IdentityInfo<MaxAdditionalFields> {
+ IdentityInfo {
+ display: Data::Raw(b"ten".to_vec().try_into().unwrap()),
+ legal: Data::Raw(b"The Right Ordinal Ten, Esq.".to_vec().try_into().unwrap()),
+ ..Default::default()
+ }
+}
+
+fn twenty() -> IdentityInfo<MaxAdditionalFields> {
+ IdentityInfo {
+ display: Data::Raw(b"twenty".to_vec().try_into().unwrap()),
+ legal: Data::Raw(b"The Right Ordinal Twenty, Esq.".to_vec().try_into().unwrap()),
+ ..Default::default()
+ }
+}
+
+#[test]
+fn editing_subaccounts_should_work() {
+ new_test_ext().execute_with(|| {
+ let data = |x| Data::Raw(vec![x; 1].try_into().unwrap());
+
+ assert_noop!(
+ Identity::add_sub(RuntimeOrigin::signed(10), 20, data(1)),
+ Error::<Test>::NoIdentity
+ );
+
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+
+ // first sub account
+ assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1)));
+ assert_eq!(SuperOf::<Test>::get(1), Some((10, data(1))));
+ assert_eq!(Balances::free_balance(10), 80);
+
+ // second sub account
+ assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 2, data(2)));
+ assert_eq!(SuperOf::<Test>::get(1), Some((10, data(1))));
+ assert_eq!(SuperOf::<Test>::get(2), Some((10, data(2))));
+ assert_eq!(Balances::free_balance(10), 70);
+
+ // third sub account is too many
+ assert_noop!(
+ Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3)),
+ Error::<Test>::TooManySubAccounts
+ );
+
+ // rename first sub account
+ assert_ok!(Identity::rename_sub(RuntimeOrigin::signed(10), 1, data(11)));
+ assert_eq!(SuperOf::<Test>::get(1), Some((10, data(11))));
+ assert_eq!(SuperOf::<Test>::get(2), Some((10, data(2))));
+ assert_eq!(Balances::free_balance(10), 70);
+
+ // remove first sub account
+ assert_ok!(Identity::remove_sub(RuntimeOrigin::signed(10), 1));
+ assert_eq!(SuperOf::<Test>::get(1), None);
+ assert_eq!(SuperOf::<Test>::get(2), Some((10, data(2))));
+ assert_eq!(Balances::free_balance(10), 80);
+
+ // add third sub account
+ assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3)));
+ assert_eq!(SuperOf::<Test>::get(1), None);
+ assert_eq!(SuperOf::<Test>::get(2), Some((10, data(2))));
+ assert_eq!(SuperOf::<Test>::get(3), Some((10, data(3))));
+ assert_eq!(Balances::free_balance(10), 70);
+ });
+}
+
+#[test]
+fn resolving_subaccount_ownership_works() {
+ new_test_ext().execute_with(|| {
+ let data = |x| Data::Raw(vec![x; 1].try_into().unwrap());
+
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(20), Box::new(twenty())));
+
+ // 10 claims 1 as a subaccount
+ assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1)));
+ assert_eq!(Balances::free_balance(1), 10);
+ assert_eq!(Balances::free_balance(10), 80);
+ assert_eq!(Balances::reserved_balance(10), 20);
+ // 20 cannot claim 1 now
+ assert_noop!(
+ Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1)),
+ Error::<Test>::AlreadyClaimed
+ );
+ // 1 wants to be with 20 so it quits from 10
+ assert_ok!(Identity::quit_sub(RuntimeOrigin::signed(1)));
+ // 1 gets the 10 that 10 paid.
+ assert_eq!(Balances::free_balance(1), 20);
+ assert_eq!(Balances::free_balance(10), 80);
+ assert_eq!(Balances::reserved_balance(10), 10);
+ // 20 can claim 1 now
+ assert_ok!(Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1)));
+ });
+}
+
+#[test]
+fn trailing_zeros_decodes_into_default_data() {
+ let encoded = Data::Raw(b"Hello".to_vec().try_into().unwrap()).encode();
+ assert!(<(Data, Data)>::decode(&mut &encoded[..]).is_err());
+ let input = &mut &encoded[..];
+ let (a, b) = <(Data, Data)>::decode(&mut AppendZerosInput::new(input)).unwrap();
+ assert_eq!(a, Data::Raw(b"Hello".to_vec().try_into().unwrap()));
+ assert_eq!(b, Data::None);
+}
+
+#[test]
+fn adding_registrar_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ let fields = IdentityFields(IdentityField::Display | IdentityField::Legal);
+ assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields));
+ assert_eq!(
+ Identity::registrars(),
+ vec![Some(RegistrarInfo { account: 3, fee: 10, fields })]
+ );
+ });
+}
+
+#[test]
+fn amount_of_registrars_is_limited() {
+ new_test_ext().execute_with(|| {
+ for i in 1..MaxRegistrars::get() + 1 {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), i as u64));
+ }
+ let last_registrar = MaxRegistrars::get() as u64 + 1;
+ assert_noop!(
+ Identity::add_registrar(RuntimeOrigin::signed(1), last_registrar),
+ Error::<Test>::TooManyRegistrars
+ );
+ });
+}
+
+#[test]
+fn registration_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ let mut three_fields = ten();
+ three_fields.additional.try_push(Default::default()).unwrap();
+ three_fields.additional.try_push(Default::default()).unwrap();
+ assert!(three_fields.additional.try_push(Default::default()).is_err());
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_eq!(Identity::identity(10).unwrap().info, ten());
+ assert_eq!(Balances::free_balance(10), 90);
+ assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10)));
+ assert_eq!(Balances::free_balance(10), 100);
+ assert_noop!(Identity::clear_identity(RuntimeOrigin::signed(10)), Error::<Test>::NotNamed);
+ });
+}
+
+#[test]
+fn uninvited_judgement_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ H256::random()
+ ),
+ Error::<Test>::InvalidIndex
+ );
+
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ H256::random()
+ ),
+ Error::<Test>::InvalidTarget
+ );
+
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ H256::random()
+ ),
+ Error::<Test>::JudgementForDifferentIdentity
+ );
+
+ let identity_hash = BlakeTwo256::hash_of(&ten());
+
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(10),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ identity_hash
+ ),
+ Error::<Test>::InvalidIndex
+ );
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::FeePaid(1),
+ identity_hash
+ ),
+ Error::<Test>::InvalidJudgement
+ );
+
+ assert_ok!(Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ identity_hash
+ ));
+ assert_eq!(Identity::identity(10).unwrap().judgements, vec![(0, Judgement::Reasonable)]);
+ });
+}
+
+#[test]
+fn clearing_judgement_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ BlakeTwo256::hash_of(&ten())
+ ));
+ assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10)));
+ assert_eq!(Identity::identity(10), None);
+ });
+}
+
+#[test]
+fn killing_slashing_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_noop!(Identity::kill_identity(RuntimeOrigin::signed(1), 10), BadOrigin);
+ assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10));
+ assert_eq!(Identity::identity(10), None);
+ assert_eq!(Balances::free_balance(10), 90);
+ assert_noop!(
+ Identity::kill_identity(RuntimeOrigin::signed(2), 10),
+ Error::<Test>::NotNamed
+ );
+ });
+}
+
+#[test]
+fn setting_subaccounts_should_work() {
+ new_test_ext().execute_with(|| {
+ let mut subs = vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))];
+ assert_noop!(
+ Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()),
+ Error::<Test>::NotFound
+ );
+
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()));
+ assert_eq!(Balances::free_balance(10), 80);
+ assert_eq!(Identity::subs_of(10), (10, vec![20].try_into().unwrap()));
+ assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap()))));
+
+ // push another item and re-set it.
+ subs.push((30, Data::Raw(vec![50; 1].try_into().unwrap())));
+ assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()));
+ assert_eq!(Balances::free_balance(10), 70);
+ assert_eq!(Identity::subs_of(10), (20, vec![20, 30].try_into().unwrap()));
+ assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap()))));
+ assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1].try_into().unwrap()))));
+
+ // switch out one of the items and re-set.
+ subs[0] = (40, Data::Raw(vec![60; 1].try_into().unwrap()));
+ assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()));
+ assert_eq!(Balances::free_balance(10), 70); // no change in the balance
+ assert_eq!(Identity::subs_of(10), (20, vec![40, 30].try_into().unwrap()));
+ assert_eq!(Identity::super_of(20), None);
+ assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1].try_into().unwrap()))));
+ assert_eq!(Identity::super_of(40), Some((10, Data::Raw(vec![60; 1].try_into().unwrap()))));
+
+ // clear
+ assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), vec![]));
+ assert_eq!(Balances::free_balance(10), 90);
+ assert_eq!(Identity::subs_of(10), (0, BoundedVec::default()));
+ assert_eq!(Identity::super_of(30), None);
+ assert_eq!(Identity::super_of(40), None);
+
+ subs.push((20, Data::Raw(vec![40; 1].try_into().unwrap())));
+ assert_noop!(
+ Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()),
+ Error::<Test>::TooManySubAccounts
+ );
+ });
+}
+
+#[test]
+fn clearing_account_should_remove_subaccounts_and_refund() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::set_subs(
+ RuntimeOrigin::signed(10),
+ vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))]
+ ));
+ assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10)));
+ assert_eq!(Balances::free_balance(10), 100);
+ assert!(Identity::super_of(20).is_none());
+ });
+}
+
+#[test]
+fn killing_account_should_remove_subaccounts_and_not_refund() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::set_subs(
+ RuntimeOrigin::signed(10),
+ vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))]
+ ));
+ assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10));
+ assert_eq!(Balances::free_balance(10), 80);
+ assert!(Identity::super_of(20).is_none());
+ });
+}
+
+#[test]
+fn cancelling_requested_judgement_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ assert_noop!(
+ Identity::cancel_request(RuntimeOrigin::signed(10), 0),
+ Error::<Test>::NoIdentity
+ );
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10));
+ assert_ok!(Identity::cancel_request(RuntimeOrigin::signed(10), 0));
+ assert_eq!(Balances::free_balance(10), 90);
+ assert_noop!(
+ Identity::cancel_request(RuntimeOrigin::signed(10), 0),
+ Error::<Test>::NotFound
+ );
+
+ assert_ok!(Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Reasonable,
+ BlakeTwo256::hash_of(&ten())
+ ));
+ assert_noop!(
+ Identity::cancel_request(RuntimeOrigin::signed(10), 0),
+ Error::<Test>::JudgementGiven
+ );
+ });
+}
+
+#[test]
+fn requesting_judgement_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_noop!(
+ Identity::request_judgement(RuntimeOrigin::signed(10), 0, 9),
+ Error::<Test>::FeeChanged
+ );
+ assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10));
+ // 10 for the judgement request, 10 for the identity.
+ assert_eq!(Balances::free_balance(10), 80);
+
+ // Re-requesting won't work as we already paid.
+ assert_noop!(
+ Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10),
+ Error::<Test>::StickyJudgement
+ );
+ assert_ok!(Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Erroneous,
+ BlakeTwo256::hash_of(&ten())
+ ));
+ // Registrar got their payment now.
+ assert_eq!(Balances::free_balance(3), 20);
+
+ // Re-requesting still won't work as it's erroneous.
+ assert_noop!(
+ Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10),
+ Error::<Test>::StickyJudgement
+ );
+
+ // Requesting from a second registrar still works.
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 4));
+ assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 1, 10));
+
+ // Re-requesting after the judgement has been reduced works.
+ assert_ok!(Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::OutOfDate,
+ BlakeTwo256::hash_of(&ten())
+ ));
+ assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10));
+ });
+}
+
+#[test]
+fn provide_judgement_should_return_judgement_payment_failed_error() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10));
+ // 10 for the judgement request, 10 for the identity.
+ assert_eq!(Balances::free_balance(10), 80);
+
+ // This forces judgement payment failed error
+ Balances::make_free_balance_be(&3, 0);
+ assert_noop!(
+ Identity::provide_judgement(
+ RuntimeOrigin::signed(3),
+ 0,
+ 10,
+ Judgement::Erroneous,
+ BlakeTwo256::hash_of(&ten())
+ ),
+ Error::<Test>::JudgementPaymentFailed
+ );
+ });
+}
+
+#[test]
+fn field_deposit_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10));
+ assert_ok!(Identity::set_identity(
+ RuntimeOrigin::signed(10),
+ Box::new(IdentityInfo {
+ additional: vec![
+ (
+ Data::Raw(b"number".to_vec().try_into().unwrap()),
+ Data::Raw(10u32.encode().try_into().unwrap())
+ ),
+ (
+ Data::Raw(b"text".to_vec().try_into().unwrap()),
+ Data::Raw(b"10".to_vec().try_into().unwrap())
+ ),
+ ]
+ .try_into()
+ .unwrap(),
+ ..Default::default()
+ })
+ ));
+ assert_eq!(Balances::free_balance(10), 70);
+ });
+}
+
+#[test]
+fn setting_account_id_should_work() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3));
+ // account 4 cannot change the first registrar's identity since it's owned by 3.
+ assert_noop!(
+ Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3),
+ Error::<Test>::InvalidIndex
+ );
+ // account 3 can, because that's the registrar's current account.
+ assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(3), 0, 4));
+ // account 4 can now, because that's their new ID.
+ assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3));
+ });
+}
+
+#[test]
+fn test_has_identity() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
+ assert!(Identity::has_identity(&10, IdentityField::Display as u64));
+ assert!(Identity::has_identity(&10, IdentityField::Legal as u64));
+ assert!(Identity::has_identity(
+ &10,
+ IdentityField::Display as u64 | IdentityField::Legal as u64
+ ));
+ assert!(!Identity::has_identity(
+ &10,
+ IdentityField::Display as u64 | IdentityField::Legal as u64 | IdentityField::Web as u64
+ ));
+ });
+}
pallets/identity/src/types.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/src/types.rs
@@ -0,0 +1,518 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// Original license:
+// This file is part of Substrate.
+
+// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use super::*;
+use codec::{Decode, Encode, MaxEncodedLen};
+use enumflags2::{bitflags, BitFlags};
+use frame_support::{
+ traits::{ConstU32, Get},
+ BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound,
+};
+use scale_info::{
+ build::{Fields, Variants},
+ meta_type, Path, Type, TypeInfo, TypeParameter,
+};
+use sp_runtime::{traits::Zero, RuntimeDebug};
+use sp_std::{fmt::Debug, iter::once, ops::Add, prelude::*};
+
+/// Either underlying data blob if it is at most 32 bytes, or a hash of it. If the data is greater
+/// than 32-bytes then it will be truncated when encoding.
+///
+/// Can also be `None`.
+#[derive(Clone, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)]
+pub enum Data {
+ /// No data here.
+ None,
+ /// The data is stored directly.
+ Raw(BoundedVec<u8, ConstU32<32>>),
+ /// Only the Blake2 hash of the data is stored. The preimage of the hash may be retrieved
+ /// through some hash-lookup service.
+ BlakeTwo256([u8; 32]),
+ /// Only the SHA2-256 hash of the data is stored. The preimage of the hash may be retrieved
+ /// through some hash-lookup service.
+ Sha256([u8; 32]),
+ /// Only the Keccak-256 hash of the data is stored. The preimage of the hash may be retrieved
+ /// through some hash-lookup service.
+ Keccak256([u8; 32]),
+ /// Only the SHA3-256 hash of the data is stored. The preimage of the hash may be retrieved
+ /// through some hash-lookup service.
+ ShaThree256([u8; 32]),
+}
+
+impl Data {
+ pub fn is_none(&self) -> bool {
+ self == &Data::None
+ }
+}
+
+impl Decode for Data {
+ fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
+ let b = input.read_byte()?;
+ Ok(match b {
+ 0 => Data::None,
+ n @ 1..=33 => {
+ let mut r: BoundedVec<_, _> = vec![0u8; n as usize - 1]
+ .try_into()
+ .expect("bound checked in match arm condition; qed");
+ input.read(&mut r[..])?;
+ Data::Raw(r)
+ },
+ 34 => Data::BlakeTwo256(<[u8; 32]>::decode(input)?),
+ 35 => Data::Sha256(<[u8; 32]>::decode(input)?),
+ 36 => Data::Keccak256(<[u8; 32]>::decode(input)?),
+ 37 => Data::ShaThree256(<[u8; 32]>::decode(input)?),
+ _ => return Err(codec::Error::from("invalid leading byte")),
+ })
+ }
+}
+
+impl Encode for Data {
+ fn encode(&self) -> Vec<u8> {
+ match self {
+ Data::None => vec![0u8; 1],
+ Data::Raw(ref x) => {
+ let l = x.len().min(32);
+ let mut r = vec![l as u8 + 1; l + 1];
+ r[1..].copy_from_slice(&x[..l as usize]);
+ r
+ },
+ Data::BlakeTwo256(ref h) => once(34u8).chain(h.iter().cloned()).collect(),
+ Data::Sha256(ref h) => once(35u8).chain(h.iter().cloned()).collect(),
+ Data::Keccak256(ref h) => once(36u8).chain(h.iter().cloned()).collect(),
+ Data::ShaThree256(ref h) => once(37u8).chain(h.iter().cloned()).collect(),
+ }
+ }
+}
+impl codec::EncodeLike for Data {}
+
+/// Add a Raw variant with the given index and a fixed sized byte array
+macro_rules! data_raw_variants {
+ ($variants:ident, $(($index:literal, $size:literal)),* ) => {
+ $variants
+ $(
+ .variant(concat!("Raw", stringify!($size)), |v| v
+ .index($index)
+ .fields(Fields::unnamed().field(|f| f.ty::<[u8; $size]>()))
+ )
+ )*
+ }
+}
+
+impl TypeInfo for Data {
+ type Identity = Self;
+
+ fn type_info() -> Type {
+ let variants = Variants::new().variant("None", |v| v.index(0));
+
+ // create a variant for all sizes of Raw data from 0-32
+ let variants = data_raw_variants!(
+ variants,
+ (1, 0),
+ (2, 1),
+ (3, 2),
+ (4, 3),
+ (5, 4),
+ (6, 5),
+ (7, 6),
+ (8, 7),
+ (9, 8),
+ (10, 9),
+ (11, 10),
+ (12, 11),
+ (13, 12),
+ (14, 13),
+ (15, 14),
+ (16, 15),
+ (17, 16),
+ (18, 17),
+ (19, 18),
+ (20, 19),
+ (21, 20),
+ (22, 21),
+ (23, 22),
+ (24, 23),
+ (25, 24),
+ (26, 25),
+ (27, 26),
+ (28, 27),
+ (29, 28),
+ (30, 29),
+ (31, 30),
+ (32, 31),
+ (33, 32)
+ );
+
+ let variants = variants
+ .variant("BlakeTwo256", |v| {
+ v.index(34).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
+ })
+ .variant("Sha256", |v| {
+ v.index(35).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
+ })
+ .variant("Keccak256", |v| {
+ v.index(36).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
+ })
+ .variant("ShaThree256", |v| {
+ v.index(37).fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
+ });
+
+ Type::builder().path(Path::new("Data", module_path!())).variant(variants)
+ }
+}
+
+impl Default for Data {
+ fn default() -> Self {
+ Self::None
+ }
+}
+
+/// An identifier for a single name registrar/identity verification service.
+pub type RegistrarIndex = u32;
+
+/// An attestation of a registrar over how accurate some `IdentityInfo` is in describing an account.
+///
+/// NOTE: Registrars may pay little attention to some fields. Registrars may want to make clear
+/// which fields their attestation is relevant for by off-chain means.
+#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
+pub enum Judgement<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
+{
+ /// The default value; no opinion is held.
+ Unknown,
+ /// No judgement is yet in place, but a deposit is reserved as payment for providing one.
+ FeePaid(Balance),
+ /// The data appears to be reasonably acceptable in terms of its accuracy, however no in depth
+ /// checks (such as in-person meetings or formal KYC) have been conducted.
+ Reasonable,
+ /// The target is known directly by the registrar and the registrar can fully attest to the
+ /// the data's accuracy.
+ KnownGood,
+ /// The data was once good but is currently out of date. There is no malicious intent in the
+ /// inaccuracy. This judgement can be removed through updating the data.
+ OutOfDate,
+ /// The data is imprecise or of sufficiently low-quality to be problematic. It is not
+ /// indicative of malicious intent. This judgement can be removed through updating the data.
+ LowQuality,
+ /// The data is erroneous. This may be indicative of malicious intent. This cannot be removed
+ /// except by the registrar.
+ Erroneous,
+}
+
+impl<Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq>
+ Judgement<Balance>
+{
+ /// Returns `true` if this judgement is indicative of a deposit being currently held. This means
+ /// it should not be cleared or replaced except by an operation which utilizes the deposit.
+ pub(crate) fn has_deposit(&self) -> bool {
+ matches!(self, Judgement::FeePaid(_))
+ }
+
+ /// Returns `true` if this judgement is one that should not be generally be replaced outside
+ /// of specialized handlers. Examples include "malicious" judgements and deposit-holding
+ /// judgements.
+ pub(crate) fn is_sticky(&self) -> bool {
+ matches!(self, Judgement::FeePaid(_) | Judgement::Erroneous)
+ }
+}
+
+/// The fields that we use to identify the owner of an account with. Each corresponds to a field
+/// in the `IdentityInfo` struct.
+#[bitflags]
+#[repr(u64)]
+#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum IdentityField {
+ Display = 0b0000000000000000000000000000000000000000000000000000000000000001,
+ Legal = 0b0000000000000000000000000000000000000000000000000000000000000010,
+ Web = 0b0000000000000000000000000000000000000000000000000000000000000100,
+ Riot = 0b0000000000000000000000000000000000000000000000000000000000001000,
+ Email = 0b0000000000000000000000000000000000000000000000000000000000010000,
+ PgpFingerprint = 0b0000000000000000000000000000000000000000000000000000000000100000,
+ Image = 0b0000000000000000000000000000000000000000000000000000000001000000,
+ Twitter = 0b0000000000000000000000000000000000000000000000000000000010000000,
+}
+
+/// Wrapper type for `BitFlags<IdentityField>` that implements `Codec`.
+#[derive(Clone, Copy, PartialEq, Default, RuntimeDebug)]
+pub struct IdentityFields(pub BitFlags<IdentityField>);
+
+impl MaxEncodedLen for IdentityFields {
+ fn max_encoded_len() -> usize {
+ u64::max_encoded_len()
+ }
+}
+
+impl Eq for IdentityFields {}
+impl Encode for IdentityFields {
+ fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
+ self.0.bits().using_encoded(f)
+ }
+}
+impl Decode for IdentityFields {
+ fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
+ let field = u64::decode(input)?;
+ Ok(Self(<BitFlags<IdentityField>>::from_bits(field as u64).map_err(|_| "invalid value")?))
+ }
+}
+impl TypeInfo for IdentityFields {
+ type Identity = Self;
+
+ fn type_info() -> Type {
+ Type::builder()
+ .path(Path::new("BitFlags", module_path!()))
+ .type_params(vec![TypeParameter::new("T", Some(meta_type::<IdentityField>()))])
+ .composite(Fields::unnamed().field(|f| f.ty::<u64>().type_name("IdentityField")))
+ }
+}
+
+/// Information concerning the identity of the controller of an account.
+///
+/// NOTE: This should be stored at the end of the storage item to facilitate the addition of extra
+/// fields in a backwards compatible way through a specialized `Decode` impl.
+#[derive(
+ CloneNoBound, Encode, Decode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
+)]
+#[codec(mel_bound())]
+#[cfg_attr(test, derive(frame_support::DefaultNoBound))]
+#[scale_info(skip_type_params(FieldLimit))]
+pub struct IdentityInfo<FieldLimit: Get<u32>> {
+ /// Additional fields of the identity that are not catered for with the struct's explicit
+ /// fields.
+ pub additional: BoundedVec<(Data, Data), FieldLimit>,
+
+ /// A reasonable display name for the controller of the account. This should be whatever it is
+ /// that it is typically known as and should not be confusable with other entities, given
+ /// reasonable context.
+ ///
+ /// Stored as UTF-8.
+ pub display: Data,
+
+ /// The full legal name in the local jurisdiction of the entity. This might be a bit
+ /// long-winded.
+ ///
+ /// Stored as UTF-8.
+ pub legal: Data,
+
+ /// A representative website held by the controller of the account.
+ ///
+ /// NOTE: `https://` is automatically prepended.
+ ///
+ /// Stored as UTF-8.
+ pub web: Data,
+
+ /// The Riot/Matrix handle held by the controller of the account.
+ ///
+ /// Stored as UTF-8.
+ pub riot: Data,
+
+ /// The email address of the controller of the account.
+ ///
+ /// Stored as UTF-8.
+ pub email: Data,
+
+ /// The PGP/GPG public key of the controller of the account.
+ pub pgp_fingerprint: Option<[u8; 20]>,
+
+ /// A graphic image representing the controller of the account. Should be a company,
+ /// organization or project logo or a headshot in the case of a human.
+ pub image: Data,
+
+ /// The Twitter identity. The leading `@` character may be elided.
+ pub twitter: Data,
+}
+
+impl<FieldLimit: Get<u32>> IdentityInfo<FieldLimit> {
+ pub(crate) fn fields(&self) -> IdentityFields {
+ let mut res = <BitFlags<IdentityField>>::empty();
+ if !self.display.is_none() {
+ res.insert(IdentityField::Display);
+ }
+ if !self.legal.is_none() {
+ res.insert(IdentityField::Legal);
+ }
+ if !self.web.is_none() {
+ res.insert(IdentityField::Web);
+ }
+ if !self.riot.is_none() {
+ res.insert(IdentityField::Riot);
+ }
+ if !self.email.is_none() {
+ res.insert(IdentityField::Email);
+ }
+ if self.pgp_fingerprint.is_some() {
+ res.insert(IdentityField::PgpFingerprint);
+ }
+ if !self.image.is_none() {
+ res.insert(IdentityField::Image);
+ }
+ if !self.twitter.is_none() {
+ res.insert(IdentityField::Twitter);
+ }
+ IdentityFields(res)
+ }
+}
+
+/// Information concerning the identity of the controller of an account.
+///
+/// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a
+/// backwards compatible way through a specialized `Decode` impl.
+#[derive(
+ CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
+)]
+#[codec(mel_bound())]
+#[scale_info(skip_type_params(MaxJudgements, MaxAdditionalFields))]
+pub struct Registration<
+ Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
+ MaxJudgements: Get<u32>,
+ MaxAdditionalFields: Get<u32>,
+> {
+ /// Judgements from the registrars on this identity. Stored ordered by `RegistrarIndex`. There
+ /// may be only a single judgement from each registrar.
+ pub judgements: BoundedVec<(RegistrarIndex, Judgement<Balance>), MaxJudgements>,
+
+ /// Amount held on deposit for this information.
+ pub deposit: Balance,
+
+ /// Information on the identity.
+ pub info: IdentityInfo<MaxAdditionalFields>,
+}
+
+impl<
+ Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add,
+ MaxJudgements: Get<u32>,
+ MaxAdditionalFields: Get<u32>,
+ > Registration<Balance, MaxJudgements, MaxAdditionalFields>
+{
+ pub(crate) fn total_deposit(&self) -> Balance {
+ self.deposit +
+ self.judgements
+ .iter()
+ .map(|(_, ref j)| if let Judgement::FeePaid(fee) = j { *fee } else { Zero::zero() })
+ .fold(Zero::zero(), |a, i| a + i)
+ }
+}
+
+impl<
+ Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
+ MaxJudgements: Get<u32>,
+ MaxAdditionalFields: Get<u32>,
+ > Decode for Registration<Balance, MaxJudgements, MaxAdditionalFields>
+{
+ fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
+ let (judgements, deposit, info) = Decode::decode(&mut AppendZerosInput::new(input))?;
+ Ok(Self { judgements, deposit, info })
+ }
+}
+
+/// Information concerning a registrar.
+#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
+pub struct RegistrarInfo<
+ Balance: Encode + Decode + Clone + Debug + Eq + PartialEq,
+ AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq,
+> {
+ /// The account of the registrar.
+ pub account: AccountId,
+
+ /// Amount required to be given to the registrar for them to provide judgement.
+ pub fee: Balance,
+
+ /// Relevant fields for this registrar. Registrar judgements are limited to attestations on
+ /// these fields.
+ pub fields: IdentityFields,
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn manual_data_type_info() {
+ let mut registry = scale_info::Registry::new();
+ let type_id = registry.register_type(&scale_info::meta_type::<Data>());
+ let registry: scale_info::PortableRegistry = registry.into();
+ let type_info = registry.resolve(type_id.id()).unwrap();
+
+ let check_type_info = |data: &Data| {
+ let variant_name = match data {
+ Data::None => "None".to_string(),
+ Data::BlakeTwo256(_) => "BlakeTwo256".to_string(),
+ Data::Sha256(_) => "Sha256".to_string(),
+ Data::Keccak256(_) => "Keccak256".to_string(),
+ Data::ShaThree256(_) => "ShaThree256".to_string(),
+ Data::Raw(bytes) => format!("Raw{}", bytes.len()),
+ };
+ if let scale_info::TypeDef::Variant(variant) = type_info.type_def() {
+ let variant = variant
+ .variants()
+ .iter()
+ .find(|v| v.name() == &variant_name)
+ .expect(&format!("Expected to find variant {}", variant_name));
+
+ let field_arr_len = variant
+ .fields()
+ .first()
+ .and_then(|f| registry.resolve(f.ty().id()))
+ .map(|ty| {
+ if let scale_info::TypeDef::Array(arr) = ty.type_def() {
+ arr.len()
+ } else {
+ panic!("Should be an array type")
+ }
+ })
+ .unwrap_or(0);
+
+ let encoded = data.encode();
+ assert_eq!(encoded[0], variant.index());
+ assert_eq!(encoded.len() as u32 - 1, field_arr_len);
+ } else {
+ panic!("Should be a variant type")
+ };
+ };
+
+ let mut data = vec![
+ Data::None,
+ Data::BlakeTwo256(Default::default()),
+ Data::Sha256(Default::default()),
+ Data::Keccak256(Default::default()),
+ Data::ShaThree256(Default::default()),
+ ];
+
+ // A Raw instance for all possible sizes of the Raw data
+ for n in 0..32 {
+ data.push(Data::Raw(vec![0u8; n as usize].try_into().unwrap()))
+ }
+
+ for d in data.iter() {
+ check_type_info(d);
+ }
+ }
+}
pallets/identity/src/weights.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/identity/src/weights.rs
@@ -0,0 +1,504 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// Original license:
+// This file is part of Substrate.
+
+// Copyright (C) 2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Autogenerated weights for pallet_identity
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+
+// Executed Command:
+// ./target/production/substrate
+// benchmark
+// pallet
+// --chain=dev
+// --steps=50
+// --repeat=20
+// --pallet=pallet_identity
+// --extrinsic=*
+// --execution=wasm
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=./frame/identity/src/weights.rs
+// --header=./HEADER-APACHE2
+// --template=./.maintain/frame-weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+/// Weight functions needed for pallet_identity.
+pub trait WeightInfo {
+ fn add_registrar(r: u32, ) -> Weight;
+ fn set_identity(r: u32, x: u32, ) -> Weight;
+ fn set_subs_new(s: u32, ) -> Weight;
+ fn set_subs_old(p: u32, ) -> Weight;
+ fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight;
+ fn request_judgement(r: u32, x: u32, ) -> Weight;
+ fn cancel_request(r: u32, x: u32, ) -> Weight;
+ fn set_fee(r: u32, ) -> Weight;
+ fn set_account_id(r: u32, ) -> Weight;
+ fn set_fields(r: u32, ) -> Weight;
+ fn provide_judgement(r: u32, x: u32, ) -> Weight;
+ fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight;
+ fn add_sub(s: u32, ) -> Weight;
+ fn rename_sub(s: u32, ) -> Weight;
+ fn remove_sub(s: u32, ) -> Weight;
+ fn quit_sub(s: u32, ) -> Weight;
+}
+
+/// Weights for pallet_identity using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn add_registrar(r: u32, ) -> Weight {
+ // Minimum execution time: 20_269 nanoseconds.
+ Weight::from_ref_time(21_910_543 as u64)
+ // Standard Error: 4_604
+ .saturating_add(Weight::from_ref_time(223_104 as u64).saturating_mul(r as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn set_identity(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 41_872 nanoseconds.
+ Weight::from_ref_time(40_230_216 as u64)
+ // Standard Error: 2_342
+ .saturating_add(Weight::from_ref_time(145_168 as u64).saturating_mul(r as u64))
+ // Standard Error: 457
+ .saturating_add(Weight::from_ref_time(291_732 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:2 w:2)
+ /// The range of component `s` is `[0, 100]`.
+ fn set_subs_new(s: u32, ) -> Weight {
+ // Minimum execution time: 12_024 nanoseconds.
+ Weight::from_ref_time(32_550_819 as u64)
+ // Standard Error: 5_057
+ .saturating_add(Weight::from_ref_time(2_521_245 as u64).saturating_mul(s as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:2)
+ /// The range of component `p` is `[0, 100]`.
+ fn set_subs_old(p: u32, ) -> Weight {
+ // Minimum execution time: 12_232 nanoseconds.
+ Weight::from_ref_time(34_009_761 as u64)
+ // Standard Error: 5_047
+ .saturating_add(Weight::from_ref_time(1_113_100 as u64).saturating_mul(p as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64)))
+ }
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:100)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `s` is `[0, 100]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 57_144 nanoseconds.
+ Weight::from_ref_time(41_559_247 as u64)
+ // Standard Error: 9_996
+ .saturating_add(Weight::from_ref_time(146_770 as u64).saturating_mul(r as u64))
+ // Standard Error: 1_952
+ .saturating_add(Weight::from_ref_time(1_086_673 as u64).saturating_mul(s as u64))
+ // Standard Error: 1_952
+ .saturating_add(Weight::from_ref_time(162_481 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(2 as u64))
+ .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity Registrars (r:1 w:0)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn request_judgement(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 44_726 nanoseconds.
+ Weight::from_ref_time(41_637_308 as u64)
+ // Standard Error: 1_907
+ .saturating_add(Weight::from_ref_time(219_078 as u64).saturating_mul(r as u64))
+ // Standard Error: 372
+ .saturating_add(Weight::from_ref_time(309_888 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn cancel_request(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 39_719 nanoseconds.
+ Weight::from_ref_time(38_008_751 as u64)
+ // Standard Error: 2_394
+ .saturating_add(Weight::from_ref_time(181_870 as u64).saturating_mul(r as u64))
+ // Standard Error: 467
+ .saturating_add(Weight::from_ref_time(314_990 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_fee(r: u32, ) -> Weight {
+ // Minimum execution time: 10_634 nanoseconds.
+ Weight::from_ref_time(11_383_704 as u64)
+ // Standard Error: 2_250
+ .saturating_add(Weight::from_ref_time(193_094 as u64).saturating_mul(r as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_account_id(r: u32, ) -> Weight {
+ // Minimum execution time: 10_840 nanoseconds.
+ Weight::from_ref_time(11_638_740 as u64)
+ // Standard Error: 1_985
+ .saturating_add(Weight::from_ref_time(193_016 as u64).saturating_mul(r as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_fields(r: u32, ) -> Weight {
+ // Minimum execution time: 10_748 nanoseconds.
+ Weight::from_ref_time(11_346_901 as u64)
+ // Standard Error: 2_132
+ .saturating_add(Weight::from_ref_time(196_630 as u64).saturating_mul(r as u64))
+ .saturating_add(T::DbWeight::get().reads(1 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:0)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn provide_judgement(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 33_682 nanoseconds.
+ Weight::from_ref_time(31_336_603 as u64)
+ // Standard Error: 3_056
+ .saturating_add(Weight::from_ref_time(200_403 as u64).saturating_mul(r as u64))
+ // Standard Error: 565
+ .saturating_add(Weight::from_ref_time(525_142 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:100)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `s` is `[0, 100]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 68_794 nanoseconds.
+ Weight::from_ref_time(52_114_486 as u64)
+ // Standard Error: 4_808
+ .saturating_add(Weight::from_ref_time(153_462 as u64).saturating_mul(r as u64))
+ // Standard Error: 939
+ .saturating_add(Weight::from_ref_time(1_084_612 as u64).saturating_mul(s as u64))
+ // Standard Error: 939
+ .saturating_add(Weight::from_ref_time(170_112 as u64).saturating_mul(x as u64))
+ .saturating_add(T::DbWeight::get().reads(3 as u64))
+ .saturating_add(T::DbWeight::get().writes(3 as u64))
+ .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[0, 99]`.
+ fn add_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 37_914 nanoseconds.
+ Weight::from_ref_time(43_488_083 as u64)
+ // Standard Error: 1_631
+ .saturating_add(Weight::from_ref_time(118_845 as u64).saturating_mul(s as u64))
+ .saturating_add(T::DbWeight::get().reads(3 as u64))
+ .saturating_add(T::DbWeight::get().writes(2 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ /// The range of component `s` is `[1, 100]`.
+ fn rename_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 16_124 nanoseconds.
+ Weight::from_ref_time(18_580_462 as u64)
+ // Standard Error: 688
+ .saturating_add(Weight::from_ref_time(67_220 as u64).saturating_mul(s as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[1, 100]`.
+ fn remove_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 41_517 nanoseconds.
+ Weight::from_ref_time(45_123_530 as u64)
+ // Standard Error: 1_530
+ .saturating_add(Weight::from_ref_time(105_429 as u64).saturating_mul(s as u64))
+ .saturating_add(T::DbWeight::get().reads(3 as u64))
+ .saturating_add(T::DbWeight::get().writes(2 as u64))
+ }
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[0, 99]`.
+ fn quit_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 30_171 nanoseconds.
+ Weight::from_ref_time(33_355_514 as u64)
+ // Standard Error: 1_286
+ .saturating_add(Weight::from_ref_time(114_716 as u64).saturating_mul(s as u64))
+ .saturating_add(T::DbWeight::get().reads(2 as u64))
+ .saturating_add(T::DbWeight::get().writes(2 as u64))
+ }
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn add_registrar(r: u32, ) -> Weight {
+ // Minimum execution time: 20_269 nanoseconds.
+ Weight::from_ref_time(21_910_543 as u64)
+ // Standard Error: 4_604
+ .saturating_add(Weight::from_ref_time(223_104 as u64).saturating_mul(r as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn set_identity(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 41_872 nanoseconds.
+ Weight::from_ref_time(40_230_216 as u64)
+ // Standard Error: 2_342
+ .saturating_add(Weight::from_ref_time(145_168 as u64).saturating_mul(r as u64))
+ // Standard Error: 457
+ .saturating_add(Weight::from_ref_time(291_732 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:2 w:2)
+ /// The range of component `s` is `[0, 100]`.
+ fn set_subs_new(s: u32, ) -> Weight {
+ // Minimum execution time: 12_024 nanoseconds.
+ Weight::from_ref_time(32_550_819 as u64)
+ // Standard Error: 5_057
+ .saturating_add(Weight::from_ref_time(2_521_245 as u64).saturating_mul(s as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:2)
+ /// The range of component `p` is `[0, 100]`.
+ fn set_subs_old(p: u32, ) -> Weight {
+ // Minimum execution time: 12_232 nanoseconds.
+ Weight::from_ref_time(34_009_761 as u64)
+ // Standard Error: 5_047
+ .saturating_add(Weight::from_ref_time(1_113_100 as u64).saturating_mul(p as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64)))
+ }
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:100)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `s` is `[0, 100]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 57_144 nanoseconds.
+ Weight::from_ref_time(41_559_247 as u64)
+ // Standard Error: 9_996
+ .saturating_add(Weight::from_ref_time(146_770 as u64).saturating_mul(r as u64))
+ // Standard Error: 1_952
+ .saturating_add(Weight::from_ref_time(1_086_673 as u64).saturating_mul(s as u64))
+ // Standard Error: 1_952
+ .saturating_add(Weight::from_ref_time(162_481 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity Registrars (r:1 w:0)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn request_judgement(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 44_726 nanoseconds.
+ Weight::from_ref_time(41_637_308 as u64)
+ // Standard Error: 1_907
+ .saturating_add(Weight::from_ref_time(219_078 as u64).saturating_mul(r as u64))
+ // Standard Error: 372
+ .saturating_add(Weight::from_ref_time(309_888 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn cancel_request(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 39_719 nanoseconds.
+ Weight::from_ref_time(38_008_751 as u64)
+ // Standard Error: 2_394
+ .saturating_add(Weight::from_ref_time(181_870 as u64).saturating_mul(r as u64))
+ // Standard Error: 467
+ .saturating_add(Weight::from_ref_time(314_990 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_fee(r: u32, ) -> Weight {
+ // Minimum execution time: 10_634 nanoseconds.
+ Weight::from_ref_time(11_383_704 as u64)
+ // Standard Error: 2_250
+ .saturating_add(Weight::from_ref_time(193_094 as u64).saturating_mul(r as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_account_id(r: u32, ) -> Weight {
+ // Minimum execution time: 10_840 nanoseconds.
+ Weight::from_ref_time(11_638_740 as u64)
+ // Standard Error: 1_985
+ .saturating_add(Weight::from_ref_time(193_016 as u64).saturating_mul(r as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ fn set_fields(r: u32, ) -> Weight {
+ // Minimum execution time: 10_748 nanoseconds.
+ Weight::from_ref_time(11_346_901 as u64)
+ // Standard Error: 2_132
+ .saturating_add(Weight::from_ref_time(196_630 as u64).saturating_mul(r as u64))
+ .saturating_add(RocksDbWeight::get().reads(1 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity Registrars (r:1 w:0)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ /// The range of component `r` is `[1, 19]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn provide_judgement(r: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 33_682 nanoseconds.
+ Weight::from_ref_time(31_336_603 as u64)
+ // Standard Error: 3_056
+ .saturating_add(Weight::from_ref_time(200_403 as u64).saturating_mul(r as u64))
+ // Standard Error: 565
+ .saturating_add(Weight::from_ref_time(525_142 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity SubsOf (r:1 w:1)
+ // Storage: Identity IdentityOf (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: Identity SuperOf (r:0 w:100)
+ /// The range of component `r` is `[1, 20]`.
+ /// The range of component `s` is `[0, 100]`.
+ /// The range of component `x` is `[0, 100]`.
+ fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight {
+ // Minimum execution time: 68_794 nanoseconds.
+ Weight::from_ref_time(52_114_486 as u64)
+ // Standard Error: 4_808
+ .saturating_add(Weight::from_ref_time(153_462 as u64).saturating_mul(r as u64))
+ // Standard Error: 939
+ .saturating_add(Weight::from_ref_time(1_084_612 as u64).saturating_mul(s as u64))
+ // Standard Error: 939
+ .saturating_add(Weight::from_ref_time(170_112 as u64).saturating_mul(x as u64))
+ .saturating_add(RocksDbWeight::get().reads(3 as u64))
+ .saturating_add(RocksDbWeight::get().writes(3 as u64))
+ .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[0, 99]`.
+ fn add_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 37_914 nanoseconds.
+ Weight::from_ref_time(43_488_083 as u64)
+ // Standard Error: 1_631
+ .saturating_add(Weight::from_ref_time(118_845 as u64).saturating_mul(s as u64))
+ .saturating_add(RocksDbWeight::get().reads(3 as u64))
+ .saturating_add(RocksDbWeight::get().writes(2 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ /// The range of component `s` is `[1, 100]`.
+ fn rename_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 16_124 nanoseconds.
+ Weight::from_ref_time(18_580_462 as u64)
+ // Standard Error: 688
+ .saturating_add(Weight::from_ref_time(67_220 as u64).saturating_mul(s as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(1 as u64))
+ }
+ // Storage: Identity IdentityOf (r:1 w:0)
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[1, 100]`.
+ fn remove_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 41_517 nanoseconds.
+ Weight::from_ref_time(45_123_530 as u64)
+ // Standard Error: 1_530
+ .saturating_add(Weight::from_ref_time(105_429 as u64).saturating_mul(s as u64))
+ .saturating_add(RocksDbWeight::get().reads(3 as u64))
+ .saturating_add(RocksDbWeight::get().writes(2 as u64))
+ }
+ // Storage: Identity SuperOf (r:1 w:1)
+ // Storage: Identity SubsOf (r:1 w:1)
+ /// The range of component `s` is `[0, 99]`.
+ fn quit_sub(s: u32, ) -> Weight {
+ // Minimum execution time: 30_171 nanoseconds.
+ Weight::from_ref_time(33_355_514 as u64)
+ // Standard Error: 1_286
+ .saturating_add(Weight::from_ref_time(114_716 as u64).saturating_mul(s as u64))
+ .saturating_add(RocksDbWeight::get().reads(2 as u64))
+ .saturating_add(RocksDbWeight::get().writes(2 as u64))
+ }
+}
runtime/opal/Cargo.tomldiffbeforeafterboth--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -276,11 +276,6 @@
git = 'https://github.com/paritytech/substrate'
branch = 'polkadot-v0.9.36'
-[dependencies.pallet-identity]
-default-features = false
-git = 'https://github.com/paritytech/substrate'
-branch = 'polkadot-v0.9.36'
-
[dependencies.pallet-balances]
default-features = false
git = "https://github.com/paritytech/substrate"
@@ -505,6 +500,7 @@
pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-collator-selection = { default-features = false, path = "../../pallets/collator-selection" }
+pallet-identity = { default-features = false, path = "../../pallets/identity" }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
pallet-structure = { default-features = false, path = "../../pallets/structure" }
runtime/quartz/Cargo.tomldiffbeforeafterboth--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -260,11 +260,6 @@
git = 'https://github.com/paritytech/substrate'
branch = 'polkadot-v0.9.36'
-[dependencies.pallet-identity]
-default-features = false
-git = 'https://github.com/paritytech/substrate'
-branch = 'polkadot-v0.9.36'
-
[dependencies.pallet-balances]
default-features = false
git = "https://github.com/paritytech/substrate"
@@ -496,6 +491,7 @@
pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-collator-selection = { default-features = false, path = "../../pallets/collator-selection" }
+pallet-identity = { default-features = false, path = "../../pallets/identity" }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
pallet-structure = { default-features = false, path = "../../pallets/structure" }
runtime/unique/Cargo.tomldiffbeforeafterboth--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -260,11 +260,6 @@
git = 'https://github.com/paritytech/substrate'
branch = 'polkadot-v0.9.36'
-[dependencies.pallet-identity]
-default-features = false
-git = 'https://github.com/paritytech/substrate'
-branch = 'polkadot-v0.9.36'
-
[dependencies.pallet-balances]
default-features = false
git = "https://github.com/paritytech/substrate"
@@ -487,6 +482,7 @@
pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-collator-selection = { default-features = false, path = "../../pallets/collator-selection" }
+pallet-identity = { default-features = false, path = "../../pallets/identity" }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
pallet-structure = { default-features = false, path = "../../pallets/structure" }