referrerpolicy=no-referrer-when-downgrade

pallet_child_bounties/
migration.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
18use super::*;
19use core::marker::PhantomData;
20use frame_support::{
21	storage_alias,
22	traits::{Get, UncheckedOnRuntimeUpgrade},
23};
24
25use alloc::collections::BTreeSet;
26#[cfg(feature = "try-runtime")]
27use alloc::vec::Vec;
28#[cfg(feature = "try-runtime")]
29use frame_support::ensure;
30
31pub mod v1 {
32	use super::*;
33
34	/// Creates a new ids for the child balances based on the child bounty count per parent bounty
35	/// instead of the total child bounty count. Translates the existing child bounties to the new
36	/// ids. Creates the `V0ToV1ChildBountyIds` map from `old_child_id` to new (`parent_id`,
37	/// `new_child_id`).
38	///
39	/// `TransferWeight` returns `Weight` of `T::Currency::transfer` and `T::Currency::free_balance`
40	/// operation which is performed during this migration.
41	pub struct MigrateToV1Impl<T, TransferWeight>(PhantomData<(T, TransferWeight)>);
42
43	#[storage_alias]
44	type ChildBountyDescriptions<T: Config + pallet_bounties::Config> = StorageMap<
45		Pallet<T>,
46		Twox64Concat,
47		BountyIndex,
48		BoundedVec<u8, <T as pallet_bounties::Config>::MaximumReasonLength>,
49	>;
50
51	impl<T: Config, TransferWeight: Get<Weight>> UncheckedOnRuntimeUpgrade
52		for MigrateToV1Impl<T, TransferWeight>
53	{
54		fn on_runtime_upgrade() -> frame_support::weights::Weight {
55			// increment reads/writes after the action
56			let mut reads = 0u64;
57			let mut writes = 0u64;
58			let mut transfer_weights: Weight = Weight::zero();
59
60			// keep ids order roughly the same with the old order
61			let mut old_bounty_ids = BTreeSet::new();
62			// first iteration collect all existing ids not to mutate map as we iterate it
63			for (parent_bounty_id, old_child_bounty_id) in ChildBounties::<T>::iter_keys() {
64				reads += 1;
65				old_bounty_ids.insert((parent_bounty_id, old_child_bounty_id));
66			}
67
68			log::info!(
69				target: LOG_TARGET,
70				"Migrating {} child bounties",
71				old_bounty_ids.len(),
72			);
73
74			for (parent_bounty_id, old_child_bounty_id) in old_bounty_ids {
75				// assign new child bounty id
76				let new_child_bounty_id = ParentTotalChildBounties::<T>::get(parent_bounty_id);
77				reads += 1;
78				ParentTotalChildBounties::<T>::insert(
79					parent_bounty_id,
80					new_child_bounty_id.saturating_add(1),
81				);
82				writes += 1;
83
84				V0ToV1ChildBountyIds::<T>::insert(
85					old_child_bounty_id,
86					(parent_bounty_id, new_child_bounty_id),
87				);
88				writes += 1;
89
90				let old_child_bounty_account =
91					Self::old_child_bounty_account_id(old_child_bounty_id);
92				let new_child_bounty_account =
93					Pallet::<T>::child_bounty_account_id(parent_bounty_id, new_child_bounty_id);
94				let old_balance = T::Currency::free_balance(&old_child_bounty_account);
95				log::info!(
96					"Transferring {:?} funds from old child bounty account {:?} to new child bounty account {:?}",
97					old_balance, old_child_bounty_account, new_child_bounty_account
98				);
99				if let Err(err) = T::Currency::transfer(
100					&old_child_bounty_account,
101					&new_child_bounty_account,
102					old_balance,
103					AllowDeath,
104				) {
105					log::error!(
106						target: LOG_TARGET,
107						"Error transferring funds: {:?}",
108						err
109					);
110				}
111				transfer_weights += TransferWeight::get();
112
113				log::info!(
114					target: LOG_TARGET,
115					"Remapped parent bounty {} child bounty id {}->{}",
116					parent_bounty_id,
117					old_child_bounty_id,
118					new_child_bounty_id,
119				);
120
121				let bounty_description = ChildBountyDescriptions::<T>::take(old_child_bounty_id);
122				writes += 1;
123				let child_bounty = ChildBounties::<T>::take(parent_bounty_id, old_child_bounty_id);
124				writes += 1;
125
126				// should always be some
127				if let Some(taken) = child_bounty {
128					ChildBounties::<T>::insert(parent_bounty_id, new_child_bounty_id, taken);
129					writes += 1;
130				} else {
131					log::error!(
132						"child bounty with old id {} not found, should be impossible",
133						old_child_bounty_id
134					);
135				}
136				if let Some(bounty_description) = bounty_description {
137					super::super::ChildBountyDescriptionsV1::<T>::insert(
138						parent_bounty_id,
139						new_child_bounty_id,
140						bounty_description,
141					);
142					writes += 1;
143				} else {
144					log::error!(
145						"child bounty description with old id {} not found, should be impossible",
146						old_child_bounty_id
147					);
148				}
149			}
150
151			log::info!(
152				target: LOG_TARGET,
153				"Migration done, reads: {}, writes: {}, transfer weights: {}",
154				reads, writes, transfer_weights
155			);
156
157			T::DbWeight::get().reads_writes(reads, writes) + transfer_weights
158		}
159
160		#[cfg(feature = "try-runtime")]
161		fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
162			let old_child_bounty_count = ChildBounties::<T>::iter_keys().count() as u32;
163			let old_child_bounty_descriptions =
164				v1::ChildBountyDescriptions::<T>::iter_keys().count() as u32;
165			let old_child_bounty_ids = ChildBounties::<T>::iter_keys().collect::<Vec<_>>();
166			Ok((old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids)
167				.encode())
168		}
169
170		#[cfg(feature = "try-runtime")]
171		fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
172			type StateType = (u32, u32, Vec<(u32, u32)>);
173			let (old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids) =
174				StateType::decode(&mut &state[..]).expect("Can't decode previous state");
175			let new_child_bounty_count = ChildBounties::<T>::iter_keys().count() as u32;
176			let new_child_bounty_descriptions =
177				super::super::ChildBountyDescriptionsV1::<T>::iter_keys().count() as u32;
178
179			ensure!(
180				old_child_bounty_count == new_child_bounty_count,
181				"child bounty count doesn't match"
182			);
183			ensure!(
184				old_child_bounty_descriptions == new_child_bounty_descriptions,
185				"child bounty descriptions count doesn't match"
186			);
187
188			let old_child_bounty_descriptions_storage =
189				v1::ChildBountyDescriptions::<T>::iter_keys().count();
190			log::info!("old child bounty descriptions: {}", old_child_bounty_descriptions_storage);
191			ensure!(
192				old_child_bounty_descriptions_storage == 0,
193				"Old bounty descriptions should have been drained."
194			);
195
196			for (_, old_child_bounty_id) in old_child_bounty_ids {
197				let old_account_id = Self::old_child_bounty_account_id(old_child_bounty_id);
198				let balance = T::Currency::total_balance(&old_account_id);
199				if !balance.is_zero() {
200					log::error!(
201						"Old child bounty id {} still has balance {:?}",
202						old_child_bounty_id,
203						balance
204					);
205				}
206			}
207
208			Ok(())
209		}
210	}
211
212	impl<T: Config, TransferWeight: Get<Weight>> MigrateToV1Impl<T, TransferWeight> {
213		fn old_child_bounty_account_id(id: BountyIndex) -> T::AccountId {
214			// This function is taken from the parent (bounties) pallet, but the
215			// prefix is changed to have different AccountId when the index of
216			// parent and child is same.
217			T::PalletId::get().into_sub_account_truncating(("cb", id))
218		}
219	}
220}
221
222/// Migrate the pallet storage from `0` to `1`.
223pub type MigrateV0ToV1<T, TransferWeight> = frame_support::migrations::VersionedMigration<
224	0,
225	1,
226	v1::MigrateToV1Impl<T, TransferWeight>,
227	Pallet<T>,
228	<T as frame_system::Config>::DbWeight,
229>;