referrerpolicy=no-referrer-when-downgrade

pallet_identity/
migration.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Storage migrations for the Identity pallet.
17
18extern crate alloc;
19
20use super::*;
21use frame_support::{
22	migrations::VersionedMigration, pallet_prelude::*, storage_alias,
23	traits::UncheckedOnRuntimeUpgrade, IterableStorageMap,
24};
25
26#[cfg(feature = "try-runtime")]
27use alloc::collections::BTreeMap;
28#[cfg(feature = "try-runtime")]
29use codec::{Decode, Encode};
30#[cfg(feature = "try-runtime")]
31use sp_runtime::TryRuntimeError;
32
33pub const PALLET_MIGRATIONS_ID: &[u8; 15] = b"pallet-identity";
34
35pub mod versioned {
36	use super::*;
37
38	pub type V0ToV1<T, const KL: u64> = VersionedMigration<
39		0,
40		1,
41		v1::VersionUncheckedMigrateV0ToV1<T, KL>,
42		crate::pallet::Pallet<T>,
43		<T as frame_system::Config>::DbWeight,
44	>;
45}
46
47/// The old identity types in v0.
48mod types_v0 {
49	use super::*;
50
51	#[storage_alias]
52	pub type IdentityOf<T: Config> = StorageMap<
53		Pallet<T>,
54		Twox64Concat,
55		<T as frame_system::Config>::AccountId,
56		Registration<
57			BalanceOf<T>,
58			<T as pallet::Config>::MaxRegistrars,
59			<T as pallet::Config>::IdentityInformation,
60		>,
61		OptionQuery,
62	>;
63}
64
65/// The old identity types in v1.
66mod types_v1 {
67	use super::*;
68
69	#[storage_alias]
70	pub type IdentityOf<T: Config> = StorageMap<
71		Pallet<T>,
72		Twox64Concat,
73		<T as frame_system::Config>::AccountId,
74		(
75			Registration<
76				BalanceOf<T>,
77				<T as pallet::Config>::MaxRegistrars,
78				<T as pallet::Config>::IdentityInformation,
79			>,
80			Option<Username<T>>,
81		),
82		OptionQuery,
83	>;
84
85	#[storage_alias]
86	pub type UsernameAuthorities<T: Config> = StorageMap<
87		Pallet<T>,
88		Twox64Concat,
89		<T as frame_system::Config>::AccountId,
90		AuthorityProperties<Suffix<T>>,
91		OptionQuery,
92	>;
93
94	#[storage_alias]
95	pub type AccountOfUsername<T: Config> = StorageMap<
96		Pallet<T>,
97		Blake2_128Concat,
98		Username<T>,
99		<T as frame_system::Config>::AccountId,
100		OptionQuery,
101	>;
102
103	#[cfg(feature = "try-runtime")]
104	#[storage_alias]
105	pub type PendingUsernames<T: Config> = StorageMap<
106		Pallet<T>,
107		Blake2_128Concat,
108		Username<T>,
109		(<T as frame_system::Config>::AccountId, BlockNumberFor<T>),
110		OptionQuery,
111	>;
112}
113
114pub mod v1 {
115	use super::*;
116
117	/// The log target.
118	const TARGET: &'static str = "runtime::identity::migration::v1";
119	/// Migration to add usernames to Identity info.
120	///
121	/// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to
122	/// prevent stalling a parachain by accumulating too much weight in the migration. To have an
123	/// unlimited migration (e.g. in a chain without PoV limits), set this to `u64::MAX`.
124	pub struct VersionUncheckedMigrateV0ToV1<T, const KL: u64>(PhantomData<T>);
125	impl<T: Config, const KL: u64> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1<T, KL> {
126		#[cfg(feature = "try-runtime")]
127		fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
128			let identities = types_v0::IdentityOf::<T>::iter().count();
129			log::info!(
130				target: TARGET,
131				"pre-upgrade state contains '{}' identities.",
132				identities
133			);
134			ensure!((identities as u64) < KL, "too many identities to migrate");
135			Ok((identities as u64).encode())
136		}
137
138		fn on_runtime_upgrade() -> Weight {
139			log::info!(
140				target: TARGET,
141				"running storage migration from version 0 to version 1."
142			);
143
144			let mut weight = T::DbWeight::get().reads(1);
145			let mut translated: u64 = 0;
146			let mut interrupted = false;
147
148			for (account, registration) in types_v0::IdentityOf::<T>::iter() {
149				types_v1::IdentityOf::<T>::insert(account, (registration, None::<Username<T>>));
150				translated.saturating_inc();
151				if translated >= KL {
152					log::warn!(
153						"Incomplete! Migration limit reached. Only {} identities migrated.",
154						translated
155					);
156					interrupted = true;
157					break
158				}
159			}
160			if !interrupted {
161				log::info!("all {} identities migrated", translated);
162			}
163
164			weight.saturating_accrue(T::DbWeight::get().reads_writes(translated, translated));
165			weight.saturating_accrue(T::DbWeight::get().writes(1));
166			weight
167		}
168
169		#[cfg(feature = "try-runtime")]
170		fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
171			let identities_to_migrate: u64 = Decode::decode(&mut &state[..])
172				.expect("failed to decode the state from pre-upgrade.");
173			let identities = types_v1::IdentityOf::<T>::iter().count() as u64;
174			log::info!("post-upgrade expects '{}' identities to have been migrated.", identities);
175			ensure!(identities_to_migrate == identities, "must migrate all identities.");
176			log::info!(target: TARGET, "migrated all identities.");
177			Ok(())
178		}
179	}
180}
181
182pub mod v2 {
183	use super::*;
184	use frame_support::{
185		migrations::{MigrationId, SteppedMigration, SteppedMigrationError},
186		weights::WeightMeter,
187	};
188
189	type HashedKey = BoundedVec<u8, ConstU32<256>>;
190	// The resulting state of the step and the actual weight consumed.
191	type StepResultOf<T> =
192		MigrationState<<T as frame_system::Config>::AccountId, Username<T>, Suffix<T>>;
193
194	#[cfg(feature = "runtime-benchmarks")]
195	pub(crate) type BenchmarkingSetupOf<T> =
196		BenchmarkingSetup<Suffix<T>, <T as frame_system::Config>::AccountId, Username<T>>;
197
198	/// Progressive states of a migration. The migration starts with the first variant and ends with
199	/// the last.
200	#[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)]
201	pub enum MigrationState<A, U, S> {
202		Authority(A),
203		FinishedAuthorities,
204		Identity(HashedKey),
205		FinishedIdentities,
206		Username(U),
207		FinishedUsernames,
208		PendingUsername(HashedKey),
209		FinishedPendingUsernames,
210		CleanupAuthorities(S),
211		FinishedCleanupAuthorities,
212		CleanupUsernames(U),
213		Finished,
214	}
215
216	#[cfg(feature = "try-runtime")]
217	#[derive(Encode, Decode)]
218	struct TryRuntimeState<T: Config> {
219		authorities: BTreeMap<Suffix<T>, (T::AccountId, u32)>,
220		identities: BTreeMap<
221			T::AccountId,
222			Registration<
223				BalanceOf<T>,
224				<T as Config>::MaxRegistrars,
225				<T as Config>::IdentityInformation,
226			>,
227		>,
228		primary_usernames: BTreeMap<T::AccountId, Username<T>>,
229		usernames: BTreeMap<Username<T>, T::AccountId>,
230		pending_usernames: BTreeMap<Username<T>, (T::AccountId, BlockNumberFor<T>)>,
231	}
232
233	pub struct LazyMigrationV1ToV2<T: Config>(PhantomData<T>);
234	impl<T: Config> SteppedMigration for LazyMigrationV1ToV2<T> {
235		type Cursor = MigrationState<T::AccountId, Username<T>, Suffix<T>>;
236		type Identifier = MigrationId<15>;
237
238		fn id() -> Self::Identifier {
239			MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 1, version_to: 2 }
240		}
241
242		fn step(
243			mut cursor: Option<Self::Cursor>,
244			meter: &mut WeightMeter,
245		) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
246			if Pallet::<T>::on_chain_storage_version() != Self::id().version_from as u16 {
247				return Ok(None);
248			}
249
250			// Check that we have enough weight for at least the next step. If we don't, then the
251			// migration cannot be complete.
252			let required = match &cursor {
253				Some(state) => Self::required_weight(&state),
254				// Worst case weight for `authority_step`.
255				None => T::WeightInfo::migration_v2_authority_step(),
256			};
257			if meter.remaining().any_lt(required) {
258				return Err(SteppedMigrationError::InsufficientWeight { required });
259			}
260
261			loop {
262				// Check that we would have enough weight to perform this step in the worst case
263				// scenario.
264				let required_weight = match &cursor {
265					Some(state) => Self::required_weight(&state),
266					// Worst case weight for `authority_step`.
267					None => T::WeightInfo::migration_v2_authority_step(),
268				};
269				if !meter.can_consume(required_weight) {
270					break;
271				}
272
273				let next = match &cursor {
274					// At first, migrate any authorities.
275					None => Self::authority_step(None),
276					// Migrate any remaining authorities.
277					Some(MigrationState::Authority(maybe_last_authority)) =>
278						Self::authority_step(Some(maybe_last_authority)),
279					// After the last authority was migrated, start migrating usernames from
280					// the former `AccountOfUsername` into `UsernameInfoOf`.
281					Some(MigrationState::FinishedAuthorities) => Self::username_step(None),
282					// Keep migrating usernames.
283					Some(MigrationState::Username(maybe_last_username)) =>
284						Self::username_step(Some(maybe_last_username)),
285					// After the last username was migrated, start migrating all identities in
286					// `IdentityOf`, which currently hold the primary username of the owner account
287					// as well as any associated identity. Accounts which set a username but not an
288					// identity also have a zero deposit identity stored, which will be removed.
289					Some(MigrationState::FinishedUsernames) => Self::identity_step(None),
290					// Keep migrating identities.
291					Some(MigrationState::Identity(last_key)) =>
292						Self::identity_step(Some(last_key.clone())),
293					// After the last identity was migrated, start migrating usernames pending
294					// approval from `PendingUsernames`.
295					Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None),
296					// Keep migrating pending usernames.
297					Some(MigrationState::PendingUsername(last_key)) =>
298						Self::pending_username_step(Some(last_key.clone())),
299					// After the last pending username was migrated, start clearing the storage
300					// previously associated with authorities in `UsernameAuthority`.
301					Some(MigrationState::FinishedPendingUsernames) =>
302						Self::cleanup_authority_step(None),
303					// Keep clearing the obsolete authority storage.
304					Some(MigrationState::CleanupAuthorities(maybe_last_username)) =>
305						Self::cleanup_authority_step(Some(maybe_last_username)),
306					// After the last obsolete authority was cleared from storage, start clearing
307					// the storage previously associated with usernames in `AccountOfUsername`.
308					Some(MigrationState::FinishedCleanupAuthorities) =>
309						Self::cleanup_username_step(None),
310					// Keep clearing the obsolete username storage.
311					Some(MigrationState::CleanupUsernames(maybe_last_username)) =>
312						Self::cleanup_username_step(Some(maybe_last_username)),
313					// After the last obsolete username was cleared from storage, the migration is
314					// done.
315					Some(MigrationState::Finished) => {
316						StorageVersion::new(Self::id().version_to as u16).put::<Pallet<T>>();
317						return Ok(None)
318					},
319				};
320
321				cursor = Some(next);
322				meter.consume(required_weight);
323			}
324
325			Ok(cursor)
326		}
327
328		#[cfg(feature = "try-runtime")]
329		fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
330			let authorities: BTreeMap<Suffix<T>, (T::AccountId, u32)> =
331				types_v1::UsernameAuthorities::<T>::iter()
332					.map(|(account, authority_properties)| {
333						(
334							authority_properties.account_id,
335							(account, authority_properties.allocation),
336						)
337					})
338					.collect();
339			let mut primary_usernames: BTreeMap<_, _> = Default::default();
340			let identities = types_v1::IdentityOf::<T>::iter()
341				.map(|(account, (identity, maybe_username))| {
342					if let Some(username) = maybe_username {
343						primary_usernames.insert(account.clone(), username);
344					}
345					(account, identity)
346				})
347				.collect::<BTreeMap<_, _>>();
348			let usernames = types_v1::AccountOfUsername::<T>::iter().collect::<BTreeMap<_, _>>();
349			let pending_usernames: BTreeMap<Username<T>, (T::AccountId, BlockNumberFor<T>)> =
350				types_v1::PendingUsernames::<T>::iter().collect();
351			let state: TryRuntimeState<T> = TryRuntimeState {
352				authorities,
353				identities,
354				primary_usernames,
355				usernames,
356				pending_usernames,
357			};
358
359			Ok(state.encode())
360		}
361
362		#[cfg(feature = "try-runtime")]
363		fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
364			let mut prev_state: TryRuntimeState<T> = TryRuntimeState::<T>::decode(&mut &state[..])
365				.expect("Failed to decode the previous storage state");
366
367			for (suffix, authority_properties) in AuthorityOf::<T>::iter() {
368				let (prev_account, prev_allocation) = prev_state
369					.authorities
370					.remove(&suffix)
371					.expect("should have authority in previous state");
372				assert_eq!(prev_account, authority_properties.account_id);
373				assert_eq!(prev_allocation, authority_properties.allocation);
374			}
375			assert!(prev_state.authorities.is_empty());
376
377			for (account, identity) in IdentityOf::<T>::iter() {
378				assert!(identity.deposit > 0u32.into());
379				let prev_identity = prev_state
380					.identities
381					.remove(&account)
382					.expect("should have identity in previous state");
383				assert_eq!(identity, prev_identity);
384			}
385
386			for (account, free_identity) in prev_state.identities.iter() {
387				assert_eq!(free_identity.deposit, 0u32.into());
388				assert!(UsernameOf::<T>::contains_key(&account));
389			}
390			prev_state.identities.clear();
391
392			for (account, primary_username) in UsernameOf::<T>::iter() {
393				let prev_primary_username = prev_state
394					.primary_usernames
395					.remove(&account)
396					.expect("should have primary username in previous state");
397				assert_eq!(prev_primary_username, primary_username);
398			}
399
400			for (username, username_info) in UsernameInfoOf::<T>::iter() {
401				let prev_account = prev_state
402					.usernames
403					.remove(&username)
404					.expect("should have username info in previous state");
405				assert_eq!(prev_account, username_info.owner);
406				assert_eq!(username_info.provider, Provider::Allocation);
407			}
408			assert!(prev_state.usernames.is_empty());
409
410			for (username, (account, expiration, provider)) in PendingUsernames::<T>::iter() {
411				let (prev_account, prev_expiration) = prev_state
412					.pending_usernames
413					.remove(&username)
414					.expect("should have pending username in previous state");
415				assert_eq!(prev_account, account);
416				assert_eq!(prev_expiration, expiration);
417				assert_eq!(provider, Provider::Allocation);
418			}
419			assert!(prev_state.pending_usernames.is_empty());
420
421			Ok(())
422		}
423	}
424
425	impl<T: Config> LazyMigrationV1ToV2<T> {
426		pub(crate) fn required_weight(
427			step: &MigrationState<T::AccountId, Username<T>, Suffix<T>>,
428		) -> Weight {
429			match step {
430				MigrationState::Authority(_) => T::WeightInfo::migration_v2_authority_step(),
431				MigrationState::FinishedAuthorities | MigrationState::Username(_) =>
432					T::WeightInfo::migration_v2_username_step(),
433				MigrationState::FinishedUsernames | MigrationState::Identity(_) =>
434					T::WeightInfo::migration_v2_identity_step(),
435				MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) =>
436					T::WeightInfo::migration_v2_pending_username_step(),
437				MigrationState::FinishedPendingUsernames |
438				MigrationState::CleanupAuthorities(_) => T::WeightInfo::migration_v2_cleanup_authority_step(),
439				MigrationState::FinishedCleanupAuthorities |
440				MigrationState::CleanupUsernames(_) => T::WeightInfo::migration_v2_cleanup_username_step(),
441				MigrationState::Finished => Weight::zero(),
442			}
443		}
444
445		// Migrate one entry from `UsernameAuthorities` to `AuthorityOf`.
446		pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf<T> {
447			let mut iter = if let Some(last_key) = maybe_last_key {
448				types_v1::UsernameAuthorities::<T>::iter_from(
449					types_v1::UsernameAuthorities::<T>::hashed_key_for(last_key),
450				)
451			} else {
452				types_v1::UsernameAuthorities::<T>::iter()
453			};
454			if let Some((authority_account, properties)) = iter.next() {
455				let suffix = properties.account_id;
456				let allocation = properties.allocation;
457				let new_properties =
458					AuthorityProperties { account_id: authority_account.clone(), allocation };
459				AuthorityOf::<T>::insert(&suffix, new_properties);
460				MigrationState::Authority(authority_account)
461			} else {
462				MigrationState::FinishedAuthorities
463			}
464		}
465
466		// Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`.
467		pub(crate) fn username_step(maybe_last_key: Option<&Username<T>>) -> StepResultOf<T> {
468			let mut iter = if let Some(last_key) = maybe_last_key {
469				types_v1::AccountOfUsername::<T>::iter_from(
470					types_v1::AccountOfUsername::<T>::hashed_key_for(last_key),
471				)
472			} else {
473				types_v1::AccountOfUsername::<T>::iter()
474			};
475
476			if let Some((username, owner_account)) = iter.next() {
477				let username_info = UsernameInformation {
478					owner: owner_account,
479					provider: Provider::new_with_allocation(),
480				};
481				UsernameInfoOf::<T>::insert(&username, username_info);
482
483				MigrationState::Username(username)
484			} else {
485				MigrationState::FinishedUsernames
486			}
487		}
488
489		// Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with
490		// it. Remove the entry if there was no real identity associated with the account.
491		pub(crate) fn identity_step(maybe_last_key: Option<HashedKey>) -> StepResultOf<T> {
492			if let Some(mut last_key) =
493				IdentityOf::<T>::translate_next::<
494					(
495						Registration<
496							BalanceOf<T>,
497							<T as pallet::Config>::MaxRegistrars,
498							<T as pallet::Config>::IdentityInformation,
499						>,
500						Option<Username<T>>,
501					),
502					_,
503				>(maybe_last_key.map(|b| b.to_vec()), |account, (identity, maybe_username)| {
504					if let Some(primary_username) = maybe_username {
505						UsernameOf::<T>::insert(&account, primary_username);
506					}
507					if identity.deposit > BalanceOf::<T>::zero() {
508						Some(identity)
509					} else {
510						None
511					}
512				}) {
513				last_key.truncate(HashedKey::bound());
514				MigrationState::Identity(
515					HashedKey::try_from(last_key)
516						.expect("truncated to bound so the conversion must succeed; qed"),
517				)
518			} else {
519				MigrationState::FinishedIdentities
520			}
521		}
522
523		// Migrate one entry from `PendingUsernames` to contain the new `Provider` field.
524		pub(crate) fn pending_username_step(maybe_last_key: Option<HashedKey>) -> StepResultOf<T> {
525			if let Some(mut last_key) =
526				PendingUsernames::<T>::translate_next::<(T::AccountId, BlockNumberFor<T>), _>(
527					maybe_last_key.map(|b| b.to_vec()),
528					|_, (owner_account, since)| {
529						Some((owner_account, since, Provider::new_with_allocation()))
530					},
531				) {
532				last_key.truncate(HashedKey::bound());
533				MigrationState::PendingUsername(
534					HashedKey::try_from(last_key)
535						.expect("truncated to bound so the conversion must succeed; qed"),
536				)
537			} else {
538				MigrationState::FinishedPendingUsernames
539			}
540		}
541
542		// Remove one entry from `UsernameAuthorities`.
543		pub(crate) fn cleanup_authority_step(
544			maybe_last_key: Option<&Suffix<T>>,
545		) -> StepResultOf<T> {
546			let mut iter = if let Some(last_key) = maybe_last_key {
547				AuthorityOf::<T>::iter_from(AuthorityOf::<T>::hashed_key_for(last_key))
548			} else {
549				AuthorityOf::<T>::iter()
550			};
551
552			if let Some((suffix, properties)) = iter.next() {
553				let _ = types_v1::UsernameAuthorities::<T>::take(&properties.account_id);
554				MigrationState::CleanupAuthorities(suffix)
555			} else {
556				MigrationState::FinishedCleanupAuthorities
557			}
558		}
559
560		// Remove one entry from `AccountOfUsername`.
561		pub(crate) fn cleanup_username_step(
562			maybe_last_key: Option<&Username<T>>,
563		) -> StepResultOf<T> {
564			let mut iter = if let Some(last_key) = maybe_last_key {
565				UsernameInfoOf::<T>::iter_from(UsernameInfoOf::<T>::hashed_key_for(last_key))
566			} else {
567				UsernameInfoOf::<T>::iter()
568			};
569
570			if let Some((username, _)) = iter.next() {
571				let _ = types_v1::AccountOfUsername::<T>::take(&username);
572				MigrationState::CleanupUsernames(username)
573			} else {
574				MigrationState::Finished
575			}
576		}
577	}
578
579	#[cfg(feature = "runtime-benchmarks")]
580	pub(crate) struct BenchmarkingSetup<S, A, U> {
581		pub(crate) suffix: S,
582		pub(crate) authority: A,
583		pub(crate) account: A,
584		pub(crate) username: U,
585	}
586
587	#[cfg(feature = "runtime-benchmarks")]
588	impl<T: Config> LazyMigrationV1ToV2<T> {
589		pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf<T> {
590			use frame_support::Hashable;
591			let suffix: Suffix<T> = b"bench".to_vec().try_into().unwrap();
592			let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0);
593			let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0);
594
595			let prop: AuthorityProperties<Suffix<T>> =
596				AuthorityProperties { account_id: suffix.clone(), allocation: 10 };
597			types_v1::UsernameAuthorities::<T>::insert(&authority, &prop);
598
599			let username: Username<T> = b"account.bench".to_vec().try_into().unwrap();
600			let info = T::IdentityInformation::create_identity_info();
601			let registration: Registration<
602				BalanceOf<T>,
603				<T as Config>::MaxRegistrars,
604				<T as Config>::IdentityInformation,
605			> = Registration { judgements: Default::default(), deposit: 10u32.into(), info };
606			frame_support::migration::put_storage_value(
607				b"Identity",
608				b"IdentityOf",
609				&account_id.twox_64_concat(),
610				(&registration, Some(username.clone())),
611			);
612			types_v1::AccountOfUsername::<T>::insert(&username, &account_id);
613			let since: BlockNumberFor<T> = 0u32.into();
614			frame_support::migration::put_storage_value(
615				b"Identity",
616				b"PendingUsernames",
617				&username.blake2_128_concat(),
618				(&account_id, since),
619			);
620			BenchmarkingSetup { suffix, authority, account: account_id, username }
621		}
622
623		pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf<T> {
624			let suffix: Suffix<T> = b"bench".to_vec().try_into().unwrap();
625			let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0);
626			let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0);
627
628			let prop: AuthorityProperties<Suffix<T>> =
629				AuthorityProperties { account_id: suffix.clone(), allocation: 10 };
630			types_v1::UsernameAuthorities::<T>::insert(&authority, &prop);
631			let prop: AuthorityProperties<T::AccountId> =
632				AuthorityProperties { account_id: authority.clone(), allocation: 10 };
633			AuthorityOf::<T>::insert(&suffix, &prop);
634
635			let username: Username<T> = b"account.bench".to_vec().try_into().unwrap();
636			let info = T::IdentityInformation::create_identity_info();
637			let registration: Registration<
638				BalanceOf<T>,
639				<T as Config>::MaxRegistrars,
640				<T as Config>::IdentityInformation,
641			> = Registration { judgements: Default::default(), deposit: 10u32.into(), info };
642			IdentityOf::<T>::insert(&account_id, &registration);
643			UsernameOf::<T>::insert(&account_id, &username);
644			let username_info = UsernameInformation {
645				owner: account_id.clone(),
646				provider: Provider::new_with_allocation(),
647			};
648			UsernameInfoOf::<T>::insert(&username, username_info);
649			types_v1::AccountOfUsername::<T>::insert(&username, &account_id);
650			let since: BlockNumberFor<T> = 0u32.into();
651			PendingUsernames::<T>::insert(
652				&username,
653				(&account_id, since, Provider::new_with_allocation()),
654			);
655			BenchmarkingSetup { suffix, authority, account: account_id, username }
656		}
657
658		pub(crate) fn check_authority_cleanup_validity(suffix: Suffix<T>, authority: T::AccountId) {
659			assert_eq!(types_v1::UsernameAuthorities::<T>::iter().count(), 0);
660			assert_eq!(AuthorityOf::<T>::get(&suffix).unwrap().account_id, authority);
661		}
662
663		pub(crate) fn check_username_cleanup_validity(
664			username: Username<T>,
665			account_id: T::AccountId,
666		) {
667			assert_eq!(types_v1::AccountOfUsername::<T>::iter().count(), 0);
668			assert_eq!(UsernameInfoOf::<T>::get(&username).unwrap().owner, account_id);
669		}
670	}
671
672	#[cfg(test)]
673	mod tests {
674		use frame_support::Hashable;
675
676		use super::*;
677		use crate::tests::{new_test_ext, Test};
678
679		fn registration(
680			with_deposit: bool,
681		) -> Registration<
682			BalanceOf<Test>,
683			<Test as Config>::MaxRegistrars,
684			<Test as Config>::IdentityInformation,
685		> {
686			Registration {
687				judgements: Default::default(),
688				deposit: if with_deposit { 10u32.into() } else { 0u32.into() },
689				info: Default::default(),
690			}
691		}
692
693		fn account_from_u8(byte: u8) -> <Test as frame_system::Config>::AccountId {
694			[byte; 32].into()
695		}
696
697		#[test]
698		fn migrate_to_v2() {
699			new_test_ext().execute_with(|| {
700				StorageVersion::new(1).put::<Pallet<Test>>();
701				// Set up the first authority.
702				let authority_1 = account_from_u8(151);
703				let suffix_1: Suffix<Test> = b"evn".to_vec().try_into().unwrap();
704				let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 };
705				types_v1::UsernameAuthorities::<Test>::insert(&authority_1, &prop);
706				// Set up the first authority.
707				let authority_2 = account_from_u8(152);
708				let suffix_2: Suffix<Test> = b"odd".to_vec().try_into().unwrap();
709				let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 };
710				types_v1::UsernameAuthorities::<Test>::insert(&authority_2, &prop);
711
712				// (owner_account, primary_username, maybe_secondary_username, has_identity)
713				// If `has_identity` is set, this `owner_account` will have a real identity
714				// associated and a non-zero deposit for it.
715				let mut usernames = vec![];
716				for i in 0u8..100u8 {
717					let account_id = account_from_u8(i);
718					let bare_username = format!("acc{}.", i).as_bytes().to_vec();
719					let mut username_1 = bare_username.clone();
720					username_1.extend(suffix_1.iter());
721					let username_1: Username<Test> = username_1.try_into().unwrap();
722					types_v1::AccountOfUsername::<Test>::insert(&username_1, &account_id);
723
724					if i % 2 == 0 {
725						let has_identity = i % 4 == 0;
726						let reg = registration(has_identity);
727						frame_support::migration::put_storage_value(
728							b"Identity",
729							b"IdentityOf",
730							&account_id.twox_64_concat(),
731							(reg, Some(username_1.clone())),
732						);
733						usernames.push((account_id, username_1, None, has_identity));
734					} else {
735						let has_identity = i % 3 == 0;
736						let mut username_2 = bare_username.clone();
737						username_2.extend(suffix_2.iter());
738						let username_2: Username<Test> = username_2.try_into().unwrap();
739						types_v1::AccountOfUsername::<Test>::insert(&username_2, &account_id);
740						let reg = registration(has_identity);
741						frame_support::migration::put_storage_value(
742							b"Identity",
743							b"IdentityOf",
744							&account_id.twox_64_concat(),
745							(reg, Some(username_2.clone())),
746						);
747						usernames.push((account_id, username_2, Some(username_1), has_identity));
748					}
749				}
750
751				// (username, owner_account, since)
752				let mut pending = vec![];
753				for i in 100u8..110u8 {
754					let account_id = account_from_u8(i);
755					let mut bare_username = format!("acc{}.", i).as_bytes().to_vec();
756					bare_username.extend(suffix_1.iter());
757					let username: Username<Test> = bare_username.try_into().unwrap();
758					let since: BlockNumberFor<Test> = i.into();
759					frame_support::migration::put_storage_value(
760						b"Identity",
761						b"PendingUsernames",
762						&username.blake2_128_concat(),
763						(&account_id, since),
764					);
765					pending.push((username, account_id, since));
766				}
767
768				let mut identity_only = vec![];
769				for i in 120u8..130u8 {
770					let account_id = account_from_u8(i);
771					let reg = registration(true);
772					frame_support::migration::put_storage_value(
773						b"Identity",
774						b"IdentityOf",
775						&account_id.twox_64_concat(),
776						(reg, None::<Username<Test>>),
777					);
778					identity_only.push(account_id);
779				}
780
781				// Run the actual migration.
782				let mut weight_meter = WeightMeter::new();
783				let mut cursor = None;
784				while let Some(new_cursor) =
785					LazyMigrationV1ToV2::<Test>::step(cursor, &mut weight_meter).unwrap()
786				{
787					cursor = Some(new_cursor);
788				}
789				assert_eq!(Pallet::<Test>::on_chain_storage_version(), 2);
790
791				// Check that the authorities were migrated.
792				let expected_prop =
793					AuthorityProperties { account_id: authority_1.clone(), allocation: 10 };
794				assert_eq!(AuthorityOf::<Test>::get(&suffix_1), Some(expected_prop));
795
796				let expected_prop =
797					AuthorityProperties { account_id: authority_2.clone(), allocation: 10 };
798				assert_eq!(AuthorityOf::<Test>::get(&suffix_2), Some(expected_prop));
799
800				// Check that the username information was migrated.
801				let count_of_usernames_without_identities =
802					usernames.iter().filter(|(_, _, _, has_id)| *has_id).count();
803				assert_eq!(UsernameOf::<Test>::iter().count(), usernames.len());
804				// All accounts have `evn` usernames, only half of them have `odd` usernames.
805				assert_eq!(
806					UsernameInfoOf::<Test>::iter().count(),
807					usernames.len() + usernames.len() / 2
808				);
809				for (owner, primary, maybe_secondary, has_identity) in usernames.iter() {
810					let username_info = UsernameInfoOf::<Test>::get(primary).unwrap();
811					assert_eq!(&username_info.owner, owner);
812					let actual_primary = UsernameOf::<Test>::get(owner).unwrap();
813					assert_eq!(primary, &actual_primary);
814					assert_eq!(IdentityOf::<Test>::contains_key(owner), *has_identity);
815					if let Some(secondary) = maybe_secondary {
816						let expected_info = UsernameInformation {
817							owner: owner.clone(),
818							provider: Provider::new_with_allocation(),
819						};
820						assert_eq!(UsernameInfoOf::<Test>::get(secondary), Some(expected_info));
821					}
822				}
823
824				// Check that existing identities were preserved.
825				for id in identity_only.iter() {
826					let expected_reg = registration(true);
827					assert_eq!(IdentityOf::<Test>::get(id), Some(expected_reg));
828					assert!(!UsernameOf::<Test>::contains_key(id));
829				}
830				let identity_count = IdentityOf::<Test>::iter().count();
831				assert_eq!(
832					identity_count,
833					count_of_usernames_without_identities + identity_only.len()
834				);
835
836				// Check that pending usernames were migrated.
837				let pending_count = PendingUsernames::<Test>::iter().count();
838				assert_eq!(pending_count, pending.len());
839				for (username, owner, since) in pending.iter() {
840					let expected_pending = (owner.clone(), *since, Provider::Allocation);
841					assert_eq!(PendingUsernames::<Test>::get(username), Some(expected_pending));
842				}
843
844				// Check that obsolete storage was cleared.
845				assert_eq!(types_v1::AccountOfUsername::<Test>::iter().count(), 0);
846				assert_eq!(types_v1::UsernameAuthorities::<Test>::iter().count(), 0);
847			});
848		}
849	}
850}