From 288d351faa452b853216e77cf52727e49afacfbd Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Sat, 24 Aug 2024 00:51:46 +0300 Subject: [PATCH 01/44] WIP username refactor Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 493 +++++++++++++--------- substrate/frame/identity/src/migration.rs | 24 +- substrate/frame/identity/src/types.rs | 39 +- 3 files changed, 351 insertions(+), 205 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 08e29ddffd12..a0c640b9ec0d 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -103,7 +103,7 @@ pub mod weights; extern crate alloc; -use crate::types::{AuthorityPropertiesOf, Suffix, Username}; +use crate::types::{AuthorityProperties, Provider, Suffix, Username, UsernameInformation}; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; use frame_support::{ @@ -128,6 +128,7 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type ProviderOf = Provider>; #[frame_support::pallet] pub mod pallet { @@ -150,6 +151,10 @@ pub mod pallet { #[pallet::constant] type ByteDeposit: Get>; + /// The amount held on deposit per registered username. + #[pallet::constant] + type UsernameDeposit: Get>; + /// 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. @@ -192,6 +197,10 @@ pub mod pallet { #[pallet::constant] type PendingUsernameExpiration: Get>; + /// TODO + #[pallet::constant] + type UsernameGracePeriod: Get>; + /// The maximum length of a suffix. #[pallet::constant] type MaxSuffixLength: Get; @@ -204,7 +213,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -219,10 +228,15 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - (Registration, T::MaxRegistrars, T::IdentityInformation>, Option>), + Registration, T::MaxRegistrars, T::IdentityInformation>, OptionQuery, >; + /// TODO[GMP] + #[pallet::storage] + pub type UsernameOf = + StorageMap<_, Twox64Concat, T::AccountId, Username, 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] @@ -266,7 +280,7 @@ pub mod pallet { /// A map of the accounts who are authorized to grant usernames. #[pallet::storage] pub type UsernameAuthorities = - StorageMap<_, Twox64Concat, T::AccountId, AuthorityPropertiesOf, OptionQuery>; + StorageMap<_, Twox64Concat, Suffix, AuthorityProperties, OptionQuery>; /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. @@ -277,6 +291,15 @@ pub mod pallet { pub type AccountOfUsername = StorageMap<_, Blake2_128Concat, Username, T::AccountId, OptionQuery>; + #[pallet::storage] + pub type UsernameInfoOf = StorageMap< + _, + Blake2_128Concat, + Username, + UsernameInformation>, + OptionQuery, + >; + /// Usernames that an authority has granted, but that the account controller has not confirmed /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call @@ -288,10 +311,14 @@ pub mod pallet { _, Blake2_128Concat, Username, - (T::AccountId, BlockNumberFor), + (T::AccountId, BlockNumberFor, ProviderOf), OptionQuery, >; + #[pallet::storage] + pub type UnbindingUsernames = + StorageMap<_, Blake2_128Concat, Username, BlockNumberFor, OptionQuery>; + #[pallet::error] pub enum Error { /// Too many subs-accounts. @@ -346,6 +373,10 @@ pub mod pallet { NoUsername, /// The username cannot be forcefully removed because it can still be accepted. NotExpired, + /// TOOD[GMP] + TooEarly, + /// TODO[GMP] + NotUnbinding, } #[pallet::event] @@ -444,24 +475,18 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = match IdentityOf::::get(&sender) { - Some((mut id, maybe_username)) => ( - { - // Only keep non-positive judgements. - id.judgements.retain(|j| j.1.is_sticky()); - id.info = *info; - id - }, - maybe_username, - ), - None => ( - Registration { - info: *info, - judgements: BoundedVec::default(), - deposit: Zero::zero(), - }, - None, - ), + let mut id = match IdentityOf::::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 new_deposit = Self::calculate_identity_deposit(&id.info); @@ -470,7 +495,7 @@ pub mod pallet { id.deposit = new_deposit; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::IdentitySet { who: sender }); Ok(Some(T::WeightInfo::set_identity(judgements as u32)).into()) @@ -562,15 +587,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; let (subs_deposit, sub_ids) = SubsOf::::take(&sender); - let (id, maybe_username) = - IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); @@ -615,7 +636,7 @@ pub mod pallet { .and_then(Option::as_ref) .ok_or(Error::::EmptyIndex)?; ensure!(max_fee >= registrar.fee, Error::::FeeChanged); - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let item = (reg_index, Judgement::FeePaid(registrar.fee)); match id.judgements.binary_search_by_key(®_index, |x| x.0) { @@ -632,7 +653,7 @@ pub mod pallet { T::Currency::reserve(&sender, registrar.fee)?; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementRequested { who: sender, @@ -659,7 +680,7 @@ pub mod pallet { reg_index: RegistrarIndex, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let pos = id .judgements @@ -674,7 +695,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, fee); debug_assert!(err_amount.is_zero()); let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementUnrequested { who: sender, @@ -813,8 +834,7 @@ pub mod pallet { .and_then(Option::as_ref) .filter(|r| r.account == sender) .ok_or(Error::::InvalidIndex)?; - let (mut id, username) = - IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; + let mut id = IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; if T::Hashing::hash_of(&id.info) != identity { return Err(Error::::JudgementForDifferentIdentity.into()) @@ -841,7 +861,7 @@ pub mod pallet { } let judgements = id.judgements.len(); - IdentityOf::::insert(&target, (id, username)); + IdentityOf::::insert(&target, id); Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); Ok(Some(T::WeightInfo::provide_judgement(judgements as u32)).into()) @@ -874,15 +894,11 @@ pub mod pallet { let target = T::Lookup::lookup(target)?; // Grab their deposit (and check that they have one). let (subs_deposit, sub_ids) = SubsOf::::take(&target); - let (id, maybe_username) = - IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } // Slash their deposit from them. T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0); @@ -1024,13 +1040,13 @@ pub mod pallet { let authority = T::Lookup::lookup(authority)?; // We don't need to check the length because it gets checked when casting into a // `BoundedVec`. - Self::validate_username(&suffix, None).map_err(|_| Error::::InvalidSuffix)?; + Self::validate_suffix(&suffix)?; let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; // The authority may already exist, but we don't need to check. They might be changing // their suffix or adding allocation, so we just want to overwrite whatever was there. UsernameAuthorities::::insert( - &authority, - AuthorityPropertiesOf:: { suffix, allocation }, + &suffix, + AuthorityProperties:: { account_id: authority.clone(), allocation }, ); Self::deposit_event(Event::AuthorityAdded { authority }); Ok(()) @@ -1041,11 +1057,15 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_username_authority())] pub fn remove_username_authority( origin: OriginFor, + suffix: Vec, authority: AccountIdLookupOf, ) -> DispatchResult { T::UsernameAuthorityOrigin::ensure_origin(origin)?; + let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; let authority = T::Lookup::lookup(authority)?; - UsernameAuthorities::::take(&authority).ok_or(Error::::NotUsernameAuthority)?; + let properties = + UsernameAuthorities::::take(&suffix).ok_or(Error::::NotUsernameAuthority)?; + ensure!(properties.account_id == authority, Error::::InvalidSuffix); Self::deposit_event(Event::AuthorityRemoved { authority }); Ok(()) } @@ -1066,35 +1086,32 @@ pub mod pallet { who: AccountIdLookupOf, username: Vec, signature: Option, + use_allocation: bool, ) -> DispatchResult { // Ensure origin is a Username Authority and has an allocation. Decrement their // allocation by one. let sender = ensure_signed(origin)?; - let suffix = UsernameAuthorities::::try_mutate( - &sender, - |maybe_authority| -> Result, DispatchError> { + let suffix = Self::validate_username(&username)?; + let provider = UsernameAuthorities::::try_mutate( + &suffix, + |maybe_authority| -> Result, DispatchError> { let properties = maybe_authority.as_mut().ok_or(Error::::NotUsernameAuthority)?; - ensure!(properties.allocation > 0, Error::::NoAllocation); - properties.allocation.saturating_dec(); - Ok(properties.suffix.clone()) + ensure!(properties.account_id == sender, Error::::NotUsernameAuthority); + if use_allocation { + ensure!(properties.allocation > 0, Error::::NoAllocation); + properties.allocation.saturating_dec(); + Ok(Provider::new_with_allocation()) + } else { + let deposit = T::UsernameDeposit::get(); + T::Currency::reserve(&sender, deposit)?; + Ok(Provider::new_with_deposit(deposit)) + } }, )?; - // Ensure that the username only contains allowed characters. We already know the suffix - // does. - let username_length = username.len().saturating_add(suffix.len()) as u32; - Self::validate_username(&username, Some(username_length))?; - - // Concatenate the username with suffix and cast into a BoundedVec. Should be infallible - // since we already ensured it is below the max length. - let mut full_username = - Vec::with_capacity(username.len().saturating_add(suffix.len()).saturating_add(1)); - full_username.extend(username); - full_username.extend(b"."); - full_username.extend(suffix); let bounded_username = - Username::::try_from(full_username).map_err(|_| Error::::InvalidUsername)?; + Username::::try_from(username).map_err(|_| Error::::InvalidUsername)?; // Usernames must be unique. Ensure it's not taken. ensure!( @@ -1112,10 +1129,10 @@ pub mod pallet { // Account has pre-signed an authorization. Verify the signature provided and grant // the username directly. Self::validate_signature(&bounded_username[..], &s, &who)?; - Self::insert_username(&who, bounded_username); + Self::insert_username(&who, bounded_username, provider); } else { // The user must accept the username, therefore, queue it. - Self::queue_acceptance(&who, bounded_username); + Self::queue_acceptance(&who, bounded_username, provider); } Ok(()) } @@ -1129,10 +1146,10 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let (approved_for, _) = + let (approved_for, _, provider) = PendingUsernames::::take(&username).ok_or(Error::::NoUsername)?; ensure!(approved_for == who.clone(), Error::::InvalidUsername); - Self::insert_username(&who, username.clone()); + Self::insert_username(&who, username.clone(), provider); Self::deposit_event(Event::UsernameSet { who: who.clone(), username }); Ok(Pays::No.into()) } @@ -1147,9 +1164,23 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - if let Some((who, expiration)) = PendingUsernames::::take(&username) { + if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); + match provider { + Provider::Authority(deposit) => { + T::Currency::unreserve(&who, deposit); + let err_amount = T::Currency::unreserve(&who, deposit); + debug_assert!(err_amount.is_zero()); + }, + Provider::Governance => { + // We don't refund the allocation, it is lost. + }, + Provider::System => { + // TODO[GMP] + return Err(Error::::InvalidTarget.into()); + }, + } Self::deposit_event(Event::PreapprovalExpired { whose: who.clone() }); Ok(Pays::No.into()) } else { @@ -1166,9 +1197,7 @@ pub mod pallet { let account_of_username = AccountOfUsername::::get(&username).ok_or(Error::::NoUsername)?; ensure!(who == account_of_username, Error::::InvalidUsername); - let (registration, _maybe_username) = - IdentityOf::::get(&who).ok_or(Error::::NoIdentity)?; - IdentityOf::::insert(&who, (registration, Some(username.clone()))); + UsernameOf::::insert(&who, username.clone()); Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); Ok(()) } @@ -1181,99 +1210,154 @@ pub mod pallet { origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { - // ensure `username` maps to `origin` (i.e. has already been set by an authority). - let _ = ensure_signed(origin)?; - let who = AccountOfUsername::::take(&username).ok_or(Error::::NoUsername)?; - ensure!(!IdentityOf::::contains_key(&who), Error::::InvalidUsername); + let who = ensure_signed(origin)?; + ensure!(!UsernameOf::::contains_key(&who), Error::::InvalidUsername); + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + match username_info.provider { + Provider::Authority(username_deposit) => { + let suffix = + Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + { + let err_amount = + T::Currency::unreserve(&authority_account, username_deposit); + debug_assert!(err_amount.is_zero()); + } + }, + Provider::Governance => { + // We don't refund the allocation, it is lost. + }, + Provider::System => return Err(Error::::InvalidTarget.into()), + } Self::deposit_event(Event::DanglingUsernameRemoved { who: who.clone(), username }); Ok(Pays::No.into()) } - } -} - -impl Pallet { - /// Information that is pertinent to identify the entity behind an account. First item is the - /// registration, second is the account's primary username. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - pub fn identity( - who: T::AccountId, - ) -> Option<( - Registration, T::MaxRegistrars, T::IdentityInformation>, - Option>, - )> { - IdentityOf::::get(who) - } - - /// 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`. - pub fn super_of(who: T::AccountId) -> Option<(T::AccountId, Data)> { - SuperOf::::get(who) - } - /// 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. - pub fn subs_of( - who: T::AccountId, - ) -> (BalanceOf, BoundedVec) { - SubsOf::::get(who) - } - - /// 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. - pub fn registrars() -> BoundedVec< - Option< - RegistrarInfo< - BalanceOf, - T::AccountId, - ::FieldsIdentifier, - >, - >, - T::MaxRegistrars, - > { - Registrars::::get() - } - - /// A map of the accounts who are authorized to grant usernames. - pub fn authority(who: T::AccountId) -> Option> { - UsernameAuthorities::::get(who) - } + /// TODO[GMP] + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::remove_dangling_username())] + pub fn unbind_username( + origin: OriginFor, + username: Username, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(UsernameOf::::contains_key(&who), Error::::InvalidUsername); + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + let authority_account = UsernameAuthorities::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + ensure!(who == authority_account, Error::::NotUsernameAuthority); + match username_info.provider { + Provider::Authority(_) | Provider::Governance => { + let now = frame_system::Pallet::::block_number(); + UnbindingUsernames::::try_mutate(&username, |maybe_init| { + if maybe_init.is_some() { + return Err(Error::::TooEarly); + } + *maybe_init = Some(now); + Ok(()) + })?; + }, + Provider::System => return Err(Error::::InvalidTarget.into()), + } + Ok(Pays::Yes.into()) + } - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. - /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one - /// primary username. - pub fn username(username: Username) -> Option { - AccountOfUsername::::get(username) - } + /// TODO[GMP] + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::remove_dangling_username())] + pub fn remove_username( + origin: OriginFor, + username: Username, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let grace_period_start = + UnbindingUsernames::::take(&username).ok_or(Error::::NotUnbinding)?; + let now = frame_system::Pallet::::block_number(); + ensure!( + grace_period_start.saturating_add(T::UsernameGracePeriod::get()) >= now, + Error::::TooEarly + ); + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + // Maybe it's a primary username, maybe not. We remove it anyway. + let _ = UsernameOf::::take(&username_info.owner); + match username_info.provider { + Provider::Authority(username_deposit) => { + let suffix = + Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + { + let err_amount = + T::Currency::unreserve(&authority_account, username_deposit); + debug_assert!(err_amount.is_zero()); + } + }, + Provider::Governance => { + // We don't refund the allocation, it is lost. + }, + Provider::System => return Err(Error::::InvalidTarget.into()), + } + Ok(Pays::No.into()) + } - /// Usernames that an authority has granted, but that the account controller has not confirmed - /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature - /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. - /// - /// First tuple item is the account and second is the acceptance deadline. - pub fn preapproved_usernames( - username: Username, - ) -> Option<(T::AccountId, BlockNumberFor)> { - PendingUsernames::::get(username) - } + /* + if let Some(username) = UsernameOf::::take(&target) { + let username_info = + UsernameInfoOf::::take(username).ok_or(Error::::NoUsername)?; + match username_info.provider { + Provider::Authority(_username_deposit) => { + // T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, + // deposit).0); + }, + _ => {}, + } + } + */ - /// Get the subs of an account. - pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> { - SubsOf::::get(who) - .1 - .into_iter() - .filter_map(|a| SuperOf::::get(&a).map(|x| (a, x.1))) - .collect() + /// TODO[GMP] + #[pallet::call_index(24)] + #[pallet::weight(T::WeightInfo::remove_dangling_username())] + pub fn kill_username( + origin: OriginFor, + username: Username, + ) -> DispatchResultWithPostInfo { + T::ForceOrigin::ensure_origin(origin)?; + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + // Maybe it's a primary username, maybe not. We remove it anyway. + let _ = UsernameOf::::take(&username_info.owner); + let _ = UnbindingUsernames::::take(&username); + match username_info.provider { + Provider::Authority(username_deposit) => { + let suffix = + Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + { + T::Slashed::on_unbalanced( + T::Currency::slash_reserved(&authority_account, username_deposit).0, + ); + } + }, + Provider::Governance => { + // We don't refund the allocation, it is lost. + }, + Provider::System => { + // Force origin can remove system usernames. + }, + } + Ok(Pays::No.into()) + } } +} +impl Pallet { /// Calculate the deposit required for a number of `sub` accounts. fn subs_deposit(subs: u32) -> BalanceOf { T::SubAccountDeposit::get().saturating_mul(BalanceOf::::from(subs)) @@ -1300,7 +1384,7 @@ impl Pallet { fields: ::FieldsIdentifier, ) -> bool { IdentityOf::::get(who) - .map_or(false, |(registration, _username)| (registration.info.has_identity(fields))) + .map_or(false, |registration| (registration.info.has_identity(fields))) } /// Calculate the deposit required for an identity. @@ -1316,19 +1400,53 @@ impl Pallet { /// conforms to the limit. It is not expected to pass a fully formatted username here (i.e. one /// with any protocol-added characters included, such as a `.`). The suffix is also separately /// validated by this function to ensure the full username conforms. - fn validate_username(username: &Vec, length: Option) -> DispatchResult { + fn validate_username(username: &Vec) -> Result, DispatchError> { // Verify input length before allocating a Vec with the user's input. `<` instead of `<=` // because it needs one element for the point (`username` + `.` + `suffix`). - if let Some(l) = length { - ensure!(l < T::MaxUsernameLength::get(), Error::::InvalidUsername); - } + ensure!( + username.len() <= T::MaxUsernameLength::get() as usize, + Error::::InvalidUsername + ); + // Usernames cannot be empty. ensure!(!username.is_empty(), Error::::InvalidUsername); + let separator_idx = + username.iter().rposition(|c| *c == b'.').ok_or(Error::::InvalidUsername)?; + ensure!(separator_idx > 0, Error::::InvalidUsername); + let suffix_start = separator_idx.checked_add(1).ok_or(Error::::InvalidUsername)?; + ensure!(suffix_start < username.len(), Error::::InvalidUsername); // Username must be lowercase and alphanumeric. ensure!( - username.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + username + .iter() + .take(separator_idx) + .all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), Error::::InvalidUsername ); + let suffix: Suffix = (&username[suffix_start..]) + .to_vec() + .try_into() + .map_err(|_| Error::::InvalidUsername)?; + Ok(suffix) + } + + fn suffix_of_username(username: &Username) -> Option> { + let separator_idx = username.iter().rposition(|c| *c == b'.')?; + let suffix_start = separator_idx.checked_add(1)?; + if suffix_start >= username.len() { + return None; + } + (&username[suffix_start..]).to_vec().try_into().ok() + } + + /// Validate that a suffix conforms to allowed characters/format. + fn validate_suffix(suffix: &Vec) -> Result<(), DispatchError> { + ensure!(suffix.len() <= T::MaxSuffixLength::get() as usize, Error::::InvalidSuffix); + ensure!(!suffix.is_empty(), Error::::InvalidSuffix); + ensure!( + suffix.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + Error::::InvalidSuffix + ); Ok(()) } @@ -1357,34 +1475,22 @@ impl Pallet { } /// A username has met all conditions. Insert the relevant storage items. - pub fn insert_username(who: &T::AccountId, username: Username) { + pub fn insert_username(who: &T::AccountId, username: Username, provider: ProviderOf) { // Check if they already have a primary. If so, leave it. If not, set it. // Likewise, check if they have an identity. If not, give them a minimal one. - let (reg, primary_username, new_is_primary) = match IdentityOf::::get(&who) { + let (primary_username, new_is_primary) = match UsernameOf::::get(&who) { // User has an existing Identity and a primary username. Leave it. - Some((reg, Some(primary))) => (reg, primary, false), + Some(primary) => (primary, false), // User has an Identity but no primary. Set the new one as primary. - Some((reg, None)) => (reg, username.clone(), true), - // User does not have an existing Identity. Give them a fresh default one and set - // their username as primary. - None => ( - Registration { - info: Default::default(), - judgements: Default::default(), - deposit: Zero::zero(), - }, - username.clone(), - true, - ), + None => (username.clone(), true), }; - // Enter in identity map. Note: In the case that the user did not have a pre-existing - // Identity, we have given them the storage item for free. If they ever call - // `set_identity` with identity info, then they will need to place the normal identity - // deposit. - IdentityOf::::insert(&who, (reg, Some(primary_username))); + if new_is_primary { + UsernameOf::::insert(&who, primary_username); + } + let username_info = UsernameInformation { owner: who.clone(), provider }; // Enter in username map. - AccountOfUsername::::insert(username.clone(), &who); + UsernameInfoOf::::insert(username.clone(), username_info); Self::deposit_event(Event::UsernameSet { who: who.clone(), username: username.clone() }); if new_is_primary { Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); @@ -1393,10 +1499,10 @@ impl Pallet { /// A username was granted by an authority, but must be accepted by `who`. Put the username /// into a queue for acceptance. - pub fn queue_acceptance(who: &T::AccountId, username: Username) { + pub fn queue_acceptance(who: &T::AccountId, username: Username, provider: ProviderOf) { let now = frame_system::Pallet::::block_number(); let expiration = now.saturating_add(T::PendingUsernameExpiration::get()); - PendingUsernames::::insert(&username, (who.clone(), expiration)); + PendingUsernames::::insert(&username, (who.clone(), expiration, provider)); Self::deposit_event(Event::UsernameQueued { who: who.clone(), username, expiration }); } @@ -1415,7 +1521,7 @@ impl Pallet { pub fn reap_identity(who: &T::AccountId) -> Result<(u32, u32, u32), DispatchError> { // `take` any storage items keyed by `target` // identity - let (id, _maybe_username) = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; let registrars = id.judgements.len() as u32; let encoded_byte_size = id.info.encoded_size() as u32; @@ -1449,7 +1555,7 @@ impl Pallet { let new_id_deposit = IdentityOf::::try_mutate( &target, |identity_of| -> Result, DispatchError> { - let (reg, _) = identity_of.as_mut().ok_or(Error::::NoIdentity)?; + let reg = identity_of.as_mut().ok_or(Error::::NoIdentity)?; // Calculate what deposit should be let encoded_byte_size = reg.info.encoded_size() as u32; let byte_deposit = @@ -1491,14 +1597,11 @@ impl Pallet { ) -> DispatchResult { IdentityOf::::insert( &who, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: info.clone(), + }, ); Ok(()) } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 8725bfd39df1..d05146b74e77 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -39,6 +39,7 @@ pub mod versioned { pub mod v1 { use super::*; + use frame_support::storage_alias; /// The log target. const TARGET: &'static str = "runtime::identity::migration::v1"; @@ -46,7 +47,6 @@ pub mod v1 { /// The old identity type, useful in pre-upgrade. mod v0 { use super::*; - use frame_support::storage_alias; #[storage_alias] pub type IdentityOf = StorageMap< @@ -62,6 +62,26 @@ pub mod v1 { >; } + mod vx { + use super::*; + + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ( + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + Option>, + ), + OptionQuery, + >; + } + /// Migration to add usernames to Identity info. /// /// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to @@ -92,7 +112,7 @@ pub mod v1 { let mut interrupted = false; for (account, registration) in v0::IdentityOf::::iter() { - IdentityOf::::insert(account, (registration, None::>)); + vx::IdentityOf::::insert(account, (registration, None::>)); translated.saturating_inc(); if translated >= KL { log::warn!( diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index 45401d53e9e9..e6de33767885 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -320,9 +320,6 @@ pub struct RegistrarInfo< pub fields: IdField, } -/// Authority properties for a given pallet configuration. -pub type AuthorityPropertiesOf = AuthorityProperties>; - /// The number of usernames that an authority may allocate. type Allocation = u32; /// A byte vec used to represent a username. @@ -330,11 +327,9 @@ pub(crate) type Suffix = BoundedVec::MaxSuffixLength>; /// Properties of a username authority. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] -pub struct AuthorityProperties { - /// The suffix added to usernames granted by this authority. Will be appended to usernames; for - /// example, a suffix of `wallet` will result in `.wallet` being appended to a user's selected - /// name. - pub suffix: Suffix, +pub struct AuthorityProperties { + /// The account of the authority. + pub account_id: Account, /// The number of usernames remaining that this authority can grant. pub allocation: Allocation, } @@ -342,6 +337,34 @@ pub struct AuthorityProperties { /// A byte vec used to represent a username. pub(crate) type Username = BoundedVec::MaxUsernameLength>; +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub enum Provider { + Governance, + Authority(Balance), + System, +} + +impl Provider { + pub fn new_with_allocation() -> Self { + Self::Governance + } + + pub fn new_with_deposit(deposit: Balance) -> Self { + Self::Authority(deposit) + } + + #[allow(unused)] + pub fn new_permanent() -> Self { + Self::System + } +} + +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub struct UsernameInformation { + pub owner: Account, + pub provider: Provider, +} + #[cfg(test)] mod tests { use super::*; From 06f84722a082a9fe68b7ac19cc064838948ba8ad Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 26 Aug 2024 19:01:57 +0300 Subject: [PATCH 02/44] Minor fixes Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 34 ++++++++++----------------- substrate/frame/identity/src/tests.rs | 2 ++ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index a0c640b9ec0d..f19d2882b87a 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -197,7 +197,8 @@ pub mod pallet { #[pallet::constant] type PendingUsernameExpiration: Get>; - /// TODO + /// The number of blocks that must pass to enable the permanent deletion of a username by + /// its respective authority. #[pallet::constant] type UsernameGracePeriod: Get>; @@ -232,7 +233,7 @@ pub mod pallet { OptionQuery, >; - /// TODO[GMP] + /// Identifies the primary username of an account. #[pallet::storage] pub type UsernameOf = StorageMap<_, Twox64Concat, T::AccountId, Username, OptionQuery>; @@ -373,9 +374,9 @@ pub mod pallet { NoUsername, /// The username cannot be forcefully removed because it can still be accepted. NotExpired, - /// TOOD[GMP] + /// The username cannot be removed because it's still in the grace period. TooEarly, - /// TODO[GMP] + /// The username cannot be removed because it is not unbinding. NotUnbinding, } @@ -1177,7 +1178,7 @@ pub mod pallet { // We don't refund the allocation, it is lost. }, Provider::System => { - // TODO[GMP] + // Usernames added by the system shouldn't ever be expired. return Err(Error::::InvalidTarget.into()); }, } @@ -1235,7 +1236,9 @@ pub mod pallet { Ok(Pays::No.into()) } - /// TODO[GMP] + /// Start the process of removing a username by placing it in the unbinding usernames map. + /// Once the grace period has passed, the username can be permanently deleted by calling + /// [remove_username](crate::Call::remove_username). #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::remove_dangling_username())] pub fn unbind_username( @@ -1267,7 +1270,7 @@ pub mod pallet { Ok(Pays::Yes.into()) } - /// TODO[GMP] + /// Permanently delete a username which has been unbinding for longer than the grace period. #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::remove_dangling_username())] pub fn remove_username( @@ -1306,21 +1309,8 @@ pub mod pallet { Ok(Pays::No.into()) } - /* - if let Some(username) = UsernameOf::::take(&target) { - let username_info = - UsernameInfoOf::::take(username).ok_or(Error::::NoUsername)?; - match username_info.provider { - Provider::Authority(_username_deposit) => { - // T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, - // deposit).0); - }, - _ => {}, - } - } - */ - - /// TODO[GMP] + /// Call with [ForceOrigin](crate::Config::ForceOrigin) privileges which deletes a username + /// and slashes any deposit associated with it. #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::remove_dangling_username())] pub fn kill_username( diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 3adb823ad5da..c4a7c8bb1b43 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -77,6 +77,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU64<100>; type ByteDeposit = ConstU64<10>; + type UsernameDeposit = ConstU64<10>; type SubAccountDeposit = ConstU64<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo; @@ -87,6 +88,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountPublic; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU64<100>; + type UsernameGracePeriod = ConstU64<2>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); From ebdd61da069e14ec3264247dab1cfeab1d5ebc16 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 26 Aug 2024 19:53:41 +0300 Subject: [PATCH 03/44] Fix test compilation Signed-off-by: georgepisaltu --- substrate/frame/identity/src/tests.rs | 407 ++++++++++---------------- 1 file changed, 156 insertions(+), 251 deletions(-) diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index c4a7c8bb1b43..57adbe9eb927 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -159,23 +159,21 @@ fn unfunded_accounts() -> [AccountIdOf; 2] { [account(100), account(101)] } -// First return value is a username that would be submitted as a parameter to the dispatchable. As -// in, it has no suffix attached. Second is a full BoundedVec username with suffix, which is what a -// user would need to sign. -fn test_username_of(int: Vec, suffix: Vec) -> (Vec, Username) { +// Returns a full BoundedVec username with suffix, which is what a user would need to sign. +fn test_username_of(int: Vec, suffix: Vec) -> Username { let base = b"testusername"; let mut username = Vec::with_capacity(base.len() + int.len()); username.extend(base); username.extend(int); let mut bounded_username = Vec::with_capacity(username.len() + suffix.len() + 1); - bounded_username.extend(username.clone()); + bounded_username.extend(username); bounded_username.extend(b"."); bounded_username.extend(suffix); let bounded_username = Username::::try_from(bounded_username) .expect("test usernames should fit within bounds"); - (username, bounded_username) + bounded_username } fn infoof_ten() -> IdentityInfo { @@ -403,7 +401,7 @@ fn registration_should_work() { RuntimeOrigin::signed(ten.clone()), Box::new(ten_info.clone()) )); - assert_eq!(IdentityOf::::get(ten.clone()).unwrap().0.info, ten_info); + assert_eq!(IdentityOf::::get(ten.clone()).unwrap().info, ten_info); assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit); assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(ten.clone()))); assert_eq!(Balances::free_balance(ten.clone()), 1000); @@ -487,7 +485,7 @@ fn uninvited_judgement_should_work() { identity_hash )); assert_eq!( - IdentityOf::::get(ten).unwrap().0.judgements, + IdentityOf::::get(ten).unwrap().judgements, vec![(0, Judgement::Reasonable)] ); }); @@ -877,20 +875,14 @@ fn poke_deposit_works() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); // Set a sub with zero deposit @@ -912,14 +904,11 @@ fn poke_deposit_works() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + },) ); // new subs deposit is 10 vvvvvvvvvvvv assert_eq!(SubsOf::::get(ten), (subs_deposit, vec![twenty].try_into().unwrap())); @@ -934,20 +923,14 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); @@ -963,14 +946,11 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + }) ); // No new subs storage item. assert!(!SubsOf::::contains_key(&ten)); @@ -991,10 +971,11 @@ fn adding_and_removing_authorities_should_work() { suffix.clone(), allocation )); + let suffix: Suffix = suffix.try_into().unwrap(); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.clone().try_into().unwrap(), + UsernameAuthorities::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation }) ); @@ -1003,20 +984,24 @@ fn adding_and_removing_authorities_should_work() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - suffix.clone(), + suffix.clone().into(), 11u32 )); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.try_into().unwrap(), + UsernameAuthorities::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation: 11 }) ); // remove - assert_ok!(Identity::remove_username_authority(RuntimeOrigin::root(), authority.clone(),)); - assert!(UsernameAuthorities::::get(&authority).is_none()); + assert_ok!(Identity::remove_username_authority( + RuntimeOrigin::root(), + suffix.clone().into(), + authority.clone(), + )); + assert!(UsernameAuthorities::::get(&suffix).is_none()); }); } @@ -1035,39 +1020,26 @@ fn set_username_with_signature_without_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); // Even though user has no balance and no identity, they get a default one for free. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Lookup from username to account works. - assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) - ); + assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); }); } @@ -1086,14 +1058,13 @@ fn set_username_with_signature_with_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); @@ -1105,25 +1076,13 @@ fn set_username_with_signature_with_existing_identity_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) - ); - assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); }); } @@ -1146,8 +1105,8 @@ fn set_username_with_bytes_signature_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); - let unwrapped_username = username_to_sign.to_vec(); + let username = test_username_of(b"42".to_vec(), suffix); + let unwrapped_username = username.to_vec(); // Sign an unwrapped version, as in `username.suffix`. let signature_on_unwrapped = MultiSignature::Sr25519( @@ -1186,28 +1145,16 @@ fn set_username_with_bytes_signature_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username, - Some(signature_on_wrapped) + username.clone().into(), + Some(signature_on_wrapped), + true, )); // The username in storage should not include ``. As in, it's the original // `username_to_sign`. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Likewise for the lookup. - assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) - ); + assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); }); } @@ -1226,45 +1173,33 @@ fn set_username_with_acceptance_should_work() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Governance)) ); // Now the user can accept - assert_ok!(Identity::accept_username( - RuntimeOrigin::signed(who.clone()), - full_username.clone() - )); + assert_ok!(Identity::accept_username(RuntimeOrigin::signed(who.clone()), username.clone())); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); // Check Identity storage - assert_eq!( - IdentityOf::::get(&who), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(full_username.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who), Some(username.clone())); // Check reverse lookup - assert_eq!(AccountOfUsername::::get::<&Username>(&full_username), Some(who)); + assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who)); }); } @@ -1297,7 +1232,7 @@ fn invalid_usernames_should_be_rejected() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - valid_suffix, + valid_suffix.clone(), allocation )); @@ -1313,13 +1248,18 @@ fn invalid_usernames_should_be_rejected() { //0 1 2 v With `.test` this makes it too long. b"testusernametestusernametest".to_vec(), ]; - for username in invalid_usernames { + for username in invalid_usernames.into_iter().map(|mut username| { + username.push(b'.'); + username.extend(valid_suffix.clone()); + username + }) { assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who.clone(), username.clone(), - None + None, + true, ), Error::::InvalidUsername ); @@ -1331,7 +1271,8 @@ fn invalid_usernames_should_be_rejected() { RuntimeOrigin::signed(authority), who, valid_username, - None + None, + true, )); }); } @@ -1354,21 +1295,24 @@ fn authorities_should_run_out_of_allocation() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi, - b"username314159".to_vec(), - None + b"username314159.test".to_vec(), + None, + true, )); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e, - b"username271828".to_vec(), - None + b"username271828.test".to_vec(), + None, + true )); assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), c, - b"username299792458".to_vec(), - None + b"username299792458.test".to_vec(), + None, + true, ), Error::::NoAllocation ); @@ -1394,90 +1338,62 @@ fn setting_primary_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (first_username, first_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let first_username = test_username_of(b"42".to_vec(), suffix.clone()); let first_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - first_username.clone(), - Some(first_signature) + first_username.clone().into(), + Some(first_signature), + true )); // First username set as primary. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // set up username - let (second_username, second_to_sign) = test_username_of(b"101".to_vec(), suffix); + let second_username = test_username_of(b"101".to_vec(), suffix); let second_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - second_username.clone(), - Some(second_signature) + second_username.clone().into(), + Some(second_signature), + true, )); // The primary is still the first username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // Lookup from both works. assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), + AccountOfUsername::::get::<&Username>(&first_username), Some(who_account.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), + AccountOfUsername::::get::<&Username>(&second_username), Some(who_account.clone()) ); assert_ok!(Identity::set_primary_username( RuntimeOrigin::signed(who_account.clone()), - second_to_sign.clone() + second_username.clone() )); // The primary is now the second username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(second_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(second_username.clone())); // Lookup from both still works. assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), + AccountOfUsername::::get::<&Username>(&first_username), Some(who_account.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), + AccountOfUsername::::get::<&Username>(&second_username), Some(who_account) ); }); @@ -1500,50 +1416,51 @@ fn must_own_primary() { // Set up first user ("pi") and a username. let pi_public = sr25519_generate(0.into(), None); let pi_account: AccountIdOf = MultiSigner::Sr25519(pi_public).into_account().into(); - let (pi_username, pi_to_sign) = - test_username_of(b"username314159".to_vec(), suffix.clone()); + let pi_username = test_username_of(b"username314159".to_vec(), suffix.clone()); let pi_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi_account.clone(), - pi_username.clone(), - Some(pi_signature) + pi_username.clone().into(), + Some(pi_signature), + true, )); // Set up second user ("e") and a username. let e_public = sr25519_generate(1.into(), None); let e_account: AccountIdOf = MultiSigner::Sr25519(e_public).into_account().into(); - let (e_username, e_to_sign) = test_username_of(b"username271828".to_vec(), suffix.clone()); + let e_username = test_username_of(b"username271828".to_vec(), suffix.clone()); let e_signature = - MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e_account.clone(), - e_username.clone(), - Some(e_signature) + e_username.clone().into(), + Some(e_signature), + true )); // Ensure that both users have their usernames. assert_eq!( - AccountOfUsername::::get::<&Username>(&pi_to_sign), + AccountOfUsername::::get::<&Username>(&pi_username), Some(pi_account.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&e_to_sign), + AccountOfUsername::::get::<&Username>(&e_username), Some(e_account.clone()) ); // Cannot set primary to a username that does not exist. - let (_, c_username) = test_username_of(b"speedoflight".to_vec(), suffix.clone()); + let c_username = test_username_of(b"speedoflight".to_vec(), suffix.clone()); assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username), Error::::NoUsername ); // Cannot take someone else's username as your primary. assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_to_sign,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_username), Error::::InvalidUsername ); }); @@ -1564,31 +1481,29 @@ fn unaccepted_usernames_should_expire() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Governance)) ); run_to_block(now + expiration - 1); // Cannot be removed assert_noop!( - Identity::remove_expired_approval( - RuntimeOrigin::signed(account(1)), - full_username.clone() - ), + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), Error::::NotExpired ); @@ -1597,11 +1512,11 @@ fn unaccepted_usernames_should_expire() { // Anyone can remove assert_ok!(Identity::remove_expired_approval( RuntimeOrigin::signed(account(1)), - full_username.clone() + username.clone() )); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); }); } @@ -1620,14 +1535,13 @@ fn removing_dangling_usernames_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); @@ -1639,45 +1553,36 @@ fn removing_dangling_usernames_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true )); // Now they set up a second username. - let (username_two, username_two_to_sign) = test_username_of(b"43".to_vec(), suffix); + let username_two = test_username_of(b"43".to_vec(), suffix); // set up user and sign message - let signature_two = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_two_to_sign[..]).unwrap(), - ); + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username_two.clone(), - Some(signature_two) + username_two.clone().into(), + Some(signature_two), + true )); // The primary should still be the first one. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // But both usernames should look up the account. assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), + AccountOfUsername::::get::<&Username>(&username), Some(who_account.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), + AccountOfUsername::::get::<&Username>(&username_two), Some(who_account.clone()) ); @@ -1685,7 +1590,7 @@ fn removing_dangling_usernames_should_work() { assert_noop!( Identity::remove_dangling_username( RuntimeOrigin::signed(caller.clone()), - username_to_sign.clone() + username.clone() ), Error::::InvalidUsername ); @@ -1697,21 +1602,21 @@ fn removing_dangling_usernames_should_work() { assert!(IdentityOf::::get(who_account.clone()).is_none()); // The reverse lookup of the primary is gone. - assert!(AccountOfUsername::::get::<&Username>(&username_to_sign).is_none()); + assert!(AccountOfUsername::::get::<&Username>(&username).is_none()); // But the reverse lookup of the non-primary is still there assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), + AccountOfUsername::::get::<&Username>(&username_two), Some(who_account) ); // Now it can be removed assert_ok!(Identity::remove_dangling_username( RuntimeOrigin::signed(caller), - username_two_to_sign.clone() + username_two.clone() )); // And the reverse lookup is gone - assert!(AccountOfUsername::::get::<&Username>(&username_two_to_sign).is_none()); + assert!(AccountOfUsername::::get::<&Username>(&username_two).is_none()); }); } From e42fb1b58f6074a079487f04795d6bd11b9e9644 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 26 Aug 2024 20:03:32 +0300 Subject: [PATCH 04/44] Fix a couple of tests Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 15 +++--- substrate/frame/identity/src/tests.rs | 75 ++++++++++++++++++--------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index f19d2882b87a..93eb458ebb0e 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -283,15 +283,12 @@ pub mod pallet { pub type UsernameAuthorities = StorageMap<_, Twox64Concat, Suffix, AuthorityProperties, OptionQuery>; - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. + /// Reverse lookup from `username` to the `AccountId` that has registered it and the provider of + /// the username. The `owner` value should be a key in the `UsernameOf` map, but it may not if + /// the user has cleared their username or it has been removed. /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one + /// Multiple usernames may map to the same `AccountId`, but `UsernameOf` will only map to one /// primary username. - #[pallet::storage] - pub type AccountOfUsername = - StorageMap<_, Blake2_128Concat, Username, T::AccountId, OptionQuery>; - #[pallet::storage] pub type UsernameInfoOf = StorageMap< _, @@ -1116,7 +1113,7 @@ pub mod pallet { // Usernames must be unique. Ensure it's not taken. ensure!( - !AccountOfUsername::::contains_key(&bounded_username), + !UsernameInfoOf::::contains_key(&bounded_username), Error::::UsernameTaken ); ensure!( @@ -1196,7 +1193,7 @@ pub mod pallet { // ensure `username` maps to `origin` (i.e. has already been set by an authority). let who = ensure_signed(origin)?; let account_of_username = - AccountOfUsername::::get(&username).ok_or(Error::::NoUsername)?; + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?.owner; ensure!(who == account_of_username, Error::::InvalidUsername); UsernameOf::::insert(&who, username.clone()); Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 57adbe9eb927..02c3ba3b91cd 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1039,7 +1039,12 @@ fn set_username_with_signature_without_existing_identity_should_work() { // Even though user has no balance and no identity, they get a default one for free. assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Lookup from username to account works. - assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); }); } @@ -1082,7 +1087,12 @@ fn set_username_with_signature_with_existing_identity_should_work() { )); assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); - assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); }); } @@ -1154,7 +1164,12 @@ fn set_username_with_bytes_signature_should_work() { // `username_to_sign`. assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Likewise for the lookup. - assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who_account)); + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); }); } @@ -1199,7 +1214,11 @@ fn set_username_with_acceptance_should_work() { // Check Identity storage assert_eq!(UsernameOf::::get(&who), Some(username.clone())); // Check reverse lookup - assert_eq!(AccountOfUsername::::get::<&Username>(&username), Some(who)); + let expected_user_info = UsernameInformation { owner: who, provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); }); } @@ -1370,13 +1389,15 @@ fn setting_primary_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // Lookup from both works. + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; assert_eq!( - AccountOfUsername::::get::<&Username>(&first_username), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_username), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info.clone()) ); assert_ok!(Identity::set_primary_username( @@ -1389,12 +1410,12 @@ fn setting_primary_should_work() { // Lookup from both still works. assert_eq!( - AccountOfUsername::::get::<&Username>(&first_username), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_username), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) ); }); } @@ -1442,13 +1463,17 @@ fn must_own_primary() { )); // Ensure that both users have their usernames. + let expected_pi_info = + UsernameInformation { owner: pi_account.clone(), provider: Provider::Governance }; assert_eq!( - AccountOfUsername::::get::<&Username>(&pi_username), - Some(pi_account.clone()) + UsernameInfoOf::::get::<&Username>(&pi_username), + Some(expected_pi_info) ); + let expected_e_info = + UsernameInformation { owner: e_account.clone(), provider: Provider::Governance }; assert_eq!( - AccountOfUsername::::get::<&Username>(&e_username), - Some(e_account.clone()) + UsernameInfoOf::::get::<&Username>(&e_username), + Some(expected_e_info) ); // Cannot set primary to a username that does not exist. @@ -1577,13 +1602,15 @@ fn removing_dangling_usernames_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // But both usernames should look up the account. + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) ); // Someone tries to remove it, but they can't @@ -1602,12 +1629,12 @@ fn removing_dangling_usernames_should_work() { assert!(IdentityOf::::get(who_account.clone()).is_none()); // The reverse lookup of the primary is gone. - assert!(AccountOfUsername::::get::<&Username>(&username).is_none()); + assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); // But the reverse lookup of the non-primary is still there assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info) ); // Now it can be removed @@ -1617,6 +1644,6 @@ fn removing_dangling_usernames_should_work() { )); // And the reverse lookup is gone - assert!(AccountOfUsername::::get::<&Username>(&username_two).is_none()); + assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); }); } From cfa74067d520e403316f51299d728fbf68010aad Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 26 Aug 2024 20:36:48 +0300 Subject: [PATCH 05/44] All tests pass Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 28 ++++++++++++-------- substrate/frame/identity/src/lib.rs | 16 +++++++---- substrate/frame/identity/src/tests.rs | 9 +++++-- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index ab04000c2281..d7f7ec47484a 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -593,12 +593,12 @@ mod benchmarks { assert_ok!(Identity::::add_username_authority( origin.clone(), authority_lookup.clone(), - suffix, + suffix.clone(), allocation )); #[extrinsic_call] - _(origin as T::RuntimeOrigin, authority_lookup); + _(origin as T::RuntimeOrigin, suffix.into(), authority_lookup); assert_last_event::(Event::::AuthorityRemoved { authority }.into()); Ok(()) @@ -636,7 +636,13 @@ mod benchmarks { assert!(signature.verify(&bounded_username[..], &public.into())); #[extrinsic_call] - _(RawOrigin::Signed(authority.clone()), who_lookup, username, Some(signature.into())); + _( + RawOrigin::Signed(authority.clone()), + who_lookup, + bounded_username.clone().into(), + Some(signature.into()), + true, + ); assert_has_event::( Event::::UsernameSet { @@ -656,7 +662,7 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + Identity::::queue_acceptance(&caller, username.clone(), Provider::Governance); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), username.clone()); @@ -669,7 +675,7 @@ mod benchmarks { fn remove_expired_approval() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + Identity::::queue_acceptance(&caller, username.clone(), Provider::Governance); let expected_expiration = frame_system::Pallet::::block_number() + T::PendingUsernameExpiration::get(); @@ -690,8 +696,8 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::insert_username(&caller, first_username, Provider::Governance); + Identity::::insert_username(&caller, second_username.clone(), Provider::Governance); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), second_username.clone()); @@ -709,11 +715,11 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::insert_username(&caller, first_username.clone(), Provider::Governance); + Identity::::insert_username(&caller, second_username.clone(), Provider::Governance); - // User calls `clear_identity`, leaving their second username as "dangling" - Identity::::clear_identity(RawOrigin::Signed(caller.clone()).into())?; + // Root calls `kill_username`, leaving their second username as "dangling" + Identity::::kill_username(RawOrigin::Root.into(), first_username.into())?; #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), second_username.clone()); diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 93eb458ebb0e..a5f49495ed1e 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1200,18 +1200,21 @@ pub mod pallet { Ok(()) } - /// Remove a username that corresponds to an account with no identity. Exists when a user - /// gets a username but then calls `clear_identity`. + /// Remove a username that corresponds to an account with no primary username. Exists when a + /// user gets a username but then the authority removes it. #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::remove_dangling_username())] pub fn remove_dangling_username( origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - ensure!(!UsernameOf::::contains_key(&who), Error::::InvalidUsername); + let _ = ensure_signed(origin)?; let username_info = UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + ensure!( + !UsernameOf::::contains_key(&username_info.owner), + Error::::InvalidUsername + ); match username_info.provider { Provider::Authority(username_deposit) => { let suffix = @@ -1229,7 +1232,10 @@ pub mod pallet { }, Provider::System => return Err(Error::::InvalidTarget.into()), } - Self::deposit_event(Event::DanglingUsernameRemoved { who: who.clone(), username }); + Self::deposit_event(Event::DanglingUsernameRemoved { + who: username_info.owner.clone(), + username, + }); Ok(Pays::No.into()) } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 02c3ba3b91cd..efd703cbfdc9 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1285,7 +1285,9 @@ fn invalid_usernames_should_be_rejected() { } // valid one works - let valid_username = b"testusernametestusernametes".to_vec(); + let mut valid_username = b"testusernametestusernametes".to_vec(); + valid_username.push(b'.'); + valid_username.extend(valid_suffix); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who, @@ -1623,11 +1625,14 @@ fn removing_dangling_usernames_should_work() { ); // Now the user calls `clear_identity` - assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(who_account.clone()),)); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(who_account.clone()))); // Identity is gone assert!(IdentityOf::::get(who_account.clone()).is_none()); + // Kill the username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username.clone().into())); + // The reverse lookup of the primary is gone. assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); From 7d351aee3b308d8f68b2b1c32acd86a3aee24c28 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 27 Aug 2024 18:42:55 +0300 Subject: [PATCH 06/44] Add tests related to username deletion Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 27 +- substrate/frame/identity/src/tests.rs | 366 ++++++++++++++++++++++++++ 2 files changed, 386 insertions(+), 7 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index a5f49495ed1e..4b2c7a372701 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1249,9 +1249,8 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - ensure!(UsernameOf::::contains_key(&who), Error::::InvalidUsername); let username_info = - UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?; let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; let authority_account = UsernameAuthorities::::get(&suffix) .map(|auth_info| auth_info.account_id) @@ -1285,13 +1284,20 @@ pub mod pallet { UnbindingUsernames::::take(&username).ok_or(Error::::NotUnbinding)?; let now = frame_system::Pallet::::block_number(); ensure!( - grace_period_start.saturating_add(T::UsernameGracePeriod::get()) >= now, + now >= grace_period_start.saturating_add(T::UsernameGracePeriod::get()), Error::::TooEarly ); let username_info = UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; - // Maybe it's a primary username, maybe not. We remove it anyway. - let _ = UsernameOf::::take(&username_info.owner); + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if match maybe_primary { + Some(primary) if *primary == username => true, + _ => false, + } { + *maybe_primary = None; + } + }); match username_info.provider { Provider::Authority(username_deposit) => { let suffix = @@ -1323,8 +1329,15 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; let username_info = UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; - // Maybe it's a primary username, maybe not. We remove it anyway. - let _ = UsernameOf::::take(&username_info.owner); + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if match maybe_primary { + Some(primary) if *primary == username => true, + _ => false, + } { + *maybe_primary = None; + } + }); let _ = UnbindingUsernames::::take(&username); match username_info.provider { Provider::Authority(username_deposit) => { diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index efd703cbfdc9..7797f8de79ef 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1652,3 +1652,369 @@ fn removing_dangling_usernames_should_work() { assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); }); } + +#[test] +fn kill_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // set up first authority + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let second_authority = account(200); + Balances::make_free_balance_be(&second_authority, initial_authority_balance); + let second_suffix: Vec = b"abc".to_vec(); + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + second_authority.clone(), + second_suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + + // set up username + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // set up user and sign message + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // Now they set up a second username. + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); + + // set up user and sign message + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit + ); + + // Now they set up a third username with another authority. + let username_three = test_username_of(b"42".to_vec(), second_suffix.clone()); + + // set up user and sign message + let signature_three = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_three[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(second_authority.clone()), + who_account.clone(), + username_three.clone().into(), + Some(signature_three), + true + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit + ); + assert_eq!(Balances::free_balance(second_authority.clone()), initial_authority_balance); + + // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::Authority(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) + ); + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) + ); + + // Regular accounts can't kill a username, not even the authority that granted it. + assert_noop!( + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't kill a username that doesn't exist. + assert_noop!( + Identity::kill_username( + RuntimeOrigin::root(), + test_username_of(b"999".to_vec(), suffix.clone()) + ), + Error::::NoUsername + ); + + // Unbind the second username. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + + // Kill the second username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_two.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); + // The unbinding map entry is gone. + assert!(UnbindingUsernames::::get::<&Username>(&username).is_none()); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), username_deposit); + + // But the reverse lookup of the primary is still there + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + assert!(UsernameInfoOf::::contains_key(&username_three)); + + // Kill the first, primary username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); + assert!(!UsernameOf::::contains_key(&who_account)); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), 0); + + // But the reverse lookup of the third and final username is still there + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_three), + Some(expected_user_info) + ); + + // Kill the third and last username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_three.clone().into())); + // Everything is gone. + assert!(!UsernameInfoOf::::contains_key(&username_three)); + }); +} + +#[test] +fn unbind_and_remove_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // Now they set up a second username. + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); + + // Set up user and sign message. + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + true + )); + // Second one is free. + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::Authority(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) + ); + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) + ); + + // Regular accounts can't kill a username, not even the authority that granted it. + assert_noop!( + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't unbind a username that doesn't exist. + let dummy_suffix = b"abc".to_vec(); + let dummy_username = test_username_of(b"999".to_vec(), dummy_suffix.clone()); + let dummy_authority = account(78); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() + ), + Error::::NoUsername + ); + + let dummy_suffix: Suffix = dummy_suffix.try_into().unwrap(); + // Only the authority that granted the username can unbind it. + UsernameInfoOf::::insert( + dummy_username.clone(), + UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }, + ); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Simulate a dummy authority. + UsernameAuthorities::::insert( + dummy_suffix.clone(), + AuthorityProperties { account_id: dummy_authority.clone(), allocation: 10 }, + ); + // But try to remove the dummy username as a different authority, not the one that + // originally granted the username. + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Clean up storage. + let _ = UsernameInfoOf::::take(dummy_username.clone()); + let _ = UsernameAuthorities::::take(dummy_suffix); + + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + assert_eq!(System::block_number(), 1); + assert_eq!(UnbindingUsernames::::get(&username_two), Some(1)); + + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username_two.clone()), + Error::::TooEarly + ); + + // Advance the block number to simulate the grace period passing. + System::set_block_number(3); + + // Simulate a dangling entry in the unbinding map without an actual username registered. + UnbindingUsernames::::insert(dummy_username.clone(), 0); + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), dummy_username.clone()), + Error::::NoUsername + ); + // Clean up storage. + UnbindingUsernames::::remove(dummy_username); + + let suffix: Suffix = suffix.try_into().unwrap(); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username( + RuntimeOrigin::signed(account(0)), + username_two.clone() + )); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username_two)); + assert!(!UsernameInfoOf::::contains_key(&username_two)); + // Primary username was preserved. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // The username was granted through a governance allocation, so no deposit was released. + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + // Allocation wasn't refunded. + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + + // Unbind the first username as well. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() + )); + assert_eq!(UnbindingUsernames::::get(&username), Some(3)); + // Advance the block number to simulate the grace period passing. + System::set_block_number(5); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone())); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username)); + assert!(!UsernameInfoOf::::contains_key(&username)); + // Primary username was also removed. + assert!(!UsernameOf::::contains_key(&who_account)); + // The username deposit was released. + assert_eq!(Balances::free_balance(authority.clone()), initial_authority_balance); + // Allocation didn't change. + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + }); +} From 5119afe3226f2158fe357c17621a4f94c04ed2b7 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 27 Aug 2024 19:08:39 +0300 Subject: [PATCH 07/44] Fix tests for accepting usernames Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 8 +- substrate/frame/identity/src/tests.rs | 141 +++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 7 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 4b2c7a372701..38694b059af5 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1167,8 +1167,12 @@ pub mod pallet { ensure!(now > expiration, Error::::NotExpired); match provider { Provider::Authority(deposit) => { - T::Currency::unreserve(&who, deposit); - let err_amount = T::Currency::unreserve(&who, deposit); + let suffix = Self::suffix_of_username(&username) + .ok_or(Error::::InvalidUsername)?; + let authority_account = UsernameAuthorities::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + let err_amount = T::Currency::unreserve(&authority_account, deposit); debug_assert!(err_amount.is_zero()); }, Provider::Governance => { diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 7797f8de79ef..5d165eb5d32e 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1177,7 +1177,9 @@ fn set_username_with_bytes_signature_should_work() { fn set_username_with_acceptance_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1188,12 +1190,12 @@ fn set_username_with_acceptance_should_work() { )); // set up username - let username = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), username.clone().into(), None, @@ -1219,6 +1221,51 @@ fn set_username_with_acceptance_should_work() { UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) ); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + + let second_caller = account(99); + let second_username = test_username_of(b"102".to_vec(), suffix); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_caller.clone(), + second_username.clone().into(), + None, + false, + )); + + // Should be pending + let username_deposit = ::UsernameDeposit::get(); + assert_eq!( + PendingUsernames::::get::<&Username>(&second_username), + Some((second_caller.clone(), expiration, Provider::Authority(username_deposit))) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // Now the user can accept + assert_ok!(Identity::accept_username( + RuntimeOrigin::signed(second_caller.clone()), + second_username.clone() + )); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&second_username).is_none()); + // Check Identity storage + assert_eq!(UsernameOf::::get(&second_caller), Some(second_username.clone())); + // Check reverse lookup + let expected_user_info = UsernameInformation { + owner: second_caller, + provider: Provider::Authority(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); }); } @@ -1494,10 +1541,12 @@ fn must_own_primary() { } #[test] -fn unaccepted_usernames_should_expire() { +fn unaccepted_usernames_through_grant_should_expire() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1508,17 +1557,22 @@ fn unaccepted_usernames_should_expire() { )); // set up username - let username = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); + let suffix: Suffix = suffix.try_into().unwrap(); + + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), username.clone().into(), None, true, )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); // Should be pending assert_eq!( @@ -1541,6 +1595,83 @@ fn unaccepted_usernames_should_expire() { RuntimeOrigin::signed(account(1)), username.clone() )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + }); +} + +#[test] +fn unaccepted_usernames_through_deposit_should_expire() { + new_test_ext().execute_with(|| { + // set up authority + let initial_authority_balance = 1000; + let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + // set up username + let username = test_username_of(b"101".to_vec(), suffix.clone()); + let now = frame_system::Pallet::::block_number(); + let expiration = now + <::PendingUsernameExpiration as Get>::get(); + + let suffix: Suffix = suffix.try_into().unwrap(); + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who.clone(), + username.clone().into(), + None, + false, + )); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + + // Should be pending + assert_eq!( + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Authority(username_deposit))) + ); + + run_to_block(now + expiration - 1); + + // Cannot be removed + assert_noop!( + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), + Error::::NotExpired + ); + + run_to_block(now + expiration); + + // Anyone can remove + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(Balances::reserved_balance(&authority), username_deposit); + assert_ok!(Identity::remove_expired_approval( + RuntimeOrigin::signed(account(1)), + username.clone() + )); + // Deposit was refunded + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); // No more pending assert!(PendingUsernames::::get::<&Username>(&username).is_none()); From 6b6495275d3a8a0f6529b38cdfdc7016bb27c0d7 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 27 Aug 2024 20:09:21 +0300 Subject: [PATCH 08/44] Add the rest of unit tests Signed-off-by: georgepisaltu --- substrate/frame/identity/src/tests.rs | 131 +++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 5d165eb5d32e..d5cc814e51c6 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1009,7 +1009,9 @@ fn adding_and_removing_authorities_should_work() { fn set_username_with_signature_without_existing_identity_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1020,7 +1022,7 @@ fn set_username_with_signature_without_existing_identity_should_work() { )); // set up username - let username = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); @@ -1029,14 +1031,15 @@ fn set_username_with_signature_without_existing_identity_should_work() { MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who_account.clone(), username.clone().into(), Some(signature), true, )); - // Even though user has no balance and no identity, they get a default one for free. + // Even though user has no balance and no identity, the authority provides the username for + // free. assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Lookup from username to account works. let expected_user_info = @@ -1045,6 +1048,61 @@ fn set_username_with_signature_without_existing_identity_should_work() { UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) ); + // No balance was reserved. + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // But the allocation decreased. + assert_eq!( + UsernameAuthorities::::get(&Identity::suffix_of_username(&username).unwrap()) + .unwrap() + .allocation, + 9 + ); + + // do the same for a username with a deposit + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // set up username + let second_username = test_username_of(b"84".to_vec(), suffix.clone()); + + // set up user and sign message + let public = sr25519_generate(1.into(), None); + let second_who: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(1.into(), &public, &second_username[..]).unwrap()); + // don't use the allocation this time + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_who.clone(), + second_username.clone().into(), + Some(signature), + false, + )); + + // Even though user has no balance and no identity, the authority placed the deposit for + // them. + assert_eq!(UsernameOf::::get(&second_who), Some(second_username.clone())); + // Lookup from username to account works. + let expected_user_info = UsernameInformation { + owner: second_who, + provider: Provider::Authority(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + // The username deposit was reserved. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // But the allocation was preserved. + assert_eq!( + UsernameAuthorities::::get( + &Identity::suffix_of_username(&second_username).unwrap() + ) + .unwrap() + .allocation, + 9 + ); }); } @@ -1096,6 +1154,73 @@ fn set_username_with_signature_with_existing_identity_should_work() { }); } +#[test] +fn set_username_through_deposit_with_existing_identity_should_work() { + new_test_ext().execute_with(|| { + // set up authority + let initial_authority_balance = 1000; + let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + // set up username + let username = test_username_of(b"42".to_vec(), suffix); + + // set up user and sign message + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + let ten_info = infoof_ten(); + let expected_identity_deposit = Identity::calculate_identity_deposit(&ten_info); + assert_ok!(Identity::set_identity( + RuntimeOrigin::signed(who_account.clone()), + Box::new(ten_info.clone()) + )); + assert_eq!( + expected_identity_deposit, + IdentityOf::::get(&who_account).unwrap().deposit + ); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false, + )); + + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // The authority placed the deposit for the username. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // No extra balance was reserved from the user for the username. + assert_eq!(Balances::free_balance(&who_account), 1000 - expected_identity_deposit); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + let expected_user_info = UsernameInformation { + owner: who_account, + provider: Provider::Authority(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + }); +} + #[test] fn set_username_with_bytes_signature_should_work() { new_test_ext().execute_with(|| { From 083b168f26820a800327e8b70e68d2d9f824635f Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 28 Aug 2024 18:08:03 +0300 Subject: [PATCH 09/44] Fix benches for new changes to usernames Signed-off-by: georgepisaltu --- .../src/weights/pallet_identity.rs | 13 +- .../src/weights/pallet_identity.rs | 13 +- .../rococo/src/weights/pallet_identity.rs | 13 +- .../westend/src/weights/pallet_identity.rs | 13 +- substrate/frame/identity/src/benchmarking.rs | 176 +++++++++++++++++- substrate/frame/identity/src/lib.rs | 40 ++-- substrate/frame/identity/src/weights.rs | 33 +++- 7 files changed, 268 insertions(+), 33 deletions(-) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs index 1e8ba87e2510..a59e2e9c958e 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -406,4 +406,13 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs index 1e8ba87e2510..a59e2e9c958e 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -406,4 +406,13 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index b334e21ea031..4a06fbac86a4 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -362,7 +362,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -390,7 +390,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -428,4 +428,13 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index dc7061615c95..493561ce2f5a 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -366,7 +366,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -394,7 +394,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -432,4 +432,13 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } } diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index d7f7ec47484a..7ac665d04a77 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -605,7 +605,7 @@ mod benchmarks { } #[benchmark] - fn set_username_for() -> Result<(), BenchmarkError> { + fn set_username_for(p: Linear<0, 1>) -> Result<(), BenchmarkError> { // Set up a username authority. let auth_origin = T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); @@ -613,6 +613,7 @@ mod benchmarks { let authority_lookup = T::Lookup::unlookup(authority.clone()); let suffix = bench_suffix(); let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); Identity::::add_username_authority( auth_origin, @@ -634,14 +635,19 @@ mod benchmarks { // Verify signature here to avoid surprise errors at runtime assert!(signature.verify(&bounded_username[..], &public.into())); + let use_allocation = match p { + 0 => false, + 1 => true, + _ => unreachable!(), + }; #[extrinsic_call] - _( + set_username_for( RawOrigin::Signed(authority.clone()), who_lookup, bounded_username.clone().into(), Some(signature.into()), - true, + use_allocation, ); assert_has_event::( @@ -654,6 +660,15 @@ mod benchmarks { assert_has_event::( Event::::PrimaryUsernameSet { who: who_account, username: bounded_username }.into(), ); + if use_allocation { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + } else { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - T::UsernameDeposit::get() + ); + } Ok(()) } @@ -672,10 +687,35 @@ mod benchmarks { } #[benchmark] - fn remove_expired_approval() -> Result<(), BenchmarkError> { + fn remove_expired_approval(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + let caller: T::AccountId = whitelisted_caller(); - let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone(), Provider::Governance); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::Authority(username_deposit) + }, + 1 => Provider::Governance, + _ => unreachable!(), + }; + Identity::::queue_acceptance(&caller, username.clone(), provider); let expected_expiration = frame_system::Pallet::::block_number() + T::PendingUsernameExpiration::get(); @@ -686,6 +726,16 @@ mod benchmarks { _(RawOrigin::Signed(caller.clone()), username); assert_last_event::(Event::::PreapprovalExpired { whose: caller }.into()); + match p { + 0 => { + assert_eq!(T::Currency::free_balance(&authority), BalanceOf::::max_value()); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } Ok(()) } @@ -730,5 +780,119 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn unbind_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::Authority(username_deposit), + ); + + #[extrinsic_call] + _(RawOrigin::Signed(authority), username.clone()); + + assert_last_event::(Event::::UsernameUnbound { username }.into()); + Ok(()) + } + + #[benchmark] + fn remove_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let authority: T::AccountId = account("authority", 0, SEED); + let suffix = bench_suffix(); + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::Authority(username_deposit), + ); + let now = frame_system::Pallet::::block_number(); + UnbindingUsernames::::insert(&username, now); + + frame_system::Pallet::::set_block_number(now + T::UsernameGracePeriod::get()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), username.clone()); + + assert_last_event::(Event::::UsernameRemoved { username }.into()); + Ok(()) + } + + #[benchmark] + fn kill_username(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::Authority(username_deposit) + }, + 1 => Provider::Governance, + _ => unreachable!(), + }; + Identity::::insert_username(&caller, username.clone(), provider); + UnbindingUsernames::::insert(&username, frame_system::Pallet::::block_number()); + + #[extrinsic_call] + _(RawOrigin::Root, username.clone()); + + assert_last_event::(Event::::UsernameKilled { username }.into()); + match p { + 0 => { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - username_deposit + ); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } + Ok(()) + } + impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 38694b059af5..873c24712d8d 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -416,6 +416,12 @@ pub mod pallet { /// A dangling username (as in, a username corresponding to an account that has removed its /// identity) has been removed. DanglingUsernameRemoved { who: T::AccountId, username: Username }, + /// A username has been unbound. + UsernameUnbound { username: Username }, + /// A username has been removed. + UsernameRemoved { username: Username }, + /// A username has been killed. + UsernameKilled { username: Username }, } #[pallet::call] @@ -1078,7 +1084,7 @@ pub mod pallet { /// - When combined with the suffix of the issuing authority be _less than_ the /// `MaxUsernameLength`. #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::set_username_for())] + #[pallet::weight(T::WeightInfo::set_username_for(if *use_allocation { 1 } else { 0 }))] pub fn set_username_for( origin: OriginFor, who: AccountIdLookupOf, @@ -1156,7 +1162,7 @@ pub mod pallet { /// accepted by the user and must now be beyond its expiration. The call must include the /// full username, as in `username.suffix`. #[pallet::call_index(19)] - #[pallet::weight(T::WeightInfo::remove_expired_approval())] + #[pallet::weight(T::WeightInfo::remove_expired_approval(0))] pub fn remove_expired_approval( origin: OriginFor, username: Username, @@ -1165,7 +1171,7 @@ pub mod pallet { if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); - match provider { + let actual_weight = match provider { Provider::Authority(deposit) => { let suffix = Self::suffix_of_username(&username) .ok_or(Error::::InvalidUsername)?; @@ -1174,17 +1180,19 @@ pub mod pallet { .ok_or(Error::::NotUsernameAuthority)?; let err_amount = T::Currency::unreserve(&authority_account, deposit); debug_assert!(err_amount.is_zero()); + T::WeightInfo::remove_expired_approval(0) }, Provider::Governance => { - // We don't refund the allocation, it is lost. + // We don't refund the allocation, it is lost, but we refund some weight. + T::WeightInfo::remove_expired_approval(1) }, Provider::System => { // Usernames added by the system shouldn't ever be expired. return Err(Error::::InvalidTarget.into()); }, - } + }; Self::deposit_event(Event::PreapprovalExpired { whose: who.clone() }); - Ok(Pays::No.into()) + Ok((Some(actual_weight), Pays::No).into()) } else { Err(Error::::NoUsername.into()) } @@ -1247,7 +1255,7 @@ pub mod pallet { /// Once the grace period has passed, the username can be permanently deleted by calling /// [remove_username](crate::Call::remove_username). #[pallet::call_index(22)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] + #[pallet::weight(T::WeightInfo::unbind_username())] pub fn unbind_username( origin: OriginFor, username: Username, @@ -1273,12 +1281,13 @@ pub mod pallet { }, Provider::System => return Err(Error::::InvalidTarget.into()), } + Self::deposit_event(Event::UsernameUnbound { username }); Ok(Pays::Yes.into()) } /// Permanently delete a username which has been unbinding for longer than the grace period. #[pallet::call_index(23)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] + #[pallet::weight(T::WeightInfo::remove_username())] pub fn remove_username( origin: OriginFor, username: Username, @@ -1319,13 +1328,14 @@ pub mod pallet { }, Provider::System => return Err(Error::::InvalidTarget.into()), } + Self::deposit_event(Event::UsernameRemoved { username }); Ok(Pays::No.into()) } /// Call with [ForceOrigin](crate::Config::ForceOrigin) privileges which deletes a username /// and slashes any deposit associated with it. #[pallet::call_index(24)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] + #[pallet::weight(T::WeightInfo::kill_username(0))] pub fn kill_username( origin: OriginFor, username: Username, @@ -1343,7 +1353,7 @@ pub mod pallet { } }); let _ = UnbindingUsernames::::take(&username); - match username_info.provider { + let actual_weight = match username_info.provider { Provider::Authority(username_deposit) => { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; @@ -1354,15 +1364,19 @@ pub mod pallet { T::Currency::slash_reserved(&authority_account, username_deposit).0, ); } + T::WeightInfo::kill_username(0) }, Provider::Governance => { - // We don't refund the allocation, it is lost. + // We don't refund the allocation, it is lost, but we do refund some weight. + T::WeightInfo::kill_username(1) }, Provider::System => { // Force origin can remove system usernames. + T::WeightInfo::kill_username(1) }, - } - Ok(Pays::No.into()) + }; + Self::deposit_event(Event::UsernameKilled { username }); + Ok((Some(actual_weight), Pays::No).into()) } } } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 008d5465bb4f..5d79f177638e 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -69,11 +69,14 @@ pub trait WeightInfo { fn quit_sub(s: u32, ) -> Weight; fn add_username_authority() -> Weight; fn remove_username_authority() -> Weight; - fn set_username_for() -> Weight; + fn set_username_for(p: u32) -> Weight; fn accept_username() -> Weight; - fn remove_expired_approval() -> Weight; + fn remove_expired_approval(p: u32) -> Weight; fn set_primary_username() -> Weight; fn remove_dangling_username() -> Weight; + fn unbind_username() -> Weight; + fn remove_username() -> Weight; + fn kill_username(p: u32) -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -380,7 +383,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -406,7 +409,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3550` @@ -441,6 +444,15 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32) -> Weight { + Weight::zero() + } } // For backwards compatibility and tests. @@ -746,7 +758,7 @@ impl WeightInfo for () { /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -772,7 +784,7 @@ impl WeightInfo for () { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3550` @@ -807,4 +819,13 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32) -> Weight { + Weight::zero() + } } From 626961950fffea0d3281bf25570673d1c79559a7 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 28 Aug 2024 21:29:12 +0300 Subject: [PATCH 10/44] Add initial migration code Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 180 ++++++++++++++++++++++ substrate/frame/identity/src/weights.rs | 14 ++ 2 files changed, 194 insertions(+) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index d05146b74e77..f0239c7f07ad 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -25,6 +25,8 @@ use codec::{Decode, Encode}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +pub const PALLET_MIGRATIONS_ID: &[u8; 15] = b"pallet-identity"; + pub mod versioned { use super::*; @@ -144,3 +146,181 @@ pub mod v1 { } } } + +pub mod v2 { + use super::*; + use frame_support::{ + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, + storage_alias, + weights::WeightMeter, + }; + + mod v1 { + use super::*; + + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ( + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + Option>, + ), + OptionQuery, + >; + + #[storage_alias] + pub type UsernameAuthorities = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + AuthorityProperties>, + OptionQuery, + >; + + #[storage_alias] + pub type AccountOfUsername = StorageMap< + Pallet, + Blake2_128Concat, + Username, + ::AccountId, + OptionQuery, + >; + + #[storage_alias] + pub type PendingUsernames = StorageMap< + Pallet, + Blake2_128Concat, + Username, + (::AccountId, BlockNumberFor), + OptionQuery, + >; + } + + #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] + pub enum MigrationState { + Authority(A), + FinishedAuthorities, + // TODO: All identities + Username(U), + Finished, + } + + pub struct LazyMigrationV2(PhantomData<(T, W)>); + impl SteppedMigration for LazyMigrationV2 { + type Cursor = MigrationState>; + type Identifier = MigrationId<15>; + + fn id() -> Self::Identifier { + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 1, version_to: 2 } + } + + fn step( + mut cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + let required = match &cursor { + Some(state) => Self::required_weight(&state), + None => W::migration_v2_authority_step(), + }; + + if meter.remaining().any_lt(required) { + return Err(SteppedMigrationError::InsufficientWeight { required }); + } + + loop { + let required = match &cursor { + Some(state) => Self::required_weight(&state), + None => W::migration_v2_authority_step(), + }; + + if meter.try_consume(required).is_err() { + break; + } + + let next = match &cursor { + None => Self::authority_step(None), + Some(MigrationState::Authority(maybe_last_authority)) => + Self::authority_step(Some(maybe_last_authority)), + Some(MigrationState::FinishedAuthorities) => Self::username_step(None), + Some(MigrationState::Username(maybe_last_username)) => + Self::username_step(Some(maybe_last_username)), + Some(MigrationState::Finished) => return Ok(None), + }; + + cursor = Some(next); + } + + Ok(cursor) + } + } + + impl LazyMigrationV2 { + fn required_weight(step: &MigrationState>) -> Weight { + match step { + MigrationState::Authority(_) => W::migration_v2_authority_step(), + MigrationState::FinishedAuthorities | + MigrationState::Username(_) | + MigrationState::Finished => W::migration_v2_username_step(), + } + } + + fn username_step( + maybe_last_key: Option<&Username>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + v1::AccountOfUsername::::iter_from(v1::AccountOfUsername::::hashed_key_for( + last_key, + )) + } else { + v1::AccountOfUsername::::iter() + }; + + if let Some((username, owner_account)) = iter.next() { + match v1::IdentityOf::::take(&owner_account) { + Some((identity, Some(primary_username))) => { + if identity.deposit > BalanceOf::::zero() { + IdentityOf::::insert(&owner_account, identity); + } + UsernameOf::::insert(&owner_account, primary_username); + }, + _ => {}, + } + let username_info = + UsernameInformation { owner: owner_account, provider: Provider::Governance }; + UsernameInfoOf::::insert(&username, username_info); + + MigrationState::Username(username) + } else { + MigrationState::Finished + } + } + + fn authority_step( + maybe_last_key: Option<&T::AccountId>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + v1::UsernameAuthorities::::iter_from( + v1::UsernameAuthorities::::hashed_key_for(last_key), + ) + } else { + v1::UsernameAuthorities::::iter() + }; + if let Some((authority_account, properties)) = iter.next() { + let suffix = properties.account_id; + let allocation = properties.allocation; + let new_properties = + AuthorityProperties { account_id: authority_account.clone(), allocation }; + UsernameAuthorities::::insert(&suffix, new_properties); + MigrationState::Authority(authority_account) + } else { + MigrationState::FinishedAuthorities + } + } + } +} diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 5d79f177638e..d46b568b105a 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -77,6 +77,8 @@ pub trait WeightInfo { fn unbind_username() -> Weight; fn remove_username() -> Weight; fn kill_username(p: u32) -> Weight; + fn migration_v2_authority_step() -> Weight; + fn migration_v2_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -453,6 +455,12 @@ impl WeightInfo for SubstrateWeight { fn kill_username(_p: u32) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } } // For backwards compatibility and tests. @@ -828,4 +836,10 @@ impl WeightInfo for () { fn kill_username(_p: u32) -> Weight { Weight::zero() } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } } From 8e326af70703e1cae3f75f73c811a3a96476a42e Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 29 Aug 2024 11:08:29 +0300 Subject: [PATCH 11/44] Finish writing migration code Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 105 +++++++++++++++++++--- substrate/frame/identity/src/weights.rs | 21 +++++ 2 files changed, 112 insertions(+), 14 deletions(-) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index f0239c7f07ad..6592d3d89b0e 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -206,8 +206,13 @@ pub mod v2 { pub enum MigrationState { Authority(A), FinishedAuthorities, - // TODO: All identities + Identity(A), + FinishedIdentities, Username(U), + FinishedUsernames, + CleanupUsernames(U), + FinishedCleanupUsernames, + CleanupIdentitiesWithoutUsername(A), Finished, } @@ -247,9 +252,19 @@ pub mod v2 { None => Self::authority_step(None), Some(MigrationState::Authority(maybe_last_authority)) => Self::authority_step(Some(maybe_last_authority)), - Some(MigrationState::FinishedAuthorities) => Self::username_step(None), + Some(MigrationState::FinishedAuthorities) => Self::identity_step(None), + Some(MigrationState::Identity(maybe_last_identity)) => + Self::identity_step(Some(maybe_last_identity)), + Some(MigrationState::FinishedIdentities) => Self::username_step(None), Some(MigrationState::Username(maybe_last_username)) => Self::username_step(Some(maybe_last_username)), + Some(MigrationState::FinishedUsernames) => Self::cleanup_username_step(None), + Some(MigrationState::CleanupUsernames(maybe_last_username)) => + Self::cleanup_username_step(Some(maybe_last_username)), + Some(MigrationState::FinishedCleanupUsernames) => + Self::cleanup_identity_step(None), + Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => + Self::identity_step(Some(maybe_last_identity)), Some(MigrationState::Finished) => return Ok(None), }; @@ -264,9 +279,15 @@ pub mod v2 { fn required_weight(step: &MigrationState>) -> Weight { match step { MigrationState::Authority(_) => W::migration_v2_authority_step(), - MigrationState::FinishedAuthorities | - MigrationState::Username(_) | - MigrationState::Finished => W::migration_v2_username_step(), + MigrationState::FinishedAuthorities | MigrationState::Identity(_) => + W::migration_v2_identity_step(), + MigrationState::FinishedIdentities | MigrationState::Username(_) => + W::migration_v2_username_step(), + MigrationState::FinishedUsernames | MigrationState::CleanupUsernames(_) => + W::migration_v2_cleanup_username_step(), + MigrationState::FinishedCleanupUsernames | + MigrationState::CleanupIdentitiesWithoutUsername(_) | + MigrationState::Finished => W::migration_v2_cleanup_identity_step(), } } @@ -282,15 +303,6 @@ pub mod v2 { }; if let Some((username, owner_account)) = iter.next() { - match v1::IdentityOf::::take(&owner_account) { - Some((identity, Some(primary_username))) => { - if identity.deposit > BalanceOf::::zero() { - IdentityOf::::insert(&owner_account, identity); - } - UsernameOf::::insert(&owner_account, primary_username); - }, - _ => {}, - } let username_info = UsernameInformation { owner: owner_account, provider: Provider::Governance }; UsernameInfoOf::::insert(&username, username_info); @@ -301,6 +313,29 @@ pub mod v2 { } } + fn identity_step( + maybe_last_key: Option<&T::AccountId>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + v1::IdentityOf::::iter_from(v1::IdentityOf::::hashed_key_for(last_key)) + } else { + v1::IdentityOf::::iter() + }; + + if let Some((account, (identity, maybe_username))) = iter.next() { + if identity.deposit > BalanceOf::::zero() { + IdentityOf::::insert(&account, identity); + } + if let Some(primary_username) = maybe_username { + UsernameOf::::insert(&account, primary_username); + } + + MigrationState::Identity(account) + } else { + MigrationState::FinishedIdentities + } + } + fn authority_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState> { @@ -322,5 +357,47 @@ pub mod v2 { MigrationState::FinishedAuthorities } } + + fn cleanup_username_step( + maybe_last_key: Option<&Username>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) + } else { + UsernameInfoOf::::iter() + }; + + if let Some((username, username_info)) = iter.next() { + let _ = v1::AccountOfUsername::::take(&username); + match UsernameOf::::get(&username_info.owner) { + Some(primary_username) if primary_username == username => { + let _ = v1::IdentityOf::::take(&username_info.owner); + }, + _ => {}, + } + + MigrationState::CleanupUsernames(username) + } else { + MigrationState::FinishedCleanupUsernames + } + } + + fn cleanup_identity_step( + maybe_last_key: Option<&T::AccountId>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + IdentityOf::::iter_from(IdentityOf::::hashed_key_for(last_key)) + } else { + IdentityOf::::iter() + }; + + if let Some((account, _)) = iter.next() { + let _ = v1::IdentityOf::::take(&account); + + MigrationState::CleanupIdentitiesWithoutUsername(account) + } else { + MigrationState::Finished + } + } } } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index d46b568b105a..5d6fd8e1d106 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -78,7 +78,10 @@ pub trait WeightInfo { fn remove_username() -> Weight; fn kill_username(p: u32) -> Weight; fn migration_v2_authority_step() -> Weight; + fn migration_v2_identity_step() -> Weight; fn migration_v2_username_step() -> Weight; + fn migration_v2_cleanup_username_step() -> Weight; + fn migration_v2_cleanup_identity_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -461,6 +464,15 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_username_step() -> Weight { Weight::zero() } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_identity_step() -> Weight { + Weight::zero() + } } // For backwards compatibility and tests. @@ -842,4 +854,13 @@ impl WeightInfo for () { fn migration_v2_authority_step() -> Weight { Weight::zero() } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_identity_step() -> Weight { + Weight::zero() + } } From 4b3ee47cb67fd81c6780c5507aa46c29318821df Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 29 Aug 2024 13:46:27 +0300 Subject: [PATCH 12/44] Add benchmarked weight for migration steps Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 72 ++++++++++++- substrate/frame/identity/src/migration.rs | 103 ++++++++++++++++--- substrate/frame/identity/src/weights.rs | 14 +++ 3 files changed, 176 insertions(+), 13 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 7ac665d04a77..68aa5704e557 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::Pallet as Identity; +use crate::{migration::v2::LazyMigrationV2, Pallet as Identity}; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -894,5 +894,75 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn migration_v2_authority_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::authority_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_username_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::username_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::pending_username_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_identity_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::identity_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::cleanup_username_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_pending_username_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::cleanup_pending_username_step(None); + } + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_identity_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::cleanup_identity_step(None); + } + Ok(()) + } + impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 6592d3d89b0e..6371fa3cf087 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -210,8 +210,12 @@ pub mod v2 { FinishedIdentities, Username(U), FinishedUsernames, + PendingUsername(U), + FinishedPendingUsernames, CleanupUsernames(U), FinishedCleanupUsernames, + CleanupPendingUsernames(U), + FinishedCleanupPendingUsernames, CleanupIdentitiesWithoutUsername(A), Finished, } @@ -258,10 +262,18 @@ pub mod v2 { Some(MigrationState::FinishedIdentities) => Self::username_step(None), Some(MigrationState::Username(maybe_last_username)) => Self::username_step(Some(maybe_last_username)), - Some(MigrationState::FinishedUsernames) => Self::cleanup_username_step(None), + Some(MigrationState::FinishedUsernames) => Self::pending_username_step(None), + Some(MigrationState::PendingUsername(maybe_last_username)) => + Self::pending_username_step(Some(maybe_last_username)), + Some(MigrationState::FinishedPendingUsernames) => + Self::cleanup_username_step(None), Some(MigrationState::CleanupUsernames(maybe_last_username)) => Self::cleanup_username_step(Some(maybe_last_username)), Some(MigrationState::FinishedCleanupUsernames) => + Self::cleanup_pending_username_step(None), + Some(MigrationState::CleanupPendingUsernames(maybe_last_username)) => + Self::cleanup_pending_username_step(Some(maybe_last_username)), + Some(MigrationState::FinishedCleanupPendingUsernames) => Self::cleanup_identity_step(None), Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => Self::identity_step(Some(maybe_last_identity)), @@ -276,22 +288,26 @@ pub mod v2 { } impl LazyMigrationV2 { - fn required_weight(step: &MigrationState>) -> Weight { + pub(crate) fn required_weight(step: &MigrationState>) -> Weight { match step { MigrationState::Authority(_) => W::migration_v2_authority_step(), MigrationState::FinishedAuthorities | MigrationState::Identity(_) => W::migration_v2_identity_step(), MigrationState::FinishedIdentities | MigrationState::Username(_) => W::migration_v2_username_step(), - MigrationState::FinishedUsernames | MigrationState::CleanupUsernames(_) => + MigrationState::FinishedUsernames | MigrationState::PendingUsername(_) => + W::migration_v2_pending_username_step(), + MigrationState::FinishedPendingUsernames | MigrationState::CleanupUsernames(_) => W::migration_v2_cleanup_username_step(), MigrationState::FinishedCleanupUsernames | - MigrationState::CleanupIdentitiesWithoutUsername(_) | - MigrationState::Finished => W::migration_v2_cleanup_identity_step(), + MigrationState::CleanupPendingUsernames(_) => W::migration_v2_cleanup_pending_username_step(), + MigrationState::FinishedCleanupPendingUsernames | + MigrationState::CleanupIdentitiesWithoutUsername(_) => W::migration_v2_cleanup_identity_step(), + MigrationState::Finished => Weight::zero(), } } - fn username_step( + pub(crate) fn username_step( maybe_last_key: Option<&Username>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -309,11 +325,11 @@ pub mod v2 { MigrationState::Username(username) } else { - MigrationState::Finished + MigrationState::FinishedUsernames } } - fn identity_step( + pub(crate) fn identity_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -336,7 +352,29 @@ pub mod v2 { } } - fn authority_step( + pub(crate) fn pending_username_step( + maybe_last_key: Option<&Username>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + v1::PendingUsernames::::iter_from(v1::PendingUsernames::::hashed_key_for( + last_key, + )) + } else { + v1::PendingUsernames::::iter() + }; + + if let Some((username, (owner_account, since))) = iter.next() { + PendingUsernames::::insert( + &username, + (owner_account, since, Provider::Governance), + ); + MigrationState::PendingUsername(username) + } else { + MigrationState::FinishedPendingUsernames + } + } + + pub(crate) fn authority_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -358,7 +396,7 @@ pub mod v2 { } } - fn cleanup_username_step( + pub(crate) fn cleanup_username_step( maybe_last_key: Option<&Username>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -382,7 +420,25 @@ pub mod v2 { } } - fn cleanup_identity_step( + pub(crate) fn cleanup_pending_username_step( + maybe_last_key: Option<&Username>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + PendingUsernames::::iter_from(PendingUsernames::::hashed_key_for(last_key)) + } else { + PendingUsernames::::iter() + }; + + if let Some((username, _)) = iter.next() { + let _ = v1::PendingUsernames::::take(&username); + + MigrationState::CleanupPendingUsernames(username) + } else { + MigrationState::FinishedCleanupPendingUsernames + } + } + + pub(crate) fn cleanup_identity_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -396,8 +452,31 @@ pub mod v2 { MigrationState::CleanupIdentitiesWithoutUsername(account) } else { - MigrationState::Finished + MigrationState::FinishedCleanupPendingUsernames } } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn setup_benchmark_env() { + use frame_benchmarking::account; + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = account("authority", 0, 0); + let account_with_username: T::AccountId = account("account", 1, 0); + let account_without_username: T::AccountId = account("account", 2, 0); + + v1::UsernameAuthorities::::insert( + &authority, + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }, + ); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration = + Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + v1::IdentityOf::::insert(&account_with_username, (®istration, Some(&username))); + v1::IdentityOf::::insert(&account_without_username, &(registration, None)); + v1::AccountOfUsername::::insert(&username, &account_with_username); + v1::PendingUsernames::::insert(&username, &(account_with_username, 0u32.into())); + } } } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 5d6fd8e1d106..a71b9136c214 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -80,7 +80,9 @@ pub trait WeightInfo { fn migration_v2_authority_step() -> Weight; fn migration_v2_identity_step() -> Weight; fn migration_v2_username_step() -> Weight; + fn migration_v2_pending_username_step() -> Weight; fn migration_v2_cleanup_username_step() -> Weight; + fn migration_v2_cleanup_pending_username_step() -> Weight; fn migration_v2_cleanup_identity_step() -> Weight; } @@ -464,12 +466,18 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_username_step() -> Weight { Weight::zero() } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } fn migration_v2_identity_step() -> Weight { Weight::zero() } fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } + fn migration_v2_cleanup_pending_username_step() -> Weight { + Weight::zero() + } fn migration_v2_cleanup_identity_step() -> Weight { Weight::zero() } @@ -851,6 +859,9 @@ impl WeightInfo for () { fn migration_v2_username_step() -> Weight { Weight::zero() } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } fn migration_v2_authority_step() -> Weight { Weight::zero() } @@ -860,6 +871,9 @@ impl WeightInfo for () { fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } + fn migration_v2_cleanup_pending_username_step() -> Weight { + Weight::zero() + } fn migration_v2_cleanup_identity_step() -> Weight { Weight::zero() } From 987fc4e70fa074d2a6b138f366458e287def5339 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 29 Aug 2024 15:10:08 +0300 Subject: [PATCH 13/44] WIP fix test Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 159 ++++++++++++++++++---- 1 file changed, 130 insertions(+), 29 deletions(-) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 6371fa3cf087..85bc41a82b78 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -256,13 +256,13 @@ pub mod v2 { None => Self::authority_step(None), Some(MigrationState::Authority(maybe_last_authority)) => Self::authority_step(Some(maybe_last_authority)), - Some(MigrationState::FinishedAuthorities) => Self::identity_step(None), - Some(MigrationState::Identity(maybe_last_identity)) => - Self::identity_step(Some(maybe_last_identity)), - Some(MigrationState::FinishedIdentities) => Self::username_step(None), + Some(MigrationState::FinishedAuthorities) => Self::username_step(None), Some(MigrationState::Username(maybe_last_username)) => Self::username_step(Some(maybe_last_username)), - Some(MigrationState::FinishedUsernames) => Self::pending_username_step(None), + Some(MigrationState::FinishedUsernames) => Self::identity_step(None), + Some(MigrationState::Identity(maybe_last_identity)) => + Self::identity_step(Some(maybe_last_identity)), + Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None), Some(MigrationState::PendingUsername(maybe_last_username)) => Self::pending_username_step(Some(maybe_last_username)), Some(MigrationState::FinishedPendingUsernames) => @@ -276,7 +276,7 @@ pub mod v2 { Some(MigrationState::FinishedCleanupPendingUsernames) => Self::cleanup_identity_step(None), Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => - Self::identity_step(Some(maybe_last_identity)), + Self::cleanup_identity_step(Some(maybe_last_identity)), Some(MigrationState::Finished) => return Ok(None), }; @@ -307,6 +307,28 @@ pub mod v2 { } } + pub(crate) fn authority_step( + maybe_last_key: Option<&T::AccountId>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + v1::UsernameAuthorities::::iter_from( + v1::UsernameAuthorities::::hashed_key_for(last_key), + ) + } else { + v1::UsernameAuthorities::::iter() + }; + if let Some((authority_account, properties)) = iter.next() { + let suffix = properties.account_id; + let allocation = properties.allocation; + let new_properties = + AuthorityProperties { account_id: authority_account.clone(), allocation }; + UsernameAuthorities::::insert(&suffix, new_properties); + MigrationState::Authority(authority_account) + } else { + MigrationState::FinishedAuthorities + } + } + pub(crate) fn username_step( maybe_last_key: Option<&Username>, ) -> MigrationState> { @@ -374,28 +396,6 @@ pub mod v2 { } } - pub(crate) fn authority_step( - maybe_last_key: Option<&T::AccountId>, - ) -> MigrationState> { - let mut iter = if let Some(last_key) = maybe_last_key { - v1::UsernameAuthorities::::iter_from( - v1::UsernameAuthorities::::hashed_key_for(last_key), - ) - } else { - v1::UsernameAuthorities::::iter() - }; - if let Some((authority_account, properties)) = iter.next() { - let suffix = properties.account_id; - let allocation = properties.allocation; - let new_properties = - AuthorityProperties { account_id: authority_account.clone(), allocation }; - UsernameAuthorities::::insert(&suffix, new_properties); - MigrationState::Authority(authority_account) - } else { - MigrationState::FinishedAuthorities - } - } - pub(crate) fn cleanup_username_step( maybe_last_key: Option<&Username>, ) -> MigrationState> { @@ -409,6 +409,7 @@ pub mod v2 { let _ = v1::AccountOfUsername::::take(&username); match UsernameOf::::get(&username_info.owner) { Some(primary_username) if primary_username == username => { + // KEY DISAPPEARS let _ = v1::IdentityOf::::take(&username_info.owner); }, _ => {}, @@ -452,7 +453,7 @@ pub mod v2 { MigrationState::CleanupIdentitiesWithoutUsername(account) } else { - MigrationState::FinishedCleanupPendingUsernames + MigrationState::Finished } } @@ -479,4 +480,104 @@ pub mod v2 { v1::PendingUsernames::::insert(&username, &(account_with_username, 0u32.into())); } } + + #[cfg(test)] + mod tests { + use super::*; + use crate::tests::{new_test_ext, Test}; + use frame_support::traits::StorageVersion; + + fn registration( + with_deposit: bool, + ) -> Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > { + Registration { + judgements: Default::default(), + deposit: if with_deposit { 10u32.into() } else { 0u32.into() }, + info: Default::default(), + } + } + + fn accoount_from_u8(byte: u8) -> ::AccountId { + [byte; 32].into() + } + + #[test] + fn migrate_to_v2() { + new_test_ext().execute_with(|| { + let storage_version = StorageVersion::new(1); + storage_version.put::>(); + + let authority_1 = accoount_from_u8(151); + let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority_1, &prop); + + let authority_2 = accoount_from_u8(152); + let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority_2, &prop); + + for i in 0u8..100u8 { + let account_id = accoount_from_u8(i); + let mut bare_username = b"acc".to_vec(); + bare_username.push(i); + bare_username.push(b'.'); + let mut username_1 = bare_username.clone(); + username_1.extend(suffix_1.iter()); + let username_1: Username = username_1.try_into().unwrap(); + v1::AccountOfUsername::::insert(&username_1, &account_id); + + if i % 2 == 0 { + let reg = registration(i % 4 == 0); + v1::IdentityOf::::insert( + &account_id, + (reg, Some(username_1.clone())), + ); + } else { + let mut username_2 = bare_username.clone(); + username_2.extend(suffix_2.iter()); + let username_2: Username = username_2.try_into().unwrap(); + v1::AccountOfUsername::::insert(&username_2, &account_id); + let reg = registration(i % 3 == 0); + v1::IdentityOf::::insert(account_id, (reg, Some(username_2.clone()))); + } + } + + for i in 100u8..110u8 { + let account_id = accoount_from_u8(i); + let mut bare_username = b"acc".to_vec(); + bare_username.push(i); + bare_username.push(b'.'); + bare_username.extend(suffix_1.iter()); + let username: Username = bare_username.try_into().unwrap(); + let since: BlockNumberFor = i.into(); + v1::PendingUsernames::::insert(&username, (account_id, since)); + } + + for i in 110u8..120u8 { + let account_id = accoount_from_u8(i); + v1::IdentityOf::::insert( + account_id, + (registration(true), None::>), + ); + } + + let mut weight_meter = WeightMeter::new(); + let mut cursor = None; + while let Some(new_cursor) = + LazyMigrationV2::::WeightInfo>::step( + cursor, + &mut weight_meter, + ) + .unwrap() + { + cursor = Some(new_cursor); + } + }); + } + } } From 831c5568eecb0cde872bec547624292ea6420aed Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 11:52:25 +0300 Subject: [PATCH 14/44] WIP some other stuff Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 4 +- substrate/frame/identity/src/migration.rs | 119 +++++++++++++++---- substrate/frame/identity/src/weights.rs | 13 +- 3 files changed, 110 insertions(+), 26 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 68aa5704e557..48181e117cad 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -959,7 +959,9 @@ mod benchmarks { LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); #[block] { - LazyMigrationV2::::WeightInfo>::cleanup_identity_step(None); + LazyMigrationV2::::WeightInfo>::cleanup_identity_without_username_step( + None, + ); } Ok(()) } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 85bc41a82b78..768baa98adf2 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -216,6 +216,8 @@ pub mod v2 { FinishedCleanupUsernames, CleanupPendingUsernames(U), FinishedCleanupPendingUsernames, + CleanupIdentitiesWithUsername(A), + FinishedCleanupIdentitiesWithUsernames, CleanupIdentitiesWithoutUsername(A), Finished, } @@ -274,9 +276,13 @@ pub mod v2 { Some(MigrationState::CleanupPendingUsernames(maybe_last_username)) => Self::cleanup_pending_username_step(Some(maybe_last_username)), Some(MigrationState::FinishedCleanupPendingUsernames) => - Self::cleanup_identity_step(None), + Self::cleanup_primary_username_identity_step(None), + Some(MigrationState::CleanupIdentitiesWithUsername(maybe_last_identity)) => + Self::cleanup_primary_username_identity_step(Some(maybe_last_identity)), + Some(MigrationState::FinishedCleanupIdentitiesWithUsernames) => + Self::cleanup_identity_without_username_step(None), Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => - Self::cleanup_identity_step(Some(maybe_last_identity)), + Self::cleanup_identity_without_username_step(Some(maybe_last_identity)), Some(MigrationState::Finished) => return Ok(None), }; @@ -302,7 +308,11 @@ pub mod v2 { MigrationState::FinishedCleanupUsernames | MigrationState::CleanupPendingUsernames(_) => W::migration_v2_cleanup_pending_username_step(), MigrationState::FinishedCleanupPendingUsernames | - MigrationState::CleanupIdentitiesWithoutUsername(_) => W::migration_v2_cleanup_identity_step(), + MigrationState::CleanupIdentitiesWithUsername(_) => + W::migration_v2_cleanup_primary_username_identity_step(), + MigrationState::FinishedCleanupIdentitiesWithUsernames | + MigrationState::CleanupIdentitiesWithoutUsername(_) => + W::migration_v2_cleanup_identity_without_username_step(), MigrationState::Finished => Weight::zero(), } } @@ -405,16 +415,8 @@ pub mod v2 { UsernameInfoOf::::iter() }; - if let Some((username, username_info)) = iter.next() { + if let Some((username, _)) = iter.next() { let _ = v1::AccountOfUsername::::take(&username); - match UsernameOf::::get(&username_info.owner) { - Some(primary_username) if primary_username == username => { - // KEY DISAPPEARS - let _ = v1::IdentityOf::::take(&username_info.owner); - }, - _ => {}, - } - MigrationState::CleanupUsernames(username) } else { MigrationState::FinishedCleanupUsernames @@ -439,7 +441,30 @@ pub mod v2 { } } - pub(crate) fn cleanup_identity_step( + pub(crate) fn cleanup_primary_username_identity_step( + maybe_last_key: Option<&T::AccountId>, + ) -> MigrationState> { + let mut iter = if let Some(last_key) = maybe_last_key { + UsernameOf::::iter_from(UsernameOf::::hashed_key_for(last_key)) + } else { + UsernameOf::::iter() + }; + + if let Some((account, primary_username)) = iter.next() { + match v1::IdentityOf::::get(&account) { + Some((_, Some(actual_primary))) if actual_primary == primary_username => { + let _ = v1::IdentityOf::::take(&account); + }, + _ => {}, + } + + MigrationState::CleanupIdentitiesWithoutUsername(account) + } else { + MigrationState::Finished + } + } + + pub(crate) fn cleanup_identity_without_username_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { @@ -448,8 +473,10 @@ pub mod v2 { IdentityOf::::iter() }; - if let Some((account, _)) = iter.next() { - let _ = v1::IdentityOf::::take(&account); + if let Some((account, reg)) = iter.next() { + if reg.deposit > 0u32.into() { + let _ = v1::IdentityOf::::take(&account); + } MigrationState::CleanupIdentitiesWithoutUsername(account) } else { @@ -508,8 +535,8 @@ pub mod v2 { #[test] fn migrate_to_v2() { new_test_ext().execute_with(|| { - let storage_version = StorageVersion::new(1); - storage_version.put::>(); + // let storage_version = StorageVersion::new(1); + // storage_version.put::>(); let authority_1 = accoount_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); @@ -521,6 +548,7 @@ pub mod v2 { let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; v1::UsernameAuthorities::::insert(&authority_2, &prop); + let mut usernames = vec![]; for i in 0u8..100u8 { let account_id = accoount_from_u8(i); let mut bare_username = b"acc".to_vec(); @@ -532,21 +560,29 @@ pub mod v2 { v1::AccountOfUsername::::insert(&username_1, &account_id); if i % 2 == 0 { - let reg = registration(i % 4 == 0); + let has_identity = i % 4 == 0; + let reg = registration(has_identity); v1::IdentityOf::::insert( &account_id, (reg, Some(username_1.clone())), ); + usernames.push((account_id, username_1, None, has_identity)); } else { + let has_identity = i % 3 == 0; let mut username_2 = bare_username.clone(); username_2.extend(suffix_2.iter()); let username_2: Username = username_2.try_into().unwrap(); v1::AccountOfUsername::::insert(&username_2, &account_id); - let reg = registration(i % 3 == 0); - v1::IdentityOf::::insert(account_id, (reg, Some(username_2.clone()))); + let reg = registration(has_identity); + v1::IdentityOf::::insert( + &account_id, + (reg, Some(username_2.clone())), + ); + usernames.push((account_id, username_2, Some(username_1), has_identity)); } } + let mut pending = vec![]; for i in 100u8..110u8 { let account_id = accoount_from_u8(i); let mut bare_username = b"acc".to_vec(); @@ -555,15 +591,18 @@ pub mod v2 { bare_username.extend(suffix_1.iter()); let username: Username = bare_username.try_into().unwrap(); let since: BlockNumberFor = i.into(); - v1::PendingUsernames::::insert(&username, (account_id, since)); + v1::PendingUsernames::::insert(&username, (account_id.clone(), since)); + pending.push((username, account_id, since)); } + let mut identity_only = vec![]; for i in 110u8..120u8 { let account_id = accoount_from_u8(i); v1::IdentityOf::::insert( - account_id, + &account_id, (registration(true), None::>), ); + identity_only.push(account_id); } let mut weight_meter = WeightMeter::new(); @@ -577,6 +616,42 @@ pub mod v2 { { cursor = Some(new_cursor); } + + let expected_prop = + AuthorityProperties { account_id: authority_1.clone(), allocation: 10 }; + assert_eq!(UsernameAuthorities::::get(&suffix_1), Some(expected_prop)); + + let expected_prop = + AuthorityProperties { account_id: authority_2.clone(), allocation: 10 }; + assert_eq!(UsernameAuthorities::::get(&suffix_2), Some(expected_prop)); + + for (owner, primary, maybe_secondary, has_identity) in usernames.iter() { + let username_info = UsernameInfoOf::::get(primary).unwrap(); + assert_eq!(&username_info.owner, owner); + let actual_primary = UsernameOf::::get(owner).unwrap(); + assert_eq!(primary, &actual_primary); + // assert_eq!(IdentityOf::::contains_key(owner), *has_identity); + if let Some(secondary) = maybe_secondary { + let expected_info = UsernameInformation { + owner: owner.clone(), + provider: Provider::Governance, + }; + assert_eq!(UsernameInfoOf::::get(secondary), Some(expected_info)); + } + } + + // let pending_count = PendingUsernames::::iter().count(); + // assert_eq!(pending_count, 10); + // for (username, owner, since) in pending.iter() { + // let expected_pending = (owner.clone(), *since, Provider::Governance); + // assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); + // } + + for id in identity_only.iter() { + let expected_reg = registration(true); + assert_eq!(IdentityOf::::get(id), Some(expected_reg)); + assert!(!UsernameOf::::contains_key(id)); + } }); } } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index a71b9136c214..55bd7d8d05da 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -83,7 +83,8 @@ pub trait WeightInfo { fn migration_v2_pending_username_step() -> Weight; fn migration_v2_cleanup_username_step() -> Weight; fn migration_v2_cleanup_pending_username_step() -> Weight; - fn migration_v2_cleanup_identity_step() -> Weight; + fn migration_v2_cleanup_primary_username_identity_step() -> Weight; + fn migration_v2_cleanup_identity_without_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -478,7 +479,10 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_cleanup_pending_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_identity_step() -> Weight { + fn migration_v2_cleanup_primary_username_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_identity_without_username_step() -> Weight { Weight::zero() } } @@ -874,7 +878,10 @@ impl WeightInfo for () { fn migration_v2_cleanup_pending_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_identity_step() -> Weight { + fn migration_v2_cleanup_primary_username_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_identity_without_username_step() -> Weight { Weight::zero() } } From f28afed88d3f96eafa7028dfdeb6bef114df5f79 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 13:12:15 +0300 Subject: [PATCH 15/44] WIP test almost fixed Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 10 +-- substrate/frame/identity/src/migration.rs | 100 ++++++++++++---------- substrate/frame/identity/src/tests.rs | 16 ++-- 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 873c24712d8d..5fa37f82ed92 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -305,7 +305,7 @@ pub mod pallet { /// /// First tuple item is the account and second is the acceptance deadline. #[pallet::storage] - pub type PendingUsernames = StorageMap< + pub type PendingAcceptance = StorageMap< _, Blake2_128Concat, Username, @@ -1123,7 +1123,7 @@ pub mod pallet { Error::::UsernameTaken ); ensure!( - !PendingUsernames::::contains_key(&bounded_username), + !PendingAcceptance::::contains_key(&bounded_username), Error::::UsernameTaken ); @@ -1151,7 +1151,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let (approved_for, _, provider) = - PendingUsernames::::take(&username).ok_or(Error::::NoUsername)?; + PendingAcceptance::::take(&username).ok_or(Error::::NoUsername)?; ensure!(approved_for == who.clone(), Error::::InvalidUsername); Self::insert_username(&who, username.clone(), provider); Self::deposit_event(Event::UsernameSet { who: who.clone(), username }); @@ -1168,7 +1168,7 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { + if let Some((who, expiration, provider)) = PendingAcceptance::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); let actual_weight = match provider { @@ -1526,7 +1526,7 @@ impl Pallet { pub fn queue_acceptance(who: &T::AccountId, username: Username, provider: ProviderOf) { let now = frame_system::Pallet::::block_number(); let expiration = now.saturating_add(T::PendingUsernameExpiration::get()); - PendingUsernames::::insert(&username, (who.clone(), expiration, provider)); + PendingAcceptance::::insert(&username, (who.clone(), expiration, provider)); Self::deposit_event(Event::UsernameQueued { who: who.clone(), username, expiration }); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 768baa98adf2..ee4d66cddf39 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -216,7 +216,7 @@ pub mod v2 { FinishedCleanupUsernames, CleanupPendingUsernames(U), FinishedCleanupPendingUsernames, - CleanupIdentitiesWithUsername(A), + CleanupIdentitiesWithUsername(U), FinishedCleanupIdentitiesWithUsernames, CleanupIdentitiesWithoutUsername(A), Finished, @@ -276,9 +276,9 @@ pub mod v2 { Some(MigrationState::CleanupPendingUsernames(maybe_last_username)) => Self::cleanup_pending_username_step(Some(maybe_last_username)), Some(MigrationState::FinishedCleanupPendingUsernames) => - Self::cleanup_primary_username_identity_step(None), + Self::cleanup_identity_with_username_step(None), Some(MigrationState::CleanupIdentitiesWithUsername(maybe_last_identity)) => - Self::cleanup_primary_username_identity_step(Some(maybe_last_identity)), + Self::cleanup_identity_with_username_step(Some(maybe_last_identity)), Some(MigrationState::FinishedCleanupIdentitiesWithUsernames) => Self::cleanup_identity_without_username_step(None), Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => @@ -294,6 +294,10 @@ pub mod v2 { } impl LazyMigrationV2 { + fn pretty_username(username: &Username) -> String { + String::from_utf8(username.to_vec()).unwrap() + } + pub(crate) fn required_weight(step: &MigrationState>) -> Weight { match step { MigrationState::Authority(_) => W::migration_v2_authority_step(), @@ -351,6 +355,7 @@ pub mod v2 { }; if let Some((username, owner_account)) = iter.next() { + log::error!("STEPPING USERNAME {}", Self::pretty_username(&username)); let username_info = UsernameInformation { owner: owner_account, provider: Provider::Governance }; UsernameInfoOf::::insert(&username, username_info); @@ -371,6 +376,7 @@ pub mod v2 { }; if let Some((account, (identity, maybe_username))) = iter.next() { + log::error!("STEPPING IDENTITY {}", account); if identity.deposit > BalanceOf::::zero() { IdentityOf::::insert(&account, identity); } @@ -396,7 +402,8 @@ pub mod v2 { }; if let Some((username, (owner_account, since))) = iter.next() { - PendingUsernames::::insert( + log::error!("STEPPING PENDING USERNAME {}", Self::pretty_username(&username)); + PendingAcceptance::::insert( &username, (owner_account, since, Provider::Governance), ); @@ -416,6 +423,7 @@ pub mod v2 { }; if let Some((username, _)) = iter.next() { + log::error!("STEPPING CLEANUP USERNAME {}", Self::pretty_username(&username)); let _ = v1::AccountOfUsername::::take(&username); MigrationState::CleanupUsernames(username) } else { @@ -427,12 +435,16 @@ pub mod v2 { maybe_last_key: Option<&Username>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { - PendingUsernames::::iter_from(PendingUsernames::::hashed_key_for(last_key)) + PendingAcceptance::::iter_from(PendingAcceptance::::hashed_key_for(last_key)) } else { - PendingUsernames::::iter() + PendingAcceptance::::iter() }; if let Some((username, _)) = iter.next() { + log::error!( + "STEPPING CLEANUP PENDING USERNAME {}", + Self::pretty_username(&username) + ); let _ = v1::PendingUsernames::::take(&username); MigrationState::CleanupPendingUsernames(username) @@ -441,26 +453,26 @@ pub mod v2 { } } - pub(crate) fn cleanup_primary_username_identity_step( - maybe_last_key: Option<&T::AccountId>, + pub(crate) fn cleanup_identity_with_username_step( + maybe_last_key: Option<&Username>, ) -> MigrationState> { let mut iter = if let Some(last_key) = maybe_last_key { - UsernameOf::::iter_from(UsernameOf::::hashed_key_for(last_key)) + UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) } else { - UsernameOf::::iter() + UsernameInfoOf::::iter() }; - if let Some((account, primary_username)) = iter.next() { - match v1::IdentityOf::::get(&account) { - Some((_, Some(actual_primary))) if actual_primary == primary_username => { - let _ = v1::IdentityOf::::take(&account); - }, - _ => {}, - } + if let Some((username, username_info)) = iter.next() { + log::error!( + "STEPPING CLEANUP IDENTITY WITH USERNAME {} FOR {}", + Self::pretty_username(&username), + username_info.owner + ); + let _ = v1::IdentityOf::::take(&username_info.owner); - MigrationState::CleanupIdentitiesWithoutUsername(account) + MigrationState::CleanupIdentitiesWithUsername(username) } else { - MigrationState::Finished + MigrationState::FinishedCleanupIdentitiesWithUsernames } } @@ -473,12 +485,13 @@ pub mod v2 { IdentityOf::::iter() }; - if let Some((account, reg)) = iter.next() { - if reg.deposit > 0u32.into() { - let _ = v1::IdentityOf::::take(&account); + if let Some((owner_account, username)) = iter.next() { + log::error!("STEPPING CLEANUP IDENTITY WITHOUT USERNAME {}", owner_account); + if UsernameOf::::contains_key(&owner_account) { + let _ = v1::IdentityOf::::take(&owner_account); } - MigrationState::CleanupIdentitiesWithoutUsername(account) + MigrationState::CleanupIdentitiesWithoutUsername(owner_account) } else { MigrationState::Finished } @@ -512,7 +525,6 @@ pub mod v2 { mod tests { use super::*; use crate::tests::{new_test_ext, Test}; - use frame_support::traits::StorageVersion; fn registration( with_deposit: bool, @@ -528,7 +540,7 @@ pub mod v2 { } } - fn accoount_from_u8(byte: u8) -> ::AccountId { + fn account_from_u8(byte: u8) -> ::AccountId { [byte; 32].into() } @@ -538,22 +550,20 @@ pub mod v2 { // let storage_version = StorageVersion::new(1); // storage_version.put::>(); - let authority_1 = accoount_from_u8(151); + let authority_1 = account_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; v1::UsernameAuthorities::::insert(&authority_1, &prop); - let authority_2 = accoount_from_u8(152); + let authority_2 = account_from_u8(152); let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; v1::UsernameAuthorities::::insert(&authority_2, &prop); let mut usernames = vec![]; - for i in 0u8..100u8 { - let account_id = accoount_from_u8(i); - let mut bare_username = b"acc".to_vec(); - bare_username.push(i); - bare_username.push(b'.'); + for i in 0u8..10u8 { + let account_id = account_from_u8(i); + let bare_username = format!("acc{}.", i).as_bytes().to_vec(); let mut username_1 = bare_username.clone(); username_1.extend(suffix_1.iter()); let username_1: Username = username_1.try_into().unwrap(); @@ -583,11 +593,9 @@ pub mod v2 { } let mut pending = vec![]; - for i in 100u8..110u8 { - let account_id = accoount_from_u8(i); - let mut bare_username = b"acc".to_vec(); - bare_username.push(i); - bare_username.push(b'.'); + for i in 20u8..25u8 { + let account_id = account_from_u8(i); + let mut bare_username = format!("acc{}.", i).as_bytes().to_vec(); bare_username.extend(suffix_1.iter()); let username: Username = bare_username.try_into().unwrap(); let since: BlockNumberFor = i.into(); @@ -596,8 +604,8 @@ pub mod v2 { } let mut identity_only = vec![]; - for i in 110u8..120u8 { - let account_id = accoount_from_u8(i); + for i in 30u8..35u8 { + let account_id = account_from_u8(i); v1::IdentityOf::::insert( &account_id, (registration(true), None::>), @@ -630,7 +638,7 @@ pub mod v2 { assert_eq!(&username_info.owner, owner); let actual_primary = UsernameOf::::get(owner).unwrap(); assert_eq!(primary, &actual_primary); - // assert_eq!(IdentityOf::::contains_key(owner), *has_identity); + assert_eq!(IdentityOf::::contains_key(owner), *has_identity); if let Some(secondary) = maybe_secondary { let expected_info = UsernameInformation { owner: owner.clone(), @@ -640,12 +648,12 @@ pub mod v2 { } } - // let pending_count = PendingUsernames::::iter().count(); - // assert_eq!(pending_count, 10); - // for (username, owner, since) in pending.iter() { - // let expected_pending = (owner.clone(), *since, Provider::Governance); - // assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); - // } + let pending_count = PendingAcceptance::::iter().count(); + assert_eq!(pending_count, 5); + for (username, owner, since) in pending.iter() { + let expected_pending = (owner.clone(), *since, Provider::Governance); + assert_eq!(PendingAcceptance::::get(username), Some(expected_pending)); + } for id in identity_only.iter() { let expected_reg = registration(true); diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index d5cc814e51c6..722579de7597 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1329,7 +1329,7 @@ fn set_username_with_acceptance_should_work() { // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&username), + PendingAcceptance::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Governance)) ); @@ -1337,7 +1337,7 @@ fn set_username_with_acceptance_should_work() { assert_ok!(Identity::accept_username(RuntimeOrigin::signed(who.clone()), username.clone())); // No more pending - assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); // Check Identity storage assert_eq!(UsernameOf::::get(&who), Some(username.clone())); // Check reverse lookup @@ -1361,7 +1361,7 @@ fn set_username_with_acceptance_should_work() { // Should be pending let username_deposit = ::UsernameDeposit::get(); assert_eq!( - PendingUsernames::::get::<&Username>(&second_username), + PendingAcceptance::::get::<&Username>(&second_username), Some((second_caller.clone(), expiration, Provider::Authority(username_deposit))) ); assert_eq!( @@ -1375,7 +1375,7 @@ fn set_username_with_acceptance_should_work() { )); // No more pending - assert!(PendingUsernames::::get::<&Username>(&second_username).is_none()); + assert!(PendingAcceptance::::get::<&Username>(&second_username).is_none()); // Check Identity storage assert_eq!(UsernameOf::::get(&second_caller), Some(second_username.clone())); // Check reverse lookup @@ -1701,7 +1701,7 @@ fn unaccepted_usernames_through_grant_should_expire() { // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&username), + PendingAcceptance::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Governance)) ); @@ -1725,7 +1725,7 @@ fn unaccepted_usernames_through_grant_should_expire() { assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); // No more pending - assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); }); } @@ -1769,7 +1769,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&username), + PendingAcceptance::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Authority(username_deposit))) ); @@ -1799,7 +1799,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); // No more pending - assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); }); } From 34611fb7865ee868f1ff18d8e1770ca9dce5b8b7 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 14:37:22 +0300 Subject: [PATCH 16/44] Fix first part of migration Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 12 -- substrate/frame/identity/src/migration.rs | 117 +++++-------------- substrate/frame/identity/src/weights.rs | 14 --- 3 files changed, 28 insertions(+), 115 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 48181e117cad..bcd898d9b2c4 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -954,17 +954,5 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn migration_v2_cleanup_identity_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); - #[block] - { - LazyMigrationV2::::WeightInfo>::cleanup_identity_without_username_step( - None, - ); - } - Ok(()) - } - impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index ee4d66cddf39..0e0d83186318 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -206,7 +206,7 @@ pub mod v2 { pub enum MigrationState { Authority(A), FinishedAuthorities, - Identity(A), + Identity(BoundedVec>), FinishedIdentities, Username(U), FinishedUsernames, @@ -215,10 +215,6 @@ pub mod v2 { CleanupUsernames(U), FinishedCleanupUsernames, CleanupPendingUsernames(U), - FinishedCleanupPendingUsernames, - CleanupIdentitiesWithUsername(U), - FinishedCleanupIdentitiesWithUsernames, - CleanupIdentitiesWithoutUsername(A), Finished, } @@ -262,8 +258,8 @@ pub mod v2 { Some(MigrationState::Username(maybe_last_username)) => Self::username_step(Some(maybe_last_username)), Some(MigrationState::FinishedUsernames) => Self::identity_step(None), - Some(MigrationState::Identity(maybe_last_identity)) => - Self::identity_step(Some(maybe_last_identity)), + Some(MigrationState::Identity(last_key)) => + Self::identity_step(Some(last_key.clone())), Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None), Some(MigrationState::PendingUsername(maybe_last_username)) => Self::pending_username_step(Some(maybe_last_username)), @@ -275,14 +271,6 @@ pub mod v2 { Self::cleanup_pending_username_step(None), Some(MigrationState::CleanupPendingUsernames(maybe_last_username)) => Self::cleanup_pending_username_step(Some(maybe_last_username)), - Some(MigrationState::FinishedCleanupPendingUsernames) => - Self::cleanup_identity_with_username_step(None), - Some(MigrationState::CleanupIdentitiesWithUsername(maybe_last_identity)) => - Self::cleanup_identity_with_username_step(Some(maybe_last_identity)), - Some(MigrationState::FinishedCleanupIdentitiesWithUsernames) => - Self::cleanup_identity_without_username_step(None), - Some(MigrationState::CleanupIdentitiesWithoutUsername(maybe_last_identity)) => - Self::cleanup_identity_without_username_step(Some(maybe_last_identity)), Some(MigrationState::Finished) => return Ok(None), }; @@ -294,6 +282,7 @@ pub mod v2 { } impl LazyMigrationV2 { + #[allow(unused)] fn pretty_username(username: &Username) -> String { String::from_utf8(username.to_vec()).unwrap() } @@ -311,12 +300,6 @@ pub mod v2 { W::migration_v2_cleanup_username_step(), MigrationState::FinishedCleanupUsernames | MigrationState::CleanupPendingUsernames(_) => W::migration_v2_cleanup_pending_username_step(), - MigrationState::FinishedCleanupPendingUsernames | - MigrationState::CleanupIdentitiesWithUsername(_) => - W::migration_v2_cleanup_primary_username_identity_step(), - MigrationState::FinishedCleanupIdentitiesWithUsernames | - MigrationState::CleanupIdentitiesWithoutUsername(_) => - W::migration_v2_cleanup_identity_without_username_step(), MigrationState::Finished => Weight::zero(), } } @@ -355,7 +338,6 @@ pub mod v2 { }; if let Some((username, owner_account)) = iter.next() { - log::error!("STEPPING USERNAME {}", Self::pretty_username(&username)); let username_info = UsernameInformation { owner: owner_account, provider: Provider::Governance }; UsernameInfoOf::::insert(&username, username_info); @@ -367,24 +349,31 @@ pub mod v2 { } pub(crate) fn identity_step( - maybe_last_key: Option<&T::AccountId>, + maybe_last_key: Option>>, ) -> MigrationState> { - let mut iter = if let Some(last_key) = maybe_last_key { - v1::IdentityOf::::iter_from(v1::IdentityOf::::hashed_key_for(last_key)) - } else { - v1::IdentityOf::::iter() - }; - - if let Some((account, (identity, maybe_username))) = iter.next() { - log::error!("STEPPING IDENTITY {}", account); - if identity.deposit > BalanceOf::::zero() { - IdentityOf::::insert(&account, identity); - } - if let Some(primary_username) = maybe_username { - UsernameOf::::insert(&account, primary_username); - } - - MigrationState::Identity(account) + use frame_support::IterableStorageMap; + if let Some(last_key) = + IdentityOf::::translate_next::< + ( + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + Option>, + ), + _, + >(maybe_last_key.map(|b| b.to_vec()), |account, (identity, maybe_username)| { + if let Some(primary_username) = maybe_username { + UsernameOf::::insert(&account, primary_username); + } + if identity.deposit > BalanceOf::::zero() { + Some(identity) + } else { + None + } + }) { + MigrationState::Identity(last_key.try_into().unwrap()) } else { MigrationState::FinishedIdentities } @@ -402,7 +391,6 @@ pub mod v2 { }; if let Some((username, (owner_account, since))) = iter.next() { - log::error!("STEPPING PENDING USERNAME {}", Self::pretty_username(&username)); PendingAcceptance::::insert( &username, (owner_account, since, Provider::Governance), @@ -423,7 +411,6 @@ pub mod v2 { }; if let Some((username, _)) = iter.next() { - log::error!("STEPPING CLEANUP USERNAME {}", Self::pretty_username(&username)); let _ = v1::AccountOfUsername::::take(&username); MigrationState::CleanupUsernames(username) } else { @@ -441,57 +428,9 @@ pub mod v2 { }; if let Some((username, _)) = iter.next() { - log::error!( - "STEPPING CLEANUP PENDING USERNAME {}", - Self::pretty_username(&username) - ); let _ = v1::PendingUsernames::::take(&username); MigrationState::CleanupPendingUsernames(username) - } else { - MigrationState::FinishedCleanupPendingUsernames - } - } - - pub(crate) fn cleanup_identity_with_username_step( - maybe_last_key: Option<&Username>, - ) -> MigrationState> { - let mut iter = if let Some(last_key) = maybe_last_key { - UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) - } else { - UsernameInfoOf::::iter() - }; - - if let Some((username, username_info)) = iter.next() { - log::error!( - "STEPPING CLEANUP IDENTITY WITH USERNAME {} FOR {}", - Self::pretty_username(&username), - username_info.owner - ); - let _ = v1::IdentityOf::::take(&username_info.owner); - - MigrationState::CleanupIdentitiesWithUsername(username) - } else { - MigrationState::FinishedCleanupIdentitiesWithUsernames - } - } - - pub(crate) fn cleanup_identity_without_username_step( - maybe_last_key: Option<&T::AccountId>, - ) -> MigrationState> { - let mut iter = if let Some(last_key) = maybe_last_key { - IdentityOf::::iter_from(IdentityOf::::hashed_key_for(last_key)) - } else { - IdentityOf::::iter() - }; - - if let Some((owner_account, username)) = iter.next() { - log::error!("STEPPING CLEANUP IDENTITY WITHOUT USERNAME {}", owner_account); - if UsernameOf::::contains_key(&owner_account) { - let _ = v1::IdentityOf::::take(&owner_account); - } - - MigrationState::CleanupIdentitiesWithoutUsername(owner_account) } else { MigrationState::Finished } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 55bd7d8d05da..3bf0f4b2807d 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -83,8 +83,6 @@ pub trait WeightInfo { fn migration_v2_pending_username_step() -> Weight; fn migration_v2_cleanup_username_step() -> Weight; fn migration_v2_cleanup_pending_username_step() -> Weight; - fn migration_v2_cleanup_primary_username_identity_step() -> Weight; - fn migration_v2_cleanup_identity_without_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -479,12 +477,6 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_cleanup_pending_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_primary_username_identity_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_identity_without_username_step() -> Weight { - Weight::zero() - } } // For backwards compatibility and tests. @@ -878,10 +870,4 @@ impl WeightInfo for () { fn migration_v2_cleanup_pending_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_primary_username_identity_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_identity_without_username_step() -> Weight { - Weight::zero() - } } From ac22ee8b14374757680b13820699bbb698e3085a Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 20:12:30 +0300 Subject: [PATCH 17/44] Fix compilation fail Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 6 +- substrate/frame/identity/src/lib.rs | 18 ++-- substrate/frame/identity/src/migration.rs | 94 +++++++++++--------- substrate/frame/identity/src/tests.rs | 36 ++++---- 4 files changed, 83 insertions(+), 71 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index bcd898d9b2c4..8430f7b30932 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -662,7 +662,7 @@ mod benchmarks { ); if use_allocation { let suffix: Suffix = suffix.try_into().unwrap(); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); } else { assert_eq!( T::Currency::free_balance(&authority), @@ -732,7 +732,7 @@ mod benchmarks { }, 1 => { let suffix: Suffix = suffix.try_into().unwrap(); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); }, _ => unreachable!(), } @@ -887,7 +887,7 @@ mod benchmarks { }, 1 => { let suffix: Suffix = suffix.try_into().unwrap(); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); }, _ => unreachable!(), } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 5fa37f82ed92..e5bff5d2a11c 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -280,7 +280,7 @@ pub mod pallet { /// A map of the accounts who are authorized to grant usernames. #[pallet::storage] - pub type UsernameAuthorities = + pub type AuthorityOf = StorageMap<_, Twox64Concat, Suffix, AuthorityProperties, OptionQuery>; /// Reverse lookup from `username` to the `AccountId` that has registered it and the provider of @@ -1048,7 +1048,7 @@ pub mod pallet { let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; // The authority may already exist, but we don't need to check. They might be changing // their suffix or adding allocation, so we just want to overwrite whatever was there. - UsernameAuthorities::::insert( + AuthorityOf::::insert( &suffix, AuthorityProperties:: { account_id: authority.clone(), allocation }, ); @@ -1068,7 +1068,7 @@ pub mod pallet { let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; let authority = T::Lookup::lookup(authority)?; let properties = - UsernameAuthorities::::take(&suffix).ok_or(Error::::NotUsernameAuthority)?; + AuthorityOf::::take(&suffix).ok_or(Error::::NotUsernameAuthority)?; ensure!(properties.account_id == authority, Error::::InvalidSuffix); Self::deposit_event(Event::AuthorityRemoved { authority }); Ok(()) @@ -1096,7 +1096,7 @@ pub mod pallet { // allocation by one. let sender = ensure_signed(origin)?; let suffix = Self::validate_username(&username)?; - let provider = UsernameAuthorities::::try_mutate( + let provider = AuthorityOf::::try_mutate( &suffix, |maybe_authority| -> Result, DispatchError> { let properties = @@ -1175,7 +1175,7 @@ pub mod pallet { Provider::Authority(deposit) => { let suffix = Self::suffix_of_username(&username) .ok_or(Error::::InvalidUsername)?; - let authority_account = UsernameAuthorities::::get(&suffix) + let authority_account = AuthorityOf::::get(&suffix) .map(|auth_info| auth_info.account_id) .ok_or(Error::::NotUsernameAuthority)?; let err_amount = T::Currency::unreserve(&authority_account, deposit); @@ -1232,7 +1232,7 @@ pub mod pallet { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = - UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) { let err_amount = T::Currency::unreserve(&authority_account, username_deposit); @@ -1264,7 +1264,7 @@ pub mod pallet { let username_info = UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?; let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; - let authority_account = UsernameAuthorities::::get(&suffix) + let authority_account = AuthorityOf::::get(&suffix) .map(|auth_info| auth_info.account_id) .ok_or(Error::::NotUsernameAuthority)?; ensure!(who == authority_account, Error::::NotUsernameAuthority); @@ -1316,7 +1316,7 @@ pub mod pallet { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = - UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) { let err_amount = T::Currency::unreserve(&authority_account, username_deposit); @@ -1358,7 +1358,7 @@ pub mod pallet { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = - UsernameAuthorities::::get(&suffix).map(|auth_info| auth_info.account_id) + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) { T::Slashed::on_unbalanced( T::Currency::slash_reserved(&authority_account, username_deposit).0, diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 0e0d83186318..21d85c7f0e4c 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -18,6 +18,7 @@ use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, + IterableStorageMap, }; #[cfg(feature = "try-runtime")] @@ -155,25 +156,11 @@ pub mod v2 { weights::WeightMeter, }; + type HashedKey = BoundedVec>; + mod v1 { use super::*; - #[storage_alias] - pub type IdentityOf = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, - ( - Registration< - BalanceOf, - ::MaxRegistrars, - ::IdentityInformation, - >, - Option>, - ), - OptionQuery, - >; - #[storage_alias] pub type UsernameAuthorities = StorageMap< Pallet, @@ -206,7 +193,7 @@ pub mod v2 { pub enum MigrationState { Authority(A), FinishedAuthorities, - Identity(BoundedVec>), + Identity(HashedKey), FinishedIdentities, Username(U), FinishedUsernames, @@ -319,7 +306,7 @@ pub mod v2 { let allocation = properties.allocation; let new_properties = AuthorityProperties { account_id: authority_account.clone(), allocation }; - UsernameAuthorities::::insert(&suffix, new_properties); + AuthorityOf::::insert(&suffix, new_properties); MigrationState::Authority(authority_account) } else { MigrationState::FinishedAuthorities @@ -349,9 +336,8 @@ pub mod v2 { } pub(crate) fn identity_step( - maybe_last_key: Option>>, + maybe_last_key: Option, ) -> MigrationState> { - use frame_support::IterableStorageMap; if let Some(last_key) = IdentityOf::::translate_next::< ( @@ -439,22 +425,35 @@ pub mod v2 { #[cfg(feature = "runtime-benchmarks")] pub(crate) fn setup_benchmark_env() { use frame_benchmarking::account; + use frame_support::Hashable; let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); let authority: T::AccountId = account("authority", 0, 0); let account_with_username: T::AccountId = account("account", 1, 0); let account_without_username: T::AccountId = account("account", 2, 0); - v1::UsernameAuthorities::::insert( - &authority, - AuthorityProperties { account_id: suffix.clone(), allocation: 10 }, - ); + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority, &prop); let username: Username = b"account.bench".to_vec().try_into().unwrap(); let info = T::IdentityInformation::create_identity_info(); - let registration = - Registration { judgements: Default::default(), deposit: 10u32.into(), info }; - v1::IdentityOf::::insert(&account_with_username, (®istration, Some(&username))); - v1::IdentityOf::::insert(&account_without_username, &(registration, None)); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_with_username.twox_64_concat(), + (®istration, Some(username.clone())), + ); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_without_username.twox_64_concat(), + (®istration, None::>), + ); v1::AccountOfUsername::::insert(&username, &account_with_username); v1::PendingUsernames::::insert(&username, &(account_with_username, 0u32.into())); } @@ -462,6 +461,8 @@ pub mod v2 { #[cfg(test)] mod tests { + use frame_support::Hashable; + use super::*; use crate::tests::{new_test_ext, Test}; @@ -483,12 +484,14 @@ pub mod v2 { [byte; 32].into() } + fn account_into_u8(account_id: &::AccountId) -> u8 { + let bytes: &[u8] = account_id.as_ref(); + bytes[0] + } + #[test] fn migrate_to_v2() { new_test_ext().execute_with(|| { - // let storage_version = StorageVersion::new(1); - // storage_version.put::>(); - let authority_1 = account_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; @@ -511,8 +514,10 @@ pub mod v2 { if i % 2 == 0 { let has_identity = i % 4 == 0; let reg = registration(has_identity); - v1::IdentityOf::::insert( - &account_id, + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), (reg, Some(username_1.clone())), ); usernames.push((account_id, username_1, None, has_identity)); @@ -523,8 +528,10 @@ pub mod v2 { let username_2: Username = username_2.try_into().unwrap(); v1::AccountOfUsername::::insert(&username_2, &account_id); let reg = registration(has_identity); - v1::IdentityOf::::insert( - &account_id, + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), (reg, Some(username_2.clone())), ); usernames.push((account_id, username_2, Some(username_1), has_identity)); @@ -545,9 +552,12 @@ pub mod v2 { let mut identity_only = vec![]; for i in 30u8..35u8 { let account_id = account_from_u8(i); - v1::IdentityOf::::insert( - &account_id, - (registration(true), None::>), + let reg = registration(true); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, None::>), ); identity_only.push(account_id); } @@ -566,11 +576,11 @@ pub mod v2 { let expected_prop = AuthorityProperties { account_id: authority_1.clone(), allocation: 10 }; - assert_eq!(UsernameAuthorities::::get(&suffix_1), Some(expected_prop)); + assert_eq!(AuthorityOf::::get(&suffix_1), Some(expected_prop)); let expected_prop = AuthorityProperties { account_id: authority_2.clone(), allocation: 10 }; - assert_eq!(UsernameAuthorities::::get(&suffix_2), Some(expected_prop)); + assert_eq!(AuthorityOf::::get(&suffix_2), Some(expected_prop)); for (owner, primary, maybe_secondary, has_identity) in usernames.iter() { let username_info = UsernameInfoOf::::get(primary).unwrap(); @@ -599,6 +609,10 @@ pub mod v2 { assert_eq!(IdentityOf::::get(id), Some(expected_reg)); assert!(!UsernameOf::::contains_key(id)); } + + assert_eq!(v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(v1::PendingUsernames::::iter().count(), 0); + assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); }); } } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 722579de7597..f88262c8f841 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -973,7 +973,7 @@ fn adding_and_removing_authorities_should_work() { )); let suffix: Suffix = suffix.try_into().unwrap(); assert_eq!( - UsernameAuthorities::::get(&suffix), + AuthorityOf::::get(&suffix), Some(AuthorityProperties::> { account_id: authority.clone(), allocation @@ -988,7 +988,7 @@ fn adding_and_removing_authorities_should_work() { 11u32 )); assert_eq!( - UsernameAuthorities::::get(&suffix), + AuthorityOf::::get(&suffix), Some(AuthorityProperties::> { account_id: authority.clone(), allocation: 11 @@ -1001,7 +1001,7 @@ fn adding_and_removing_authorities_should_work() { suffix.clone().into(), authority.clone(), )); - assert!(UsernameAuthorities::::get(&suffix).is_none()); + assert!(AuthorityOf::::get(&suffix).is_none()); }); } @@ -1052,7 +1052,7 @@ fn set_username_with_signature_without_existing_identity_should_work() { assert_eq!(Balances::free_balance(&authority), initial_authority_balance); // But the allocation decreased. assert_eq!( - UsernameAuthorities::::get(&Identity::suffix_of_username(&username).unwrap()) + AuthorityOf::::get(&Identity::suffix_of_username(&username).unwrap()) .unwrap() .allocation, 9 @@ -1096,11 +1096,9 @@ fn set_username_with_signature_without_existing_identity_should_work() { ); // But the allocation was preserved. assert_eq!( - UsernameAuthorities::::get( - &Identity::suffix_of_username(&second_username).unwrap() - ) - .unwrap() - .allocation, + AuthorityOf::::get(&Identity::suffix_of_username(&second_username).unwrap()) + .unwrap() + .allocation, 9 ); }); @@ -1688,7 +1686,7 @@ fn unaccepted_usernames_through_grant_should_expire() { let suffix: Suffix = suffix.try_into().unwrap(); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who.clone(), @@ -1697,7 +1695,7 @@ fn unaccepted_usernames_through_grant_should_expire() { true, )); assert_eq!(Balances::free_balance(&authority), initial_authority_balance); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // Should be pending assert_eq!( @@ -1722,7 +1720,7 @@ fn unaccepted_usernames_through_grant_should_expire() { )); assert_eq!(Balances::free_balance(&authority), initial_authority_balance); // Allocation wasn't refunded - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // No more pending assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); @@ -1753,7 +1751,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { let suffix: Suffix = suffix.try_into().unwrap(); let username_deposit: BalanceOf = ::UsernameDeposit::get(); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who.clone(), @@ -1765,7 +1763,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { Balances::free_balance(&authority), initial_authority_balance - username_deposit ); - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); // Should be pending assert_eq!( @@ -1796,7 +1794,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { // Deposit was refunded assert_eq!(Balances::free_balance(&authority), initial_authority_balance); // Allocation wasn't refunded - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 10); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); // No more pending assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); @@ -2191,7 +2189,7 @@ fn unbind_and_remove_username_should_work() { Error::::NotUsernameAuthority ); // Simulate a dummy authority. - UsernameAuthorities::::insert( + AuthorityOf::::insert( dummy_suffix.clone(), AuthorityProperties { account_id: dummy_authority.clone(), allocation: 10 }, ); @@ -2206,7 +2204,7 @@ fn unbind_and_remove_username_should_work() { ); // Clean up storage. let _ = UsernameInfoOf::::take(dummy_username.clone()); - let _ = UsernameAuthorities::::take(dummy_suffix); + let _ = AuthorityOf::::take(dummy_suffix); // We can successfully unbind the username as the authority that granted it. assert_ok!(Identity::unbind_username( @@ -2251,7 +2249,7 @@ fn unbind_and_remove_username_should_work() { initial_authority_balance - username_deposit ); // Allocation wasn't refunded. - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // Unbind the first username as well. assert_ok!(Identity::unbind_username( @@ -2271,6 +2269,6 @@ fn unbind_and_remove_username_should_work() { // The username deposit was released. assert_eq!(Balances::free_balance(authority.clone()), initial_authority_balance); // Allocation didn't change. - assert_eq!(UsernameAuthorities::::get(&suffix).unwrap().allocation, 9); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); }); } From 717439ae931547b300ae102bbecb2818724deb23 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 20:22:02 +0300 Subject: [PATCH 18/44] Fix tests Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 10 ++++ substrate/frame/identity/src/migration.rs | 54 ++++++++++++++------ substrate/frame/identity/src/weights.rs | 7 +++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 8430f7b30932..57c56064361a 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -934,6 +934,16 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { + LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + #[block] + { + LazyMigrationV2::::WeightInfo>::cleanup_authority_step(None); + } + Ok(()) + } + #[benchmark] fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 21d85c7f0e4c..4f71204b4c87 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -190,7 +190,7 @@ pub mod v2 { } #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] - pub enum MigrationState { + pub enum MigrationState { Authority(A), FinishedAuthorities, Identity(HashedKey), @@ -199,6 +199,8 @@ pub mod v2 { FinishedUsernames, PendingUsername(U), FinishedPendingUsernames, + CleanupAuthorities(S), + FinishedCleanupAuthorities, CleanupUsernames(U), FinishedCleanupUsernames, CleanupPendingUsernames(U), @@ -207,7 +209,7 @@ pub mod v2 { pub struct LazyMigrationV2(PhantomData<(T, W)>); impl SteppedMigration for LazyMigrationV2 { - type Cursor = MigrationState>; + type Cursor = MigrationState, Suffix>; type Identifier = MigrationId<15>; fn id() -> Self::Identifier { @@ -251,6 +253,10 @@ pub mod v2 { Some(MigrationState::PendingUsername(maybe_last_username)) => Self::pending_username_step(Some(maybe_last_username)), Some(MigrationState::FinishedPendingUsernames) => + Self::cleanup_authority_step(None), + Some(MigrationState::CleanupAuthorities(maybe_last_username)) => + Self::cleanup_authority_step(Some(maybe_last_username)), + Some(MigrationState::FinishedCleanupAuthorities) => Self::cleanup_username_step(None), Some(MigrationState::CleanupUsernames(maybe_last_username)) => Self::cleanup_username_step(Some(maybe_last_username)), @@ -274,7 +280,9 @@ pub mod v2 { String::from_utf8(username.to_vec()).unwrap() } - pub(crate) fn required_weight(step: &MigrationState>) -> Weight { + pub(crate) fn required_weight( + step: &MigrationState, Suffix>, + ) -> Weight { match step { MigrationState::Authority(_) => W::migration_v2_authority_step(), MigrationState::FinishedAuthorities | MigrationState::Identity(_) => @@ -283,8 +291,10 @@ pub mod v2 { W::migration_v2_username_step(), MigrationState::FinishedUsernames | MigrationState::PendingUsername(_) => W::migration_v2_pending_username_step(), - MigrationState::FinishedPendingUsernames | MigrationState::CleanupUsernames(_) => - W::migration_v2_cleanup_username_step(), + MigrationState::FinishedPendingUsernames | + MigrationState::CleanupAuthorities(_) => W::migration_v2_cleanup_authority_step(), + MigrationState::FinishedCleanupAuthorities | + MigrationState::CleanupUsernames(_) => W::migration_v2_cleanup_username_step(), MigrationState::FinishedCleanupUsernames | MigrationState::CleanupPendingUsernames(_) => W::migration_v2_cleanup_pending_username_step(), MigrationState::Finished => Weight::zero(), @@ -293,7 +303,7 @@ pub mod v2 { pub(crate) fn authority_step( maybe_last_key: Option<&T::AccountId>, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { let mut iter = if let Some(last_key) = maybe_last_key { v1::UsernameAuthorities::::iter_from( v1::UsernameAuthorities::::hashed_key_for(last_key), @@ -315,7 +325,7 @@ pub mod v2 { pub(crate) fn username_step( maybe_last_key: Option<&Username>, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { let mut iter = if let Some(last_key) = maybe_last_key { v1::AccountOfUsername::::iter_from(v1::AccountOfUsername::::hashed_key_for( last_key, @@ -337,7 +347,7 @@ pub mod v2 { pub(crate) fn identity_step( maybe_last_key: Option, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { if let Some(last_key) = IdentityOf::::translate_next::< ( @@ -367,7 +377,7 @@ pub mod v2 { pub(crate) fn pending_username_step( maybe_last_key: Option<&Username>, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { let mut iter = if let Some(last_key) = maybe_last_key { v1::PendingUsernames::::iter_from(v1::PendingUsernames::::hashed_key_for( last_key, @@ -387,9 +397,26 @@ pub mod v2 { } } + pub(crate) fn cleanup_authority_step( + maybe_last_key: Option<&Suffix>, + ) -> MigrationState, Suffix> { + let mut iter = if let Some(last_key) = maybe_last_key { + AuthorityOf::::iter_from(AuthorityOf::::hashed_key_for(last_key)) + } else { + AuthorityOf::::iter() + }; + + if let Some((suffix, properties)) = iter.next() { + let _ = v1::UsernameAuthorities::::take(&properties.account_id); + MigrationState::CleanupAuthorities(suffix) + } else { + MigrationState::FinishedCleanupAuthorities + } + } + pub(crate) fn cleanup_username_step( maybe_last_key: Option<&Username>, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { let mut iter = if let Some(last_key) = maybe_last_key { UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) } else { @@ -406,7 +433,7 @@ pub mod v2 { pub(crate) fn cleanup_pending_username_step( maybe_last_key: Option<&Username>, - ) -> MigrationState> { + ) -> MigrationState, Suffix> { let mut iter = if let Some(last_key) = maybe_last_key { PendingAcceptance::::iter_from(PendingAcceptance::::hashed_key_for(last_key)) } else { @@ -484,11 +511,6 @@ pub mod v2 { [byte; 32].into() } - fn account_into_u8(account_id: &::AccountId) -> u8 { - let bytes: &[u8] = account_id.as_ref(); - bytes[0] - } - #[test] fn migrate_to_v2() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 3bf0f4b2807d..9bcb1d790930 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -81,6 +81,7 @@ pub trait WeightInfo { fn migration_v2_identity_step() -> Weight; fn migration_v2_username_step() -> Weight; fn migration_v2_pending_username_step() -> Weight; + fn migration_v2_cleanup_authority_step() -> Weight; fn migration_v2_cleanup_username_step() -> Weight; fn migration_v2_cleanup_pending_username_step() -> Weight; } @@ -471,6 +472,9 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_identity_step() -> Weight { Weight::zero() } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } @@ -864,6 +868,9 @@ impl WeightInfo for () { fn migration_v2_identity_step() -> Weight { Weight::zero() } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } From 2736a05b95840db85839d3e7a5c9299a7a4d9573 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Fri, 30 Aug 2024 22:03:14 +0300 Subject: [PATCH 19/44] Finish migration Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 42 ++- substrate/frame/identity/src/lib.rs | 11 +- substrate/frame/identity/src/migration.rs | 267 ++++++++++++------- substrate/frame/identity/src/tests.rs | 16 +- substrate/frame/identity/src/weights.rs | 7 - 5 files changed, 199 insertions(+), 144 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 57c56064361a..c746bf331ce0 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -896,71 +896,69 @@ mod benchmarks { #[benchmark] fn migration_v2_authority_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + assert_eq!(AuthorityOf::::iter().count(), 0); #[block] { - LazyMigrationV2::::WeightInfo>::authority_step(None); + LazyMigrationV2::::authority_step(None); } + assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); Ok(()) } #[benchmark] fn migration_v2_username_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + assert_eq!(UsernameInfoOf::::iter().count(), 0); #[block] { - LazyMigrationV2::::WeightInfo>::username_step(None); + LazyMigrationV2::::username_step(None); } + assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); Ok(()) } #[benchmark] fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); #[block] { - LazyMigrationV2::::WeightInfo>::pending_username_step(None); + LazyMigrationV2::::pending_username_step(None); } + assert!(PendingUsernames::::get(&setup.username).is_some()); Ok(()) } #[benchmark] fn migration_v2_identity_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); #[block] { - LazyMigrationV2::::WeightInfo>::identity_step(None); + LazyMigrationV2::::identity_step(None); } + assert!(IdentityOf::::get(&setup.account).is_some()); Ok(()) } #[benchmark] fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); #[block] { - LazyMigrationV2::::WeightInfo>::cleanup_authority_step(None); + LazyMigrationV2::::cleanup_authority_step(None); } + LazyMigrationV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); Ok(()) } #[benchmark] fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); + let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); #[block] { - LazyMigrationV2::::WeightInfo>::cleanup_username_step(None); - } - Ok(()) - } - - #[benchmark] - fn migration_v2_cleanup_pending_username_step() -> Result<(), BenchmarkError> { - LazyMigrationV2::::WeightInfo>::setup_benchmark_env(); - #[block] - { - LazyMigrationV2::::WeightInfo>::cleanup_pending_username_step(None); + LazyMigrationV2::::cleanup_username_step(None); } + LazyMigrationV2::::check_username_cleanup_validity(setup.username, setup.account); Ok(()) } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index e5bff5d2a11c..35f544aa4d82 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -305,7 +305,7 @@ pub mod pallet { /// /// First tuple item is the account and second is the acceptance deadline. #[pallet::storage] - pub type PendingAcceptance = StorageMap< + pub type PendingUsernames = StorageMap< _, Blake2_128Concat, Username, @@ -1123,7 +1123,7 @@ pub mod pallet { Error::::UsernameTaken ); ensure!( - !PendingAcceptance::::contains_key(&bounded_username), + !PendingUsernames::::contains_key(&bounded_username), Error::::UsernameTaken ); @@ -1151,7 +1151,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let (approved_for, _, provider) = - PendingAcceptance::::take(&username).ok_or(Error::::NoUsername)?; + PendingUsernames::::take(&username).ok_or(Error::::NoUsername)?; ensure!(approved_for == who.clone(), Error::::InvalidUsername); Self::insert_username(&who, username.clone(), provider); Self::deposit_event(Event::UsernameSet { who: who.clone(), username }); @@ -1168,7 +1168,7 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - if let Some((who, expiration, provider)) = PendingAcceptance::::take(&username) { + if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); let actual_weight = match provider { @@ -1286,6 +1286,7 @@ pub mod pallet { } /// Permanently delete a username which has been unbinding for longer than the grace period. + /// Caller is refunded the fee if the username expired and the removal was successful. #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::remove_username())] pub fn remove_username( @@ -1526,7 +1527,7 @@ impl Pallet { pub fn queue_acceptance(who: &T::AccountId, username: Username, provider: ProviderOf) { let now = frame_system::Pallet::::block_number(); let expiration = now.saturating_add(T::PendingUsernameExpiration::get()); - PendingAcceptance::::insert(&username, (who.clone(), expiration, provider)); + PendingUsernames::::insert(&username, (who.clone(), expiration, provider)); Self::deposit_event(Event::UsernameQueued { who: who.clone(), username, expiration }); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 4f71204b4c87..f9d75cc83c51 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -158,6 +158,10 @@ pub mod v2 { type HashedKey = BoundedVec>; + #[cfg(feature = "runtime-benchmarks")] + pub(crate) type BenchmarkingSetupOf = + BenchmarkingSetup, ::AccountId, Username>; + mod v1 { use super::*; @@ -178,15 +182,6 @@ pub mod v2 { ::AccountId, OptionQuery, >; - - #[storage_alias] - pub type PendingUsernames = StorageMap< - Pallet, - Blake2_128Concat, - Username, - (::AccountId, BlockNumberFor), - OptionQuery, - >; } #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] @@ -197,18 +192,16 @@ pub mod v2 { FinishedIdentities, Username(U), FinishedUsernames, - PendingUsername(U), + PendingUsername(HashedKey), FinishedPendingUsernames, CleanupAuthorities(S), FinishedCleanupAuthorities, CleanupUsernames(U), - FinishedCleanupUsernames, - CleanupPendingUsernames(U), Finished, } - pub struct LazyMigrationV2(PhantomData<(T, W)>); - impl SteppedMigration for LazyMigrationV2 { + pub struct LazyMigrationV2(PhantomData); + impl SteppedMigration for LazyMigrationV2 { type Cursor = MigrationState, Suffix>; type Identifier = MigrationId<15>; @@ -222,7 +215,7 @@ pub mod v2 { ) -> Result, SteppedMigrationError> { let required = match &cursor { Some(state) => Self::required_weight(&state), - None => W::migration_v2_authority_step(), + None => ::WeightInfo::migration_v2_authority_step(), }; if meter.remaining().any_lt(required) { @@ -232,7 +225,7 @@ pub mod v2 { loop { let required = match &cursor { Some(state) => Self::required_weight(&state), - None => W::migration_v2_authority_step(), + None => ::WeightInfo::migration_v2_authority_step(), }; if meter.try_consume(required).is_err() { @@ -240,30 +233,47 @@ pub mod v2 { } let next = match &cursor { + // At first, migrate any authorities. None => Self::authority_step(None), + // Migrate any remaining authorities. Some(MigrationState::Authority(maybe_last_authority)) => Self::authority_step(Some(maybe_last_authority)), + // After the last authority was migrated, start migrating usernames from + // the former `AccountOfUsername` into `UsernameInfoOf`. Some(MigrationState::FinishedAuthorities) => Self::username_step(None), + // Keep migrating usernames. Some(MigrationState::Username(maybe_last_username)) => Self::username_step(Some(maybe_last_username)), + // After the last username was migrated, start migrating all identities in + // `IdentityOf`, which currently hold the primary username of the owner account + // as well as any associated identity. Accounts which set a username but not an + // identity also have a zero deposit identity stored, which will be removed. Some(MigrationState::FinishedUsernames) => Self::identity_step(None), + // Keep migrating identities. Some(MigrationState::Identity(last_key)) => Self::identity_step(Some(last_key.clone())), + // After the last identity was migrated, start migrating usernames pending + // approval from `PendingUsernames`. Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None), - Some(MigrationState::PendingUsername(maybe_last_username)) => - Self::pending_username_step(Some(maybe_last_username)), + // Keep migrating pending usernames. + Some(MigrationState::PendingUsername(last_key)) => + Self::pending_username_step(Some(last_key.clone())), + // After the last pending username was migrated, start clearing the storage + // previously associated with authorities in `UsernameAuthority`. Some(MigrationState::FinishedPendingUsernames) => Self::cleanup_authority_step(None), + // Keep clearing the obsolete authority storage. Some(MigrationState::CleanupAuthorities(maybe_last_username)) => Self::cleanup_authority_step(Some(maybe_last_username)), + // After the last obsolete authority was cleared from storage, start clearing + // the storage previously associated with usernames in `AccountOfUsername`. Some(MigrationState::FinishedCleanupAuthorities) => Self::cleanup_username_step(None), + // Keep clearing the obsolete username storage. Some(MigrationState::CleanupUsernames(maybe_last_username)) => Self::cleanup_username_step(Some(maybe_last_username)), - Some(MigrationState::FinishedCleanupUsernames) => - Self::cleanup_pending_username_step(None), - Some(MigrationState::CleanupPendingUsernames(maybe_last_username)) => - Self::cleanup_pending_username_step(Some(maybe_last_username)), + // After the last obsolete username was cleared from storage, the migration is + // done. Some(MigrationState::Finished) => return Ok(None), }; @@ -274,33 +284,30 @@ pub mod v2 { } } - impl LazyMigrationV2 { - #[allow(unused)] - fn pretty_username(username: &Username) -> String { - String::from_utf8(username.to_vec()).unwrap() - } - + impl LazyMigrationV2 { pub(crate) fn required_weight( step: &MigrationState, Suffix>, ) -> Weight { match step { - MigrationState::Authority(_) => W::migration_v2_authority_step(), - MigrationState::FinishedAuthorities | MigrationState::Identity(_) => - W::migration_v2_identity_step(), - MigrationState::FinishedIdentities | MigrationState::Username(_) => - W::migration_v2_username_step(), - MigrationState::FinishedUsernames | MigrationState::PendingUsername(_) => - W::migration_v2_pending_username_step(), + MigrationState::Authority(_) => + ::WeightInfo::migration_v2_authority_step(), + MigrationState::FinishedAuthorities | MigrationState::Username(_) => + ::WeightInfo::migration_v2_username_step(), + MigrationState::FinishedUsernames | MigrationState::Identity(_) => + ::WeightInfo::migration_v2_identity_step(), + MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => + ::WeightInfo::migration_v2_pending_username_step(), MigrationState::FinishedPendingUsernames | - MigrationState::CleanupAuthorities(_) => W::migration_v2_cleanup_authority_step(), + MigrationState::CleanupAuthorities(_) => + ::WeightInfo::migration_v2_cleanup_authority_step(), MigrationState::FinishedCleanupAuthorities | - MigrationState::CleanupUsernames(_) => W::migration_v2_cleanup_username_step(), - MigrationState::FinishedCleanupUsernames | - MigrationState::CleanupPendingUsernames(_) => W::migration_v2_cleanup_pending_username_step(), + MigrationState::CleanupUsernames(_) => + ::WeightInfo::migration_v2_cleanup_username_step(), MigrationState::Finished => Weight::zero(), } } + // Migrate one entry from `UsernameAuthorities` to `AuthorityOf`. pub(crate) fn authority_step( maybe_last_key: Option<&T::AccountId>, ) -> MigrationState, Suffix> { @@ -323,6 +330,7 @@ pub mod v2 { } } + // Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`. pub(crate) fn username_step( maybe_last_key: Option<&Username>, ) -> MigrationState, Suffix> { @@ -345,6 +353,8 @@ pub mod v2 { } } + // Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with + // it. Remove the entry if there was no real identity associated with the account. pub(crate) fn identity_step( maybe_last_key: Option, ) -> MigrationState, Suffix> { @@ -375,28 +385,22 @@ pub mod v2 { } } + // Migrate one entry from `PendingUsernames` to contain the new `Provider` field. pub(crate) fn pending_username_step( - maybe_last_key: Option<&Username>, + maybe_last_key: Option, ) -> MigrationState, Suffix> { - let mut iter = if let Some(last_key) = maybe_last_key { - v1::PendingUsernames::::iter_from(v1::PendingUsernames::::hashed_key_for( - last_key, - )) - } else { - v1::PendingUsernames::::iter() - }; - - if let Some((username, (owner_account, since))) = iter.next() { - PendingAcceptance::::insert( - &username, - (owner_account, since, Provider::Governance), - ); - MigrationState::PendingUsername(username) + if let Some(last_key) = + PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( + maybe_last_key.map(|b| b.to_vec()), + |_, (owner_account, since)| Some((owner_account, since, Provider::Governance)), + ) { + MigrationState::PendingUsername(last_key.try_into().unwrap()) } else { MigrationState::FinishedPendingUsernames } } + // Remove one entry from `UsernameAuthorities`. pub(crate) fn cleanup_authority_step( maybe_last_key: Option<&Suffix>, ) -> MigrationState, Suffix> { @@ -414,6 +418,7 @@ pub mod v2 { } } + // Remove one entry from `AccountOfUsername`. pub(crate) fn cleanup_username_step( maybe_last_key: Option<&Username>, ) -> MigrationState, Suffix> { @@ -426,37 +431,27 @@ pub mod v2 { if let Some((username, _)) = iter.next() { let _ = v1::AccountOfUsername::::take(&username); MigrationState::CleanupUsernames(username) - } else { - MigrationState::FinishedCleanupUsernames - } - } - - pub(crate) fn cleanup_pending_username_step( - maybe_last_key: Option<&Username>, - ) -> MigrationState, Suffix> { - let mut iter = if let Some(last_key) = maybe_last_key { - PendingAcceptance::::iter_from(PendingAcceptance::::hashed_key_for(last_key)) - } else { - PendingAcceptance::::iter() - }; - - if let Some((username, _)) = iter.next() { - let _ = v1::PendingUsernames::::take(&username); - - MigrationState::CleanupPendingUsernames(username) } else { MigrationState::Finished } } + } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) struct BenchmarkingSetup { + pub(crate) suffix: S, + pub(crate) authority: A, + pub(crate) account: A, + pub(crate) username: U, + } - #[cfg(feature = "runtime-benchmarks")] - pub(crate) fn setup_benchmark_env() { - use frame_benchmarking::account; + #[cfg(feature = "runtime-benchmarks")] + impl LazyMigrationV2 { + pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { use frame_support::Hashable; let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); - let authority: T::AccountId = account("authority", 0, 0); - let account_with_username: T::AccountId = account("account", 1, 0); - let account_without_username: T::AccountId = account("account", 2, 0); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); let prop: AuthorityProperties> = AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; @@ -472,17 +467,61 @@ pub mod v2 { frame_support::migration::put_storage_value( b"Identity", b"IdentityOf", - &account_with_username.twox_64_concat(), + &account_id.twox_64_concat(), (®istration, Some(username.clone())), ); + v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); frame_support::migration::put_storage_value( b"Identity", - b"IdentityOf", - &account_without_username.twox_64_concat(), - (®istration, None::>), + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), ); - v1::AccountOfUsername::::insert(&username, &account_with_username); - v1::PendingUsernames::::insert(&username, &(account_with_username, 0u32.into())); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf { + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority, &prop); + let prop: AuthorityProperties = + AuthorityProperties { account_id: authority.clone(), allocation: 10 }; + AuthorityOf::::insert(&suffix, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + IdentityOf::::insert(&account_id, ®istration); + UsernameOf::::insert(&account_id, &username); + let username_info = + UsernameInformation { owner: account_id.clone(), provider: Provider::Governance }; + UsernameInfoOf::::insert(&username, username_info); + v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + PendingUsernames::::insert(&username, (&account_id, since, Provider::Governance)); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { + assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); + } + + pub(crate) fn check_username_cleanup_validity( + username: Username, + account_id: T::AccountId, + ) { + assert_eq!(v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); } } @@ -514,18 +553,22 @@ pub mod v2 { #[test] fn migrate_to_v2() { new_test_ext().execute_with(|| { + // Set up the first authority. let authority_1 = account_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; v1::UsernameAuthorities::::insert(&authority_1, &prop); - + // Set up the first authority. let authority_2 = account_from_u8(152); let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; v1::UsernameAuthorities::::insert(&authority_2, &prop); + // (owner_account, primary_username, maybe_secondary_username, has_identity) + // If `has_identity` is set, this `owner_account` will have a real identity + // associated and a non-zero deposit for it. let mut usernames = vec![]; - for i in 0u8..10u8 { + for i in 0u8..100u8 { let account_id = account_from_u8(i); let bare_username = format!("acc{}.", i).as_bytes().to_vec(); let mut username_1 = bare_username.clone(); @@ -560,19 +603,25 @@ pub mod v2 { } } + // (username, owner_account, since) let mut pending = vec![]; - for i in 20u8..25u8 { + for i in 100u8..110u8 { let account_id = account_from_u8(i); let mut bare_username = format!("acc{}.", i).as_bytes().to_vec(); bare_username.extend(suffix_1.iter()); let username: Username = bare_username.try_into().unwrap(); let since: BlockNumberFor = i.into(); - v1::PendingUsernames::::insert(&username, (account_id.clone(), since)); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); pending.push((username, account_id, since)); } let mut identity_only = vec![]; - for i in 30u8..35u8 { + for i in 120u8..130u8 { let account_id = account_from_u8(i); let reg = registration(true); frame_support::migration::put_storage_value( @@ -584,18 +633,16 @@ pub mod v2 { identity_only.push(account_id); } + // Run the actual migration. let mut weight_meter = WeightMeter::new(); let mut cursor = None; while let Some(new_cursor) = - LazyMigrationV2::::WeightInfo>::step( - cursor, - &mut weight_meter, - ) - .unwrap() + LazyMigrationV2::::step(cursor, &mut weight_meter).unwrap() { cursor = Some(new_cursor); } + // Check that the authorities were migrated. let expected_prop = AuthorityProperties { account_id: authority_1.clone(), allocation: 10 }; assert_eq!(AuthorityOf::::get(&suffix_1), Some(expected_prop)); @@ -604,6 +651,15 @@ pub mod v2 { AuthorityProperties { account_id: authority_2.clone(), allocation: 10 }; assert_eq!(AuthorityOf::::get(&suffix_2), Some(expected_prop)); + // Check that the username information was migrated. + let count_of_usernames_without_identities = + usernames.iter().filter(|(_, _, _, has_id)| *has_id).count(); + assert_eq!(UsernameOf::::iter().count(), usernames.len()); + // All accounts have `evn` usernames, only half of them have `odd` usernames. + assert_eq!( + UsernameInfoOf::::iter().count(), + usernames.len() + usernames.len() / 2 + ); for (owner, primary, maybe_secondary, has_identity) in usernames.iter() { let username_info = UsernameInfoOf::::get(primary).unwrap(); assert_eq!(&username_info.owner, owner); @@ -619,21 +675,28 @@ pub mod v2 { } } - let pending_count = PendingAcceptance::::iter().count(); - assert_eq!(pending_count, 5); - for (username, owner, since) in pending.iter() { - let expected_pending = (owner.clone(), *since, Provider::Governance); - assert_eq!(PendingAcceptance::::get(username), Some(expected_pending)); - } - + // Check that existing identities were preserved. for id in identity_only.iter() { let expected_reg = registration(true); assert_eq!(IdentityOf::::get(id), Some(expected_reg)); assert!(!UsernameOf::::contains_key(id)); } + let identity_count = IdentityOf::::iter().count(); + assert_eq!( + identity_count, + count_of_usernames_without_identities + identity_only.len() + ); + + // Check that pending usernames were migrated. + let pending_count = PendingUsernames::::iter().count(); + assert_eq!(pending_count, pending.len()); + for (username, owner, since) in pending.iter() { + let expected_pending = (owner.clone(), *since, Provider::Governance); + assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); + } + // Check that obsolete storage was cleared. assert_eq!(v1::AccountOfUsername::::iter().count(), 0); - assert_eq!(v1::PendingUsernames::::iter().count(), 0); assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); }); } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index f88262c8f841..2ab1f396b2b7 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1327,7 +1327,7 @@ fn set_username_with_acceptance_should_work() { // Should be pending assert_eq!( - PendingAcceptance::::get::<&Username>(&username), + PendingUsernames::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Governance)) ); @@ -1335,7 +1335,7 @@ fn set_username_with_acceptance_should_work() { assert_ok!(Identity::accept_username(RuntimeOrigin::signed(who.clone()), username.clone())); // No more pending - assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); // Check Identity storage assert_eq!(UsernameOf::::get(&who), Some(username.clone())); // Check reverse lookup @@ -1359,7 +1359,7 @@ fn set_username_with_acceptance_should_work() { // Should be pending let username_deposit = ::UsernameDeposit::get(); assert_eq!( - PendingAcceptance::::get::<&Username>(&second_username), + PendingUsernames::::get::<&Username>(&second_username), Some((second_caller.clone(), expiration, Provider::Authority(username_deposit))) ); assert_eq!( @@ -1373,7 +1373,7 @@ fn set_username_with_acceptance_should_work() { )); // No more pending - assert!(PendingAcceptance::::get::<&Username>(&second_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&second_username).is_none()); // Check Identity storage assert_eq!(UsernameOf::::get(&second_caller), Some(second_username.clone())); // Check reverse lookup @@ -1699,7 +1699,7 @@ fn unaccepted_usernames_through_grant_should_expire() { // Should be pending assert_eq!( - PendingAcceptance::::get::<&Username>(&username), + PendingUsernames::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Governance)) ); @@ -1723,7 +1723,7 @@ fn unaccepted_usernames_through_grant_should_expire() { assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // No more pending - assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); }); } @@ -1767,7 +1767,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { // Should be pending assert_eq!( - PendingAcceptance::::get::<&Username>(&username), + PendingUsernames::::get::<&Username>(&username), Some((who.clone(), expiration, Provider::Authority(username_deposit))) ); @@ -1797,7 +1797,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); // No more pending - assert!(PendingAcceptance::::get::<&Username>(&username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); }); } diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 9bcb1d790930..154cb1b4f3c9 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -83,7 +83,6 @@ pub trait WeightInfo { fn migration_v2_pending_username_step() -> Weight; fn migration_v2_cleanup_authority_step() -> Weight; fn migration_v2_cleanup_username_step() -> Weight; - fn migration_v2_cleanup_pending_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -478,9 +477,6 @@ impl WeightInfo for SubstrateWeight { fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_pending_username_step() -> Weight { - Weight::zero() - } } // For backwards compatibility and tests. @@ -874,7 +870,4 @@ impl WeightInfo for () { fn migration_v2_cleanup_username_step() -> Weight { Weight::zero() } - fn migration_v2_cleanup_pending_username_step() -> Weight { - Weight::zero() - } } From db04e869b7728a468b973f5b7c2dc1a79cced38e Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 2 Sep 2024 19:14:01 +0300 Subject: [PATCH 20/44] Get rid of benchmarks Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 70 +------ substrate/frame/identity/src/migration.rs | 186 ++++++------------- substrate/frame/identity/src/weights.rs | 42 ----- 3 files changed, 54 insertions(+), 244 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index c746bf331ce0..c2d3e6a6127d 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::{migration::v2::LazyMigrationV2, Pallet as Identity}; +use crate::Pallet as Identity; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -894,73 +894,5 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn migration_v2_authority_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); - assert_eq!(AuthorityOf::::iter().count(), 0); - #[block] - { - LazyMigrationV2::::authority_step(None); - } - assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); - Ok(()) - } - - #[benchmark] - fn migration_v2_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); - assert_eq!(UsernameInfoOf::::iter().count(), 0); - #[block] - { - LazyMigrationV2::::username_step(None); - } - assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); - Ok(()) - } - - #[benchmark] - fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); - #[block] - { - LazyMigrationV2::::pending_username_step(None); - } - assert!(PendingUsernames::::get(&setup.username).is_some()); - Ok(()) - } - - #[benchmark] - fn migration_v2_identity_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); - #[block] - { - LazyMigrationV2::::identity_step(None); - } - assert!(IdentityOf::::get(&setup.account).is_some()); - Ok(()) - } - - #[benchmark] - fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); - #[block] - { - LazyMigrationV2::::cleanup_authority_step(None); - } - LazyMigrationV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); - Ok(()) - } - - #[benchmark] - fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); - #[block] - { - LazyMigrationV2::::cleanup_username_step(None); - } - LazyMigrationV2::::check_username_cleanup_validity(setup.username, setup.account); - Ok(()) - } - impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index f9d75cc83c51..097c019b80d9 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -157,10 +157,9 @@ pub mod v2 { }; type HashedKey = BoundedVec>; - - #[cfg(feature = "runtime-benchmarks")] - pub(crate) type BenchmarkingSetupOf = - BenchmarkingSetup, ::AccountId, Username>; + // The resulting state of the step and the actual weight consumed. + type StepResultOf = + (MigrationState<::AccountId, Username, Suffix>, Weight); mod v1 { use super::*; @@ -213,26 +212,30 @@ pub mod v2 { mut cursor: Option, meter: &mut WeightMeter, ) -> Result, SteppedMigrationError> { + // Check that we have enough weight for at least the next step. If we don't, then the + // migration cannot be complete. let required = match &cursor { Some(state) => Self::required_weight(&state), - None => ::WeightInfo::migration_v2_authority_step(), + // Worst case weight for `authority_step`. + None => T::DbWeight::get().reads_writes(1, 1), }; - if meter.remaining().any_lt(required) { return Err(SteppedMigrationError::InsufficientWeight { required }); } loop { + // Check that we would have enough weight to perform this step in the worst case + // scenario. let required = match &cursor { Some(state) => Self::required_weight(&state), - None => ::WeightInfo::migration_v2_authority_step(), + // Worst case weight for `authority_step`. + None => T::DbWeight::get().reads_writes(1, 1), }; - - if meter.try_consume(required).is_err() { + if !meter.can_consume(required) { break; } - let next = match &cursor { + let (next, actual_weight) = match &cursor { // At first, migrate any authorities. None => Self::authority_step(None), // Migrate any remaining authorities. @@ -278,6 +281,13 @@ pub mod v2 { }; cursor = Some(next); + // After performing one step, consume the actual weight. + if actual_weight.any_gt(required) { + defensive!( + "actual weight should not be greater than the worst case scenario weight" + ); + } + meter.consume(actual_weight); } Ok(cursor) @@ -289,28 +299,23 @@ pub mod v2 { step: &MigrationState, Suffix>, ) -> Weight { match step { - MigrationState::Authority(_) => - ::WeightInfo::migration_v2_authority_step(), + MigrationState::Authority(_) => T::DbWeight::get().reads_writes(1, 1), MigrationState::FinishedAuthorities | MigrationState::Username(_) => - ::WeightInfo::migration_v2_username_step(), + T::DbWeight::get().reads_writes(1, 1), MigrationState::FinishedUsernames | MigrationState::Identity(_) => - ::WeightInfo::migration_v2_identity_step(), + T::DbWeight::get().reads_writes(1, 2), MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => - ::WeightInfo::migration_v2_pending_username_step(), + T::DbWeight::get().reads_writes(1, 1), MigrationState::FinishedPendingUsernames | - MigrationState::CleanupAuthorities(_) => - ::WeightInfo::migration_v2_cleanup_authority_step(), + MigrationState::CleanupAuthorities(_) => T::DbWeight::get().reads_writes(1, 1), MigrationState::FinishedCleanupAuthorities | - MigrationState::CleanupUsernames(_) => - ::WeightInfo::migration_v2_cleanup_username_step(), + MigrationState::CleanupUsernames(_) => T::DbWeight::get().reads_writes(1, 1), MigrationState::Finished => Weight::zero(), } } // Migrate one entry from `UsernameAuthorities` to `AuthorityOf`. - pub(crate) fn authority_step( - maybe_last_key: Option<&T::AccountId>, - ) -> MigrationState, Suffix> { + pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { v1::UsernameAuthorities::::iter_from( v1::UsernameAuthorities::::hashed_key_for(last_key), @@ -324,16 +329,17 @@ pub mod v2 { let new_properties = AuthorityProperties { account_id: authority_account.clone(), allocation }; AuthorityOf::::insert(&suffix, new_properties); - MigrationState::Authority(authority_account) + ( + MigrationState::Authority(authority_account), + T::DbWeight::get().reads_writes(1, 1), + ) } else { - MigrationState::FinishedAuthorities + (MigrationState::FinishedAuthorities, T::DbWeight::get().reads(1)) } } // Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`. - pub(crate) fn username_step( - maybe_last_key: Option<&Username>, - ) -> MigrationState, Suffix> { + pub(crate) fn username_step(maybe_last_key: Option<&Username>) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { v1::AccountOfUsername::::iter_from(v1::AccountOfUsername::::hashed_key_for( last_key, @@ -347,17 +353,15 @@ pub mod v2 { UsernameInformation { owner: owner_account, provider: Provider::Governance }; UsernameInfoOf::::insert(&username, username_info); - MigrationState::Username(username) + (MigrationState::Username(username), T::DbWeight::get().reads_writes(1, 1)) } else { - MigrationState::FinishedUsernames + (MigrationState::FinishedUsernames, T::DbWeight::get().reads(1)) } } // Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with // it. Remove the entry if there was no real identity associated with the account. - pub(crate) fn identity_step( - maybe_last_key: Option, - ) -> MigrationState, Suffix> { + pub(crate) fn identity_step(maybe_last_key: Option) -> StepResultOf { if let Some(last_key) = IdentityOf::::translate_next::< ( @@ -379,31 +383,35 @@ pub mod v2 { None } }) { - MigrationState::Identity(last_key.try_into().unwrap()) + ( + MigrationState::Identity(last_key.try_into().unwrap()), + T::DbWeight::get().reads_writes(1, 2), + ) } else { - MigrationState::FinishedIdentities + (MigrationState::FinishedIdentities, T::DbWeight::get().reads(1)) } } // Migrate one entry from `PendingUsernames` to contain the new `Provider` field. - pub(crate) fn pending_username_step( - maybe_last_key: Option, - ) -> MigrationState, Suffix> { + pub(crate) fn pending_username_step(maybe_last_key: Option) -> StepResultOf { if let Some(last_key) = PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( maybe_last_key.map(|b| b.to_vec()), |_, (owner_account, since)| Some((owner_account, since, Provider::Governance)), ) { - MigrationState::PendingUsername(last_key.try_into().unwrap()) + ( + MigrationState::PendingUsername(last_key.try_into().unwrap()), + T::DbWeight::get().reads_writes(1, 1), + ) } else { - MigrationState::FinishedPendingUsernames + (MigrationState::FinishedPendingUsernames, T::DbWeight::get().reads(1)) } } // Remove one entry from `UsernameAuthorities`. pub(crate) fn cleanup_authority_step( maybe_last_key: Option<&Suffix>, - ) -> MigrationState, Suffix> { + ) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { AuthorityOf::::iter_from(AuthorityOf::::hashed_key_for(last_key)) } else { @@ -412,16 +420,16 @@ pub mod v2 { if let Some((suffix, properties)) = iter.next() { let _ = v1::UsernameAuthorities::::take(&properties.account_id); - MigrationState::CleanupAuthorities(suffix) + (MigrationState::CleanupAuthorities(suffix), T::DbWeight::get().reads_writes(1, 1)) } else { - MigrationState::FinishedCleanupAuthorities + (MigrationState::FinishedCleanupAuthorities, T::DbWeight::get().reads(1)) } } // Remove one entry from `AccountOfUsername`. pub(crate) fn cleanup_username_step( maybe_last_key: Option<&Username>, - ) -> MigrationState, Suffix> { + ) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) } else { @@ -430,101 +438,13 @@ pub mod v2 { if let Some((username, _)) = iter.next() { let _ = v1::AccountOfUsername::::take(&username); - MigrationState::CleanupUsernames(username) + (MigrationState::CleanupUsernames(username), T::DbWeight::get().reads_writes(1, 1)) } else { - MigrationState::Finished + (MigrationState::Finished, T::DbWeight::get().reads(1)) } } } - #[cfg(feature = "runtime-benchmarks")] - pub(crate) struct BenchmarkingSetup { - pub(crate) suffix: S, - pub(crate) authority: A, - pub(crate) account: A, - pub(crate) username: U, - } - - #[cfg(feature = "runtime-benchmarks")] - impl LazyMigrationV2 { - pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { - use frame_support::Hashable; - let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); - let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); - let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); - - let prop: AuthorityProperties> = - AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority, &prop); - - let username: Username = b"account.bench".to_vec().try_into().unwrap(); - let info = T::IdentityInformation::create_identity_info(); - let registration: Registration< - BalanceOf, - ::MaxRegistrars, - ::IdentityInformation, - > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; - frame_support::migration::put_storage_value( - b"Identity", - b"IdentityOf", - &account_id.twox_64_concat(), - (®istration, Some(username.clone())), - ); - v1::AccountOfUsername::::insert(&username, &account_id); - let since: BlockNumberFor = 0u32.into(); - frame_support::migration::put_storage_value( - b"Identity", - b"PendingUsernames", - &username.blake2_128_concat(), - (&account_id, since), - ); - BenchmarkingSetup { suffix, authority, account: account_id, username } - } - - pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf { - let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); - let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); - let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); - - let prop: AuthorityProperties> = - AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority, &prop); - let prop: AuthorityProperties = - AuthorityProperties { account_id: authority.clone(), allocation: 10 }; - AuthorityOf::::insert(&suffix, &prop); - - let username: Username = b"account.bench".to_vec().try_into().unwrap(); - let info = T::IdentityInformation::create_identity_info(); - let registration: Registration< - BalanceOf, - ::MaxRegistrars, - ::IdentityInformation, - > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; - IdentityOf::::insert(&account_id, ®istration); - UsernameOf::::insert(&account_id, &username); - let username_info = - UsernameInformation { owner: account_id.clone(), provider: Provider::Governance }; - UsernameInfoOf::::insert(&username, username_info); - v1::AccountOfUsername::::insert(&username, &account_id); - let since: BlockNumberFor = 0u32.into(); - PendingUsernames::::insert(&username, (&account_id, since, Provider::Governance)); - BenchmarkingSetup { suffix, authority, account: account_id, username } - } - - pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { - assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); - assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); - } - - pub(crate) fn check_username_cleanup_validity( - username: Username, - account_id: T::AccountId, - ) { - assert_eq!(v1::AccountOfUsername::::iter().count(), 0); - assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); - } - } - #[cfg(test)] mod tests { use frame_support::Hashable; diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 154cb1b4f3c9..5d79f177638e 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -77,12 +77,6 @@ pub trait WeightInfo { fn unbind_username() -> Weight; fn remove_username() -> Weight; fn kill_username(p: u32) -> Weight; - fn migration_v2_authority_step() -> Weight; - fn migration_v2_identity_step() -> Weight; - fn migration_v2_username_step() -> Weight; - fn migration_v2_pending_username_step() -> Weight; - fn migration_v2_cleanup_authority_step() -> Weight; - fn migration_v2_cleanup_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -459,24 +453,6 @@ impl WeightInfo for SubstrateWeight { fn kill_username(_p: u32) -> Weight { Weight::zero() } - fn migration_v2_authority_step() -> Weight { - Weight::zero() - } - fn migration_v2_username_step() -> Weight { - Weight::zero() - } - fn migration_v2_pending_username_step() -> Weight { - Weight::zero() - } - fn migration_v2_identity_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_authority_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_username_step() -> Weight { - Weight::zero() - } } // For backwards compatibility and tests. @@ -852,22 +828,4 @@ impl WeightInfo for () { fn kill_username(_p: u32) -> Weight { Weight::zero() } - fn migration_v2_username_step() -> Weight { - Weight::zero() - } - fn migration_v2_pending_username_step() -> Weight { - Weight::zero() - } - fn migration_v2_authority_step() -> Weight { - Weight::zero() - } - fn migration_v2_identity_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_authority_step() -> Weight { - Weight::zero() - } - fn migration_v2_cleanup_username_step() -> Weight { - Weight::zero() - } } From 040cd62d84092f877327fd2b8a9222b84c0a0db5 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 2 Sep 2024 19:21:18 +0300 Subject: [PATCH 21/44] Some renames Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 18 +++++----- substrate/frame/identity/src/migration.rs | 14 +++++--- substrate/frame/identity/src/tests.rs | 40 +++++++++++------------ substrate/frame/identity/src/types.rs | 8 ++--- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 35f544aa4d82..c98e0cc66026 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1172,7 +1172,7 @@ pub mod pallet { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); let actual_weight = match provider { - Provider::Authority(deposit) => { + Provider::AuthorityDeposit(deposit) => { let suffix = Self::suffix_of_username(&username) .ok_or(Error::::InvalidUsername)?; let authority_account = AuthorityOf::::get(&suffix) @@ -1182,7 +1182,7 @@ pub mod pallet { debug_assert!(err_amount.is_zero()); T::WeightInfo::remove_expired_approval(0) }, - Provider::Governance => { + Provider::Allocation => { // We don't refund the allocation, it is lost, but we refund some weight. T::WeightInfo::remove_expired_approval(1) }, @@ -1228,7 +1228,7 @@ pub mod pallet { Error::::InvalidUsername ); match username_info.provider { - Provider::Authority(username_deposit) => { + Provider::AuthorityDeposit(username_deposit) => { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = @@ -1239,7 +1239,7 @@ pub mod pallet { debug_assert!(err_amount.is_zero()); } }, - Provider::Governance => { + Provider::Allocation => { // We don't refund the allocation, it is lost. }, Provider::System => return Err(Error::::InvalidTarget.into()), @@ -1269,7 +1269,7 @@ pub mod pallet { .ok_or(Error::::NotUsernameAuthority)?; ensure!(who == authority_account, Error::::NotUsernameAuthority); match username_info.provider { - Provider::Authority(_) | Provider::Governance => { + Provider::AuthorityDeposit(_) | Provider::Allocation => { let now = frame_system::Pallet::::block_number(); UnbindingUsernames::::try_mutate(&username, |maybe_init| { if maybe_init.is_some() { @@ -1313,7 +1313,7 @@ pub mod pallet { } }); match username_info.provider { - Provider::Authority(username_deposit) => { + Provider::AuthorityDeposit(username_deposit) => { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = @@ -1324,7 +1324,7 @@ pub mod pallet { debug_assert!(err_amount.is_zero()); } }, - Provider::Governance => { + Provider::Allocation => { // We don't refund the allocation, it is lost. }, Provider::System => return Err(Error::::InvalidTarget.into()), @@ -1355,7 +1355,7 @@ pub mod pallet { }); let _ = UnbindingUsernames::::take(&username); let actual_weight = match username_info.provider { - Provider::Authority(username_deposit) => { + Provider::AuthorityDeposit(username_deposit) => { let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = @@ -1367,7 +1367,7 @@ pub mod pallet { } T::WeightInfo::kill_username(0) }, - Provider::Governance => { + Provider::Allocation => { // We don't refund the allocation, it is lost, but we do refund some weight. T::WeightInfo::kill_username(1) }, diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 097c019b80d9..aaf10a6c58ba 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -349,8 +349,10 @@ pub mod v2 { }; if let Some((username, owner_account)) = iter.next() { - let username_info = - UsernameInformation { owner: owner_account, provider: Provider::Governance }; + let username_info = UsernameInformation { + owner: owner_account, + provider: Provider::new_with_allocation(), + }; UsernameInfoOf::::insert(&username, username_info); (MigrationState::Username(username), T::DbWeight::get().reads_writes(1, 1)) @@ -397,7 +399,9 @@ pub mod v2 { if let Some(last_key) = PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( maybe_last_key.map(|b| b.to_vec()), - |_, (owner_account, since)| Some((owner_account, since, Provider::Governance)), + |_, (owner_account, since)| { + Some((owner_account, since, Provider::new_with_allocation())) + }, ) { ( MigrationState::PendingUsername(last_key.try_into().unwrap()), @@ -589,7 +593,7 @@ pub mod v2 { if let Some(secondary) = maybe_secondary { let expected_info = UsernameInformation { owner: owner.clone(), - provider: Provider::Governance, + provider: Provider::new_with_allocation(), }; assert_eq!(UsernameInfoOf::::get(secondary), Some(expected_info)); } @@ -611,7 +615,7 @@ pub mod v2 { let pending_count = PendingUsernames::::iter().count(); assert_eq!(pending_count, pending.len()); for (username, owner, since) in pending.iter() { - let expected_pending = (owner.clone(), *since, Provider::Governance); + let expected_pending = (owner.clone(), *since, Provider::Allocation); assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 2ab1f396b2b7..9634801c7929 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1043,7 +1043,7 @@ fn set_username_with_signature_without_existing_identity_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Lookup from username to account works. let expected_user_info = - UsernameInformation { owner: who_account, provider: Provider::Governance }; + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) @@ -1083,7 +1083,7 @@ fn set_username_with_signature_without_existing_identity_should_work() { // Lookup from username to account works. let expected_user_info = UsernameInformation { owner: second_who, - provider: Provider::Authority(username_deposit), + provider: Provider::AuthorityDeposit(username_deposit), }; assert_eq!( UsernameInfoOf::::get::<&Username>(&second_username), @@ -1144,7 +1144,7 @@ fn set_username_with_signature_with_existing_identity_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); let expected_user_info = - UsernameInformation { owner: who_account, provider: Provider::Governance }; + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) @@ -1210,7 +1210,7 @@ fn set_username_through_deposit_with_existing_identity_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); let expected_user_info = UsernameInformation { owner: who_account, - provider: Provider::Authority(username_deposit), + provider: Provider::AuthorityDeposit(username_deposit), }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), @@ -1288,7 +1288,7 @@ fn set_username_with_bytes_signature_should_work() { assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Likewise for the lookup. let expected_user_info = - UsernameInformation { owner: who_account, provider: Provider::Governance }; + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) @@ -1328,7 +1328,7 @@ fn set_username_with_acceptance_should_work() { // Should be pending assert_eq!( PendingUsernames::::get::<&Username>(&username), - Some((who.clone(), expiration, Provider::Governance)) + Some((who.clone(), expiration, Provider::Allocation)) ); // Now the user can accept @@ -1339,7 +1339,7 @@ fn set_username_with_acceptance_should_work() { // Check Identity storage assert_eq!(UsernameOf::::get(&who), Some(username.clone())); // Check reverse lookup - let expected_user_info = UsernameInformation { owner: who, provider: Provider::Governance }; + let expected_user_info = UsernameInformation { owner: who, provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info) @@ -1360,7 +1360,7 @@ fn set_username_with_acceptance_should_work() { let username_deposit = ::UsernameDeposit::get(); assert_eq!( PendingUsernames::::get::<&Username>(&second_username), - Some((second_caller.clone(), expiration, Provider::Authority(username_deposit))) + Some((second_caller.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) ); assert_eq!( Balances::free_balance(&authority), @@ -1379,7 +1379,7 @@ fn set_username_with_acceptance_should_work() { // Check reverse lookup let expected_user_info = UsernameInformation { owner: second_caller, - provider: Provider::Authority(username_deposit), + provider: Provider::AuthorityDeposit(username_deposit), }; assert_eq!( UsernameInfoOf::::get::<&Username>(&second_username), @@ -1562,7 +1562,7 @@ fn setting_primary_should_work() { // Lookup from both works. let expected_user_info = - UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&first_username), Some(expected_user_info.clone()) @@ -1636,13 +1636,13 @@ fn must_own_primary() { // Ensure that both users have their usernames. let expected_pi_info = - UsernameInformation { owner: pi_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: pi_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&pi_username), Some(expected_pi_info) ); let expected_e_info = - UsernameInformation { owner: e_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: e_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&e_username), Some(expected_e_info) @@ -1700,7 +1700,7 @@ fn unaccepted_usernames_through_grant_should_expire() { // Should be pending assert_eq!( PendingUsernames::::get::<&Username>(&username), - Some((who.clone(), expiration, Provider::Governance)) + Some((who.clone(), expiration, Provider::Allocation)) ); run_to_block(now + expiration - 1); @@ -1768,7 +1768,7 @@ fn unaccepted_usernames_through_deposit_should_expire() { // Should be pending assert_eq!( PendingUsernames::::get::<&Username>(&username), - Some((who.clone(), expiration, Provider::Authority(username_deposit))) + Some((who.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) ); run_to_block(now + expiration - 1); @@ -1859,7 +1859,7 @@ fn removing_dangling_usernames_should_work() { // But both usernames should look up the account. let expected_user_info = - UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info.clone()) @@ -2003,7 +2003,7 @@ fn kill_username_should_work() { // But both usernames should look up the account. let expected_user_info = UsernameInformation { owner: who_account.clone(), - provider: Provider::Authority(username_deposit), + provider: Provider::AuthorityDeposit(username_deposit), }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), @@ -2064,7 +2064,7 @@ fn kill_username_should_work() { // But the reverse lookup of the third and final username is still there let expected_user_info = - UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username_three), Some(expected_user_info) @@ -2144,14 +2144,14 @@ fn unbind_and_remove_username_should_work() { // But both usernames should look up the account. let expected_user_info = UsernameInformation { owner: who_account.clone(), - provider: Provider::Authority(username_deposit), + provider: Provider::AuthorityDeposit(username_deposit), }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username), Some(expected_user_info.clone()) ); let expected_user_info = - UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }; + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( UsernameInfoOf::::get::<&Username>(&username_two), Some(expected_user_info.clone()) @@ -2179,7 +2179,7 @@ fn unbind_and_remove_username_should_work() { // Only the authority that granted the username can unbind it. UsernameInfoOf::::insert( dummy_username.clone(), - UsernameInformation { owner: who_account.clone(), provider: Provider::Governance }, + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }, ); assert_noop!( Identity::unbind_username( diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index e6de33767885..ece3c34f82ef 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -339,18 +339,18 @@ pub(crate) type Username = BoundedVec::MaxUsernameLength>; #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] pub enum Provider { - Governance, - Authority(Balance), + Allocation, + AuthorityDeposit(Balance), System, } impl Provider { pub fn new_with_allocation() -> Self { - Self::Governance + Self::Allocation } pub fn new_with_deposit(deposit: Balance) -> Self { - Self::Authority(deposit) + Self::AuthorityDeposit(deposit) } #[allow(unused)] From 36b474ecd1ba262deff15414e5755ee68e72c3a0 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 2 Sep 2024 19:37:33 +0300 Subject: [PATCH 22/44] Update docs Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index c98e0cc66026..175e95fa3830 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -42,15 +42,25 @@ //! //! ### Usernames //! -//! The pallet provides functionality for username authorities to issue usernames. When an account -//! receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -//! reverse lookup from username to account. +//! The pallet provides functionality for username authorities to issue usernames, which are +//! independent of the identity information functionality; an account can set: +//! - an identity without setting a username +//! - a username without setting an identity +//! - an identity and a username //! -//! Username authorities are given an allocation by governance to prevent state bloat. Usernames -//! impose no cost or deposit on the user. +//! The username functionality implemented in this pallet is meant to be a user friendly lookup of +//! accounts. There are mappings in both directions, "account -> username" and "username -> +//! account". +//! +//! To grant a username, a username authority can either: +//! - be given an allocation by governane of a specific amount of usernames to issue for free, +//! without any deposit associated with storage costs; +//! - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative +//! to other deposits in the system) //! //! Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -//! only map to a single username, known as the _primary_. +//! only map to a single username, known as the _primary_. This primary username will be the result +//! of a lookup in the [UsernameOf] map for any given account. //! //! ## Interface //! @@ -65,7 +75,9 @@ //! * `accept_username` - Accept a username issued by a username authority. //! * `remove_expired_approval` - Remove a username that was issued but never accepted. //! * `set_primary_username` - Set a given username as an account's primary. -//! * `remove_dangling_username` - Remove a username that maps to an account without an identity. +//! * `remove_dangling_username` - Remove a username that maps to an account without a primary +//! username. +//! * `remove_username` - Remove a username after its grace period has ended. //! //! #### For General Users with Sub-Identities //! * `set_subs` - Set the sub-accounts of an identity. @@ -81,12 +93,14 @@ //! //! #### For Username Authorities //! * `set_username_for` - Set a username for a given account. The account must approve it. +//! * `unbind_username` - Start the grace period for a username. //! //! #### For Superusers //! * `add_registrar` - Add a new registrar to the system. //! * `kill_identity` - Forcibly remove the associated identity; the deposit is lost. //! * `add_username_authority` - Add an account with the ability to issue usernames. //! * `remove_username_authority` - Remove an account with the ability to issue usernames. +//! * `kill_username` - Forcibly remove a username. //! //! [`Call`]: ./enum.Call.html //! [`Config`]: ./trait.Config.html From 7c5193ac5cba7025583d17c9c5fc97fda9136f74 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 4 Sep 2024 18:25:39 +0300 Subject: [PATCH 23/44] Small refactoring Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 22 +++--- substrate/frame/identity/src/lib.rs | 53 ++++++------- substrate/frame/identity/src/tests.rs | 78 +++++++++++++++++--- 3 files changed, 108 insertions(+), 45 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index c2d3e6a6127d..10814bece71b 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -677,7 +677,7 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone(), Provider::Governance); + Identity::::queue_acceptance(&caller, username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), username.clone()); @@ -710,9 +710,9 @@ mod benchmarks { let provider = match p { 0 => { let _ = T::Currency::reserve(&authority, username_deposit); - Provider::Authority(username_deposit) + Provider::AuthorityDeposit(username_deposit) }, - 1 => Provider::Governance, + 1 => Provider::Allocation, _ => unreachable!(), }; Identity::::queue_acceptance(&caller, username.clone(), provider); @@ -746,8 +746,8 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username, Provider::Governance); - Identity::::insert_username(&caller, second_username.clone(), Provider::Governance); + Identity::::insert_username(&caller, first_username, Provider::Allocation); + Identity::::insert_username(&caller, second_username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), second_username.clone()); @@ -765,8 +765,8 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username.clone(), Provider::Governance); - Identity::::insert_username(&caller, second_username.clone(), Provider::Governance); + Identity::::insert_username(&caller, first_username.clone(), Provider::Allocation); + Identity::::insert_username(&caller, second_username.clone(), Provider::Allocation); // Root calls `kill_username`, leaving their second username as "dangling" Identity::::kill_username(RawOrigin::Root.into(), first_username.into())?; @@ -805,7 +805,7 @@ mod benchmarks { Identity::::insert_username( &caller, username.clone(), - Provider::Authority(username_deposit), + Provider::AuthorityDeposit(username_deposit), ); #[extrinsic_call] @@ -828,7 +828,7 @@ mod benchmarks { Identity::::insert_username( &caller, username.clone(), - Provider::Authority(username_deposit), + Provider::AuthorityDeposit(username_deposit), ); let now = frame_system::Pallet::::block_number(); UnbindingUsernames::::insert(&username, now); @@ -866,9 +866,9 @@ mod benchmarks { let provider = match p { 0 => { let _ = T::Currency::reserve(&authority, username_deposit); - Provider::Authority(username_deposit) + Provider::AuthorityDeposit(username_deposit) }, - 1 => Provider::Governance, + 1 => Provider::Allocation, _ => unreachable!(), }; Identity::::insert_username(&caller, username.clone(), provider); diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 175e95fa3830..9a3d3c31559e 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -123,7 +123,9 @@ use codec::Encode; use frame_support::{ ensure, pallet_prelude::{DispatchError, DispatchResult}, - traits::{BalanceStatus, Currency, Get, OnUnbalanced, ReservableCurrency, StorageVersion}, + traits::{ + BalanceStatus, Currency, Defensive, Get, OnUnbalanced, ReservableCurrency, StorageVersion, + }, BoundedVec, }; use frame_system::pallet_prelude::*; @@ -165,7 +167,8 @@ pub mod pallet { #[pallet::constant] type ByteDeposit: Get>; - /// The amount held on deposit per registered username. + /// The amount held on deposit per registered username. This value should change only in + /// runtime upgrades with proper migration of existing deposits. #[pallet::constant] type UsernameDeposit: Get>; @@ -389,6 +392,11 @@ pub mod pallet { TooEarly, /// The username cannot be removed because it is not unbinding. NotUnbinding, + /// The username cannot be unbound because it is already unbinding. + AlreadyUnbinding, + /// The action cannot be performed because of insufficient privileges (e.g. authority + /// trying to unbind a username provided by the system). + InsufficientPrivileges, } #[pallet::event] @@ -1266,14 +1274,11 @@ pub mod pallet { } /// Start the process of removing a username by placing it in the unbinding usernames map. - /// Once the grace period has passed, the username can be permanently deleted by calling + /// Once the grace period has passed, the username can be deleted by calling /// [remove_username](crate::Call::remove_username). #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::unbind_username())] - pub fn unbind_username( - origin: OriginFor, - username: Username, - ) -> DispatchResultWithPostInfo { + pub fn unbind_username(origin: OriginFor, username: Username) -> DispatchResult { let who = ensure_signed(origin)?; let username_info = UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?; @@ -1287,16 +1292,16 @@ pub mod pallet { let now = frame_system::Pallet::::block_number(); UnbindingUsernames::::try_mutate(&username, |maybe_init| { if maybe_init.is_some() { - return Err(Error::::TooEarly); + return Err(Error::::AlreadyUnbinding); } *maybe_init = Some(now); Ok(()) })?; }, - Provider::System => return Err(Error::::InvalidTarget.into()), + Provider::System => return Err(Error::::InsufficientPrivileges.into()), } Self::deposit_event(Event::UsernameUnbound { username }); - Ok(Pays::Yes.into()) + Ok(()) } /// Permanently delete a username which has been unbinding for longer than the grace period. @@ -1315,21 +1320,20 @@ pub mod pallet { now >= grace_period_start.saturating_add(T::UsernameGracePeriod::get()), Error::::TooEarly ); - let username_info = - UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + let username_info = UsernameInfoOf::::take(&username) + .defensive_proof("an unbinding username must exist") + .ok_or(Error::::NoUsername)?; // If this is the primary username, remove the entry from the account -> username map. UsernameOf::::mutate(&username_info.owner, |maybe_primary| { - if match maybe_primary { - Some(primary) if *primary == username => true, - _ => false, - } { + if maybe_primary.as_ref().map_or(false, |primary| *primary == username) { *maybe_primary = None; } }); match username_info.provider { Provider::AuthorityDeposit(username_deposit) => { - let suffix = - Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + let suffix = Self::suffix_of_username(&username) + .defensive_proof("registered username must be valid") + .ok_or(Error::::InvalidUsername)?; if let Some(authority_account) = AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) { @@ -1341,7 +1345,7 @@ pub mod pallet { Provider::Allocation => { // We don't refund the allocation, it is lost. }, - Provider::System => return Err(Error::::InvalidTarget.into()), + Provider::System => return Err(Error::::InsufficientPrivileges.into()), } Self::deposit_event(Event::UsernameRemoved { username }); Ok(Pays::No.into()) @@ -1435,13 +1439,11 @@ impl Pallet { /// Validate that a username conforms to allowed characters/format. /// - /// The function will validate the characters in `username` and that `length` (if `Some`) - /// conforms to the limit. It is not expected to pass a fully formatted username here (i.e. one - /// with any protocol-added characters included, such as a `.`). The suffix is also separately - /// validated by this function to ensure the full username conforms. + /// The function will validate the characters in `username`. It is expected to pass a fully + /// formatted username here (i.e. "username.suffix"). The suffix is also separately validated + /// and returned by this function. fn validate_username(username: &Vec) -> Result, DispatchError> { - // Verify input length before allocating a Vec with the user's input. `<` instead of `<=` - // because it needs one element for the point (`username` + `.` + `suffix`). + // Verify input length before allocating a Vec with the user's input. ensure!( username.len() <= T::MaxUsernameLength::get() as usize, Error::::InvalidUsername @@ -1469,6 +1471,7 @@ impl Pallet { Ok(suffix) } + /// Return the suffix of a username, if it is valid. fn suffix_of_username(username: &Username) -> Option> { let separator_idx = username.iter().rposition(|c| *c == b'.')?; let suffix_start = separator_idx.checked_add(1)?; diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 9634801c7929..5c1f4ee64192 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -2223,15 +2223,6 @@ fn unbind_and_remove_username_should_work() { // Advance the block number to simulate the grace period passing. System::set_block_number(3); - // Simulate a dangling entry in the unbinding map without an actual username registered. - UnbindingUsernames::::insert(dummy_username.clone(), 0); - assert_noop!( - Identity::remove_username(RuntimeOrigin::signed(account(0)), dummy_username.clone()), - Error::::NoUsername - ); - // Clean up storage. - UnbindingUsernames::::remove(dummy_username); - let suffix: Suffix = suffix.try_into().unwrap(); // We can now remove the username from any account. assert_ok!(Identity::remove_username( @@ -2272,3 +2263,72 @@ fn unbind_and_remove_username_should_work() { assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); }); } + +#[test] +#[should_panic] +fn unbind_dangling_username_defensive_should_panic() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() + )); + assert_eq!(System::block_number(), 1); + assert_eq!(UnbindingUsernames::::get(&username), Some(1)); + + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::TooEarly + ); + + // Advance the block number to simulate the grace period passing. + System::set_block_number(3); + + // Simulate a dangling entry in the unbinding map without an actual username registered. + UsernameInfoOf::::remove(&username); + UsernameOf::::remove(&who_account); + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::NoUsername + ); + }); +} From 3c0beaa560be78c2ff08c7e115fb6d436b109d07 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 4 Sep 2024 18:38:27 +0300 Subject: [PATCH 24/44] Change unbinding username to store expiry Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 5 +++-- substrate/frame/identity/src/lib.rs | 16 +++++++++------- substrate/frame/identity/src/tests.rs | 19 ++++++++++++++----- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 10814bece71b..6a9251537625 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -831,9 +831,10 @@ mod benchmarks { Provider::AuthorityDeposit(username_deposit), ); let now = frame_system::Pallet::::block_number(); - UnbindingUsernames::::insert(&username, now); + let expiry = now + T::UsernameGracePeriod::get(); + UnbindingUsernames::::insert(&username, expiry); - frame_system::Pallet::::set_block_number(now + T::UsernameGracePeriod::get()); + frame_system::Pallet::::set_block_number(expiry); #[extrinsic_call] _(RawOrigin::Signed(caller), username.clone()); diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 9a3d3c31559e..837950273d92 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -318,7 +318,7 @@ pub mod pallet { /// Usernames that an authority has granted, but that the account controller has not confirmed /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. + /// [accept_username](`Call::accept_username`). /// /// First tuple item is the account and second is the acceptance deadline. #[pallet::storage] @@ -330,6 +330,10 @@ pub mod pallet { OptionQuery, >; + /// Usernames for which the authority that granted them has started the removal process by + /// unbinding them. Each unbinding username maps to its grace period expiry, which is the first + /// block in which the username could be deleted through a + /// [remove_username](`Call::remove_username`) call. #[pallet::storage] pub type UnbindingUsernames = StorageMap<_, Blake2_128Concat, Username, BlockNumberFor, OptionQuery>; @@ -1290,11 +1294,12 @@ pub mod pallet { match username_info.provider { Provider::AuthorityDeposit(_) | Provider::Allocation => { let now = frame_system::Pallet::::block_number(); + let grace_period_expiry = now.saturating_add(T::UsernameGracePeriod::get()); UnbindingUsernames::::try_mutate(&username, |maybe_init| { if maybe_init.is_some() { return Err(Error::::AlreadyUnbinding); } - *maybe_init = Some(now); + *maybe_init = Some(grace_period_expiry); Ok(()) })?; }, @@ -1313,13 +1318,10 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - let grace_period_start = + let grace_period_expiry = UnbindingUsernames::::take(&username).ok_or(Error::::NotUnbinding)?; let now = frame_system::Pallet::::block_number(); - ensure!( - now >= grace_period_start.saturating_add(T::UsernameGracePeriod::get()), - Error::::TooEarly - ); + ensure!(now >= grace_period_expiry, Error::::TooEarly); let username_info = UsernameInfoOf::::take(&username) .defensive_proof("an unbinding username must exist") .ok_or(Error::::NoUsername)?; diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 5c1f4ee64192..5ecc7fb14f2d 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -2211,8 +2211,14 @@ fn unbind_and_remove_username_should_work() { RuntimeOrigin::signed(authority.clone()), username_two.clone() )); - assert_eq!(System::block_number(), 1); - assert_eq!(UnbindingUsernames::::get(&username_two), Some(1)); + let grace_period: BlockNumberFor = ::UsernameGracePeriod::get(); + let now = 1; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!( + UnbindingUsernames::::get(&username_two), + Some(expected_grace_period_expiry) + ); // Still in the grace period. assert_noop!( @@ -2221,7 +2227,7 @@ fn unbind_and_remove_username_should_work() { ); // Advance the block number to simulate the grace period passing. - System::set_block_number(3); + System::set_block_number(expected_grace_period_expiry); let suffix: Suffix = suffix.try_into().unwrap(); // We can now remove the username from any account. @@ -2247,9 +2253,12 @@ fn unbind_and_remove_username_should_work() { RuntimeOrigin::signed(authority.clone()), username.clone() )); - assert_eq!(UnbindingUsernames::::get(&username), Some(3)); + let now: BlockNumberFor = expected_grace_period_expiry; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!(UnbindingUsernames::::get(&username), Some(expected_grace_period_expiry)); // Advance the block number to simulate the grace period passing. - System::set_block_number(5); + System::set_block_number(expected_grace_period_expiry); // We can now remove the username from any account. assert_ok!(Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone())); // The username is gone. From 494b5217c11a50281a745d540790c67802dc8949 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 4 Sep 2024 18:58:02 +0300 Subject: [PATCH 25/44] Fix various configs Signed-off-by: georgepisaltu --- .../parachains/runtimes/people/people-rococo/src/people.rs | 3 +++ .../parachains/runtimes/people/people-westend/src/people.rs | 3 +++ polkadot/runtime/common/src/integration_tests.rs | 2 ++ polkadot/runtime/rococo/src/lib.rs | 3 +++ polkadot/runtime/westend/src/lib.rs | 3 +++ substrate/bin/node/runtime/src/lib.rs | 3 +++ substrate/frame/alliance/src/mock.rs | 4 ++++ 7 files changed, 21 insertions(+) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs index 8211447d68c8..690bb974bd17 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/people.rs b/cumulus/parachains/runtimes/people/people-westend/src/people.rs index 0255fd074b11..47551f6d4bdc 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 7a689a517eaa..aad1e283bdf7 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -279,6 +279,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU32<100>; type ByteDeposit = ConstU32<10>; + type UsernameDeposit = ConstU32<10>; type SubAccountDeposit = ConstU32<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo>; @@ -289,6 +290,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<100>; + type UsernameGracePeriod = ConstU32<10>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index dfc41b15bb1d..0b22a660e8a4 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -681,6 +681,7 @@ parameter_types! { // Minimum 100 bytes/ROC deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -692,6 +693,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -703,6 +705,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index e8fe11615d74..6b66ddc8e394 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -924,6 +924,7 @@ parameter_types! { // Minimum 100 bytes/KSM deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -936,6 +937,7 @@ impl pallet_identity::Config for Runtime { type Slashed = (); type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -946,6 +948,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ef5c52bf6e6e..661433b4b98e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1526,6 +1526,7 @@ parameter_types! { // information, already accounted for by the byte deposit pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 2 * DOLLARS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -1537,6 +1538,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -1548,6 +1550,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = pallet_identity::weights::SubstrateWeight; diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 9cd96019781e..b43e58e88e69 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -82,11 +82,13 @@ impl pallet_collective::Config for Test { parameter_types! { pub const BasicDeposit: u64 = 100; pub const ByteDeposit: u64 = 10; + pub const UsernameDeposit: u64 = 10; pub const SubAccountDeposit: u64 = 100; pub const MaxSubAccounts: u32 = 2; pub const MaxAdditionalFields: u32 = 2; pub const MaxRegistrars: u32 = 20; pub const PendingUsernameExpiration: u64 = 100; + pub const UsernameGracePeriod: u64 = 10; } ord_parameter_types! { pub const One: u64 = 1; @@ -103,6 +105,7 @@ impl pallet_identity::Config for Test { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -114,6 +117,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountU64; type UsernameAuthorityOrigin = EnsureOneOrRoot; type PendingUsernameExpiration = PendingUsernameExpiration; + type UsernameGracePeriod = UsernameGracePeriod; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); From 0d6fdd7b3762c2b0cd428d4bb7ae8995d4fd9942 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 4 Sep 2024 18:59:52 +0300 Subject: [PATCH 26/44] Fix `IdentityVerifier` impls Signed-off-by: georgepisaltu --- substrate/bin/node/runtime/src/impls.rs | 2 +- substrate/frame/alliance/src/mock.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 43e7a766e0e8..2e096342451d 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -65,7 +65,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { use pallet_identity::{IdentityOf, Judgement}; IdentityOf::::get(who) - .map(|(registration, _)| registration.judgements) + .map(|registration| registration.judgements) .map_or(false, |judgements| { judgements .iter() diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 8f23c26dfb57..625cabf3457f 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -153,7 +153,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { if let Some(judgements) = - IdentityOf::::get(who).map(|(registration, _)| registration.judgements) + IdentityOf::::get(who).map(|registration| registration.judgements) { judgements .iter() From ec16e5625828b9a87978e571e6216e1452c6cdaf Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 5 Sep 2024 13:01:16 +0300 Subject: [PATCH 27/44] Update readme Signed-off-by: georgepisaltu --- substrate/frame/identity/README.md | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index 94b2ae0231d7..3e5f70f779cd 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -27,15 +27,24 @@ no state-bloat attack is viable. #### Usernames -The pallet provides functionality for username authorities to issue usernames. When an account -receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -reverse lookup from username to account. +The pallet provides functionality for username authorities to issue usernames, which are independent +of the identity information functionality; an account can set: +- an identity without setting a username +- a username without setting an identity +- an identity and a username -Username authorities are given an allocation by governance to prevent state bloat. Usernames -impose no cost or deposit on the user. +The username functionality implemented in this pallet is meant to be a user friendly lookup of +accounts. There are mappings in both directions, "account -> username" and "username -> account". -Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -only map to a single username, known as the *primary*. +To grant a username, a username authority can either: +- be given an allocation by governane of a specific amount of usernames to issue for free, + without any deposit associated with storage costs; +- put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative + to other deposits in the system). + +Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can only +map to a single username, known as the _primary_. This primary username will be the result of a +lookup in the `UsernameOf` map for any given account. ### Interface @@ -50,7 +59,8 @@ only map to a single username, known as the *primary*. - `accept_username` - Accept a username issued by a username authority. - `remove_expired_approval` - Remove a username that was issued but never accepted. - `set_primary_username` - Set a given username as an account's primary. -- `remove_dangling_username` - Remove a username that maps to an account without an identity. +- `remove_dangling_username` - Remove a username that maps to an account without a primary username. +- `remove_username` - Remove a username after its grace period has ended. ##### For General Users with Sub-Identities - `set_subs` - Set the sub-accounts of an identity. @@ -66,12 +76,14 @@ only map to a single username, known as the *primary*. ##### For Username Authorities - `set_username_for` - Set a username for a given account. The account must approve it. +- `unbind_username` - Start the grace period for a username. ##### For Superusers - `add_registrar` - Add a new registrar to the system. - `kill_identity` - Forcibly remove the associated identity; the deposit is lost. - `add_username_authority` - Add an account with the ability to issue usernames. - `remove_username_authority` - Remove an account with the ability to issue usernames. +- `kill_username` - Forcibly remove a username. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html From 4cf38d12164c972e68827a0549f719e190a22d0e Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 5 Sep 2024 15:12:14 +0300 Subject: [PATCH 28/44] Fix compilation in identity migrator Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 837950273d92..d89c4ff8f666 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1403,6 +1403,15 @@ pub mod pallet { } impl Pallet { + /// Get the subs of an account. + pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> { + SubsOf::::get(who) + .1 + .into_iter() + .filter_map(|a| SuperOf::::get(&a).map(|x| (a, x.1))) + .collect() + } + /// Calculate the deposit required for a number of `sub` accounts. fn subs_deposit(subs: u32) -> BalanceOf { T::SubAccountDeposit::get().saturating_mul(BalanceOf::::from(subs)) From 23c353b94bd14b3b3bd56bbda8c123579ef1a5f3 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 10 Sep 2024 18:50:20 +0300 Subject: [PATCH 29/44] Reintroduce benchmarks for migration Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 70 +++++++- substrate/frame/identity/src/migration.rs | 162 ++++++++++++++----- substrate/frame/identity/src/weights.rs | 42 +++++ 3 files changed, 233 insertions(+), 41 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 6a9251537625..40a3d6ad4afc 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::Pallet as Identity; +use crate::{migration::v2::LazyMigrationV2, Pallet as Identity}; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -895,5 +895,73 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn migration_v2_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + assert_eq!(AuthorityOf::::iter().count(), 0); + #[block] + { + LazyMigrationV2::::authority_step(None); + } + assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + assert_eq!(UsernameInfoOf::::iter().count(), 0); + #[block] + { + LazyMigrationV2::::username_step(None); + } + assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); + Ok(()) + } + + #[benchmark] + fn migration_v2_identity_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV2::::identity_step(None); + } + assert!(IdentityOf::::get(&setup.account).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV2::::pending_username_step(None); + } + assert!(PendingUsernames::::get(&setup.username).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV2::::cleanup_authority_step(None); + } + LazyMigrationV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV2::::cleanup_username_step(None); + } + LazyMigrationV2::::check_username_cleanup_validity(setup.username, setup.account); + Ok(()) + } + impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index aaf10a6c58ba..cf2515acf398 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -159,7 +159,11 @@ pub mod v2 { type HashedKey = BoundedVec>; // The resulting state of the step and the actual weight consumed. type StepResultOf = - (MigrationState<::AccountId, Username, Suffix>, Weight); + MigrationState<::AccountId, Username, Suffix>; + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) type BenchmarkingSetupOf = + BenchmarkingSetup, ::AccountId, Username>; mod v1 { use super::*; @@ -217,7 +221,7 @@ pub mod v2 { let required = match &cursor { Some(state) => Self::required_weight(&state), // Worst case weight for `authority_step`. - None => T::DbWeight::get().reads_writes(1, 1), + None => T::WeightInfo::migration_v2_authority_step(), }; if meter.remaining().any_lt(required) { return Err(SteppedMigrationError::InsufficientWeight { required }); @@ -226,16 +230,16 @@ pub mod v2 { loop { // Check that we would have enough weight to perform this step in the worst case // scenario. - let required = match &cursor { + let required_weight = match &cursor { Some(state) => Self::required_weight(&state), // Worst case weight for `authority_step`. - None => T::DbWeight::get().reads_writes(1, 1), + None => T::WeightInfo::migration_v2_authority_step(), }; - if !meter.can_consume(required) { + if !meter.can_consume(required_weight) { break; } - let (next, actual_weight) = match &cursor { + let next = match &cursor { // At first, migrate any authorities. None => Self::authority_step(None), // Migrate any remaining authorities. @@ -281,13 +285,7 @@ pub mod v2 { }; cursor = Some(next); - // After performing one step, consume the actual weight. - if actual_weight.any_gt(required) { - defensive!( - "actual weight should not be greater than the worst case scenario weight" - ); - } - meter.consume(actual_weight); + meter.consume(required_weight); } Ok(cursor) @@ -299,17 +297,17 @@ pub mod v2 { step: &MigrationState, Suffix>, ) -> Weight { match step { - MigrationState::Authority(_) => T::DbWeight::get().reads_writes(1, 1), + MigrationState::Authority(_) => T::WeightInfo::migration_v2_authority_step(), MigrationState::FinishedAuthorities | MigrationState::Username(_) => - T::DbWeight::get().reads_writes(1, 1), + T::WeightInfo::migration_v2_username_step(), MigrationState::FinishedUsernames | MigrationState::Identity(_) => - T::DbWeight::get().reads_writes(1, 2), + T::WeightInfo::migration_v2_identity_step(), MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => - T::DbWeight::get().reads_writes(1, 1), + T::WeightInfo::migration_v2_pending_username_step(), MigrationState::FinishedPendingUsernames | - MigrationState::CleanupAuthorities(_) => T::DbWeight::get().reads_writes(1, 1), + MigrationState::CleanupAuthorities(_) => T::WeightInfo::migration_v2_cleanup_authority_step(), MigrationState::FinishedCleanupAuthorities | - MigrationState::CleanupUsernames(_) => T::DbWeight::get().reads_writes(1, 1), + MigrationState::CleanupUsernames(_) => T::WeightInfo::migration_v2_cleanup_username_step(), MigrationState::Finished => Weight::zero(), } } @@ -329,12 +327,9 @@ pub mod v2 { let new_properties = AuthorityProperties { account_id: authority_account.clone(), allocation }; AuthorityOf::::insert(&suffix, new_properties); - ( - MigrationState::Authority(authority_account), - T::DbWeight::get().reads_writes(1, 1), - ) + MigrationState::Authority(authority_account) } else { - (MigrationState::FinishedAuthorities, T::DbWeight::get().reads(1)) + MigrationState::FinishedAuthorities } } @@ -355,9 +350,9 @@ pub mod v2 { }; UsernameInfoOf::::insert(&username, username_info); - (MigrationState::Username(username), T::DbWeight::get().reads_writes(1, 1)) + MigrationState::Username(username) } else { - (MigrationState::FinishedUsernames, T::DbWeight::get().reads(1)) + MigrationState::FinishedUsernames } } @@ -385,12 +380,9 @@ pub mod v2 { None } }) { - ( - MigrationState::Identity(last_key.try_into().unwrap()), - T::DbWeight::get().reads_writes(1, 2), - ) + MigrationState::Identity(last_key.try_into().unwrap()) } else { - (MigrationState::FinishedIdentities, T::DbWeight::get().reads(1)) + MigrationState::FinishedIdentities } } @@ -403,12 +395,9 @@ pub mod v2 { Some((owner_account, since, Provider::new_with_allocation())) }, ) { - ( - MigrationState::PendingUsername(last_key.try_into().unwrap()), - T::DbWeight::get().reads_writes(1, 1), - ) + MigrationState::PendingUsername(last_key.try_into().unwrap()) } else { - (MigrationState::FinishedPendingUsernames, T::DbWeight::get().reads(1)) + MigrationState::FinishedPendingUsernames } } @@ -424,9 +413,9 @@ pub mod v2 { if let Some((suffix, properties)) = iter.next() { let _ = v1::UsernameAuthorities::::take(&properties.account_id); - (MigrationState::CleanupAuthorities(suffix), T::DbWeight::get().reads_writes(1, 1)) + MigrationState::CleanupAuthorities(suffix) } else { - (MigrationState::FinishedCleanupAuthorities, T::DbWeight::get().reads(1)) + MigrationState::FinishedCleanupAuthorities } } @@ -442,13 +431,106 @@ pub mod v2 { if let Some((username, _)) = iter.next() { let _ = v1::AccountOfUsername::::take(&username); - (MigrationState::CleanupUsernames(username), T::DbWeight::get().reads_writes(1, 1)) + MigrationState::CleanupUsernames(username) } else { - (MigrationState::Finished, T::DbWeight::get().reads(1)) + MigrationState::Finished } } } + #[cfg(feature = "runtime-benchmarks")] + pub(crate) struct BenchmarkingSetup { + pub(crate) suffix: S, + pub(crate) authority: A, + pub(crate) account: A, + pub(crate) username: U, + } + + #[cfg(feature = "runtime-benchmarks")] + impl LazyMigrationV2 { + pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { + use frame_support::Hashable; + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (®istration, Some(username.clone())), + ); + v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf { + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + v1::UsernameAuthorities::::insert(&authority, &prop); + let prop: AuthorityProperties = + AuthorityProperties { account_id: authority.clone(), allocation: 10 }; + AuthorityOf::::insert(&suffix, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + IdentityOf::::insert(&account_id, ®istration); + UsernameOf::::insert(&account_id, &username); + let username_info = UsernameInformation { + owner: account_id.clone(), + provider: Provider::new_with_allocation(), + }; + UsernameInfoOf::::insert(&username, username_info); + v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + PendingUsernames::::insert( + &username, + (&account_id, since, Provider::new_with_allocation()), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { + assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); + } + + pub(crate) fn check_username_cleanup_validity( + username: Username, + account_id: T::AccountId, + ) { + assert_eq!(v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); + } + } + #[cfg(test)] mod tests { use frame_support::Hashable; diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 5d79f177638e..159d4fa4eb87 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -77,6 +77,12 @@ pub trait WeightInfo { fn unbind_username() -> Weight; fn remove_username() -> Weight; fn kill_username(p: u32) -> Weight; + fn migration_v2_authority_step() -> Weight; + fn migration_v2_username_step() -> Weight; + fn migration_v2_identity_step() -> Weight; + fn migration_v2_pending_username_step() -> Weight; + fn migration_v2_cleanup_authority_step() -> Weight; + fn migration_v2_cleanup_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -453,6 +459,24 @@ impl WeightInfo for SubstrateWeight { fn kill_username(_p: u32) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } // For backwards compatibility and tests. @@ -828,4 +852,22 @@ impl WeightInfo for () { fn kill_username(_p: u32) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } From 1035f6f400b85efd239945a8981a6a7e8d17bb8c Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 10 Sep 2024 18:58:33 +0300 Subject: [PATCH 30/44] Refactor storage alias types Signed-off-by: georgepisaltu --- substrate/frame/identity/README.md | 2 +- substrate/frame/identity/src/lib.rs | 2 +- substrate/frame/identity/src/migration.rs | 160 +++++++++++----------- 3 files changed, 79 insertions(+), 85 deletions(-) diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index 3e5f70f779cd..35ce11c71e14 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -37,7 +37,7 @@ The username functionality implemented in this pallet is meant to be a user frie accounts. There are mappings in both directions, "account -> username" and "username -> account". To grant a username, a username authority can either: -- be given an allocation by governane of a specific amount of usernames to issue for free, +- be given an allocation by governance of a specific amount of usernames to issue for free, without any deposit associated with storage costs; - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative to other deposits in the system). diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index d89c4ff8f666..5b09bf523504 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -53,7 +53,7 @@ //! account". //! //! To grant a username, a username authority can either: -//! - be given an allocation by governane of a specific amount of usernames to issue for free, +//! - be given an allocation by governance of a specific amount of usernames to issue for free, //! without any deposit associated with storage costs; //! - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative //! to other deposits in the system) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index cf2515acf398..ed9e50f7201c 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -17,8 +17,8 @@ use super::*; use frame_support::{ - migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, - IterableStorageMap, + migrations::VersionedMigration, pallet_prelude::*, storage_alias, + traits::UncheckedOnRuntimeUpgrade, IterableStorageMap, }; #[cfg(feature = "try-runtime")] @@ -40,51 +40,68 @@ pub mod versioned { >; } -pub mod v1 { +/// The old identity types in v0. +mod types_v0 { use super::*; - use frame_support::storage_alias; - /// The log target. - const TARGET: &'static str = "runtime::identity::migration::v1"; + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + OptionQuery, + >; +} - /// The old identity type, useful in pre-upgrade. - mod v0 { - use super::*; +/// The old identity types in v1. +mod types_v1 { + use super::*; - #[storage_alias] - pub type IdentityOf = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ( Registration< BalanceOf, ::MaxRegistrars, ::IdentityInformation, >, - OptionQuery, - >; - } + Option>, + ), + OptionQuery, + >; - mod vx { - use super::*; + #[storage_alias] + pub type UsernameAuthorities = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + AuthorityProperties>, + OptionQuery, + >; - #[storage_alias] - pub type IdentityOf = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, - ( - Registration< - BalanceOf, - ::MaxRegistrars, - ::IdentityInformation, - >, - Option>, - ), - OptionQuery, - >; - } + #[storage_alias] + pub type AccountOfUsername = StorageMap< + Pallet, + Blake2_128Concat, + Username, + ::AccountId, + OptionQuery, + >; +} + +pub mod v1 { + use super::*; + /// The log target. + const TARGET: &'static str = "runtime::identity::migration::v1"; /// Migration to add usernames to Identity info. /// /// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to @@ -94,7 +111,7 @@ pub mod v1 { impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let identities = v0::IdentityOf::::iter().count(); + let identities = types_v0::IdentityOf::::iter().count(); log::info!( target: TARGET, "pre-upgrade state contains '{}' identities.", @@ -114,8 +131,8 @@ pub mod v1 { let mut translated: u64 = 0; let mut interrupted = false; - for (account, registration) in v0::IdentityOf::::iter() { - vx::IdentityOf::::insert(account, (registration, None::>)); + for (account, registration) in types_v0::IdentityOf::::iter() { + types_v1::IdentityOf::::insert(account, (registration, None::>)); translated.saturating_inc(); if translated >= KL { log::warn!( @@ -139,7 +156,7 @@ pub mod v1 { fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { let identities_to_migrate: u64 = Decode::decode(&mut &state[..]) .expect("failed to decode the state from pre-upgrade."); - let identities = IdentityOf::::iter().count() as u64; + let identities = types_v1::IdentityOf::::iter().count() as u64; log::info!("post-upgrade expects '{}' identities to have been migrated.", identities); ensure!(identities_to_migrate == identities, "must migrate all identities."); log::info!(target: TARGET, "migrated all identities."); @@ -152,7 +169,6 @@ pub mod v2 { use super::*; use frame_support::{ migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, - storage_alias, weights::WeightMeter, }; @@ -165,28 +181,6 @@ pub mod v2 { pub(crate) type BenchmarkingSetupOf = BenchmarkingSetup, ::AccountId, Username>; - mod v1 { - use super::*; - - #[storage_alias] - pub type UsernameAuthorities = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, - AuthorityProperties>, - OptionQuery, - >; - - #[storage_alias] - pub type AccountOfUsername = StorageMap< - Pallet, - Blake2_128Concat, - Username, - ::AccountId, - OptionQuery, - >; - } - #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] pub enum MigrationState { Authority(A), @@ -315,11 +309,11 @@ pub mod v2 { // Migrate one entry from `UsernameAuthorities` to `AuthorityOf`. pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { - v1::UsernameAuthorities::::iter_from( - v1::UsernameAuthorities::::hashed_key_for(last_key), + types_v1::UsernameAuthorities::::iter_from( + types_v1::UsernameAuthorities::::hashed_key_for(last_key), ) } else { - v1::UsernameAuthorities::::iter() + types_v1::UsernameAuthorities::::iter() }; if let Some((authority_account, properties)) = iter.next() { let suffix = properties.account_id; @@ -336,11 +330,11 @@ pub mod v2 { // Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`. pub(crate) fn username_step(maybe_last_key: Option<&Username>) -> StepResultOf { let mut iter = if let Some(last_key) = maybe_last_key { - v1::AccountOfUsername::::iter_from(v1::AccountOfUsername::::hashed_key_for( - last_key, - )) + types_v1::AccountOfUsername::::iter_from( + types_v1::AccountOfUsername::::hashed_key_for(last_key), + ) } else { - v1::AccountOfUsername::::iter() + types_v1::AccountOfUsername::::iter() }; if let Some((username, owner_account)) = iter.next() { @@ -412,7 +406,7 @@ pub mod v2 { }; if let Some((suffix, properties)) = iter.next() { - let _ = v1::UsernameAuthorities::::take(&properties.account_id); + let _ = types_v1::UsernameAuthorities::::take(&properties.account_id); MigrationState::CleanupAuthorities(suffix) } else { MigrationState::FinishedCleanupAuthorities @@ -430,7 +424,7 @@ pub mod v2 { }; if let Some((username, _)) = iter.next() { - let _ = v1::AccountOfUsername::::take(&username); + let _ = types_v1::AccountOfUsername::::take(&username); MigrationState::CleanupUsernames(username) } else { MigrationState::Finished @@ -456,7 +450,7 @@ pub mod v2 { let prop: AuthorityProperties> = AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority, &prop); + types_v1::UsernameAuthorities::::insert(&authority, &prop); let username: Username = b"account.bench".to_vec().try_into().unwrap(); let info = T::IdentityInformation::create_identity_info(); @@ -471,7 +465,7 @@ pub mod v2 { &account_id.twox_64_concat(), (®istration, Some(username.clone())), ); - v1::AccountOfUsername::::insert(&username, &account_id); + types_v1::AccountOfUsername::::insert(&username, &account_id); let since: BlockNumberFor = 0u32.into(); frame_support::migration::put_storage_value( b"Identity", @@ -489,7 +483,7 @@ pub mod v2 { let prop: AuthorityProperties> = AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority, &prop); + types_v1::UsernameAuthorities::::insert(&authority, &prop); let prop: AuthorityProperties = AuthorityProperties { account_id: authority.clone(), allocation: 10 }; AuthorityOf::::insert(&suffix, &prop); @@ -508,7 +502,7 @@ pub mod v2 { provider: Provider::new_with_allocation(), }; UsernameInfoOf::::insert(&username, username_info); - v1::AccountOfUsername::::insert(&username, &account_id); + types_v1::AccountOfUsername::::insert(&username, &account_id); let since: BlockNumberFor = 0u32.into(); PendingUsernames::::insert( &username, @@ -518,7 +512,7 @@ pub mod v2 { } pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { - assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); } @@ -526,7 +520,7 @@ pub mod v2 { username: Username, account_id: T::AccountId, ) { - assert_eq!(v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); } } @@ -563,12 +557,12 @@ pub mod v2 { let authority_1 = account_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority_1, &prop); + types_v1::UsernameAuthorities::::insert(&authority_1, &prop); // Set up the first authority. let authority_2 = account_from_u8(152); let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; - v1::UsernameAuthorities::::insert(&authority_2, &prop); + types_v1::UsernameAuthorities::::insert(&authority_2, &prop); // (owner_account, primary_username, maybe_secondary_username, has_identity) // If `has_identity` is set, this `owner_account` will have a real identity @@ -580,7 +574,7 @@ pub mod v2 { let mut username_1 = bare_username.clone(); username_1.extend(suffix_1.iter()); let username_1: Username = username_1.try_into().unwrap(); - v1::AccountOfUsername::::insert(&username_1, &account_id); + types_v1::AccountOfUsername::::insert(&username_1, &account_id); if i % 2 == 0 { let has_identity = i % 4 == 0; @@ -597,7 +591,7 @@ pub mod v2 { let mut username_2 = bare_username.clone(); username_2.extend(suffix_2.iter()); let username_2: Username = username_2.try_into().unwrap(); - v1::AccountOfUsername::::insert(&username_2, &account_id); + types_v1::AccountOfUsername::::insert(&username_2, &account_id); let reg = registration(has_identity); frame_support::migration::put_storage_value( b"Identity", @@ -702,8 +696,8 @@ pub mod v2 { } // Check that obsolete storage was cleared. - assert_eq!(v1::AccountOfUsername::::iter().count(), 0); - assert_eq!(v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); }); } } From 448c034efb9f811543a4716729dcdac7052bfa9b Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 10 Sep 2024 19:00:52 +0300 Subject: [PATCH 31/44] Add dummy weights Signed-off-by: georgepisaltu --- .../src/weights/pallet_identity.rs | 18 ++++++++++++++++++ .../src/weights/pallet_identity.rs | 18 ++++++++++++++++++ .../rococo/src/weights/pallet_identity.rs | 18 ++++++++++++++++++ .../westend/src/weights/pallet_identity.rs | 18 ++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs index a59e2e9c958e..e5f7e2c0d2ae 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs @@ -415,4 +415,22 @@ impl pallet_identity::WeightInfo for WeightInfo { fn kill_username(_p: u32, ) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs index a59e2e9c958e..e5f7e2c0d2ae 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs @@ -415,4 +415,22 @@ impl pallet_identity::WeightInfo for WeightInfo { fn kill_username(_p: u32, ) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index 4a06fbac86a4..7b11bda5de31 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -437,4 +437,22 @@ impl pallet_identity::WeightInfo for WeightInfo { fn kill_username(_p: u32, ) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index 493561ce2f5a..1482de8e56c1 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -441,4 +441,22 @@ impl pallet_identity::WeightInfo for WeightInfo { fn kill_username(_p: u32, ) -> Weight { Weight::zero() } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() + } } From 35bcc68d50d10d5816e1768383cfedd31ea976cd Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 11:22:06 +0300 Subject: [PATCH 32/44] Small refactor Signed-off-by: georgepisaltu --- substrate/frame/identity/src/benchmarking.rs | 30 ++++++++++---------- substrate/frame/identity/src/migration.rs | 12 ++++---- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 40a3d6ad4afc..43e64cb873e2 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::{migration::v2::LazyMigrationV2, Pallet as Identity}; +use crate::{migration::v2::LazyMigrationV1ToV2, Pallet as Identity}; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -897,11 +897,11 @@ mod benchmarks { #[benchmark] fn migration_v2_authority_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); assert_eq!(AuthorityOf::::iter().count(), 0); #[block] { - LazyMigrationV2::::authority_step(None); + LazyMigrationV1ToV2::::authority_step(None); } assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); Ok(()) @@ -909,11 +909,11 @@ mod benchmarks { #[benchmark] fn migration_v2_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); assert_eq!(UsernameInfoOf::::iter().count(), 0); #[block] { - LazyMigrationV2::::username_step(None); + LazyMigrationV1ToV2::::username_step(None); } assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); Ok(()) @@ -921,10 +921,10 @@ mod benchmarks { #[benchmark] fn migration_v2_identity_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); #[block] { - LazyMigrationV2::::identity_step(None); + LazyMigrationV1ToV2::::identity_step(None); } assert!(IdentityOf::::get(&setup.account).is_some()); Ok(()) @@ -932,10 +932,10 @@ mod benchmarks { #[benchmark] fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_migration(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); #[block] { - LazyMigrationV2::::pending_username_step(None); + LazyMigrationV1ToV2::::pending_username_step(None); } assert!(PendingUsernames::::get(&setup.username).is_some()); Ok(()) @@ -943,23 +943,23 @@ mod benchmarks { #[benchmark] fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); #[block] { - LazyMigrationV2::::cleanup_authority_step(None); + LazyMigrationV1ToV2::::cleanup_authority_step(None); } - LazyMigrationV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); + LazyMigrationV1ToV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); Ok(()) } #[benchmark] fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { - let setup = LazyMigrationV2::::setup_benchmark_env_for_cleanup(); + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); #[block] { - LazyMigrationV2::::cleanup_username_step(None); + LazyMigrationV1ToV2::::cleanup_username_step(None); } - LazyMigrationV2::::check_username_cleanup_validity(setup.username, setup.account); + LazyMigrationV1ToV2::::check_username_cleanup_validity(setup.username, setup.account); Ok(()) } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index ed9e50f7201c..aebe8dab5c59 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -181,6 +181,8 @@ pub mod v2 { pub(crate) type BenchmarkingSetupOf = BenchmarkingSetup, ::AccountId, Username>; + /// Progressive states of a migration. The migration starts with the first variant and ends with + /// the last. #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] pub enum MigrationState { Authority(A), @@ -197,8 +199,8 @@ pub mod v2 { Finished, } - pub struct LazyMigrationV2(PhantomData); - impl SteppedMigration for LazyMigrationV2 { + pub struct LazyMigrationV1ToV2(PhantomData); + impl SteppedMigration for LazyMigrationV1ToV2 { type Cursor = MigrationState, Suffix>; type Identifier = MigrationId<15>; @@ -286,7 +288,7 @@ pub mod v2 { } } - impl LazyMigrationV2 { + impl LazyMigrationV1ToV2 { pub(crate) fn required_weight( step: &MigrationState, Suffix>, ) -> Weight { @@ -441,7 +443,7 @@ pub mod v2 { } #[cfg(feature = "runtime-benchmarks")] - impl LazyMigrationV2 { + impl LazyMigrationV1ToV2 { pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { use frame_support::Hashable; let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); @@ -637,7 +639,7 @@ pub mod v2 { let mut weight_meter = WeightMeter::new(); let mut cursor = None; while let Some(new_cursor) = - LazyMigrationV2::::step(cursor, &mut weight_meter).unwrap() + LazyMigrationV1ToV2::::step(cursor, &mut weight_meter).unwrap() { cursor = Some(new_cursor); } From 54c67b61fcb0778ca3cd680f5b205375a24aeaa6 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 12:36:50 +0300 Subject: [PATCH 33/44] Add prdoc Signed-off-by: georgepisaltu --- prdoc/pr_5554.prdoc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 prdoc/pr_5554.prdoc diff --git a/prdoc/pr_5554.prdoc b/prdoc/pr_5554.prdoc new file mode 100644 index 000000000000..7bc5a7a5b031 --- /dev/null +++ b/prdoc/pr_5554.prdoc @@ -0,0 +1,30 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Identity Decouple usernames from identities + +doc: + - audience: Runtime Dev + description: | + This PR refactors pallet-identity to decouple usernames from identities. Usernames are now + separated from identities in storage, allowing for correct deposit accounting and for + authorities to put up their own deposit to create a username and remove usernames. Various + storage maps had to be refactored and migrated to allow this to happen. + - audience: Node Dev + description: | + This PR refactors pallet-identity to decouple usernames from identities. Authorities can now + put up their own deposit to create a username and remove usernames. + +crates: + - name: pallet-identity + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: kitchensink-runtime + bump: major \ No newline at end of file From 7a9d48c91263c418bf23bd56a69611efcb6191b3 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 15:43:41 +0300 Subject: [PATCH 34/44] Enable migration Signed-off-by: georgepisaltu --- Cargo.lock | 4 + .../runtimes/people/people-rococo/Cargo.toml | 4 + .../runtimes/people/people-rococo/src/lib.rs | 19 ++ .../people/people-rococo/src/weights/mod.rs | 1 + .../src/weights/pallet_migrations.rs | 172 +++++++++++++++++ .../runtimes/people/people-westend/Cargo.toml | 4 + .../runtimes/people/people-westend/src/lib.rs | 19 ++ .../people/people-westend/src/weights/mod.rs | 1 + .../src/weights/pallet_migrations.rs | 172 +++++++++++++++++ polkadot/runtime/rococo/Cargo.toml | 4 + polkadot/runtime/rococo/src/lib.rs | 20 ++ polkadot/runtime/rococo/src/weights/mod.rs | 1 + .../rococo/src/weights/pallet_migrations.rs | 173 ++++++++++++++++++ polkadot/runtime/westend/Cargo.toml | 4 + polkadot/runtime/westend/src/lib.rs | 20 ++ polkadot/runtime/westend/src/weights/mod.rs | 1 + .../westend/src/weights/pallet_migrations.rs | 173 ++++++++++++++++++ substrate/bin/node/runtime/src/lib.rs | 5 +- 18 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs create mode 100644 cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_migrations.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_migrations.rs diff --git a/Cargo.lock b/Cargo.lock index 8abecaf5e9ba..b9bfd8c17e4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12684,6 +12684,7 @@ dependencies = [ "pallet-collator-selection", "pallet-identity", "pallet-message-queue", + "pallet-migrations", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -12783,6 +12784,7 @@ dependencies = [ "pallet-collator-selection", "pallet-identity", "pallet-message-queue", + "pallet-migrations", "pallet-multisig", "pallet-session", "pallet-timestamp", @@ -16676,6 +16678,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-migrations", "pallet-mmr", "pallet-multisig", "pallet-nis", @@ -23719,6 +23722,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-migrations", "pallet-mmr", "pallet-multisig", "pallet-nomination-pools", diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index c676587b1de4..c7562e5e36cb 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } @@ -103,6 +104,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -152,6 +154,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -181,6 +184,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index cb9177d0c23b..0ef3307d6cf8 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -416,6 +416,21 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -450,6 +465,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -467,6 +485,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs index 3396a8caea05..bb966bcedb08 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -24,6 +24,7 @@ pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// Copyright (C) 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. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index ab7dd04bb78a..2a4f9939cf8c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } @@ -103,6 +104,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-session/std", "pallet-timestamp/std", @@ -152,6 +154,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -181,6 +184,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 9813c5cb6acc..67b9ec624010 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -416,6 +416,21 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -450,6 +465,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -467,6 +485,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs index 3396a8caea05..bb966bcedb08 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -24,6 +24,7 @@ pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// Copyright (C) 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. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 4aaaf94da586..efcf3c311626 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -65,6 +65,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nis = { workspace = true } @@ -156,6 +157,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nis/std", @@ -238,6 +240,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nis/runtime-benchmarks", @@ -295,6 +298,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nis/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 4ba32ce934e6..263c6257fc76 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -222,6 +222,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = weights::frame_system::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { @@ -1368,6 +1369,21 @@ impl validator_manager::Config for Runtime { type PrivilegedOrigin = EnsureRoot; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + impl pallet_sudo::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -1500,6 +1516,9 @@ construct_runtime! { Crowdloan: crowdloan = 73, Coretime: coretime = 74, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // Pallet for sending XCM. XcmPallet: pallet_xcm = 99, @@ -1757,6 +1776,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_parameters, Parameters] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 020f8e22594a..1ad7436a431e 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -26,6 +26,7 @@ pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nis; diff --git a/polkadot/runtime/rococo/src/weights/pallet_migrations.rs b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 83c0eb037f4a..e3249b86e2e7 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -66,6 +66,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nomination-pools = { workspace = true } @@ -166,6 +167,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools-benchmarking?/std", @@ -255,6 +257,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", @@ -316,6 +319,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d31aca354dd9..eb610019d1ed 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1513,6 +1513,21 @@ impl pallet_root_testing::Config for Runtime { type RuntimeEvent = RuntimeEvent; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; @@ -1712,6 +1727,10 @@ mod runtime { #[runtime::pallet_index(66)] pub type Coretime = coretime; + // Migrations pallet + #[runtime::pallet_index(98)] + pub type MultiBlockMigrations = pallet_migrations; + // Pallet for sending XCM. #[runtime::pallet_index(99)] pub type XcmPallet = pallet_xcm; @@ -1840,6 +1859,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 1e7b01bc472b..59a099f230f3 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -27,6 +27,7 @@ pub mod pallet_fast_unstake; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nomination_pools; diff --git a/polkadot/runtime/westend/src/weights/pallet_migrations.rs b/polkadot/runtime/westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a6ce754b3a30..bf62c33b9136 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2125,7 +2125,10 @@ impl pallet_migrations::Config for Runtime { type Migrations = (); // Benchmarks need mocked migrations to guarantee that they succeed. #[cfg(feature = "runtime-benchmarks")] - type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type Migrations = ( + pallet_migrations::mock_helpers::MockedMigrations, + pallet_identity::migration::v2::LazyMigrationV1ToV2, + ); type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); From 4acddb0c673b04675a7e15b7a45927ffe44979d3 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 15:56:36 +0300 Subject: [PATCH 35/44] Fix compilation Signed-off-by: georgepisaltu --- substrate/bin/node/runtime/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index bf62c33b9136..a6ce754b3a30 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2125,10 +2125,7 @@ impl pallet_migrations::Config for Runtime { type Migrations = (); // Benchmarks need mocked migrations to guarantee that they succeed. #[cfg(feature = "runtime-benchmarks")] - type Migrations = ( - pallet_migrations::mock_helpers::MockedMigrations, - pallet_identity::migration::v2::LazyMigrationV1ToV2, - ); + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); From a49211e75c608c6193f0f4badda9a116de50aced Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 16:16:36 +0300 Subject: [PATCH 36/44] Manually set the storage version Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index aebe8dab5c59..3a6308afa17d 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -212,6 +212,10 @@ pub mod v2 { mut cursor: Option, meter: &mut WeightMeter, ) -> Result, SteppedMigrationError> { + if Pallet::::on_chain_storage_version() != Self::id().version_from as u16 { + return Ok(None); + } + // Check that we have enough weight for at least the next step. If we don't, then the // migration cannot be complete. let required = match &cursor { @@ -277,7 +281,10 @@ pub mod v2 { Self::cleanup_username_step(Some(maybe_last_username)), // After the last obsolete username was cleared from storage, the migration is // done. - Some(MigrationState::Finished) => return Ok(None), + Some(MigrationState::Finished) => { + StorageVersion::new(Self::id().version_to as u16).put::>(); + return Ok(None) + }, }; cursor = Some(next); @@ -555,6 +562,7 @@ pub mod v2 { #[test] fn migrate_to_v2() { new_test_ext().execute_with(|| { + StorageVersion::new(1).put::>(); // Set up the first authority. let authority_1 = account_from_u8(151); let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); @@ -643,6 +651,7 @@ pub mod v2 { { cursor = Some(new_cursor); } + assert_eq!(Pallet::::on_chain_storage_version(), 2); // Check that the authorities were migrated. let expected_prop = From e44d6d2eb46c02f36ac1e0f0dfa8a81d435666bb Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Wed, 11 Sep 2024 16:59:09 +0300 Subject: [PATCH 37/44] Fix bench compile Signed-off-by: georgepisaltu --- cumulus/parachains/runtimes/people/people-rococo/src/lib.rs | 6 +++++- .../parachains/runtimes/people/people-westend/src/lib.rs | 6 +++++- polkadot/runtime/rococo/src/lib.rs | 6 +++++- polkadot/runtime/westend/src/lib.rs | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 0ef3307d6cf8..2bbe10a94ccd 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -422,7 +422,11 @@ parameter_types! { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 67b9ec624010..58b92c471776 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -422,7 +422,11 @@ parameter_types! { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 263c6257fc76..14b8486d76a5 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1375,7 +1375,11 @@ parameter_types! { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index eb610019d1ed..0842dc97fa89 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1519,7 +1519,11 @@ parameter_types! { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Migrations = (pallet_identity::migration::v2::LazyMigrationV1ToV2,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); From bb0153c8cc853ae182aa679e89d53dee33f988a1 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 12 Sep 2024 13:02:58 +0300 Subject: [PATCH 38/44] Actually enable MBMs for omitted runtimes Signed-off-by: georgepisaltu --- cumulus/parachains/runtimes/people/people-rococo/src/lib.rs | 1 + cumulus/parachains/runtimes/people/people-westend/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 2bbe10a94ccd..875340a7f5a8 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -189,6 +189,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 58b92c471776..19a06d7877e1 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -189,6 +189,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 0842dc97fa89..57e9927482eb 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -223,6 +223,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = weights::frame_system::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { From af85fc774032524dd7d34192018777515da6a5cb Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Thu, 12 Sep 2024 15:16:04 +0300 Subject: [PATCH 39/44] Remove obsolete dangling username call Signed-off-by: georgepisaltu --- .../src/weights/pallet_identity.rs | 14 --- .../src/weights/pallet_identity.rs | 14 --- .../rococo/src/weights/pallet_identity.rs | 14 --- .../westend/src/weights/pallet_identity.rs | 14 --- prdoc/pr_5554.prdoc | 9 +- substrate/frame/identity/src/benchmarking.rs | 22 ---- substrate/frame/identity/src/lib.rs | 45 +------- substrate/frame/identity/src/tests.rs | 106 ------------------ substrate/frame/identity/src/weights.rs | 27 ----- 9 files changed, 6 insertions(+), 259 deletions(-) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs index e5f7e2c0d2ae..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs @@ -392,20 +392,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } fn unbind_username() -> Weight { Weight::zero() } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs index e5f7e2c0d2ae..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs @@ -392,20 +392,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } fn unbind_username() -> Weight { Weight::zero() } diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index 7b11bda5de31..38f9b4d51051 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -414,20 +414,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } fn unbind_username() -> Weight { Weight::zero() } diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index 1482de8e56c1..60899dd4d173 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -418,20 +418,6 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } fn unbind_username() -> Weight { Weight::zero() } diff --git a/prdoc/pr_5554.prdoc b/prdoc/pr_5554.prdoc index 7bc5a7a5b031..7116e04d2372 100644 --- a/prdoc/pr_5554.prdoc +++ b/prdoc/pr_5554.prdoc @@ -4,16 +4,13 @@ title: Identity Decouple usernames from identities doc: - - audience: Runtime Dev + - audience: [Runtime Dev, Runtime User] description: | This PR refactors pallet-identity to decouple usernames from identities. Usernames are now separated from identities in storage, allowing for correct deposit accounting and for authorities to put up their own deposit to create a username and remove usernames. Various - storage maps had to be refactored and migrated to allow this to happen. - - audience: Node Dev - description: | - This PR refactors pallet-identity to decouple usernames from identities. Authorities can now - put up their own deposit to create a username and remove usernames. + storage maps had to be refactored and migrated to allow this to happen. The call to remove a + dangling username is now replaced by the permissioned `kill_username` call. crates: - name: pallet-identity diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 43e64cb873e2..bab581e92540 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -758,28 +758,6 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn remove_dangling_username() -> Result<(), BenchmarkError> { - let caller: T::AccountId = whitelisted_caller(); - let first_username = bounded_username::(bench_username(), bench_suffix()); - let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); - - // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username.clone(), Provider::Allocation); - Identity::::insert_username(&caller, second_username.clone(), Provider::Allocation); - - // Root calls `kill_username`, leaving their second username as "dangling" - Identity::::kill_username(RawOrigin::Root.into(), first_username.into())?; - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), second_username.clone()); - - assert_last_event::( - Event::::DanglingUsernameRemoved { who: caller, username: second_username }.into(), - ); - Ok(()) - } - #[benchmark] fn unbind_username() -> Result<(), BenchmarkError> { // Set up a username authority. diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 5b09bf523504..a74d0413469a 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -1238,49 +1238,10 @@ pub mod pallet { Ok(()) } - /// Remove a username that corresponds to an account with no primary username. Exists when a - /// user gets a username but then the authority removes it. - #[pallet::call_index(21)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] - pub fn remove_dangling_username( - origin: OriginFor, - username: Username, - ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - let username_info = - UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; - ensure!( - !UsernameOf::::contains_key(&username_info.owner), - Error::::InvalidUsername - ); - match username_info.provider { - Provider::AuthorityDeposit(username_deposit) => { - let suffix = - Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; - if let Some(authority_account) = - AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) - { - let err_amount = - T::Currency::unreserve(&authority_account, username_deposit); - debug_assert!(err_amount.is_zero()); - } - }, - Provider::Allocation => { - // We don't refund the allocation, it is lost. - }, - Provider::System => return Err(Error::::InvalidTarget.into()), - } - Self::deposit_event(Event::DanglingUsernameRemoved { - who: username_info.owner.clone(), - username, - }); - Ok(Pays::No.into()) - } - /// Start the process of removing a username by placing it in the unbinding usernames map. /// Once the grace period has passed, the username can be deleted by calling /// [remove_username](crate::Call::remove_username). - #[pallet::call_index(22)] + #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::unbind_username())] pub fn unbind_username(origin: OriginFor, username: Username) -> DispatchResult { let who = ensure_signed(origin)?; @@ -1311,7 +1272,7 @@ pub mod pallet { /// Permanently delete a username which has been unbinding for longer than the grace period. /// Caller is refunded the fee if the username expired and the removal was successful. - #[pallet::call_index(23)] + #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::remove_username())] pub fn remove_username( origin: OriginFor, @@ -1355,7 +1316,7 @@ pub mod pallet { /// Call with [ForceOrigin](crate::Config::ForceOrigin) privileges which deletes a username /// and slashes any deposit associated with it. - #[pallet::call_index(24)] + #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::kill_username(0))] pub fn kill_username( origin: OriginFor, diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 5ecc7fb14f2d..a095085a8188 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -1801,112 +1801,6 @@ fn unaccepted_usernames_through_deposit_should_expire() { }); } -#[test] -fn removing_dangling_usernames_should_work() { - new_test_ext().execute_with(|| { - // set up authority - let [authority, caller] = unfunded_accounts(); - let suffix: Vec = b"test".to_vec(); - let allocation: u32 = 10; - assert_ok!(Identity::add_username_authority( - RuntimeOrigin::root(), - authority.clone(), - suffix.clone(), - allocation - )); - - // set up username - let username = test_username_of(b"42".to_vec(), suffix.clone()); - - // set up user and sign message - let public = sr25519_generate(0.into(), None); - let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); - - // Set an identity for who. They need some balance though. - Balances::make_free_balance_be(&who_account, 1000); - let ten_info = infoof_ten(); - assert_ok!(Identity::set_identity( - RuntimeOrigin::signed(who_account.clone()), - Box::new(ten_info.clone()) - )); - assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority.clone()), - who_account.clone(), - username.clone().into(), - Some(signature), - true - )); - - // Now they set up a second username. - let username_two = test_username_of(b"43".to_vec(), suffix); - - // set up user and sign message - let signature_two = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); - - assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), - who_account.clone(), - username_two.clone().into(), - Some(signature_two), - true - )); - - // The primary should still be the first one. - assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); - - // But both usernames should look up the account. - let expected_user_info = - UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; - assert_eq!( - UsernameInfoOf::::get::<&Username>(&username), - Some(expected_user_info.clone()) - ); - assert_eq!( - UsernameInfoOf::::get::<&Username>(&username_two), - Some(expected_user_info.clone()) - ); - - // Someone tries to remove it, but they can't - assert_noop!( - Identity::remove_dangling_username( - RuntimeOrigin::signed(caller.clone()), - username.clone() - ), - Error::::InvalidUsername - ); - - // Now the user calls `clear_identity` - assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(who_account.clone()))); - - // Identity is gone - assert!(IdentityOf::::get(who_account.clone()).is_none()); - - // Kill the username. - assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username.clone().into())); - - // The reverse lookup of the primary is gone. - assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); - - // But the reverse lookup of the non-primary is still there - assert_eq!( - UsernameInfoOf::::get::<&Username>(&username_two), - Some(expected_user_info) - ); - - // Now it can be removed - assert_ok!(Identity::remove_dangling_username( - RuntimeOrigin::signed(caller), - username_two.clone() - )); - - // And the reverse lookup is gone - assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); - }); -} - #[test] fn kill_username_should_work() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 159d4fa4eb87..a74cca9dc8ec 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -73,7 +73,6 @@ pub trait WeightInfo { fn accept_username() -> Weight; fn remove_expired_approval(p: u32) -> Weight; fn set_primary_username() -> Weight; - fn remove_dangling_username() -> Weight; fn unbind_username() -> Weight; fn remove_username() -> Weight; fn kill_username(p: u32) -> Weight; @@ -437,19 +436,6 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } fn unbind_username() -> Weight { Weight::zero() } @@ -830,19 +816,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } fn unbind_username() -> Weight { Weight::zero() } From 7fe2d820e2923f08b21820a132b3faf39422ff0c Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 16 Sep 2024 10:45:04 +0300 Subject: [PATCH 40/44] Update docs Signed-off-by: georgepisaltu --- substrate/frame/identity/src/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index a74d0413469a..d85065e93092 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -52,7 +52,8 @@ //! accounts. There are mappings in both directions, "account -> username" and "username -> //! account". //! -//! To grant a username, a username authority can either: +//! Usernames are granted by authorities and grouped by suffix, with each suffix being administered +//! by one authority. To grant a username, a username authority can either: //! - be given an allocation by governance of a specific amount of usernames to issue for free, //! without any deposit associated with storage costs; //! - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative @@ -1056,8 +1057,9 @@ pub mod pallet { /// Add an `AccountId` with permission to grant usernames with a given `suffix` appended. /// - /// The authority can grant up to `allocation` usernames. To top up their allocation, they - /// should just issue (or request via governance) a new `add_username_authority` call. + /// The authority can grant up to `allocation` usernames. To top up the allocation or + /// change the account used to grant usernames, this call can be used with the updated + /// parameters to overwrite the existing configuration. #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::add_username_authority())] pub fn add_username_authority( @@ -1072,8 +1074,7 @@ pub mod pallet { // `BoundedVec`. Self::validate_suffix(&suffix)?; let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; - // The authority may already exist, but we don't need to check. They might be changing - // their suffix or adding allocation, so we just want to overwrite whatever was there. + // The call is `UsernameAuthorityOrigin` guarded, overwrite the old entry if it exists. AuthorityOf::::insert( &suffix, AuthorityProperties:: { account_id: authority.clone(), allocation }, @@ -1102,7 +1103,11 @@ pub mod pallet { /// Set the username for `who`. Must be called by a username authority. /// - /// The authority must have an `allocation`. Users can either pre-sign their usernames or + /// If `use_allocation` is set, the authority must have a username allocation available to + /// spend. Otherwise, the authority will need to put up a deposit for registering the + /// username. + /// + /// Users can either pre-sign their usernames or /// accept them later. /// /// Usernames must: From c3d22fe6911b685c5143ea8fc974449f4aadb677 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 16 Sep 2024 12:20:52 +0300 Subject: [PATCH 41/44] Truncate keys Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 3a6308afa17d..5855f5d84749 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -362,7 +362,7 @@ pub mod v2 { // Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with // it. Remove the entry if there was no real identity associated with the account. pub(crate) fn identity_step(maybe_last_key: Option) -> StepResultOf { - if let Some(last_key) = + if let Some(mut last_key) = IdentityOf::::translate_next::< ( Registration< @@ -383,7 +383,11 @@ pub mod v2 { None } }) { - MigrationState::Identity(last_key.try_into().unwrap()) + last_key.truncate(HashedKey::bound()); + MigrationState::Identity( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) } else { MigrationState::FinishedIdentities } @@ -391,14 +395,18 @@ pub mod v2 { // Migrate one entry from `PendingUsernames` to contain the new `Provider` field. pub(crate) fn pending_username_step(maybe_last_key: Option) -> StepResultOf { - if let Some(last_key) = + if let Some(mut last_key) = PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( maybe_last_key.map(|b| b.to_vec()), |_, (owner_account, since)| { Some((owner_account, since, Provider::new_with_allocation())) }, ) { - MigrationState::PendingUsername(last_key.try_into().unwrap()) + last_key.truncate(HashedKey::bound()); + MigrationState::PendingUsername( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) } else { MigrationState::FinishedPendingUsernames } From a11ef4aa2a6856d24e196ff34ca2d0877ede7ffd Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 30 Sep 2024 11:38:07 +0300 Subject: [PATCH 42/44] Add try runtime checks Signed-off-by: georgepisaltu --- substrate/frame/identity/src/migration.rs | 127 ++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 5855f5d84749..3a78692cfcd7 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -15,12 +15,16 @@ //! Storage migrations for the Identity pallet. +extern crate alloc; + use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, storage_alias, traits::UncheckedOnRuntimeUpgrade, IterableStorageMap, }; +#[cfg(feature = "try-runtime")] +use alloc::collections::BTreeMap; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; #[cfg(feature = "try-runtime")] @@ -95,6 +99,16 @@ mod types_v1 { ::AccountId, OptionQuery, >; + + #[cfg(feature = "try-runtime")] + #[storage_alias] + pub type PendingUsernames = StorageMap< + Pallet, + Blake2_128Concat, + Username, + (::AccountId, BlockNumberFor), + OptionQuery, + >; } pub mod v1 { @@ -199,6 +213,23 @@ pub mod v2 { Finished, } + #[cfg(feature = "try-runtime")] + #[derive(Encode, Decode)] + struct TryRuntimeState { + authorities: BTreeMap, (T::AccountId, u32)>, + identities: BTreeMap< + T::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + >, + primary_usernames: BTreeMap>, + usernames: BTreeMap, T::AccountId>, + pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)>, + } + pub struct LazyMigrationV1ToV2(PhantomData); impl SteppedMigration for LazyMigrationV1ToV2 { type Cursor = MigrationState, Suffix>; @@ -293,6 +324,102 @@ pub mod v2 { Ok(cursor) } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let authorities: BTreeMap, (T::AccountId, u32)> = + types_v1::UsernameAuthorities::::iter() + .map(|(account, authority_properties)| { + ( + authority_properties.account_id, + (account, authority_properties.allocation), + ) + }) + .collect(); + let mut primary_usernames: BTreeMap<_, _> = Default::default(); + let identities = types_v1::IdentityOf::::iter() + .map(|(account, (identity, maybe_username))| { + if let Some(username) = maybe_username { + primary_usernames.insert(account.clone(), username); + } + (account, identity) + }) + .collect::>(); + let usernames = types_v1::AccountOfUsername::::iter().collect::>(); + let pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)> = + types_v1::PendingUsernames::::iter().collect(); + let state: TryRuntimeState = TryRuntimeState { + authorities, + identities, + primary_usernames, + usernames, + pending_usernames, + }; + + Ok(state.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let mut prev_state: TryRuntimeState = TryRuntimeState::::decode(&mut &state[..]) + .expect("Failed to decode the previous storage state"); + + for (suffix, authority_properties) in AuthorityOf::::iter() { + let (prev_account, prev_allocation) = prev_state + .authorities + .remove(&suffix) + .expect("should have authority in previous state"); + assert_eq!(prev_account, authority_properties.account_id); + assert_eq!(prev_allocation, authority_properties.allocation); + } + assert!(prev_state.authorities.is_empty()); + + for (account, identity) in IdentityOf::::iter() { + assert!(identity.deposit > 0u32.into()); + let prev_identity = prev_state + .identities + .remove(&account) + .expect("should have identity in previous state"); + assert_eq!(identity, prev_identity); + } + + for (account, free_identity) in prev_state.identities.iter() { + assert_eq!(free_identity.deposit, 0u32.into()); + assert!(UsernameOf::::contains_key(&account)); + } + prev_state.identities.clear(); + + for (account, primary_username) in UsernameOf::::iter() { + let prev_primary_username = prev_state + .primary_usernames + .remove(&account) + .expect("should have primary username in previous state"); + assert_eq!(prev_primary_username, primary_username); + } + + for (username, username_info) in UsernameInfoOf::::iter() { + let prev_account = prev_state + .usernames + .remove(&username) + .expect("should have username info in previous state"); + assert_eq!(prev_account, username_info.owner); + assert_eq!(username_info.provider, Provider::Allocation); + } + assert!(prev_state.usernames.is_empty()); + + for (username, (account, expiration, provider)) in PendingUsernames::::iter() { + let (prev_account, prev_expiration) = prev_state + .pending_usernames + .remove(&username) + .expect("should have pending username in previous state"); + assert_eq!(prev_account, account); + assert_eq!(prev_expiration, expiration); + assert_eq!(provider, Provider::Allocation); + } + assert!(prev_state.pending_usernames.is_empty()); + + Ok(()) + } } impl LazyMigrationV1ToV2 { From 976e0ffae48f0025358bc8d4c34b4180e85a319a Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Mon, 30 Sep 2024 11:42:28 +0300 Subject: [PATCH 43/44] Fix docs Signed-off-by: georgepisaltu --- substrate/frame/identity/README.md | 1 - substrate/frame/identity/src/lib.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index 35ce11c71e14..32b75d159a9b 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -59,7 +59,6 @@ lookup in the `UsernameOf` map for any given account. - `accept_username` - Accept a username issued by a username authority. - `remove_expired_approval` - Remove a username that was issued but never accepted. - `set_primary_username` - Set a given username as an account's primary. -- `remove_dangling_username` - Remove a username that maps to an account without a primary username. - `remove_username` - Remove a username after its grace period has ended. ##### For General Users with Sub-Identities diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index d85065e93092..11b43f958c4e 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -76,8 +76,6 @@ //! * `accept_username` - Accept a username issued by a username authority. //! * `remove_expired_approval` - Remove a username that was issued but never accepted. //! * `set_primary_username` - Set a given username as an account's primary. -//! * `remove_dangling_username` - Remove a username that maps to an account without a primary -//! username. //! * `remove_username` - Remove a username after its grace period has ended. //! //! #### For General Users with Sub-Identities From ae07a64ac38d92ab4c6594fe78eb817b141efe84 Mon Sep 17 00:00:00 2001 From: georgepisaltu Date: Tue, 29 Oct 2024 13:59:16 +0200 Subject: [PATCH 44/44] Update prdoc Signed-off-by: georgepisaltu --- prdoc/pr_5554.prdoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prdoc/pr_5554.prdoc b/prdoc/pr_5554.prdoc index 7116e04d2372..3ebf00b38ed7 100644 --- a/prdoc/pr_5554.prdoc +++ b/prdoc/pr_5554.prdoc @@ -13,6 +13,8 @@ doc: dangling username is now replaced by the permissioned `kill_username` call. crates: + - name: pallet-alliance + bump: major - name: pallet-identity bump: major - name: rococo-runtime @@ -23,5 +25,7 @@ crates: bump: major - name: people-westend-runtime bump: major + - name: polkadot-runtime-common + bump: major - name: kitchensink-runtime bump: major \ No newline at end of file