// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! Storage migrations for srml-staking.
/// Indicator of a version of a storage layout.
pub type VersionNumber = u32;
// the current expected version of the storage
pub const CURRENT_VERSION: VersionNumber = 2;
/// The inner logic of migrations.
#[cfg(any(test, feature = "migrate"))]
pub mod inner {
use crate::{Store, Module, Trait};
use frame_support::{StorageLinkedMap, StoragePrefixedMap, StorageValue};
use codec::{Encode, Decode};
use sp_std::vec::Vec;
use super::{CURRENT_VERSION, VersionNumber};
// the minimum supported version of the migration logic.
const MIN_SUPPORTED_VERSION: VersionNumber = 0;
// migrate storage from v0 to v1.
//
// this upgrades the `Nominators` linked_map value type from `Vec` to
// `Option>`
pub fn to_v1(version: &mut VersionNumber) {
if *version != 0 { return }
*version += 1;
let now = >::current_era();
let res = as Store>::Nominators::translate::, _, _>(
|key| key,
|targets| crate::Nominations {
targets,
submitted_in: now,
suppressed: false,
},
);
if let Err(e) = res {
frame_support::print("Encountered error in migration of Staking::Nominators map.");
if e.is_none() {
frame_support::print("Staking::Nominators map reinitialized");
}
}
frame_support::print("Finished migrating Staking storage to v1.");
}
// migrate storage from v1 to v2: adds another field to the `SlashingSpans`
// struct.
pub fn to_v2(version: &mut VersionNumber) {
use crate::{EraIndex, slashing::SpanIndex};
#[derive(Decode)]
struct V1SlashingSpans {
span_index: SpanIndex,
last_start: EraIndex,
prior: Vec,
}
#[derive(Encode)]
struct V2SlashingSpans {
span_index: SpanIndex,
last_start: EraIndex,
last_nonzero_slash: EraIndex,
prior: Vec,
}
if *version != 1 { return }
*version += 1;
let prefix = as Store>::SlashingSpans::final_prefix();
let mut current_key = prefix.to_vec();
loop {
let maybe_next_key = sp_io::storage::next_key(¤t_key[..])
.filter(|v| v.starts_with(&prefix[..]));
match maybe_next_key {
Some(next_key) => {
let maybe_spans = sp_io::storage::get(&next_key[..])
.and_then(|v| V1SlashingSpans::decode(&mut &v[..]).ok());
if let Some(spans) = maybe_spans {
let new_val = V2SlashingSpans {
span_index: spans.span_index,
last_start: spans.last_start,
last_nonzero_slash: spans.last_start,
prior: spans.prior,
}.encode();
sp_io::storage::set(&next_key[..], &new_val[..]);
}
current_key = next_key;
}
None => break,
}
}
}
pub(super) fn perform_migrations() {
as Store>::StorageVersion::mutate(|version| {
if *version < MIN_SUPPORTED_VERSION {
frame_support::print("Cannot migrate staking storage because version is less than\
minimum.");
frame_support::print(*version);
return
}
if *version == CURRENT_VERSION { return }
to_v1::(version);
to_v2::(version);
});
}
}
#[cfg(not(any(test, feature = "migrate")))]
mod inner {
pub(super) fn perform_migrations() { }
}
/// Perform all necessary storage migrations to get storage into the expected stsate for current
/// logic. No-op if fully upgraded.
pub(crate) fn perform_migrations() {
inner::perform_migrations::();
}