referrerpolicy=no-referrer-when-downgrade

pallet_elections_phragmen/migrations/
v3.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Migrations to version [`3.0.0`], as denoted by the changelog.
19
20use super::super::LOG_TARGET;
21use crate::{Config, Pallet};
22use alloc::vec::Vec;
23use codec::{Decode, Encode, FullCodec};
24use frame_support::{
25	pallet_prelude::ValueQuery, traits::StorageVersion, weights::Weight, Twox64Concat,
26};
27use sp_runtime::RuntimeDebug;
28
29#[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq)]
30struct SeatHolder<AccountId, Balance> {
31	who: AccountId,
32	stake: Balance,
33	deposit: Balance,
34}
35
36#[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq)]
37struct Voter<AccountId, Balance> {
38	votes: Vec<AccountId>,
39	stake: Balance,
40	deposit: Balance,
41}
42
43/// Trait to implement to give information about types used for migration
44pub trait V2ToV3 {
45	/// System config account id
46	type AccountId: 'static + FullCodec;
47
48	/// Elections-phragmen currency balance.
49	type Balance: 'static + FullCodec + Copy;
50}
51
52#[frame_support::storage_alias]
53type Candidates<V, T: Config> =
54	StorageValue<Pallet<T>, Vec<(<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance)>, ValueQuery>;
55
56#[frame_support::storage_alias]
57type Members<V, T: Config> = StorageValue<
58	Pallet<T>,
59	Vec<SeatHolder<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>>,
60	ValueQuery,
61>;
62
63#[frame_support::storage_alias]
64type RunnersUp<V, T: Config> = StorageValue<
65	Pallet<T>,
66	Vec<SeatHolder<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>>,
67	ValueQuery,
68>;
69
70#[frame_support::storage_alias]
71type Voting<V, T: Config> = StorageMap<
72	Pallet<T>,
73	Twox64Concat,
74	<V as V2ToV3>::AccountId,
75	Voter<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>,
76>;
77
78/// Apply all of the migrations from 2 to 3.
79///
80/// ### Warning
81///
82/// This code will **ONLY** check that the storage version is less than or equal to 2_0_0.
83/// Further check might be needed at the user runtime.
84///
85/// Be aware that this migration is intended to be used only for the mentioned versions. Use
86/// with care and run at your own risk.
87pub fn apply<V: V2ToV3, T: Config>(
88	old_voter_bond: V::Balance,
89	old_candidacy_bond: V::Balance,
90) -> Weight {
91	let storage_version = StorageVersion::get::<Pallet<T>>();
92	log::info!(
93		target: LOG_TARGET,
94		"Running migration for elections-phragmen with storage version {:?}",
95		storage_version,
96	);
97
98	if storage_version <= 2 {
99		migrate_voters_to_recorded_deposit::<V, T>(old_voter_bond);
100		migrate_candidates_to_recorded_deposit::<V, T>(old_candidacy_bond);
101		migrate_runners_up_to_recorded_deposit::<V, T>(old_candidacy_bond);
102		migrate_members_to_recorded_deposit::<V, T>(old_candidacy_bond);
103
104		StorageVersion::new(3).put::<Pallet<T>>();
105
106		Weight::MAX
107	} else {
108		log::warn!(
109			target: LOG_TARGET,
110			"Attempted to apply migration to V3 but failed because storage version is {:?}",
111			storage_version,
112		);
113		Weight::zero()
114	}
115}
116
117/// Migrate from the old legacy voting bond (fixed) to the new one (per-vote dynamic).
118pub fn migrate_voters_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
119	Voting::<V, T>::translate::<(V::Balance, Vec<V::AccountId>), _>(|_who, (stake, votes)| {
120		Some(Voter { votes, stake, deposit: old_deposit })
121	});
122
123	log::info!(target: LOG_TARGET, "migrated {} voter accounts.", Voting::<V, T>::iter().count());
124}
125
126/// Migrate all candidates to recorded deposit.
127pub fn migrate_candidates_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
128	let _ = Candidates::<V, T>::translate::<Vec<V::AccountId>, _>(|maybe_old_candidates| {
129		maybe_old_candidates.map(|old_candidates| {
130			log::info!(target: LOG_TARGET, "migrated {} candidate accounts.", old_candidates.len());
131			old_candidates.into_iter().map(|c| (c, old_deposit)).collect::<Vec<_>>()
132		})
133	});
134}
135
136/// Migrate all members to recorded deposit.
137pub fn migrate_members_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
138	let _ = Members::<V, T>::translate::<Vec<(V::AccountId, V::Balance)>, _>(|maybe_old_members| {
139		maybe_old_members.map(|old_members| {
140			log::info!(target: LOG_TARGET, "migrated {} member accounts.", old_members.len());
141			old_members
142				.into_iter()
143				.map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit })
144				.collect::<Vec<_>>()
145		})
146	});
147}
148
149/// Migrate all runners-up to recorded deposit.
150pub fn migrate_runners_up_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
151	let _ = RunnersUp::<V, T>::translate::<Vec<(V::AccountId, V::Balance)>, _>(
152		|maybe_old_runners_up| {
153			maybe_old_runners_up.map(|old_runners_up| {
154				log::info!(
155					target: LOG_TARGET,
156					"migrated {} runner-up accounts.",
157					old_runners_up.len(),
158				);
159				old_runners_up
160					.into_iter()
161					.map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit })
162					.collect::<Vec<_>>()
163			})
164		},
165	);
166}