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 },
100 ReferendumInfo::Finished { approved, end } => {
101 ReferendumInfo::Finished { approved, end }
102 },
103 })
104 },
105 );
106
107 let props = v0::PublicProps::<T>::take()
108 .into_iter()
109 .map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a))
110 .collect::<Vec<_>>();
111 let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone());
112 PublicProps::<T>::put(bounded);
113 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
114
115 if props.len() as u32 > T::MaxProposals::get() {
116 log::error!(
117 target: TARGET,
118 "truncated {} public proposals to {}; continuing",
119 props.len(),
120 T::MaxProposals::get()
121 );
122 }
123
124 if let Some((hash, threshold)) = v0::NextExternal::<T>::take() {
125 log::info!(target: TARGET, "migrating next external proposal");
126 NextExternal::<T>::put((Bounded::from_legacy_hash(hash), threshold));
127 }
128
129 StorageVersion::new(1).put::<Pallet<T>>();
130
131 weight.saturating_add(T::DbWeight::get().reads_writes(1, 3))
132 }
133
134 #[cfg(feature = "try-runtime")]
135 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
136 ensure!(StorageVersion::get::<Pallet<T>>() == 1, "must upgrade");
137
138 let (old_props_count, old_ref_count): (u32, u32) =
139 Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
140 let new_props_count = crate::PublicProps::<T>::get().len() as u32;
141 ensure!(new_props_count == old_props_count, "must migrate all public proposals");
142 let new_ref_count = crate::ReferendumInfoOf::<T>::iter().count() as u32;
143 ensure!(new_ref_count == old_ref_count, "must migrate all referenda");
144
145 log::info!(
146 target: TARGET,
147 "{} public proposals migrated, {} referenda migrated",
148 new_props_count,
149 new_ref_count,
150 );
151 Ok(())
152 }
153 }
154}
155
156#[cfg(test)]
157#[cfg(feature = "try-runtime")]
158mod test {
159 use super::*;
160 use crate::{
161 tests::{Test as T, *},
162 types::*,
163 };
164 use sp_runtime::bounded_vec;
165
166 #[allow(deprecated)]
167 #[test]
168 fn migration_works() {
169 new_test_ext().execute_with(|| {
170 assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
171 let hash = H256::repeat_byte(1);
175 let status = ReferendumStatus {
176 end: 1u32.into(),
177 proposal: hash,
178 threshold: VoteThreshold::SuperMajorityApprove,
179 delay: 1u32.into(),
180 tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
181 };
182 v0::ReferendumInfoOf::<T>::insert(1u32, ReferendumInfo::Ongoing(status));
183
184 v0::ReferendumInfoOf::<T>::insert(
186 2u32,
187 ReferendumInfo::Finished { approved: true, end: 123u32.into() },
188 );
189
190 let hash2 = H256::repeat_byte(2);
192 v0::PublicProps::<T>::put(vec![(3u32, hash, 123u64), (4u32, hash2, 123u64)]);
193
194 v0::NextExternal::<T>::put((hash, VoteThreshold::SuperMajorityApprove));
196
197 let state = v1::Migration::<T>::pre_upgrade().unwrap();
199 let _weight = v1::Migration::<T>::on_runtime_upgrade();
200 v1::Migration::<T>::post_upgrade(state).unwrap();
201 assert_eq!(
205 ReferendumInfoOf::<T>::get(1u32),
206 Some(ReferendumInfo::Ongoing(ReferendumStatus {
207 end: 1u32.into(),
208 proposal: Bounded::from_legacy_hash(hash),
209 threshold: VoteThreshold::SuperMajorityApprove,
210 delay: 1u32.into(),
211 tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
212 }))
213 );
214 assert_eq!(
216 ReferendumInfoOf::<T>::get(2u32),
217 Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() })
218 );
219 let props: BoundedVec<_, <Test as Config>::MaxProposals> = bounded_vec![
221 (3u32, Bounded::from_legacy_hash(hash), 123u64),
222 (4u32, Bounded::from_legacy_hash(hash2), 123u64)
223 ];
224 assert_eq!(PublicProps::<T>::get(), props);
225 assert_eq!(
227 NextExternal::<T>::get(),
228 Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove))
229 );
230 });
231 }
232}