1use crate::{Config, Pallet, Weight, LOG_TARGET};
19use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgrade};
20use log;
21
22pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
24
25pub fn migrate<T: Config<I>, I: 'static>() -> Weight {
27 let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
28 let mut weight: Weight = Weight::zero();
29
30 if on_chain_version < 1 {
31 weight = weight.saturating_add(v0_to_v1::migrate::<T, I>());
32 }
33
34 if on_chain_version < 2 {
35 weight = weight.saturating_add(v1_to_v2::migrate::<T, I>());
36 }
37
38 STORAGE_VERSION.put::<Pallet<T, I>>();
39 weight = weight.saturating_add(T::DbWeight::get().writes(1));
40
41 weight
42}
43
44pub struct Migration<T, I = ()>(PhantomData<(T, I)>);
46
47impl<T: Config<I>, I: 'static> OnRuntimeUpgrade for Migration<T, I> {
48 fn on_runtime_upgrade() -> Weight {
49 migrate::<T, I>()
50 }
51}
52
53mod v0_to_v1 {
55 use super::*;
56
57 pub fn migrate<T: Config<I>, I: 'static>() -> Weight {
58 log::info!(target: LOG_TARGET, "Running migration v0_to_v1.");
59
60 let res = migration::clear_storage_prefix(
61 <Pallet<T, I>>::name().as_bytes(),
62 b"UpForKicking",
63 b"",
64 None,
65 None,
66 );
67
68 log::info!(
69 target: LOG_TARGET,
70 "Cleared '{}' entries from 'UpForKicking' storage prefix",
71 res.unique
72 );
73
74 if res.maybe_cursor.is_some() {
75 log::error!(
76 target: LOG_TARGET,
77 "Storage prefix 'UpForKicking' is not completely cleared."
78 );
79 }
80
81 T::DbWeight::get().writes(res.unique.into())
82 }
83}
84
85pub(crate) mod v1_to_v2 {
88 use super::*;
89 use crate::{MemberRole, Members};
90
91 #[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)]
93 pub enum MemberRoleV1 {
94 Founder,
95 Fellow,
96 Ally,
97 Retiring,
98 }
99
100 pub fn migrate<T: Config<I>, I: 'static>() -> Weight {
101 log::info!(target: LOG_TARGET, "Running migration v1_to_v2: `Members` storage map collapses `Founder` and `Fellow` keys into one `Fellow`.");
102 let founders_vec = take_members::<T, I>(MemberRoleV1::Founder).into_inner();
104 let mut fellows_vec = take_members::<T, I>(MemberRoleV1::Fellow).into_inner();
105 let allies = take_members::<T, I>(MemberRoleV1::Ally);
106 let retiring = take_members::<T, I>(MemberRoleV1::Retiring);
107 if founders_vec
108 .len()
109 .saturating_add(fellows_vec.len())
110 .saturating_add(allies.len())
111 .saturating_add(retiring.len()) ==
112 0
113 {
114 return T::DbWeight::get().reads(4)
115 }
116 log::info!(
117 target: LOG_TARGET,
118 "Members storage v1 contains, '{}' founders, '{}' fellows, '{}' allies, '{}' retiring members.",
119 founders_vec.len(),
120 fellows_vec.len(),
121 allies.len(),
122 retiring.len(),
123 );
124 fellows_vec.extend(founders_vec);
126 fellows_vec.sort();
127 if fellows_vec.len() as u32 > T::MaxMembersCount::get() {
128 log::error!(
129 target: LOG_TARGET,
130 "Merged list of founders and fellows do not fit into `T::MaxMembersCount` bound. Truncating the merged set into max members count."
131 );
132 fellows_vec.truncate(T::MaxMembersCount::get() as usize);
133 }
134 let fellows: BoundedVec<T::AccountId, T::MaxMembersCount> =
135 fellows_vec.try_into().unwrap_or_default();
136 Members::<T, I>::insert(&MemberRole::Fellow, fellows.clone());
138 Members::<T, I>::insert(&MemberRole::Ally, allies.clone());
139 Members::<T, I>::insert(&MemberRole::Retiring, retiring.clone());
140 log::info!(
141 target: LOG_TARGET,
142 "Members storage updated with, '{}' fellows, '{}' allies, '{}' retiring members.",
143 fellows.len(),
144 allies.len(),
145 retiring.len(),
146 );
147 T::DbWeight::get().reads_writes(4, 4)
148 }
149
150 fn take_members<T: Config<I>, I: 'static>(
151 role: MemberRoleV1,
152 ) -> BoundedVec<T::AccountId, T::MaxMembersCount> {
153 migration::take_storage_item::<
154 MemberRoleV1,
155 BoundedVec<T::AccountId, T::MaxMembersCount>,
156 Twox64Concat,
157 >(<Pallet<T, I>>::name().as_bytes(), b"Members", role)
158 .unwrap_or_default()
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165 use crate::{mock::*, MemberRole, Members};
166
167 #[test]
168 fn migration_v1_to_v2_works() {
169 new_test_ext().execute_with(|| {
170 assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4)));
171 assert_eq!(Members::<Test>::get(MemberRole::Ally), vec![4]);
172 assert_eq!(Members::<Test>::get(MemberRole::Fellow), vec![1, 2, 3]);
173 v1_to_v2::migrate::<Test, ()>();
174 assert_eq!(Members::<Test>::get(MemberRole::Fellow), vec![1, 2, 3, 4]);
175 assert_eq!(Members::<Test>::get(MemberRole::Ally), vec![]);
176 assert_eq!(Members::<Test>::get(MemberRole::Retiring), vec![]);
177 });
178 }
179}