referrerpolicy=no-referrer-when-downgrade

pallet_contracts/migration/
v11.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//! Overflowing bounded DeletionQueue.
19//! See <https://github.com/paritytech/substrate/pull/13702>.
20
21use crate::{
22	migration::{IsFinished, MigrationStep},
23	weights::WeightInfo,
24	Config, Pallet, TrieId, Weight, LOG_TARGET,
25};
26use alloc::vec::Vec;
27use codec::{Decode, Encode};
28use core::marker::PhantomData;
29use frame_support::{pallet_prelude::*, storage_alias, weights::WeightMeter, DefaultNoBound};
30#[cfg(feature = "try-runtime")]
31use sp_runtime::TryRuntimeError;
32
33mod v10 {
34	use super::*;
35
36	#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
37	pub struct DeletedContract {
38		pub(crate) trie_id: TrieId,
39	}
40
41	#[storage_alias]
42	pub type DeletionQueue<T: Config> = StorageValue<Pallet<T>, Vec<DeletedContract>>;
43}
44
45#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, DefaultNoBound, Clone)]
46#[scale_info(skip_type_params(T))]
47pub struct DeletionQueueManager<T: Config> {
48	insert_counter: u32,
49	delete_counter: u32,
50	_phantom: PhantomData<T>,
51}
52
53#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime"))]
54pub fn fill_old_queue<T: Config>(len: usize) {
55	let queue: Vec<v10::DeletedContract> =
56		core::iter::repeat_with(|| v10::DeletedContract { trie_id: Default::default() })
57			.take(len)
58			.collect();
59	v10::DeletionQueue::<T>::set(Some(queue));
60}
61
62#[storage_alias]
63type DeletionQueue<T: Config> = StorageMap<Pallet<T>, Twox64Concat, u32, TrieId>;
64
65#[storage_alias]
66type DeletionQueueCounter<T: Config> = StorageValue<Pallet<T>, DeletionQueueManager<T>, ValueQuery>;
67
68#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
69pub struct Migration<T: Config> {
70	_phantom: PhantomData<T>,
71}
72
73impl<T: Config> MigrationStep for Migration<T> {
74	const VERSION: u16 = 11;
75
76	// It would be more correct to make our use the now removed [DeletionQueueDepth](https://github.com/paritytech/substrate/pull/13702/files#diff-70e9723e9db62816e35f6f885b6770a8449c75a6c2733e9fa7a245fe52c4656c)
77	// but in practice the queue is always empty, so 128 is a good enough approximation for not
78	// underestimating the weight of our migration.
79	fn max_step_weight() -> Weight {
80		T::WeightInfo::v11_migration_step(128)
81	}
82
83	fn step(&mut self, meter: &mut WeightMeter) -> IsFinished {
84		let Some(old_queue) = v10::DeletionQueue::<T>::take() else {
85			meter.consume(T::WeightInfo::v11_migration_step(0));
86			return IsFinished::Yes
87		};
88		let len = old_queue.len();
89
90		log::debug!(
91			target: LOG_TARGET,
92			"Migrating deletion queue with {} deleted contracts",
93			old_queue.len()
94		);
95
96		if !old_queue.is_empty() {
97			let mut queue = DeletionQueueManager::<T>::default();
98			for contract in old_queue {
99				<DeletionQueue<T>>::insert(queue.insert_counter, contract.trie_id);
100				queue.insert_counter += 1;
101			}
102
103			<DeletionQueueCounter<T>>::set(queue);
104		}
105
106		meter.consume(T::WeightInfo::v11_migration_step(len as u32));
107		IsFinished::Yes
108	}
109
110	#[cfg(feature = "try-runtime")]
111	fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
112		let old_queue = v10::DeletionQueue::<T>::take().unwrap_or_default();
113
114		if old_queue.is_empty() {
115			let len = 10u32;
116			log::debug!(
117				target: LOG_TARGET,
118				"Injecting {len} entries to deletion queue to test migration"
119			);
120			fill_old_queue::<T>(len as usize);
121			return Ok(len.encode())
122		}
123
124		Ok((old_queue.len() as u32).encode())
125	}
126
127	#[cfg(feature = "try-runtime")]
128	fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
129		let len = <u32 as Decode>::decode(&mut &state[..])
130			.expect("pre_upgrade_step provides a valid state; qed");
131		let counter = <DeletionQueueCounter<T>>::get();
132		ensure!(counter.insert_counter == len, "invalid insert counter");
133		ensure!(counter.delete_counter == 0, "invalid delete counter");
134		Ok(())
135	}
136}