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					},
280					// After the last authority was migrated, start migrating usernames from
281					// the former `AccountOfUsername` into `UsernameInfoOf`.
282					Some(MigrationState::FinishedAuthorities) => Self::username_step(None),
283					// Keep migrating usernames.
284					Some(MigrationState::Username(maybe_last_username)) => {
285						Self::username_step(Some(maybe_last_username))
286					},
287					// After the last username was migrated, start migrating all identities in
288					// `IdentityOf`, which currently hold the primary username of the owner account
289					// as well as any associated identity. Accounts which set a username but not an
290					// identity also have a zero deposit identity stored, which will be removed.
291					Some(MigrationState::FinishedUsernames) => Self::identity_step(None),
292					// Keep migrating identities.
293					Some(MigrationState::Identity(last_key)) => {
294						Self::identity_step(Some(last_key.clone()))
295					},
296					// After the last identity was migrated, start migrating usernames pending
297					// approval from `PendingUsernames`.
298					Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None),
299					// Keep migrating pending usernames.
300					Some(MigrationState::PendingUsername(last_key)) => {
301						Self::pending_username_step(Some(last_key.clone()))
302					},
303					// After the last pending username was migrated, start clearing the storage
304					// previously associated with authorities in `UsernameAuthority`.
305					Some(MigrationState::FinishedPendingUsernames) => {
306						Self::cleanup_authority_step(None)
307					},
308					// Keep clearing the obsolete authority storage.
309					Some(MigrationState::CleanupAuthorities(maybe_last_username)) => {
310						Self::cleanup_authority_step(Some(maybe_last_username))
311					},
312					// After the last obsolete authority was cleared from storage, start clearing
313					// the storage previously associated with usernames in `AccountOfUsername`.
314					Some(MigrationState::FinishedCleanupAuthorities) => {
315						Self::cleanup_username_step(None)
316					},
317					// Keep clearing the obsolete username storage.
318					Some(MigrationState::CleanupUsernames(maybe_last_username)) => {
319						Self::cleanup_username_step(Some(maybe_last_username))
320					},
321					// After the last obsolete username was cleared from storage, the migration is
322					// done.
323					Some(MigrationState::Finished) => {
324						StorageVersion::new(Self::id().version_to as u16).put::<Pallet<T>>();
325						return Ok(None);
326					},
327				};
328
329				cursor = Some(next);
330				meter.consume(required_weight);
331			}
332
333			Ok(cursor)
334		}
335
336		#[cfg(feature = "try-runtime")]
337		fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
338			let authorities: BTreeMap<Suffix<T>, (T::AccountId, u32)> =
339				types_v1::UsernameAuthorities::<T>::iter()
340					.map(|(account, authority_properties)| {
341						(
342							authority_properties.account_id,
343							(account, authority_properties.allocation),
344						)
345					})
346					.collect();
347			let mut primary_usernames: BTreeMap<_, _> = Default::default();
348			let identities = types_v1::IdentityOf::<T>::iter()
349				.map(|(account, (identity, maybe_username))| {
350					if let Some(username) = maybe_username {
351						primary_usernames.insert(account.clone(), username);
352					}
353					(account, identity)
354				})
355				.collect::<BTreeMap<_, _>>();
356			let usernames = types_v1::AccountOfUsername::<T>::iter().collect::<BTreeMap<_, _>>();
357			let pending_usernames: BTreeMap<Username<T>, (T::AccountId, BlockNumberFor<T>)> =
358				types_v1::PendingUsernames::<T>::iter().collect();
359			let state: TryRuntimeState<T> = TryRuntimeState {
360				authorities,
361				identities,
362				primary_usernames,
363				usernames,
364				pending_usernames,
365			};
366
367			Ok(state.encode())
368		}
369
370		#[cfg(feature = "try-runtime")]
371		fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
372			let mut prev_state: TryRuntimeState<T> = TryRuntimeState::<T>::decode(&mut &state[..])
373				.expect("Failed to decode the previous storage state");
374
375			for (suffix, authority_properties) in AuthorityOf::<T>::iter() {
376				let (prev_account, prev_allocation) = prev_state
377					.authorities
378					.remove(&suffix)
379					.expect("should have authority in previous state");
380				assert_eq!(prev_account, authority_properties.account_id);
381				assert_eq!(prev_allocation, authority_properties.allocation);
382			}
383			assert!(prev_state.authorities.is_empty());
384
385			for (account, identity) in IdentityOf::<T>::iter() {
386				assert!(identity.deposit > 0u32.into());
387				let prev_identity = prev_state
388					.identities
389					.remove(&account)
390					.expect("should have identity in previous state");
391				assert_eq!(identity, prev_identity);
392			}
393
394			for (account, free_identity) in prev_state.identities.iter() {
395				assert_eq!(free_identity.deposit, 0u32.into());
396				assert!(UsernameOf::<T>::contains_key(&account));
397			}
398			prev_state.identities.clear();
399
400			for (account, primary_username) in UsernameOf::<T>::iter() {
401				let prev_primary_username = prev_state
402					.primary_usernames
403					.remove(&account)
404					.expect("should have primary username in previous state");
405				assert_eq!(prev_primary_username, primary_username);
406			}
407
408			for (username, username_info) in UsernameInfoOf::<T>::iter() {
409				let prev_account = prev_state
410					.usernames
411					.remove(&username)
412					.expect("should have username info in previous state");
413				assert_eq!(prev_account, username_info.owner);
414				assert_eq!(username_info.provider, Provider::Allocation);
415			}
416			assert!(prev_state.usernames.is_empty());
417
418			for (username, (account, expiration, provider)) in PendingUsernames::<T>::iter() {
419				let (prev_account, prev_expiration) = prev_state
420					.pending_usernames
421					.remove(&username)
422					.expect("should have pending username in previous state");
423				assert_eq!(prev_account, account);
424				assert_eq!(prev_expiration, expiration);
425				assert_eq!(provider, Provider::Allocation);
426			}
427			assert!(prev_state.pending_usernames.is_empty());
428
429			Ok(())
430		}
431	}
432
433	impl<T: Config> LazyMigrationV1ToV2<T> {
434		pub(crate) fn required_weight(
435			step: &MigrationState<T::AccountId, Username<T>, Suffix<T>>,
436		) -> Weight {
437			match step {
438				MigrationState::Authority(_) => T::WeightInfo::migration_v2_authority_step(),
439				MigrationState::FinishedAuthorities | MigrationState::Username(_) => {
440					T::WeightInfo::migration_v2_username_step()
441				},
442				MigrationState::FinishedUsernames | MigrationState::Identity(_) => {
443					T::WeightInfo::migration_v2_identity_step()
444				},
445				MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => {
446					T::WeightInfo::migration_v2_pending_username_step()
447				},
448				MigrationState::FinishedPendingUsernames |
449				MigrationState::CleanupAuthorities(_) => T::WeightInfo::migration_v2_cleanup_authority_step(),
450				MigrationState::FinishedCleanupAuthorities |
451				MigrationState::CleanupUsernames(_) => T::WeightInfo::migration_v2_cleanup_username_step(),
452				MigrationState::Finished => Weight::zero(),
453			}
454		}
455
456		// Migrate one entry from `UsernameAuthorities` to `AuthorityOf`.
457		pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf<T> {
458			let mut iter = if let Some(last_key) = maybe_last_key {
459				types_v1::UsernameAuthorities::<T>::iter_from(
460					types_v1::UsernameAuthorities::<T>::hashed_key_for(last_key),
461				)
462			} else {
463				types_v1::UsernameAuthorities::<T>::iter()
464			};
465			if let Some((authority_account, properties)) = iter.next() {
466				let suffix = properties.account_id;
467				let allocation = properties.allocation;
468				let new_properties =
469					AuthorityProperties { account_id: authority_account.clone(), allocation };
470				AuthorityOf::<T>::insert(&suffix, new_properties);
471				MigrationState::Authority(authority_account)
472			} else {
473				MigrationState::FinishedAuthorities
474			}
475		}
476
477		// Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`.
478		pub(crate) fn username_step(maybe_last_key: Option<&Username<T>>) -> StepResultOf<T> {
479			let mut iter = if let Some(last_key) = maybe_last_key {
480				types_v1::AccountOfUsername::<T>::iter_from(
481					types_v1::AccountOfUsername::<T>::hashed_key_for(last_key),
482				)
483			} else {
484				types_v1::AccountOfUsername::<T>::iter()
485			};
486
487			if let Some((username, owner_account)) = iter.next() {
488				let username_info = UsernameInformation {
489					owner: owner_account,
490					provider: Provider::new_with_allocation(),
491				};
492				UsernameInfoOf::<T>::insert(&username, username_info);
493
494				MigrationState::Username(username)
495			} else {
496				MigrationState::FinishedUsernames
497			}
498		}
499
500		// Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with
501		// it. Remove the entry if there was no real identity associated with the account.
502		pub(crate) fn identity_step(maybe_last_key: Option<HashedKey>) -> StepResultOf<T> {
503			if let Some(mut last_key) =
504				IdentityOf::<T>::translate_next::<
505					(
506						Registration<
507							BalanceOf<T>,
508							<T as pallet::Config>::MaxRegistrars,
509							<T as pallet::Config>::IdentityInformation,
510						>,
511						Option<Username<T>>,
512					),
513					_,
514				>(maybe_last_key.map(|b| b.to_vec()), |account, (identity, maybe_username)| {
515					if let Some(primary_username) = maybe_username {
516						UsernameOf::<T>::insert(&account, primary_username);
517					}
518					if identity.deposit > BalanceOf::<T>::zero() {
519						Some(identity)
520					} else {
521						None
522					}
523				}) {
524				last_key.truncate(HashedKey::bound());
525				MigrationState::Identity(
526					HashedKey::try_from(last_key)
527						.expect("truncated to bound so the conversion must succeed; qed"),
528				)
529			} else {
530				MigrationState::FinishedIdentities
531			}
532		}
533
534		// Migrate one entry from `PendingUsernames` to contain the new `Provider` field.
535		pub(crate) fn pending_username_step(maybe_last_key: Option<HashedKey>) -> StepResultOf<T> {
536			if let Some(mut last_key) =
537				PendingUsernames::<T>::translate_next::<(T::AccountId, BlockNumberFor<T>), _>(
538					maybe_last_key.map(|b| b.to_vec()),
539					|_, (owner_account, since)| {
540						Some((owner_account, since, Provider::new_with_allocation()))
541					},
542				) {
543				last_key.truncate(HashedKey::bound());
544				MigrationState::PendingUsername(
545					HashedKey::try_from(last_key)
546						.expect("truncated to bound so the conversion must succeed; qed"),
547				)
548			} else {
549				MigrationState::FinishedPendingUsernames
550			}
551		}
552
553		// Remove one entry from `UsernameAuthorities`.
554		pub(crate) fn cleanup_authority_step(
555			maybe_last_key: Option<&Suffix<T>>,
556		) -> StepResultOf<T> {
557			let mut iter = if let Some(last_key) = maybe_last_key {
558				AuthorityOf::<T>::iter_from(AuthorityOf::<T>::hashed_key_for(last_key))
559			} else {
560				AuthorityOf::<T>::iter()
561			};
562
563			if let Some((suffix, properties)) = iter.next() {
564				let _ = types_v1::UsernameAuthorities::<T>::take(&properties.account_id);
565				MigrationState::CleanupAuthorities(suffix)
566			} else {
567				MigrationState::FinishedCleanupAuthorities
568			}
569		}
570
571		// Remove one entry from `AccountOfUsername`.
572		pub(crate) fn cleanup_username_step(
573			maybe_last_key: Option<&Username<T>>,
574		) -> StepResultOf<T> {
575			let mut iter = if let Some(last_key) = maybe_last_key {
576				UsernameInfoOf::<T>::iter_from(UsernameInfoOf::<T>::hashed_key_for(last_key))
577			} else {
578				UsernameInfoOf::<T>::iter()
579			};
580
581			if let Some((username, _)) = iter.next() {
582				let _ = types_v1::AccountOfUsername::<T>::take(&username);
583				MigrationState::CleanupUsernames(username)
584			} else {
585				MigrationState::Finished
586			}
587		}
588	}
589
590	#[cfg(feature = "runtime-benchmarks")]
591	pub(crate) struct BenchmarkingSetup<S, A, U> {
592		pub(crate) suffix: S,
593		pub(crate) authority: A,
594		pub(crate) account: A,
595		pub(crate) username: U,
596	}
597
598	#[cfg(feature = "runtime-benchmarks")]
599	impl<T: Config> LazyMigrationV1ToV2<T> {
600		pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf<T> {
601			use frame_support::Hashable;
602			let suffix: Suffix<T> = b"bench".to_vec().try_into().unwrap();
603			let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0);
604			let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0);
605
606			let prop: AuthorityProperties<Suffix<T>> =
607				AuthorityProperties { account_id: suffix.clone(), allocation: 10 };
608			types_v1::UsernameAuthorities::<T>::insert(&authority, &prop);
609
610			let username: Username<T> = b"account.bench".to_vec().try_into().unwrap();
611			let info = T::IdentityInformation::create_identity_info();
612			let registration: Registration<
613				BalanceOf<T>,
614				<T as Config>::MaxRegistrars,
615				<T as Config>::IdentityInformation,
616			> = Registration { judgements: Default::default(), deposit: 10u32.into(), info };
617			frame_support::migration::put_storage_value(
618				b"Identity",
619				b"IdentityOf",
620				&account_id.twox_64_concat(),
621				(&registration, Some(username.clone())),
622			);
623			types_v1::AccountOfUsername::<T>::insert(&username, &account_id);
624			let since: BlockNumberFor<T> = 0u32.into();
625			frame_support::migration::put_storage_value(
626				b"Identity",
627				b"PendingUsernames",
628				&username.blake2_128_concat(),
629				(&account_id, since),
630			);
631			BenchmarkingSetup { suffix, authority, account: account_id, username }
632		}
633
634		pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf<T> {
635			let suffix: Suffix<T> = b"bench".to_vec().try_into().unwrap();
636			let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0);
637			let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0);
638
639			let prop: AuthorityProperties<Suffix<T>> =
640				AuthorityProperties { account_id: suffix.clone(), allocation: 10 };
641			types_v1::UsernameAuthorities::<T>::insert(&authority, &prop);
642			let prop: AuthorityProperties<T::AccountId> =
643				AuthorityProperties { account_id: authority.clone(), allocation: 10 };
644			AuthorityOf::<T>::insert(&suffix, &prop);
645
646			let username: Username<T> = b"account.bench".to_vec().try_into().unwrap();
647			let info = T::IdentityInformation::create_identity_info();
648			let registration: Registration<
649				BalanceOf<T>,
650				<T as Config>::MaxRegistrars,
651				<T as Config>::IdentityInformation,
652			> = Registration { judgements: Default::default(), deposit: 10u32.into(), info };
653			IdentityOf::<T>::insert(&account_id, &registration);
654			UsernameOf::<T>::insert(&account_id, &username);
655			let username_info = UsernameInformation {
656				owner: account_id.clone(),
657				provider: Provider::new_with_allocation(),
658			};
659			UsernameInfoOf::<T>::insert(&username, username_info);
660			types_v1::AccountOfUsername::<T>::insert(&username, &account_id);
661			let since: BlockNumberFor<T> = 0u32.into();
662			PendingUsernames::<T>::insert(
663				&username,
664				(&account_id, since, Provider::new_with_allocation()),
665			);
666			BenchmarkingSetup { suffix, authority, account: account_id, username }
667		}
668
669		pub(crate) fn check_authority_cleanup_validity(suffix: Suffix<T>, authority: T::AccountId) {
670			assert_eq!(types_v1::UsernameAuthorities::<T>::iter().count(), 0);
671			assert_eq!(AuthorityOf::<T>::get(&suffix).unwrap().account_id, authority);
672		}
673
674		pub(crate) fn check_username_cleanup_validity(
675			username: Username<T>,
676			account_id: T::AccountId,
677		) {
678			assert_eq!(types_v1::AccountOfUsername::<T>::iter().count(), 0);
679			assert_eq!(UsernameInfoOf::<T>::get(&username).unwrap().owner, account_id);
680		}
681	}
682
683	#[cfg(test)]
684	mod tests {
685		use frame_support::Hashable;
686
687		use super::*;
688		use crate::tests::{new_test_ext, Test};
689
690		fn registration(
691			with_deposit: bool,
692		) -> Registration<
693			BalanceOf<Test>,
694			<Test as Config>::MaxRegistrars,
695			<Test as Config>::IdentityInformation,
696		> {
697			Registration {
698				judgements: Default::default(),
699				deposit: if with_deposit { 10u32.into() } else { 0u32.into() },
700				info: Default::default(),
701			}
702		}
703
704		fn account_from_u8(byte: u8) -> <Test as frame_system::Config>::AccountId {
705			[byte; 32].into()
706		}
707
708		#[test]
709		fn migrate_to_v2() {
710			new_test_ext().execute_with(|| {
711				StorageVersion::new(1).put::<Pallet<Test>>();
712				// Set up the first authority.
713				let authority_1 = account_from_u8(151);
714				let suffix_1: Suffix<Test> = b"evn".to_vec().try_into().unwrap();
715				let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 };
716				types_v1::UsernameAuthorities::<Test>::insert(&authority_1, &prop);
717				// Set up the first authority.
718				let authority_2 = account_from_u8(152);
719				let suffix_2: Suffix<Test> = b"odd".to_vec().try_into().unwrap();
720				let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 };
721				types_v1::UsernameAuthorities::<Test>::insert(&authority_2, &prop);
722
723				// (owner_account, primary_username, maybe_secondary_username, has_identity)
724				// If `has_identity` is set, this `owner_account` will have a real identity
725				// associated and a non-zero deposit for it.
726				let mut usernames = vec![];
727				for i in 0u8..100u8 {
728					let account_id = account_from_u8(i);
729					let bare_username = format!("acc{}.", i).as_bytes().to_vec();
730					let mut username_1 = bare_username.clone();
731					username_1.extend(suffix_1.iter());
732					let username_1: Username<Test> = username_1.try_into().unwrap();
733					types_v1::AccountOfUsername::<Test>::insert(&username_1, &account_id);
734
735					if i % 2 == 0 {
736						let has_identity = i % 4 == 0;
737						let reg = registration(has_identity);
738						frame_support::migration::put_storage_value(
739							b"Identity",
740							b"IdentityOf",
741							&account_id.twox_64_concat(),
742							(reg, Some(username_1.clone())),
743						);
744						usernames.push((account_id, username_1, None, has_identity));
745					} else {
746						let has_identity = i % 3 == 0;
747						let mut username_2 = bare_username.clone();
748						username_2.extend(suffix_2.iter());
749						let username_2: Username<Test> = username_2.try_into().unwrap();
750						types_v1::AccountOfUsername::<Test>::insert(&username_2, &account_id);
751						let reg = registration(has_identity);
752						frame_support::migration::put_storage_value(
753							b"Identity",
754							b"IdentityOf",
755							&account_id.twox_64_concat(),
756							(reg, Some(username_2.clone())),
757						);
758						usernames.push((account_id, username_2, Some(username_1), has_identity));
759					}
760				}
761
762				// (username, owner_account, since)
763				let mut pending = vec![];
764				for i in 100u8..110u8 {
765					let account_id = account_from_u8(i);
766					let mut bare_username = format!("acc{}.", i).as_bytes().to_vec();
767					bare_username.extend(suffix_1.iter());
768					let username: Username<Test> = bare_username.try_into().unwrap();
769					let since: BlockNumberFor<Test> = i.into();
770					frame_support::migration::put_storage_value(
771						b"Identity",
772						b"PendingUsernames",
773						&username.blake2_128_concat(),
774						(&account_id, since),
775					);
776					pending.push((username, account_id, since));
777				}
778
779				let mut identity_only = vec![];
780				for i in 120u8..130u8 {
781					let account_id = account_from_u8(i);
782					let reg = registration(true);
783					frame_support::migration::put_storage_value(
784						b"Identity",
785						b"IdentityOf",
786						&account_id.twox_64_concat(),
787						(reg, None::<Username<Test>>),
788					);
789					identity_only.push(account_id);
790				}
791
792				// Run the actual migration.
793				let mut weight_meter = WeightMeter::new();
794				let mut cursor = None;
795				while let Some(new_cursor) =
796					LazyMigrationV1ToV2::<Test>::step(cursor, &mut weight_meter).unwrap()
797				{
798					cursor = Some(new_cursor);
799				}
800				assert_eq!(Pallet::<Test>::on_chain_storage_version(), 2);
801
802				// Check that the authorities were migrated.
803				let expected_prop =
804					AuthorityProperties { account_id: authority_1.clone(), allocation: 10 };
805				assert_eq!(AuthorityOf::<Test>::get(&suffix_1), Some(expected_prop));
806
807				let expected_prop =
808					AuthorityProperties { account_id: authority_2.clone(), allocation: 10 };
809				assert_eq!(AuthorityOf::<Test>::get(&suffix_2), Some(expected_prop));
810
811				// Check that the username information was migrated.
812				let count_of_usernames_without_identities =
813					usernames.iter().filter(|(_, _, _, has_id)| *has_id).count();
814				assert_eq!(UsernameOf::<Test>::iter().count(), usernames.len());
815				// All accounts have `evn` usernames, only half of them have `odd` usernames.
816				assert_eq!(
817					UsernameInfoOf::<Test>::iter().count(),
818					usernames.len() + usernames.len() / 2
819				);
820				for (owner, primary, maybe_secondary, has_identity) in usernames.iter() {
821					let username_info = UsernameInfoOf::<Test>::get(primary).unwrap();
822					assert_eq!(&username_info.owner, owner);
823					let actual_primary = UsernameOf::<Test>::get(owner).unwrap();
824					assert_eq!(primary, &actual_primary);
825					assert_eq!(IdentityOf::<Test>::contains_key(owner), *has_identity);
826					if let Some(secondary) = maybe_secondary {
827						let expected_info = UsernameInformation {
828							owner: owner.clone(),
829							provider: Provider::new_with_allocation(),
830						};
831						assert_eq!(UsernameInfoOf::<Test>::get(secondary), Some(expected_info));
832					}
833				}
834
835				// Check that existing identities were preserved.
836				for id in identity_only.iter() {
837					let expected_reg = registration(true);
838					assert_eq!(IdentityOf::<Test>::get(id), Some(expected_reg));
839					assert!(!UsernameOf::<Test>::contains_key(id));
840				}
841				let identity_count = IdentityOf::<Test>::iter().count();
842				assert_eq!(
843					identity_count,
844					count_of_usernames_without_identities + identity_only.len()
845				);
846
847				// Check that pending usernames were migrated.
848				let pending_count = PendingUsernames::<Test>::iter().count();
849				assert_eq!(pending_count, pending.len());
850				for (username, owner, since) in pending.iter() {
851					let expected_pending = (owner.clone(), *since, Provider::Allocation);
852					assert_eq!(PendingUsernames::<Test>::get(username), Some(expected_pending));
853				}
854
855				// Check that obsolete storage was cleared.
856				assert_eq!(types_v1::AccountOfUsername::<Test>::iter().count(), 0);
857				assert_eq!(types_v1::UsernameAuthorities::<Test>::iter().count(), 0);
858			});
859		}
860	}
861}