referrerpolicy=no-referrer-when-downgrade

pallet_revive/migrations/
v1.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//! # Multi-Block Migration v1
19//!
20//! This migrate the old `ContractInfoOf` storage to the new `AccountInfoOf`.
21
22extern crate alloc;
23
24use super::PALLET_MIGRATIONS_ID;
25use crate::{weights::WeightInfo, AccountInfo, AccountInfoOf, Config, H160};
26use frame_support::{
27	migrations::{MigrationId, SteppedMigration, SteppedMigrationError},
28	pallet_prelude::PhantomData,
29	weights::WeightMeter,
30};
31
32#[cfg(feature = "try-runtime")]
33use alloc::collections::btree_map::BTreeMap;
34
35#[cfg(feature = "try-runtime")]
36use alloc::vec::Vec;
37
38/// Module containing the old storage items.
39pub mod old {
40	use super::Config;
41	use crate::{pallet::Pallet, ContractInfo, H160};
42	use frame_support::{storage_alias, Identity};
43
44	#[storage_alias]
45	/// The storage item that is being migrated from.
46	pub type ContractInfoOf<T: Config> = StorageMap<Pallet<T>, Identity, H160, ContractInfo<T>>;
47}
48
49/// Migrates the items of the [`old::ContractInfoOf`] map into [`crate::AccountInfoOf`].
50pub struct Migration<T: Config>(PhantomData<T>);
51
52impl<T: Config> SteppedMigration for Migration<T> {
53	type Cursor = H160;
54	type Identifier = MigrationId<17>;
55
56	fn id() -> Self::Identifier {
57		MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 0, version_to: 1 }
58	}
59
60	fn step(
61		mut cursor: Option<Self::Cursor>,
62		meter: &mut WeightMeter,
63	) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
64		let required = <T as Config>::WeightInfo::v1_migration_step();
65		if meter.remaining().any_lt(required) {
66			return Err(SteppedMigrationError::InsufficientWeight { required });
67		}
68
69		loop {
70			if meter.try_consume(required).is_err() {
71				break;
72			}
73
74			let iter = if let Some(last_key) = cursor {
75				old::ContractInfoOf::<T>::iter_from(old::ContractInfoOf::<T>::hashed_key_for(
76					last_key,
77				))
78			} else {
79				old::ContractInfoOf::<T>::iter()
80			};
81
82			if let Some((last_key, value)) = iter.drain().next() {
83				AccountInfoOf::<T>::insert(
84					last_key,
85					AccountInfo { account_type: value.into(), ..Default::default() },
86				);
87				cursor = Some(last_key)
88			} else {
89				cursor = None;
90				break
91			}
92		}
93		Ok(cursor)
94	}
95
96	#[cfg(feature = "try-runtime")]
97	fn pre_upgrade() -> Result<Vec<u8>, frame_support::sp_runtime::TryRuntimeError> {
98		use codec::Encode;
99
100		// Return the state of the storage before the migration.
101		Ok(old::ContractInfoOf::<T>::iter().collect::<BTreeMap<_, _>>().encode())
102	}
103
104	#[cfg(feature = "try-runtime")]
105	fn post_upgrade(prev: Vec<u8>) -> Result<(), frame_support::sp_runtime::TryRuntimeError> {
106		use codec::Decode;
107
108		// Check the state of the storage after the migration.
109		let prev_map = BTreeMap::<H160, crate::ContractInfo<T>>::decode(&mut &prev[..])
110			.expect("Failed to decode the previous storage state");
111
112		// Check the len of prev and post are the same.
113		assert_eq!(
114			AccountInfoOf::<T>::iter().count(),
115			prev_map.len(),
116			"Migration failed: the number of items in the storage after the migration is not the same as before"
117		);
118
119		for (key, value) in prev_map {
120			let new_value = AccountInfo::<T>::load_contract(&key);
121			assert_eq!(
122				Some(value),
123				new_value,
124				"Migration failed: the value after the migration is not the same as before"
125			);
126		}
127
128		Ok(())
129	}
130}
131
132#[test]
133fn migrate_to_v1() {
134	use crate::{
135		tests::{ExtBuilder, Test},
136		ContractInfo,
137	};
138	ExtBuilder::default().build().execute_with(|| {
139		for i in 0..10u8 {
140			let addr = H160::from([i; 20]);
141			old::ContractInfoOf::<Test>::insert(
142				addr,
143				ContractInfo::new(&addr, 1u32.into(), Default::default()).unwrap(),
144			);
145		}
146
147		let mut cursor = None;
148		let mut weight_meter = WeightMeter::new();
149		while let Some(new_cursor) = Migration::<Test>::step(cursor, &mut weight_meter).unwrap() {
150			cursor = Some(new_cursor);
151		}
152
153		assert_eq!(old::ContractInfoOf::<Test>::iter().count(), 0);
154		assert_eq!(AccountInfoOf::<Test>::iter().count(), 10);
155	})
156}