Make IdentityInfo generic in pallet-identity (#1661)

Fixes #179 

# Description

This PR makes the structure containing identity information used in
`pallet-identity` generic through the pallet `Config`. Additionally, the
old structure is now available in a separate module called `simple`
(pending rename) and is compatible with the new interface.

Another change in this PR is that while the `additional` field in
`IdentityInfo` stays for backwards compatibility reasons, the associated
costs are stil present in the pallet through the `additional` function
in the `IdentityInformationProvider` interface. This function is marked
as deprecated as it is only a temporary solution to the backwards
compatibility problem we had. In short, we could have removed the
additional fields in the struct and done a migration, but we chose to
wait and do it off-chain through the genesis of the system parachain.
After we move the identity pallet to the parachain, additional fields
will be migrated into the existing fields and the `additional` key-value
store will be removed. Until that happens, this interface will provide
the necessary information to properly account for the associated costs.

Additionally, this PR fixes an unrelated issue; the `IdentityField` enum
used to represent the fields as bitflags couldn't store more than 8
fields, even though it was marked as `#[repr(u64)]`. This was because of
the `derive` implementation of `TypeInfo`, which assumed `u8` semantics.
The custom implementation of this trait in
https://github.com/paritytech/polkadot-sdk/commit/0105cc0396b7a53d0b290f48b1225847f6d17321
fixes the issue.

---------

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Co-authored-by: Sam Johnson <sam@durosoft.com>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
This commit is contained in:
georgepisaltu
2023-10-24 13:47:11 +02:00
committed by GitHub
parent 35eb133baa
commit 9185195185
10 changed files with 402 additions and 292 deletions
+63 -100
View File
@@ -73,6 +73,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
mod benchmarking;
pub mod simple;
#[cfg(test)]
mod tests;
mod types;
@@ -85,7 +86,7 @@ pub use weights::WeightInfo;
pub use pallet::*;
pub use types::{
Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo,
Data, IdentityFields, IdentityInformationProvider, Judgement, RegistrarIndex, RegistrarInfo,
Registration,
};
@@ -133,6 +134,9 @@ pub mod pallet {
#[pallet::constant]
type MaxAdditionalFields: Get<u32>;
/// Structure holding information about an identity.
type IdentityInformation: IdentityInformationProvider;
/// Maxmimum number of registrars allowed in the system. Needed to bound the complexity
/// of, e.g., updating judgements.
#[pallet::constant]
@@ -163,7 +167,7 @@ pub mod pallet {
_,
Twox64Concat,
T::AccountId,
Registration<BalanceOf<T>, T::MaxRegistrars, T::MaxAdditionalFields>,
Registration<BalanceOf<T>, T::MaxRegistrars, T::IdentityInformation>,
OptionQuery,
>;
@@ -197,7 +201,16 @@ pub mod pallet {
#[pallet::getter(fn registrars)]
pub(super) type Registrars<T: Config> = StorageValue<
_,
BoundedVec<Option<RegistrarInfo<BalanceOf<T>, T::AccountId>>, T::MaxRegistrars>,
BoundedVec<
Option<
RegistrarInfo<
BalanceOf<T>,
T::AccountId,
<T::IdentityInformation as IdentityInformationProvider>::IdentityField,
>,
>,
T::MaxRegistrars,
>,
ValueQuery,
>;
@@ -277,9 +290,6 @@ pub mod pallet {
/// - `account`: the account of the registrar.
///
/// Emits `RegistrarAdded` if successful.
///
/// ## Complexity
/// - `O(R)` where `R` registrar-count (governance-bounded and code-bounded).
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::add_registrar(T::MaxRegistrars::get()))]
pub fn add_registrar(
@@ -317,22 +327,18 @@ pub mod pallet {
/// - `info`: The identity information.
///
/// Emits `IdentitySet` if successful.
///
/// ## Complexity
/// - `O(X + X' + R)`
/// - where `X` additional-field-count (deposit-bounded and code-bounded)
/// - where `R` judgements-count (registrar-count-bounded)
#[pallet::call_index(1)]
#[pallet::weight( T::WeightInfo::set_identity(
T::MaxRegistrars::get(), // R
T::MaxAdditionalFields::get(), // X
#[pallet::weight(T::WeightInfo::set_identity(
T::MaxRegistrars::get(),
T::MaxAdditionalFields::get(),
))]
pub fn set_identity(
origin: OriginFor<T>,
info: Box<IdentityInfo<T::MaxAdditionalFields>>,
info: Box<T::IdentityInformation>,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
let extra_fields = info.additional.len() as u32;
#[allow(deprecated)]
let extra_fields = info.additional() as u32;
ensure!(extra_fields <= T::MaxAdditionalFields::get(), Error::<T>::TooManyFields);
let fd = <BalanceOf<T>>::from(extra_fields) * T::FieldDeposit::get();
@@ -364,11 +370,7 @@ pub mod pallet {
<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())
Ok(Some(T::WeightInfo::set_identity(judgements as u32, extra_fields)).into())
}
/// Set the sub-accounts of the sender.
@@ -380,11 +382,6 @@ pub mod pallet {
/// identity.
///
/// - `subs`: The identity's (new) sub-accounts.
///
/// ## Complexity
/// - `O(P + S)`
/// - where `P` old-subs-count (hard- and deposit-bounded).
/// - where `S` subs-count (hard- and deposit-bounded).
// 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
@@ -392,8 +389,8 @@ pub mod pallet {
// 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.
#[pallet::weight(T::WeightInfo::set_subs_old(T::MaxSubAccounts::get())
.saturating_add(T::WeightInfo::set_subs_new(subs.len() as u32))
)]
pub fn set_subs(
origin: OriginFor<T>,
@@ -453,17 +450,11 @@ pub mod pallet {
/// identity.
///
/// Emits `IdentityCleared` if successful.
///
/// ## Complexity
/// - `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).
#[pallet::call_index(3)]
#[pallet::weight(T::WeightInfo::clear_identity(
T::MaxRegistrars::get(), // R
T::MaxSubAccounts::get(), // S
T::MaxAdditionalFields::get(), // X
T::MaxRegistrars::get(),
T::MaxSubAccounts::get(),
T::MaxAdditionalFields::get(),
))]
pub fn clear_identity(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
@@ -480,10 +471,11 @@ pub mod pallet {
Self::deposit_event(Event::IdentityCleared { who: sender, deposit });
#[allow(deprecated)]
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
id.judgements.len() as u32,
sub_ids.len() as u32,
id.info.additional() as u32,
))
.into())
}
@@ -504,15 +496,10 @@ pub mod pallet {
/// ```
///
/// Emits `JudgementRequested` if successful.
///
/// ## Complexity
/// - `O(R + X)`.
/// - where `R` registrar-count (governance-bounded).
/// - where `X` additional-field-count (deposit-bounded and code-bounded).
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::request_judgement(
T::MaxRegistrars::get(), // R
T::MaxAdditionalFields::get(), // X
T::MaxRegistrars::get(),
T::MaxAdditionalFields::get(),
))]
pub fn request_judgement(
origin: OriginFor<T>,
@@ -543,7 +530,8 @@ pub mod pallet {
T::Currency::reserve(&sender, registrar.fee)?;
let judgements = id.judgements.len();
let extra_fields = id.info.additional.len();
#[allow(deprecated)]
let extra_fields = id.info.additional();
<IdentityOf<T>>::insert(&sender, id);
Self::deposit_event(Event::JudgementRequested {
@@ -565,15 +553,10 @@ pub mod pallet {
/// - `reg_index`: The index of the registrar whose judgement is no longer requested.
///
/// Emits `JudgementUnrequested` if successful.
///
/// ## Complexity
/// - `O(R + X)`.
/// - where `R` registrar-count (governance-bounded).
/// - where `X` additional-field-count (deposit-bounded and code-bounded).
#[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::cancel_request(
T::MaxRegistrars::get(), // R
T::MaxAdditionalFields::get(), // X
T::MaxRegistrars::get(),
T::MaxAdditionalFields::get(),
))]
pub fn cancel_request(
origin: OriginFor<T>,
@@ -595,7 +578,8 @@ pub mod pallet {
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();
#[allow(deprecated)]
let extra_fields = id.info.additional();
<IdentityOf<T>>::insert(&sender, id);
Self::deposit_event(Event::JudgementUnrequested {
@@ -613,12 +597,8 @@ pub mod pallet {
///
/// - `index`: the index of the registrar whose fee is to be set.
/// - `fee`: the new fee.
///
/// ## Complexity
/// - `O(R)`.
/// - where `R` registrar-count (governance-bounded).
#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] // R
#[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))]
pub fn set_fee(
origin: OriginFor<T>,
#[pallet::compact] index: RegistrarIndex,
@@ -640,7 +620,7 @@ pub mod pallet {
.ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
Ok(rs.len())
})?;
Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into()) // R
Ok(Some(T::WeightInfo::set_fee(registrars as u32)).into())
}
/// Change the account associated with a registrar.
@@ -650,12 +630,8 @@ pub mod pallet {
///
/// - `index`: the index of the registrar whose fee is to be set.
/// - `new`: the new account ID.
///
/// ## Complexity
/// - `O(R)`.
/// - where `R` registrar-count (governance-bounded).
#[pallet::call_index(7)]
#[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] // R
#[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))]
pub fn set_account_id(
origin: OriginFor<T>,
#[pallet::compact] index: RegistrarIndex,
@@ -678,7 +654,7 @@ pub mod pallet {
.ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
Ok(rs.len())
})?;
Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into()) // R
Ok(Some(T::WeightInfo::set_account_id(registrars as u32)).into())
}
/// Set the field information for a registrar.
@@ -688,16 +664,14 @@ pub mod pallet {
///
/// - `index`: the index of the registrar whose fee is to be set.
/// - `fields`: the fields that the registrar concerns themselves with.
///
/// ## Complexity
/// - `O(R)`.
/// - where `R` registrar-count (governance-bounded).
#[pallet::call_index(8)]
#[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] // R
#[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))]
pub fn set_fields(
origin: OriginFor<T>,
#[pallet::compact] index: RegistrarIndex,
fields: IdentityFields,
fields: IdentityFields<
<T::IdentityInformation as IdentityInformationProvider>::IdentityField,
>,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
@@ -715,10 +689,7 @@ pub mod pallet {
.ok_or_else(|| DispatchError::from(Error::<T>::InvalidIndex))?;
Ok(rs.len())
})?;
Ok(Some(T::WeightInfo::set_fields(
registrars as u32, // R
))
.into())
Ok(Some(T::WeightInfo::set_fields(registrars as u32)).into())
}
/// Provide a judgement for an account's identity.
@@ -730,18 +701,14 @@ pub mod pallet {
/// - `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.
/// - `identity`: The hash of the [`IdentityInformationProvider`] for that the judgement is
/// provided.
///
/// Emits `JudgementGiven` if successful.
///
/// ## Complexity
/// - `O(R + X)`.
/// - where `R` registrar-count (governance-bounded).
/// - where `X` additional-field-count (deposit-bounded and code-bounded).
#[pallet::call_index(9)]
#[pallet::weight(T::WeightInfo::provide_judgement(
T::MaxRegistrars::get(), // R
T::MaxAdditionalFields::get(), // X
T::MaxRegistrars::get(),
T::MaxAdditionalFields::get(),
))]
pub fn provide_judgement(
origin: OriginFor<T>,
@@ -785,7 +752,8 @@ pub mod pallet {
}
let judgements = id.judgements.len();
let extra_fields = id.info.additional.len();
#[allow(deprecated)]
let extra_fields = id.info.additional();
<IdentityOf<T>>::insert(&target, id);
Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index });
@@ -805,17 +773,11 @@ pub mod pallet {
/// with a registered identity.
///
/// Emits `IdentityKilled` if successful.
///
/// ## Complexity
/// - `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).
#[pallet::call_index(10)]
#[pallet::weight(T::WeightInfo::kill_identity(
T::MaxRegistrars::get(), // R
T::MaxSubAccounts::get(), // S
T::MaxAdditionalFields::get(), // X
T::MaxRegistrars::get(),
T::MaxSubAccounts::get(),
T::MaxAdditionalFields::get(),
))]
pub fn kill_identity(
origin: OriginFor<T>,
@@ -837,10 +799,11 @@ pub mod pallet {
Self::deposit_event(Event::IdentityKilled { who: target, deposit });
#[allow(deprecated)]
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
id.judgements.len() as u32,
sub_ids.len() as u32,
id.info.additional() as u32,
))
.into())
}
@@ -975,6 +938,6 @@ impl<T: Config> Pallet<T> {
/// 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)
.map_or(false, |registration| (registration.info.has_identity(fields)))
}
}