// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Overflowing bounded DeletionQueue. //! See . use crate::{ migration::{IsFinished, MigrationStep}, weights::WeightInfo, Config, Pallet, TrieId, Weight, LOG_TARGET, }; use codec::{Decode, Encode}; use frame_support::{pallet_prelude::*, storage_alias, weights::WeightMeter, DefaultNoBound}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; use sp_std::{marker::PhantomData, prelude::*}; mod v10 { use super::*; #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct DeletedContract { pub(crate) trie_id: TrieId, } #[storage_alias] pub type DeletionQueue = StorageValue, Vec>; } #[derive(Encode, Decode, TypeInfo, MaxEncodedLen, DefaultNoBound, Clone)] #[scale_info(skip_type_params(T))] pub struct DeletionQueueManager { insert_counter: u32, delete_counter: u32, _phantom: PhantomData, } #[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime"))] pub fn fill_old_queue(len: usize) { let queue: Vec = core::iter::repeat_with(|| v10::DeletedContract { trie_id: Default::default() }) .take(len) .collect(); v10::DeletionQueue::::set(Some(queue)); } #[storage_alias] type DeletionQueue = StorageMap, Twox64Concat, u32, TrieId>; #[storage_alias] type DeletionQueueCounter = StorageValue, DeletionQueueManager, ValueQuery>; #[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)] pub struct Migration { _phantom: PhantomData, } impl MigrationStep for Migration { const VERSION: u16 = 11; // It would be more correct to make our use the now removed [DeletionQueueDepth](https://github.com/paritytech/substrate/pull/13702/files#diff-70e9723e9db62816e35f6f885b6770a8449c75a6c2733e9fa7a245fe52c4656c) // but in practice the queue is always empty, so 128 is a good enough approximation for not // underestimating the weight of our migration. fn max_step_weight() -> Weight { T::WeightInfo::v11_migration_step(128) } fn step(&mut self, meter: &mut WeightMeter) -> IsFinished { let Some(old_queue) = v10::DeletionQueue::::take() else { meter.consume(T::WeightInfo::v11_migration_step(0)); return IsFinished::Yes }; let len = old_queue.len(); log::debug!( target: LOG_TARGET, "Migrating deletion queue with {} deleted contracts", old_queue.len() ); if !old_queue.is_empty() { let mut queue = DeletionQueueManager::::default(); for contract in old_queue { >::insert(queue.insert_counter, contract.trie_id); queue.insert_counter += 1; } >::set(queue); } meter.consume(T::WeightInfo::v11_migration_step(len as u32)); IsFinished::Yes } #[cfg(feature = "try-runtime")] fn pre_upgrade_step() -> Result, TryRuntimeError> { let old_queue = v10::DeletionQueue::::take().unwrap_or_default(); if old_queue.is_empty() { let len = 10u32; log::debug!( target: LOG_TARGET, "Injecting {len} entries to deletion queue to test migration" ); fill_old_queue::(len as usize); return Ok(len.encode()) } Ok((old_queue.len() as u32).encode()) } #[cfg(feature = "try-runtime")] fn post_upgrade_step(state: Vec) -> Result<(), TryRuntimeError> { let len = ::decode(&mut &state[..]) .expect("pre_upgrade_step provides a valid state; qed"); let counter = >::get(); ensure!(counter.insert_counter == len, "invalid insert counter"); ensure!(counter.delete_counter == 0, "invalid delete counter"); Ok(()) } }