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

            
18
use super::*;
19
use frame_support::{
20
	migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade,
21
};
22

            
23
#[cfg(feature = "try-runtime")]
24
use codec::{Decode, Encode};
25
#[cfg(feature = "try-runtime")]
26
use sp_runtime::TryRuntimeError;
27

            
28
pub mod versioned {
29
	use super::*;
30

            
31
	pub type V0ToV1<T, const KL: u64> = VersionedMigration<
32
		0,
33
		1,
34
		v1::VersionUncheckedMigrateV0ToV1<T, KL>,
35
		crate::pallet::Pallet<T>,
36
		<T as frame_system::Config>::DbWeight,
37
	>;
38
}
39

            
40
pub mod v1 {
41
	use super::*;
42

            
43
	/// The log target.
44
	const TARGET: &'static str = "runtime::identity::migration::v1";
45

            
46
	/// The old identity type, useful in pre-upgrade.
47
	mod v0 {
48
		use super::*;
49
		use frame_support::storage_alias;
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
	/// Migration to add usernames to Identity info.
66
	///
67
	/// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to
68
	/// prevent stalling a parachain by accumulating too much weight in the migration. To have an
69
	/// unlimited migration (e.g. in a chain without PoV limits), set this to `u64::MAX`.
70
	pub struct VersionUncheckedMigrateV0ToV1<T, const KL: u64>(PhantomData<T>);
71
	impl<T: Config, const KL: u64> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1<T, KL> {
72
		#[cfg(feature = "try-runtime")]
73
		fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
74
			let identities = v0::IdentityOf::<T>::iter().count();
75
			log::info!(
76
				target: TARGET,
77
				"pre-upgrade state contains '{}' identities.",
78
				identities
79
			);
80
			ensure!((identities as u64) < KL, "too many identities to migrate");
81
			Ok((identities as u64).encode())
82
		}
83

            
84
		fn on_runtime_upgrade() -> Weight {
85
			log::info!(
86
				target: TARGET,
87
				"running storage migration from version 0 to version 1."
88
			);
89

            
90
			let mut weight = T::DbWeight::get().reads(1);
91
			let mut translated: u64 = 0;
92
			let mut interrupted = false;
93

            
94
			for (account, registration) in v0::IdentityOf::<T>::iter() {
95
				IdentityOf::<T>::insert(account, (registration, None::<Username<T>>));
96
				translated.saturating_inc();
97
				if translated >= KL {
98
					log::warn!(
99
						"Incomplete! Migration limit reached. Only {} identities migrated.",
100
						translated
101
					);
102
					interrupted = true;
103
					break
104
				}
105
			}
106
			if !interrupted {
107
				log::info!("all {} identities migrated", translated);
108
			}
109

            
110
			weight.saturating_accrue(T::DbWeight::get().reads_writes(translated, translated));
111
			weight.saturating_accrue(T::DbWeight::get().writes(1));
112
			weight
113
		}
114

            
115
		#[cfg(feature = "try-runtime")]
116
		fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
117
			let identities_to_migrate: u64 = Decode::decode(&mut &state[..])
118
				.expect("failed to decode the state from pre-upgrade.");
119
			let identities = IdentityOf::<T>::iter().count() as u64;
120
			log::info!("post-upgrade expects '{}' identities to have been migrated.", identities);
121
			ensure!(identities_to_migrate == identities, "must migrate all identities.");
122
			log::info!(target: TARGET, "migrated all identities.");
123
			Ok(())
124
		}
125
	}
126
}