use super::*;
use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade};
const TARGET: &str = "ceremonies::migration::v1";
mod v0 {
use super::*;
#[storage_alias]
pub(super) type AttestationRegistry<T: Config> = StorageDoubleMap<
Pallet<T>,
Blake2_128Concat,
CommunityCeremony,
Blake2_128Concat,
AttestationIndexType,
Vec<<T as frame_system::Config>::AccountId>,
OptionQuery,
>;
}
pub mod v1 {
use super::*;
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config + frame_system::Config> OnRuntimeUpgrade for MigrateToV1<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::DispatchError> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
let attestations = v0::AttestationRegistry::<T>::iter();
let mut attestation_count = 0u32;
for a in attestations {
let count = a.2.len() as u32;
ensure!(count <= T::MaxAttestations::get(), "too many attestations");
attestation_count = attestation_count + count;
}
log::info!(target: TARGET, "{} attestations will be migrated.", attestation_count,);
Ok((attestation_count).encode())
}
fn on_runtime_upgrade() -> Weight {
let weight = T::DbWeight::get().reads(1);
if StorageVersion::get::<Pallet<T>>() != 0 {
log::warn!(
target: TARGET,
"skipping on_runtime_upgrade: executed on wrong storage version.\
Expected version 0"
);
return weight
}
StorageVersion::new(1).put::<Pallet<T>>();
weight.saturating_add(T::DbWeight::get().reads_writes(1, 2))
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
let old_attestation_count: u32 =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_attestation_count =
crate::AttestationRegistry::<T>::iter().fold(0, |acc, x| acc + x.2.len()) as u32;
assert_eq!(
old_attestation_count, new_attestation_count,
"must migrate all attestations"
);
log::info!(target: TARGET, "{} attestations migrated", new_attestation_count);
Ok(())
}
}
}
#[cfg(test)]
#[cfg(feature = "try-runtime")]
mod test {
use super::*;
use frame_support::{assert_err, traits::OnRuntimeUpgrade};
use mock::{new_test_ext, TestRuntime};
use sp_std::str::FromStr;
use test_utils::*;
#[allow(deprecated)]
#[test]
fn migration_works() {
new_test_ext().execute_with(|| {
assert_eq!(StorageVersion::get::<Pallet<TestRuntime>>(), 0);
let cids = vec![
CommunityIdentifier::from_str("111112Fvv9e").unwrap(),
CommunityIdentifier::from_str("333332Fvv9e").unwrap(),
];
let attestations_0 =
vec![AccountId::from(AccountKeyring::Alice), AccountId::from(AccountKeyring::Bob)];
let attestations_1 = vec![
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Ferdie),
AccountId::from(AccountKeyring::Charlie),
];
let attestations_2 = vec![
AccountId::from(AccountKeyring::Dave),
AccountId::from(AccountKeyring::Ferdie),
AccountId::from(AccountKeyring::Charlie),
];
v0::AttestationRegistry::<TestRuntime>::insert((cids[0], 1), 0, attestations_0.clone());
v0::AttestationRegistry::<TestRuntime>::insert((cids[0], 2), 3, attestations_1.clone());
v0::AttestationRegistry::<TestRuntime>::insert((cids[0], 1), 3, attestations_1.clone());
v0::AttestationRegistry::<TestRuntime>::insert((cids[1], 2), 3, attestations_2.clone());
let state = v1::MigrateToV1::<TestRuntime>::pre_upgrade().unwrap();
let _weight = v1::MigrateToV1::<TestRuntime>::on_runtime_upgrade();
v1::MigrateToV1::<TestRuntime>::post_upgrade(state).unwrap();
assert_eq!(
crate::AttestationRegistry::<TestRuntime>::get((cids[0], 1), 0),
Some(
BoundedVec::<
<TestRuntime as frame_system::Config>::AccountId,
<TestRuntime as Config>::MaxAttestations,
>::try_from(attestations_0)
.unwrap()
)
);
assert_eq!(
crate::AttestationRegistry::<TestRuntime>::get((cids[0], 2), 3),
Some(
BoundedVec::<
<TestRuntime as frame_system::Config>::AccountId,
<TestRuntime as Config>::MaxAttestations,
>::try_from(attestations_1.clone())
.unwrap()
)
);
assert_eq!(
crate::AttestationRegistry::<TestRuntime>::get((cids[0], 1), 3),
Some(
BoundedVec::<
<TestRuntime as frame_system::Config>::AccountId,
<TestRuntime as Config>::MaxAttestations,
>::try_from(attestations_1)
.unwrap()
)
);
assert_eq!(
crate::AttestationRegistry::<TestRuntime>::get((cids[1], 2), 3),
Some(
BoundedVec::<
<TestRuntime as frame_system::Config>::AccountId,
<TestRuntime as Config>::MaxAttestations,
>::try_from(attestations_2)
.unwrap()
)
);
});
}
#[allow(deprecated)]
#[test]
fn migration_fails_with_too_many_attestations() {
new_test_ext().execute_with(|| {
assert_eq!(StorageVersion::get::<Pallet<TestRuntime>>(), 0);
let attestations = vec![
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
AccountId::from(AccountKeyring::Alice),
];
v0::AttestationRegistry::<TestRuntime>::insert(
(CommunityIdentifier::from_str("111112Fvv9d").unwrap(), 1),
0,
attestations,
);
let state = v1::MigrateToV1::<TestRuntime>::pre_upgrade();
assert_err!(state, "too many attestations");
});
}
}