pallet_democracy/migrations/
v1.rs1use crate::*;
21use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec};
22use frame_system::pallet_prelude::BlockNumberFor;
23use sp_core::H256;
24
25const TARGET: &'static str = "runtime::democracy::migration::v1";
27
28mod v0 {
30 use super::*;
31
32 #[storage_alias]
33 pub type PublicProps<T: Config> = StorageValue<
34 Pallet<T>,
35 Vec<(PropIndex, <T as frame_system::Config>::Hash, <T as frame_system::Config>::AccountId)>,
36 ValueQuery,
37 >;
38
39 #[storage_alias]
40 pub type NextExternal<T: Config> =
41 StorageValue<Pallet<T>, (<T as frame_system::Config>::Hash, VoteThreshold)>;
42
43 #[cfg(feature = "try-runtime")]
44 #[storage_alias]
45 pub type ReferendumInfoOf<T: Config> = StorageMap<
46 Pallet<T>,
47 frame_support::Twox64Concat,
48 ReferendumIndex,
49 ReferendumInfo<BlockNumberFor<T>, <T as frame_system::Config>::Hash, BalanceOf<T>>,
50 >;
51}
52
53pub mod v1 {
54 use super::*;
55
56 pub struct Migration<T>(core::marker::PhantomData<T>);
58
59 impl<T: Config + frame_system::Config<Hash = H256>> OnRuntimeUpgrade for Migration<T> {
60 #[cfg(feature = "try-runtime")]
61 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
62 ensure!(StorageVersion::get::<Pallet<T>>() == 0, "can only upgrade from version 0");
63
64 let props_count = v0::PublicProps::<T>::get().len();
65 log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,);
66 ensure!(props_count <= T::MaxProposals::get() as usize, Error::<T>::TooMany);
67
68 let referenda_count = v0::ReferendumInfoOf::<T>::iter().count();
69 log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count);
70
71 Ok((props_count as u32, referenda_count as u32).encode())
72 }
73
74 #[allow(deprecated)]
75 fn on_runtime_upgrade() -> Weight {
76 let mut weight = T::DbWeight::get().reads(1);
77 if StorageVersion::get::<Pallet<T>>() != 0 {
78 log::warn!(
79 target: TARGET,
80 "skipping on_runtime_upgrade: executed on wrong storage version.\
81 Expected version 0"
82 );
83 return weight
84 }
85
86 ReferendumInfoOf::<T>::translate(
87 |index, old: ReferendumInfo<BlockNumberFor<T>, T::Hash, BalanceOf<T>>| {
88 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
89 log::info!(target: TARGET, "migrating referendum #{:?}", &index);
90 Some(match old {
91 ReferendumInfo::Ongoing(status) =>
92 ReferendumInfo::Ongoing(ReferendumStatus {
93 end: status.end,
94 proposal: Bounded::from_legacy_hash(status.proposal),
95 threshold: status.threshold,
96 delay: status.delay,
97 tally: status.tally,
98 }),
99 ReferendumInfo::Finished { approved, end } =>
100 ReferendumInfo::Finished { approved, end },
101 })
102 },
103 );
104
105 let props = v0::PublicProps::<T>::take()
106 .into_iter()
107 .map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a))
108 .collect::<Vec<_>>();
109 let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone());
110 PublicProps::<T>::put(bounded);
111 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
112
113 if props.len() as u32 > T::MaxProposals::get() {
114 log::error!(
115 target: TARGET,
116 "truncated {} public proposals to {}; continuing",
117 props.len(),
118 T::MaxProposals::get()
119 );
120 }
121
122 if let Some((hash, threshold)) = v0::NextExternal::<T>::take() {
123 log::info!(target: TARGET, "migrating next external proposal");
124 NextExternal::<T>::put((Bounded::from_legacy_hash(hash), threshold));
125 }
126
127 StorageVersion::new(1).put::<Pallet<T>>();
128
129 weight.saturating_add(T::DbWeight::get().reads_writes(1, 3))
130 }
131
132 #[cfg(feature = "try-runtime")]
133 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
134 ensure!(StorageVersion::get::<Pallet<T>>() == 1, "must upgrade");
135
136 let (old_props_count, old_ref_count): (u32, u32) =
137 Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
138 let new_props_count = crate::PublicProps::<T>::get().len() as u32;
139 ensure!(new_props_count == old_props_count, "must migrate all public proposals");
140 let new_ref_count = crate::ReferendumInfoOf::<T>::iter().count() as u32;
141 ensure!(new_ref_count == old_ref_count, "must migrate all referenda");
142
143 log::info!(
144 target: TARGET,
145 "{} public proposals migrated, {} referenda migrated",
146 new_props_count,
147 new_ref_count,
148 );
149 Ok(())
150 }
151 }
152}
153
154#[cfg(test)]
155#[cfg(feature = "try-runtime")]
156mod test {
157 use super::*;
158 use crate::{
159 tests::{Test as T, *},
160 types::*,
161 };
162 use sp_runtime::bounded_vec;
163
164 #[allow(deprecated)]
165 #[test]
166 fn migration_works() {
167 new_test_ext().execute_with(|| {
168 assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
169 let hash = H256::repeat_byte(1);
173 let status = ReferendumStatus {
174 end: 1u32.into(),
175 proposal: hash,
176 threshold: VoteThreshold::SuperMajorityApprove,
177 delay: 1u32.into(),
178 tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
179 };
180 v0::ReferendumInfoOf::<T>::insert(1u32, ReferendumInfo::Ongoing(status));
181
182 v0::ReferendumInfoOf::<T>::insert(
184 2u32,
185 ReferendumInfo::Finished { approved: true, end: 123u32.into() },
186 );
187
188 let hash2 = H256::repeat_byte(2);
190 v0::PublicProps::<T>::put(vec![(3u32, hash, 123u64), (4u32, hash2, 123u64)]);
191
192 v0::NextExternal::<T>::put((hash, VoteThreshold::SuperMajorityApprove));
194
195 let state = v1::Migration::<T>::pre_upgrade().unwrap();
197 let _weight = v1::Migration::<T>::on_runtime_upgrade();
198 v1::Migration::<T>::post_upgrade(state).unwrap();
199 assert_eq!(
203 ReferendumInfoOf::<T>::get(1u32),
204 Some(ReferendumInfo::Ongoing(ReferendumStatus {
205 end: 1u32.into(),
206 proposal: Bounded::from_legacy_hash(hash),
207 threshold: VoteThreshold::SuperMajorityApprove,
208 delay: 1u32.into(),
209 tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
210 }))
211 );
212 assert_eq!(
214 ReferendumInfoOf::<T>::get(2u32),
215 Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() })
216 );
217 let props: BoundedVec<_, <Test as Config>::MaxProposals> = bounded_vec![
219 (3u32, Bounded::from_legacy_hash(hash), 123u64),
220 (4u32, Bounded::from_legacy_hash(hash2), 123u64)
221 ];
222 assert_eq!(PublicProps::<T>::get(), props);
223 assert_eq!(
225 NextExternal::<T>::get(),
226 Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove))
227 );
228 });
229 }
230}