Repository: paritytech/substrate
File: frame/society/src/migrations.rs (Rust)

Code before:
		I: Instance + 'static,
		PastPayouts: Get<Vec<(<T as frame_system::Config>::AccountId, BalanceOf<T, I>)>>,
	> OnRuntimeUpgrade for VersionUncheckedMigrateToV2<T, I, PastPayouts>
{
	#[cfg(feature = "try-runtime")]
	fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
		ensure!(can_migrate::<T, I>(), "pallet_society: already upgraded");

		let current = Pallet::<T, I>::current_storage_version();
		let onchain = Pallet::<T, I>::on_chain_storage_version();
		ensure!(onchain == 0 && current == 2, "pallet_society: invalid version");

		Ok((old::Candidates::<T, I>::get(), old::Members::<T, I>::get()).encode())
	}

	fn on_runtime_upgrade() -> Weight {
		let onchain = Pallet::<T, I>::on_chain_storage_version();
		if onchain < 2 {
			log::info!(
				target: TARGET,
				"Running migration against onchain version {:?}",
				onchain
			);
			from_original::<T, I>(&mut PastPayouts::get()).defensive_unwrap_or(Weight::MAX)
		} else {
			defensive!("Unexpected onchain version: {:?}. Expected 0.");
			T::DbWeight::get().reads(1)
		}
	}

	#[cfg(feature = "try-runtime")]
	fn post_upgrade(data: Vec<u8>) -> Result<(), TryRuntimeError> {
		let old: (
			Vec<Bid<<T as frame_system::Config>::AccountId, BalanceOf<T, I>>>,
			Vec<<T as frame_system::Config>::AccountId>,
		) = Decode::decode(&mut &data[..]).expect("Bad data");
		let mut old_candidates =
			old.0.into_iter().map(|x| (x.who, x.kind, x.value)).collect::<Vec<_>>();
		let mut old_members = old.1;
		let mut candidates =
			Candidates::<T, I>::iter().map(|(k, v)| (k, v.kind, v.bid)).collect::<Vec<_>>();
		let mut members = Members::<T, I>::iter_keys().collect::<Vec<_>>();

		old_candidates.sort_by_key(|x| x.0.clone());
		candidates.sort_by_key(|x| x.0.clone());
		assert_eq!(candidates, old_candidates);

		members.sort();
		old_members.sort();
		assert_eq!(members, old_members);


Review comment (bug):
```suggestion
```

We don't want migrations to fail when they are already applied. I know this is only defensive and will not trigger on chain, but it could fail in the try runtime checks.

Code after:
{
	#[cfg(feature = "try-runtime")]
	fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
		let current = Pallet::<T, I>::current_storage_version();
		let onchain = Pallet::<T, I>::on_chain_storage_version();
		ensure!(onchain == 0 && current == 2, "pallet_society: invalid version");

		Ok((old::Candidates::<T, I>::get(), old::Members::<T, I>::get()).encode())
	}

	fn on_runtime_upgrade() -> Weight {
		let onchain = Pallet::<T, I>::on_chain_storage_version();
		if onchain < 2 {
			log::info!(
				target: TARGET,
				"Running migration against onchain version {:?}",
				onchain
			);
			from_original::<T, I>(&mut PastPayouts::get()).defensive_unwrap_or(Weight::MAX)
		} else {
			log::warn!("Unexpected onchain version: {:?} (expected 0)", onchain);
			T::DbWeight::get().reads(1)
		}
	}

	#[cfg(feature = "try-runtime")]
	fn post_upgrade(data: Vec<u8>) -> Result<(), TryRuntimeError> {
		let old: (
			Vec<Bid<<T as frame_system::Config>::AccountId, BalanceOf<T, I>>>,
			Vec<<T as frame_system::Config>::AccountId>,
		) = Decode::decode(&mut &data[..]).expect("Bad data");
		let mut old_candidates =
			old.0.into_iter().map(|x| (x.who, x.kind, x.value)).collect::<Vec<_>>();
		let mut old_members = old.1;
		let mut candidates =
			Candidates::<T, I>::iter().map(|(k, v)| (k, v.kind, v.bid)).collect::<Vec<_>>();
		let mut members = Members::<T, I>::iter_keys().collect::<Vec<_>>();

		old_candidates.sort_by_key(|x| x.0.clone());
		candidates.sort_by_key(|x| x.0.clone());
		assert_eq!(candidates, old_candidates);

		members.sort();
		old_members.sort();
		assert_eq!(members, old_members);

		ensure!(
			Pallet::<T, I>::on_chain_storage_version() == 2,
			"The onchain version must be updated after the migration."
		);