use crate::{
migration::{IsFinished, MigrationStep},
weights::WeightInfo,
Config, Pallet, TrieId, Weight, LOG_TARGET,
};
use alloc::vec::Vec;
use codec::{Decode, Encode};
use core::marker::PhantomData;
use frame_support::{pallet_prelude::*, storage_alias, weights::WeightMeter, DefaultNoBound};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
mod v10 {
use super::*;
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct DeletedContract {
pub(crate) trie_id: TrieId,
}
#[storage_alias]
pub type DeletionQueue<T: Config> = StorageValue<Pallet<T>, Vec<DeletedContract>>;
}
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, DefaultNoBound, Clone)]
#[scale_info(skip_type_params(T))]
pub struct DeletionQueueManager<T: Config> {
insert_counter: u32,
delete_counter: u32,
_phantom: PhantomData<T>,
}
#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime"))]
pub fn fill_old_queue<T: Config>(len: usize) {
let queue: Vec<v10::DeletedContract> =
core::iter::repeat_with(|| v10::DeletedContract { trie_id: Default::default() })
.take(len)
.collect();
v10::DeletionQueue::<T>::set(Some(queue));
}
#[storage_alias]
type DeletionQueue<T: Config> = StorageMap<Pallet<T>, Twox64Concat, u32, TrieId>;
#[storage_alias]
type DeletionQueueCounter<T: Config> = StorageValue<Pallet<T>, DeletionQueueManager<T>, ValueQuery>;
#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
pub struct Migration<T: Config> {
_phantom: PhantomData<T>,
}
impl<T: Config> MigrationStep for Migration<T> {
const VERSION: u16 = 11;
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::<T>::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::<T>::default();
for contract in old_queue {
<DeletionQueue<T>>::insert(queue.insert_counter, contract.trie_id);
queue.insert_counter += 1;
}
<DeletionQueueCounter<T>>::set(queue);
}
meter.consume(T::WeightInfo::v11_migration_step(len as u32));
IsFinished::Yes
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
let old_queue = v10::DeletionQueue::<T>::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::<T>(len as usize);
return Ok(len.encode())
}
Ok((old_queue.len() as u32).encode())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
let len = <u32 as Decode>::decode(&mut &state[..])
.expect("pre_upgrade_step provides a valid state; qed");
let counter = <DeletionQueueCounter<T>>::get();
ensure!(counter.insert_counter == len, "invalid insert counter");
ensure!(counter.delete_counter == 0, "invalid delete counter");
Ok(())
}
}