BREAKING - Try-runtime: Use proper error types (#13993)

* Try-state: DispatchResult as return type

* try_state for the rest of the pallets

* pre_upgrade

* post_upgrade

* try_runtime_upgrade

* fixes

* bags-list fix

* fix

* update test

* warning fix

* ...

* final fixes 🤞

* warning..

* frame-support

* warnings

* Update frame/staking/src/migrations.rs

Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>

* fix

* fix warning

* nit fix

* merge fixes

* small fix

* should be good now

* missed these ones

* introduce TryRuntimeError and TryRuntimeResult

* fixes

* fix

* removed TryRuntimeResult & made some fixes

* fix testsg

* tests passing

* unnecessary imports

* Update frame/assets/src/migration.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

---------

Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Sergej Sakac
2023-05-23 08:56:10 +02:00
committed by GitHub
parent 918d1ef80d
commit df87bae1a9
34 changed files with 419 additions and 276 deletions
+15 -11
View File
@@ -18,6 +18,9 @@
use super::*;
use frame_support::{log, traits::OnRuntimeUpgrade};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
pub mod v1 {
use frame_support::{pallet_prelude::*, weights::Weight};
@@ -92,7 +95,7 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
frame_support::ensure!(
Pallet::<T>::on_chain_storage_version() == 0,
"must upgrade linearly"
@@ -102,13 +105,13 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), TryRuntimeError> {
let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect(
"the state parameter should be something that was generated by pre_upgrade",
);
let post_count = Asset::<T>::iter().count() as u32;
assert_eq!(
prev_count, post_count,
ensure!(
prev_count == post_count,
"the asset count before and after the migration should be the same"
);
@@ -116,17 +119,18 @@ pub mod v1 {
let onchain_version = Pallet::<T>::on_chain_storage_version();
frame_support::ensure!(current_version == 1, "must_upgrade");
assert_eq!(
current_version, onchain_version,
ensure!(
current_version == onchain_version,
"after migration, the current_version and onchain_version should be the same"
);
Asset::<T>::iter().for_each(|(_id, asset)| {
assert!(
Asset::<T>::iter().try_for_each(|(_id, asset)| -> Result<(), TryRuntimeError> {
ensure!(
asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen,
"assets should only be live or frozen. None should be in destroying status, or undefined state"
)
});
"assets should only be live or frozen. None should be in destroying status, or undefined state"
);
Ok(())
})?;
Ok(())
}
}
+6 -3
View File
@@ -59,6 +59,9 @@ use frame_system::ensure_signed;
use sp_runtime::traits::{AtLeast32BitUnsigned, Bounded, StaticLookup};
use sp_std::prelude::*;
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
use sp_runtime::TryRuntimeError;
#[cfg(any(feature = "runtime-benchmarks", test))]
mod benchmarks;
@@ -267,7 +270,7 @@ pub mod pallet {
}
#[cfg(feature = "try-runtime")]
fn try_state(_: BlockNumberFor<T>) -> Result<(), &'static str> {
fn try_state(_: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
<Self as SortedListProvider<T::AccountId>>::try_state()
}
}
@@ -275,7 +278,7 @@ pub mod pallet {
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
pub fn do_try_state() -> Result<(), &'static str> {
pub fn do_try_state() -> Result<(), TryRuntimeError> {
List::<T, I>::do_try_state()
}
}
@@ -355,7 +358,7 @@ impl<T: Config<I>, I: 'static> SortedListProvider<T::AccountId> for Pallet<T, I>
}
#[cfg(feature = "try-runtime")]
fn try_state() -> Result<(), &'static str> {
fn try_state() -> Result<(), TryRuntimeError> {
Self::do_try_state()
}
+8 -8
View File
@@ -42,6 +42,9 @@ use sp_std::{
prelude::*,
};
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
use sp_runtime::TryRuntimeError;
#[derive(Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, PalletError)]
pub enum ListError {
/// A duplicate id has been detected.
@@ -512,11 +515,11 @@ impl<T: Config<I>, I: 'static> List<T, I> {
/// * and sanity-checks all bags and nodes. This will cascade down all the checks and makes sure
/// all bags and nodes are checked per *any* update to `List`.
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
pub(crate) fn do_try_state() -> Result<(), &'static str> {
pub(crate) fn do_try_state() -> Result<(), TryRuntimeError> {
let mut seen_in_list = BTreeSet::new();
ensure!(
Self::iter().map(|node| node.id).all(|id| seen_in_list.insert(id)),
"duplicate identified",
"duplicate identified"
);
let iter_count = Self::iter().count() as u32;
@@ -750,7 +753,7 @@ impl<T: Config<I>, I: 'static> Bag<T, I> {
/// * Ensures tail has no next.
/// * Ensures there are no loops, traversal from head to tail is correct.
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
fn do_try_state(&self) -> Result<(), &'static str> {
fn do_try_state(&self) -> Result<(), TryRuntimeError> {
frame_support::ensure!(
self.head()
.map(|head| head.prev().is_none())
@@ -895,15 +898,12 @@ impl<T: Config<I>, I: 'static> Node<T, I> {
}
#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))]
fn do_try_state(&self) -> Result<(), &'static str> {
fn do_try_state(&self) -> Result<(), TryRuntimeError> {
let expected_bag = Bag::<T, I>::get(self.bag_upper).ok_or("bag not found for node")?;
let id = self.id();
frame_support::ensure!(
expected_bag.contains(id),
"node does not exist in the expected bag"
);
frame_support::ensure!(expected_bag.contains(id), "node does not exist in the bag");
let non_terminal_check = !self.is_terminal() &&
expected_bag.head.as_ref() != Some(id) &&
+9 -2
View File
@@ -22,6 +22,7 @@ use crate::{
};
use frame_election_provider_support::{SortedListProvider, VoteWeight};
use frame_support::{assert_ok, assert_storage_noop};
use sp_runtime::TryRuntimeError;
fn node(
id: AccountId,
@@ -359,7 +360,10 @@ mod list {
// make sure there are no duplicates.
ExtBuilder::default().build_and_execute_no_post_check(|| {
Bag::<Runtime>::get(10).unwrap().insert_unchecked(2, 10);
assert_eq!(List::<Runtime>::do_try_state(), Err("duplicate identified"));
assert_eq!(
List::<Runtime>::do_try_state(),
TryRuntimeError::Other("duplicate identified").into()
);
});
// ensure count is in sync with `ListNodes::count()`.
@@ -373,7 +377,10 @@ mod list {
CounterForListNodes::<Runtime>::mutate(|counter| *counter += 1);
assert_eq!(crate::ListNodes::<Runtime>::count(), 5);
assert_eq!(List::<Runtime>::do_try_state(), Err("iter_count != stored_count"));
assert_eq!(
List::<Runtime>::do_try_state(),
TryRuntimeError::Other("iter_count != stored_count").into()
);
});
}
+6 -3
View File
@@ -24,6 +24,9 @@ use frame_support::traits::OnRuntimeUpgrade;
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
#[cfg(feature = "try-runtime")]
use sp_std::vec::Vec;
@@ -35,7 +38,7 @@ impl<T: crate::Config<I>, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix<T,
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
// The old explicit storage item.
#[frame_support::storage_alias]
type CounterForListNodes<T: crate::Config<I>, I: 'static> =
@@ -88,7 +91,7 @@ mod old {
pub struct AddScore<T: crate::Config<I>, I: 'static = ()>(sp_std::marker::PhantomData<(T, I)>);
impl<T: crate::Config<I>, I: 'static> OnRuntimeUpgrade for AddScore<T, I> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
// The list node data should be corrupt at this point, so this is zero.
ensure!(crate::ListNodes::<T, I>::iter().count() == 0, "list node data is not corrupt");
// We can use the helper `old::ListNode` to get the existing data.
@@ -119,7 +122,7 @@ impl<T: crate::Config<I>, I: 'static> OnRuntimeUpgrade for AddScore<T, I> {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(node_count_before: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(node_count_before: Vec<u8>) -> Result<(), TryRuntimeError> {
let node_count_before: u32 = Decode::decode(&mut node_count_before.as_slice())
.expect("the state parameter should be something that was generated by pre_upgrade");
// Now the list node data is not corrupt anymore.
+53 -50
View File
@@ -60,6 +60,9 @@ use frame_support::{
weights::Weight,
};
#[cfg(any(feature = "try-runtime", test))]
use sp_runtime::TryRuntimeError;
#[cfg(test)]
mod tests;
@@ -346,9 +349,8 @@ pub mod pallet {
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
#[cfg(feature = "try-runtime")]
fn try_state(_n: BlockNumberFor<T>) -> Result<(), &'static str> {
Self::do_try_state()?;
Ok(())
fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
Self::do_try_state()
}
}
@@ -967,77 +969,78 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Looking at prime account:
/// * The prime account must be a member of the collective.
#[cfg(any(feature = "try-runtime", test))]
fn do_try_state() -> DispatchResult {
Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult {
ensure!(
Self::proposal_of(proposal).is_some(),
DispatchError::Other(
fn do_try_state() -> Result<(), TryRuntimeError> {
Self::proposals()
.into_iter()
.try_for_each(|proposal| -> Result<(), TryRuntimeError> {
ensure!(
Self::proposal_of(proposal).is_some(),
"Proposal hash from `Proposals` is not found inside the `ProposalOf` mapping."
)
);
Ok(())
})?;
);
Ok(())
})?;
ensure!(
Self::proposals().into_iter().count() <= Self::proposal_count() as usize,
DispatchError::Other("The actual number of proposals is greater than `ProposalCount`")
"The actual number of proposals is greater than `ProposalCount`"
);
ensure!(
Self::proposals().into_iter().count() == <ProposalOf<T, I>>::iter_keys().count(),
DispatchError::Other("Proposal count inside `Proposals` is not equal to the proposal count in `ProposalOf`")
"Proposal count inside `Proposals` is not equal to the proposal count in `ProposalOf`"
);
Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult {
if let Some(votes) = Self::voting(proposal) {
let ayes = votes.ayes.len();
let nays = votes.nays.len();
Self::proposals()
.into_iter()
.try_for_each(|proposal| -> Result<(), TryRuntimeError> {
if let Some(votes) = Self::voting(proposal) {
let ayes = votes.ayes.len();
let nays = votes.nays.len();
ensure!(
ayes.saturating_add(nays) <= T::MaxMembers::get() as usize,
DispatchError::Other("The sum of ayes and nays is greater than `MaxMembers`")
);
}
Ok(())
})?;
ensure!(
ayes.saturating_add(nays) <= T::MaxMembers::get() as usize,
"The sum of ayes and nays is greater than `MaxMembers`"
);
}
Ok(())
})?;
let mut proposal_indices = vec![];
Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult {
if let Some(votes) = Self::voting(proposal) {
let proposal_index = votes.index;
ensure!(
!proposal_indices.contains(&proposal_index),
DispatchError::Other("The proposal index is not unique.")
);
proposal_indices.push(proposal_index);
}
Ok(())
})?;
Self::proposals()
.into_iter()
.try_for_each(|proposal| -> Result<(), TryRuntimeError> {
if let Some(votes) = Self::voting(proposal) {
let proposal_index = votes.index;
ensure!(
!proposal_indices.contains(&proposal_index),
"The proposal index is not unique."
);
proposal_indices.push(proposal_index);
}
Ok(())
})?;
<Voting<T, I>>::iter_keys().try_for_each(|proposal_hash| -> DispatchResult {
ensure!(
Self::proposals().contains(&proposal_hash),
DispatchError::Other(
<Voting<T, I>>::iter_keys().try_for_each(
|proposal_hash| -> Result<(), TryRuntimeError> {
ensure!(
Self::proposals().contains(&proposal_hash),
"`Proposals` doesn't contain the proposal hash from the `Voting` storage map."
)
);
Ok(())
})?;
);
Ok(())
},
)?;
ensure!(
Self::members().len() <= T::MaxMembers::get() as usize,
DispatchError::Other("The member count is greater than `MaxMembers`.")
"The member count is greater than `MaxMembers`."
);
ensure!(
Self::members().windows(2).all(|members| members[0] <= members[1]),
DispatchError::Other("The members are not sorted by value.")
"The members are not sorted by value."
);
if let Some(prime) = Self::prime() {
ensure!(
Self::members().contains(&prime),
DispatchError::Other("Prime account is not a member.")
);
ensure!(Self::members().contains(&prime), "Prime account is not a member.");
}
Ok(())
+11 -8
View File
@@ -28,6 +28,9 @@ use frame_support::{
use sp_runtime::traits::Saturating;
use sp_std::{marker::PhantomData, prelude::*};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// Performs all necessary migrations based on `StorageVersion`.
pub struct Migration<T: Config>(PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for Migration<T> {
@@ -66,7 +69,7 @@ impl<T: Config> OnRuntimeUpgrade for Migration<T> {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
let version = <Pallet<T>>::on_chain_storage_version();
if version == 7 {
@@ -77,7 +80,7 @@ impl<T: Config> OnRuntimeUpgrade for Migration<T> {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
let version = Decode::decode(&mut state.as_ref()).map_err(|_| "Cannot decode version")?;
post_checks::post_upgrade::<T>(version)
}
@@ -355,7 +358,7 @@ mod v8 {
}
#[cfg(feature = "try-runtime")]
pub fn pre_upgrade<T: Config>() -> Result<(), &'static str> {
pub fn pre_upgrade<T: Config>() -> Result<(), TryRuntimeError> {
use frame_support::traits::ReservableCurrency;
for (key, value) in ContractInfoOf::<T, OldContractInfo<T>>::iter() {
let reserved = T::Currency::reserved_balance(&key);
@@ -418,7 +421,7 @@ mod post_checks {
type ContractInfoOf<T: Config, V> =
StorageMap<Pallet<T>, Twox64Concat, <T as frame_system::Config>::AccountId, V>;
pub fn post_upgrade<T: Config>(old_version: StorageVersion) -> Result<(), &'static str> {
pub fn post_upgrade<T: Config>(old_version: StorageVersion) -> Result<(), TryRuntimeError> {
if old_version < 7 {
return Ok(())
}
@@ -434,7 +437,7 @@ mod post_checks {
Ok(())
}
fn v8<T: Config>() -> Result<(), &'static str> {
fn v8<T: Config>() -> Result<(), TryRuntimeError> {
use frame_support::traits::ReservableCurrency;
for (key, value) in ContractInfoOf::<T, ContractInfo<T>>::iter() {
let reserved = T::Currency::reserved_balance(&key);
@@ -455,13 +458,13 @@ mod post_checks {
storage_bytes.saturating_accrue(len);
storage_items.saturating_accrue(1);
}
ensure!(storage_bytes == value.storage_bytes, "Storage bytes do not match.",);
ensure!(storage_items == value.storage_items, "Storage items do not match.",);
ensure!(storage_bytes == value.storage_bytes, "Storage bytes do not match.");
ensure!(storage_items == value.storage_items, "Storage items do not match.");
}
Ok(())
}
fn v9<T: Config>() -> Result<(), &'static str> {
fn v9<T: Config>() -> Result<(), TryRuntimeError> {
for value in CodeStorage::<T>::iter_values() {
ensure!(
value.determinism == Determinism::Enforced,
+7 -7
View File
@@ -61,12 +61,12 @@ pub mod v1 {
impl<T: Config + frame_system::Config<Hash = H256>> OnRuntimeUpgrade for Migration<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 0, "can only upgrade from version 0");
let props_count = v0::PublicProps::<T>::get().len();
log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,);
ensure!(props_count <= T::MaxProposals::get() as usize, "too many proposals");
ensure!(props_count <= T::MaxProposals::get() as usize, Error::<T>::TooMany);
let referenda_count = v0::ReferendumInfoOf::<T>::iter().count();
log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count);
@@ -133,15 +133,15 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 1, "must upgrade");
let (old_props_count, old_ref_count): (u32, u32) =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_props_count = crate::PublicProps::<T>::get().len() as u32;
assert_eq!(new_props_count, old_props_count, "must migrate all public proposals");
ensure!(new_props_count == old_props_count, "must migrate all public proposals");
let new_ref_count = crate::ReferendumInfoOf::<T>::iter().count() as u32;
assert_eq!(new_ref_count, old_ref_count, "must migrate all referenda");
ensure!(new_ref_count == old_ref_count, "must migrate all referenda");
log::info!(
target: TARGET,
@@ -257,6 +257,9 @@ use sp_runtime::{
};
use sp_std::prelude::*;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(test)]
@@ -883,7 +886,7 @@ pub mod pallet {
}
#[cfg(feature = "try-runtime")]
fn try_state(_n: T::BlockNumber) -> Result<(), &'static str> {
fn try_state(_n: T::BlockNumber) -> Result<(), TryRuntimeError> {
Self::do_try_state()
}
}
@@ -1579,7 +1582,7 @@ impl<T: Config> Pallet<T> {
#[cfg(feature = "try-runtime")]
impl<T: Config> Pallet<T> {
fn do_try_state() -> Result<(), &'static str> {
fn do_try_state() -> Result<(), TryRuntimeError> {
Self::try_state_snapshot()?;
Self::try_state_signed_submissions_map()?;
Self::try_state_phase_off()
@@ -1588,7 +1591,7 @@ impl<T: Config> Pallet<T> {
// [`Snapshot`] state check. Invariants:
// - [`DesiredTargets`] exists if and only if [`Snapshot`] is present.
// - [`SnapshotMetadata`] exist if and only if [`Snapshot`] is present.
fn try_state_snapshot() -> Result<(), &'static str> {
fn try_state_snapshot() -> Result<(), TryRuntimeError> {
if <Snapshot<T>>::exists() &&
<SnapshotMetadata<T>>::exists() &&
<DesiredTargets<T>>::exists()
@@ -1600,7 +1603,7 @@ impl<T: Config> Pallet<T> {
{
Ok(())
} else {
Err("If snapshot exists, metadata and desired targets should be set too. Otherwise, none should be set.")
Err("If snapshot exists, metadata and desired targets should be set too. Otherwise, none should be set.".into())
}
}
@@ -1608,28 +1611,34 @@ impl<T: Config> Pallet<T> {
// - All [`SignedSubmissionIndices`] are present in [`SignedSubmissionsMap`], and no more;
// - [`SignedSubmissionNextIndex`] is not present in [`SignedSubmissionsMap`];
// - [`SignedSubmissionIndices`] is sorted by election score.
fn try_state_signed_submissions_map() -> Result<(), &'static str> {
fn try_state_signed_submissions_map() -> Result<(), TryRuntimeError> {
let mut last_score: ElectionScore = Default::default();
let indices = <SignedSubmissionIndices<T>>::get();
for (i, indice) in indices.iter().enumerate() {
let submission = <SignedSubmissionsMap<T>>::get(indice.2);
if submission.is_none() {
return Err("All signed submissions indices must be part of the submissions map")
return Err(
"All signed submissions indices must be part of the submissions map".into()
)
}
if i == 0 {
last_score = indice.0
} else {
if last_score.strict_threshold_better(indice.0, Perbill::zero()) {
return Err("Signed submission indices vector must be ordered by election score")
return Err(
"Signed submission indices vector must be ordered by election score".into()
)
}
last_score = indice.0;
}
}
if <SignedSubmissionsMap<T>>::iter().nth(indices.len()).is_some() {
return Err("Signed submissions map length should be the same as the indices vec length")
return Err(
"Signed submissions map length should be the same as the indices vec length".into()
)
}
match <SignedSubmissionNextIndex<T>>::get() {
@@ -1637,7 +1646,8 @@ impl<T: Config> Pallet<T> {
next =>
if <SignedSubmissionsMap<T>>::get(next).is_some() {
return Err(
"The next submissions index should not be in the submissions maps already",
"The next submissions index should not be in the submissions maps already"
.into(),
)
} else {
Ok(())
@@ -1647,12 +1657,12 @@ impl<T: Config> Pallet<T> {
// [`Phase::Off`] state check. Invariants:
// - If phase is `Phase::Off`, [`Snapshot`] must be none.
fn try_state_phase_off() -> Result<(), &'static str> {
fn try_state_phase_off() -> Result<(), TryRuntimeError> {
match Self::current_phase().is_off() {
false => Ok(()),
true =>
if <Snapshot<T>>::get().is_some() {
Err("Snapshot must be none when in Phase::Off")
Err("Snapshot must be none when in Phase::Off".into())
} else {
Ok(())
},
@@ -189,6 +189,9 @@ pub use sp_npos_elections::{
};
pub use traits::NposSolution;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
// re-export for the solution macro, with the dependencies of the macro.
#[doc(hidden)]
pub use codec;
@@ -564,7 +567,7 @@ pub trait SortedListProvider<AccountId> {
/// Check internal state of the list. Only meant for debugging.
#[cfg(feature = "try-runtime")]
fn try_state() -> Result<(), &'static str>;
fn try_state() -> Result<(), TryRuntimeError>;
/// If `who` changes by the returned amount they are guaranteed to have a worst case change
/// in their list position.
+19 -14
View File
@@ -115,6 +115,9 @@ use sp_runtime::{
};
use sp_std::{cmp::Ordering, prelude::*};
#[cfg(any(feature = "try-runtime", test))]
use sp_runtime::TryRuntimeError;
mod benchmarking;
pub mod weights;
pub use weights::WeightInfo;
@@ -327,7 +330,7 @@ pub mod pallet {
}
#[cfg(feature = "try-runtime")]
fn try_state(_n: T::BlockNumber) -> Result<(), &'static str> {
fn try_state(_n: T::BlockNumber) -> Result<(), TryRuntimeError> {
Self::do_try_state()
}
}
@@ -1193,7 +1196,7 @@ impl<T: Config> ContainsLengthBound for Pallet<T> {
#[cfg(any(feature = "try-runtime", test))]
impl<T: Config> Pallet<T> {
fn do_try_state() -> Result<(), &'static str> {
fn do_try_state() -> Result<(), TryRuntimeError> {
Self::try_state_members()?;
Self::try_state_runners_up()?;
Self::try_state_candidates()?;
@@ -1204,20 +1207,20 @@ impl<T: Config> Pallet<T> {
/// [`Members`] state checks. Invariants:
/// - Members are always sorted based on account ID.
fn try_state_members() -> Result<(), &'static str> {
fn try_state_members() -> Result<(), TryRuntimeError> {
let mut members = Members::<T>::get().clone();
members.sort_by_key(|m| m.who.clone());
if Members::<T>::get() == members {
Ok(())
} else {
Err("try_state checks: Members must be always sorted by account ID")
Err("try_state checks: Members must be always sorted by account ID".into())
}
}
// [`RunnersUp`] state checks. Invariants:
// - Elements are sorted based on weight (worst to best).
fn try_state_runners_up() -> Result<(), &'static str> {
fn try_state_runners_up() -> Result<(), TryRuntimeError> {
let mut sorted = RunnersUp::<T>::get();
// worst stake first
sorted.sort_by(|a, b| a.stake.cmp(&b.stake));
@@ -1225,27 +1228,28 @@ impl<T: Config> Pallet<T> {
if RunnersUp::<T>::get() == sorted {
Ok(())
} else {
Err("try_state checks: Runners Up must always be sorted by stake (worst to best)")
Err("try_state checks: Runners Up must always be sorted by stake (worst to best)"
.into())
}
}
// [`Candidates`] state checks. Invariants:
// - Always sorted based on account ID.
fn try_state_candidates() -> Result<(), &'static str> {
fn try_state_candidates() -> Result<(), TryRuntimeError> {
let mut candidates = Candidates::<T>::get().clone();
candidates.sort_by_key(|(c, _)| c.clone());
if Candidates::<T>::get() == candidates {
Ok(())
} else {
Err("try_state checks: Candidates must be always sorted by account ID")
Err("try_state checks: Candidates must be always sorted by account ID".into())
}
}
// [`Candidates`] and [`RunnersUp`] state checks. Invariants:
// - Candidates and runners-ups sets are disjoint.
fn try_state_candidates_runners_up_disjoint() -> Result<(), &'static str> {
fn try_state_candidates_runners_up_disjoint() -> Result<(), TryRuntimeError> {
match Self::intersects(&Self::candidates_ids(), &Self::runners_up_ids()) {
true => Err("Candidates and runners up sets should always be disjoint"),
true => Err("Candidates and runners up sets should always be disjoint".into()),
false => Ok(()),
}
}
@@ -1253,11 +1257,12 @@ impl<T: Config> Pallet<T> {
// [`Members`], [`Candidates`] and [`RunnersUp`] state checks. Invariants:
// - Members and candidates sets are disjoint;
// - Members and runners-ups sets are disjoint.
fn try_state_members_disjoint() -> Result<(), &'static str> {
fn try_state_members_disjoint() -> Result<(), TryRuntimeError> {
match Self::intersects(&Pallet::<T>::members_ids(), &Self::candidates_ids()) &&
Self::intersects(&Pallet::<T>::members_ids(), &Self::runners_up_ids())
{
true => Err("Members set should be disjoint from candidates and runners-up sets"),
true =>
Err("Members set should be disjoint from candidates and runners-up sets".into()),
false => Ok(()),
}
}
@@ -1265,14 +1270,14 @@ impl<T: Config> Pallet<T> {
// [`Members`], [`RunnersUp`] and approval stake state checks. Invariants:
// - Selected members should have approval stake;
// - Selected RunnersUp should have approval stake.
fn try_state_members_approval_stake() -> Result<(), &'static str> {
fn try_state_members_approval_stake() -> Result<(), TryRuntimeError> {
match Members::<T>::get()
.iter()
.chain(RunnersUp::<T>::get().iter())
.all(|s| s.stake != BalanceOf::<T>::zero())
{
true => Ok(()),
false => Err("Members and RunnersUp must have approval stake"),
false => Err("Members and RunnersUp must have approval stake".into()),
}
}
+4 -1
View File
@@ -137,6 +137,9 @@ use sp_runtime::{
};
use sp_std::{marker::PhantomData, prelude::*};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
#[allow(dead_code)]
const LOG_TARGET: &str = "runtime::executive";
@@ -338,7 +341,7 @@ where
/// `true`. Also, if set to `true`, it runs the `pre_upgrade` and `post_upgrade` hooks.
pub fn try_runtime_upgrade(
checks: frame_try_runtime::UpgradeCheckSelect,
) -> Result<Weight, &'static str> {
) -> Result<Weight, TryRuntimeError> {
if checks.try_state() {
let _guard = frame_support::StorageNoopGuard::default();
<AllPalletsWithSystem as frame_support::traits::TryState<System::BlockNumber>>::try_state(
+5 -2
View File
@@ -91,6 +91,9 @@ pub mod pallet {
use sp_std::{prelude::*, vec::Vec};
pub use weights::WeightInfo;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
#[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)]
#[codec(mel_bound(T: Config))]
#[scale_info(skip_type_params(T))]
@@ -228,10 +231,10 @@ pub mod pallet {
}
#[cfg(feature = "try-runtime")]
fn try_state(_n: T::BlockNumber) -> Result<(), &'static str> {
fn try_state(_n: T::BlockNumber) -> Result<(), TryRuntimeError> {
// ensure that the value of `ErasToCheckPerBlock` is less than
// `T::MaxErasToCheckPerBlock`.
assert!(
ensure!(
ErasToCheckPerBlock::<T>::get() <= T::MaxErasToCheckPerBlock::get(),
"the value of `ErasToCheckPerBlock` is greater than `T::MaxErasToCheckPerBlock`",
);
+15 -4
View File
@@ -25,6 +25,11 @@ pub mod v1 {
use sp_staking::EraIndex;
use sp_std::prelude::*;
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
fn on_runtime_upgrade() -> Weight {
@@ -65,14 +70,20 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(Pallet::<T>::on_chain_storage_version(), 0);
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(
Pallet::<T>::on_chain_storage_version() == 0,
"The onchain storage version must be zero for the migration to execute."
);
Ok(Default::default())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(Pallet::<T>::on_chain_storage_version(), 1);
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
ensure!(
Pallet::<T>::on_chain_storage_version() == 1,
"The onchain version must be updated after the migration."
);
Ok(())
}
}
+2 -2
View File
@@ -43,7 +43,7 @@ pub mod v1 {
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain < 1, "this migration can be deleted");
@@ -72,7 +72,7 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain < 2, "this migration needs to be removed");
ensure!(onchain == 1, "this migration needs to be run");
+7 -4
View File
@@ -18,6 +18,9 @@
use super::*;
use frame_support::{log, traits::OnRuntimeUpgrade};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
pub mod v1 {
use frame_support::{pallet_prelude::*, weights::Weight};
@@ -90,7 +93,7 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
let current_version = Pallet::<T>::current_storage_version();
let onchain_version = Pallet::<T>::on_chain_storage_version();
ensure!(onchain_version == 0 && current_version == 1, "migration from version 0 to 1.");
@@ -99,13 +102,13 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), TryRuntimeError> {
let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect(
"the state parameter should be something that was generated by pre_upgrade",
);
let post_count = Collection::<T>::iter().count() as u32;
assert_eq!(
prev_count, post_count,
ensure!(
prev_count == post_count,
"the records count before and after the migration should be the same"
);
+52 -25
View File
@@ -378,6 +378,9 @@ use sp_runtime::{
use sp_staking::{EraIndex, OnStakerSlash, StakingInterface};
use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
#[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
use sp_runtime::TryRuntimeError;
/// The log target of this pallet.
pub const LOG_TARGET: &str = "runtime::nomination-pools";
@@ -2626,7 +2629,7 @@ pub mod pallet {
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
#[cfg(feature = "try-runtime")]
fn try_state(_n: BlockNumberFor<T>) -> Result<(), &'static str> {
fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
Self::do_try_state(u8::MAX)
}
@@ -3055,7 +3058,7 @@ impl<T: Config> Pallet<T> {
/// multiple `level`s, where the higher the level, the more checks we performs. So,
/// `try_state(255)` is the strongest sanity check, and `0` performs no checks.
#[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
pub fn do_try_state(level: u8) -> Result<(), &'static str> {
pub fn do_try_state(level: u8) -> Result<(), TryRuntimeError> {
if level.is_zero() {
return Ok(())
}
@@ -3063,12 +3066,24 @@ impl<T: Config> Pallet<T> {
// result in the same set of keys, in the same order.
let bonded_pools = BondedPools::<T>::iter_keys().collect::<Vec<_>>();
let reward_pools = RewardPools::<T>::iter_keys().collect::<Vec<_>>();
assert_eq!(bonded_pools, reward_pools);
ensure!(
bonded_pools == reward_pools,
"`BondedPools` and `RewardPools` must all have the EXACT SAME key-set."
);
assert!(Metadata::<T>::iter_keys().all(|k| bonded_pools.contains(&k)));
assert!(SubPoolsStorage::<T>::iter_keys().all(|k| bonded_pools.contains(&k)));
ensure!(
SubPoolsStorage::<T>::iter_keys().all(|k| bonded_pools.contains(&k)),
"`SubPoolsStorage` must be a subset of the above superset."
);
ensure!(
Metadata::<T>::iter_keys().all(|k| bonded_pools.contains(&k)),
"`Metadata` keys must be a subset of the above superset."
);
assert!(MaxPools::<T>::get().map_or(true, |max| bonded_pools.len() <= (max as usize)));
ensure!(
MaxPools::<T>::get().map_or(true, |max| bonded_pools.len() <= (max as usize)),
Error::<T>::MaxPools
);
for id in reward_pools {
let account = Self::create_reward_account(id);
@@ -3088,9 +3103,9 @@ impl<T: Config> Pallet<T> {
let mut pools_members = BTreeMap::<PoolId, u32>::new();
let mut pools_members_pending_rewards = BTreeMap::<PoolId, BalanceOf<T>>::new();
let mut all_members = 0u32;
PoolMembers::<T>::iter().for_each(|(_, d)| {
PoolMembers::<T>::iter().try_for_each(|(_, d)| -> Result<(), TryRuntimeError> {
let bonded_pool = BondedPools::<T>::get(d.pool_id).unwrap();
assert!(!d.total_points().is_zero(), "no member should have zero points: {d:?}");
ensure!(!d.total_points().is_zero(), "No member should have zero points");
*pools_members.entry(d.pool_id).or_default() += 1;
all_members += 1;
@@ -3103,9 +3118,11 @@ impl<T: Config> Pallet<T> {
let pending_rewards = d.pending_rewards(current_rc).unwrap();
*pools_members_pending_rewards.entry(d.pool_id).or_default() += pending_rewards;
} // else this pool has been heavily slashed and cannot have any rewards anymore.
});
RewardPools::<T>::iter_keys().for_each(|id| {
Ok(())
})?;
RewardPools::<T>::iter_keys().try_for_each(|id| -> Result<(), TryRuntimeError> {
// the sum of the pending rewards must be less than the leftover balance. Since the
// reward math rounds down, we might accumulate some dust here.
log!(
@@ -3115,30 +3132,40 @@ impl<T: Config> Pallet<T> {
pools_members_pending_rewards.get(&id),
RewardPool::<T>::current_balance(id)
);
assert!(
ensure!(
RewardPool::<T>::current_balance(id) >=
pools_members_pending_rewards.get(&id).copied().unwrap_or_default()
)
});
BondedPools::<T>::iter().for_each(|(id, inner)| {
let bonded_pool = BondedPool { id, inner };
assert_eq!(
pools_members.get(&id).copied().unwrap_or_default(),
bonded_pool.member_counter
pools_members_pending_rewards.get(&id).copied().unwrap_or_default(),
"The sum of the pending rewards must be less than the leftover balance."
);
Ok(())
})?;
BondedPools::<T>::iter().try_for_each(|(id, inner)| -> Result<(), TryRuntimeError> {
let bonded_pool = BondedPool { id, inner };
ensure!(
pools_members.get(&id).copied().unwrap_or_default() ==
bonded_pool.member_counter,
"Each `BondedPool.member_counter` must be equal to the actual count of members of this pool"
);
ensure!(
MaxPoolMembersPerPool::<T>::get()
.map_or(true, |max| bonded_pool.member_counter <= max),
Error::<T>::MaxPoolMembers
);
assert!(MaxPoolMembersPerPool::<T>::get()
.map_or(true, |max| bonded_pool.member_counter <= max));
let depositor = PoolMembers::<T>::get(&bonded_pool.roles.depositor).unwrap();
assert!(
ensure!(
bonded_pool.is_destroying_and_only_depositor(depositor.active_points()) ||
depositor.active_points() >= MinCreateBond::<T>::get(),
"depositor must always have MinCreateBond stake in the pool, except for when the \
pool is being destroyed and the depositor is the last member",
);
});
assert!(MaxPoolMembers::<T>::get().map_or(true, |max| all_members <= max));
Ok(())
})?;
ensure!(
MaxPoolMembers::<T>::get().map_or(true, |max| all_members <= max),
Error::<T>::MaxPoolMembers
);
if level <= 1 {
return Ok(())
@@ -20,6 +20,9 @@ use crate::log;
use frame_support::traits::OnRuntimeUpgrade;
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
pub mod v1 {
use super::*;
@@ -100,9 +103,12 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
// new version must be set.
assert_eq!(Pallet::<T>::on_chain_storage_version(), 1);
ensure!(
Pallet::<T>::on_chain_storage_version() == 1,
"The onchain version must be updated after the migration."
);
Pallet::<T>::try_state(frame_system::Pallet::<T>::block_number())?;
Ok(())
}
@@ -352,38 +358,47 @@ pub mod v2 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
// all reward accounts must have more than ED.
RewardPools::<T>::iter().for_each(|(id, _)| {
assert!(
RewardPools::<T>::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> {
ensure!(
T::Currency::free_balance(&Pallet::<T>::create_reward_account(id)) >=
T::Currency::minimum_balance()
)
});
T::Currency::minimum_balance(),
"Reward accounts must have greater balance than ED."
);
Ok(())
})?;
Ok(Vec::new())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
// new version must be set.
assert_eq!(Pallet::<T>::on_chain_storage_version(), 2);
ensure!(
Pallet::<T>::on_chain_storage_version() == 2,
"The onchain version must be updated after the migration."
);
// no reward or bonded pool has been skipped.
assert_eq!(RewardPools::<T>::iter().count() as u32, RewardPools::<T>::count());
assert_eq!(BondedPools::<T>::iter().count() as u32, BondedPools::<T>::count());
ensure!(
RewardPools::<T>::iter().count() as u32 == RewardPools::<T>::count(),
"The count of reward pools must remain the same after the migration."
);
ensure!(
BondedPools::<T>::iter().count() as u32 == BondedPools::<T>::count(),
"The count of reward pools must remain the same after the migration."
);
// all reward pools must have exactly ED in them. This means no reward can be claimed,
// and that setting reward counters all over the board to zero will work henceforth.
RewardPools::<T>::iter().for_each(|(id, _)| {
assert_eq!(
RewardPool::<T>::current_balance(id),
Zero::zero(),
"reward pool({}) balance is {:?}",
id,
RewardPool::<T>::current_balance(id)
RewardPools::<T>::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> {
ensure!(
RewardPool::<T>::current_balance(id) == Zero::zero(),
"Reward pool balance must be zero.",
);
});
Ok(())
})?;
log!(info, "post upgrade hook for MigrateToV2 executed.");
Ok(())
@@ -435,7 +450,7 @@ pub mod v3 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(
Pallet::<T>::current_storage_version() > Pallet::<T>::on_chain_storage_version(),
"the on_chain version is equal or more than the current one"
@@ -444,7 +459,7 @@ pub mod v3 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
ensure!(
Metadata::<T>::iter_keys().all(|id| BondedPools::<T>::contains_key(&id)),
"not all of the stale metadata has been removed"
@@ -535,7 +550,7 @@ pub mod v4 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(
Pallet::<T>::current_storage_version() > Pallet::<T>::on_chain_storage_version(),
"the on_chain version is equal or more than the current one"
@@ -544,7 +559,7 @@ pub mod v4 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
// ensure all BondedPools items now contain an `inner.commission: Commission` field.
ensure!(
BondedPools::<T>::iter().all(|(_, inner)| inner.commission.current.is_none() &&
@@ -620,7 +635,7 @@ pub mod v5 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(
Pallet::<T>::current_storage_version() > Pallet::<T>::on_chain_storage_version(),
"the on_chain version is equal or more than the current one"
@@ -654,7 +669,7 @@ pub mod v5 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(data: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(data: Vec<u8>) -> Result<(), TryRuntimeError> {
let old_rpool_values: u64 = Decode::decode(&mut &data[..]).unwrap();
let rpool_keys = RewardPools::<T>::iter_keys().count() as u64;
let rpool_values = RewardPools::<T>::iter_values().count() as u64;
@@ -4269,10 +4269,7 @@ mod create {
assert!(!BondedPools::<Runtime>::contains_key(2));
assert!(!RewardPools::<Runtime>::contains_key(2));
assert!(!PoolMembers::<Runtime>::contains_key(11));
assert_err!(
StakingMock::active_stake(&next_pool_stash),
DispatchError::Other("balance not found")
);
assert_err!(StakingMock::active_stake(&next_pool_stash), "balance not found");
Balances::make_free_balance_be(&11, StakingMock::minimum_nominator_bond() + ed);
assert_ok!(Pools::create(
+4 -2
View File
@@ -29,6 +29,8 @@ use sp_std::vec::Vec;
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
mod v0 {
use super::*;
@@ -51,7 +53,7 @@ pub mod v1 {
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain < 1, "pallet_offences::MigrateToV1 migration can be deleted");
@@ -81,7 +83,7 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain == 1, "pallet_offences::MigrateToV1 needs to be run");
ensure!(
+9 -4
View File
@@ -24,6 +24,11 @@ use frame_support::{
};
use sp_std::collections::btree_map::BTreeMap;
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// The log target.
const TARGET: &'static str = "runtime::preimage::migration::v1";
@@ -78,8 +83,8 @@ pub mod v1 {
impl<T: Config> OnRuntimeUpgrade for Migration<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 0, "can only upgrade from version 0");
let images = v0::image_count::<T>().expect("v0 storage corrupted");
log::info!(target: TARGET, "Migrating {} images", &images);
@@ -148,7 +153,7 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(state: Vec<u8>) -> DispatchResult {
let old_images: u32 =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_images = image_count::<T>().expect("V1 storage corrupted");
@@ -161,7 +166,7 @@ pub mod v1 {
old_images
);
}
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
ensure!(StorageVersion::get::<Pallet<T>>() == 1, "must upgrade");
Ok(())
}
}
+8 -8
View File
@@ -22,6 +22,9 @@ use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade};
use log;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// Initial version of storage types.
pub mod v0 {
use super::*;
@@ -95,9 +98,9 @@ pub mod v1 {
pub struct MigrateV0ToV1<T, I = ()>(PhantomData<(T, I)>);
impl<T: Config<I>, I: 'static> OnRuntimeUpgrade for MigrateV0ToV1<T, I> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
assert_eq!(onchain_version, 0, "migration from version 0 to 1.");
ensure!(onchain_version == 0, "migration from version 0 to 1.");
let referendum_count = v0::ReferendumInfoFor::<T, I>::iter().count();
log::info!(
target: TARGET,
@@ -147,16 +150,13 @@ pub mod v1 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
assert_eq!(onchain_version, 1, "must upgrade from version 0 to 1.");
ensure!(onchain_version == 1, "must upgrade from version 0 to 1.");
let pre_referendum_count: u32 = Decode::decode(&mut &state[..])
.expect("failed to decode the state from pre-upgrade.");
let post_referendum_count = ReferendumInfoFor::<T, I>::iter().count() as u32;
assert_eq!(
post_referendum_count, pre_referendum_count,
"must migrate all referendums."
);
ensure!(post_referendum_count == pre_referendum_count, "must migrate all referendums.");
log::info!(target: TARGET, "migrated all referendums.");
Ok(())
}
+15 -12
View File
@@ -20,6 +20,9 @@
use super::*;
use frame_support::traits::OnRuntimeUpgrade;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// The log target.
const TARGET: &'static str = "runtime::scheduler::migration";
@@ -97,8 +100,8 @@ pub mod v3 {
impl<T: Config<Hash = PreimageHash>> OnRuntimeUpgrade for MigrateToV4<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 3, "Can only upgrade from version 3");
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 3, "Can only upgrade from version 3");
let agendas = Agenda::<T>::iter_keys().count() as u32;
let decodable_agendas = Agenda::<T>::iter_values().count() as u32;
@@ -125,7 +128,7 @@ pub mod v3 {
agenda.len(),
max_scheduled_per_block,
);
return Err("Agenda would overflow `MaxScheduledPerBlock`.")
return Err("Agenda would overflow `MaxScheduledPerBlock`.".into())
}
}
// Check that bounding the calls will not overflow `MAX_LENGTH`.
@@ -142,7 +145,7 @@ pub mod v3 {
block_number,
l,
);
return Err("Call is too large.")
return Err("Call is too large.".into())
}
},
_ => (),
@@ -169,12 +172,12 @@ pub mod v3 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 4, "Must upgrade");
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 4, "Must upgrade");
// Check that everything decoded fine.
for k in crate::Agenda::<T>::iter_keys() {
assert!(crate::Agenda::<T>::try_get(k).is_ok(), "Cannot decode V4 Agenda");
ensure!(crate::Agenda::<T>::try_get(k).is_ok(), "Cannot decode V4 Agenda");
}
let old_agendas: u32 =
@@ -210,7 +213,7 @@ pub mod v4 {
impl<T: Config> OnRuntimeUpgrade for CleanupAgendas<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
assert_eq!(
StorageVersion::get::<Pallet<T>>(),
4,
@@ -285,8 +288,8 @@ pub mod v4 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 4, "Version must not change");
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
ensure!(StorageVersion::get::<Pallet<T>>() == 4, "Version must not change");
let (old_agendas, non_empty_agendas): (u32, u32) =
Decode::decode(&mut state.as_ref()).expect("Must decode pre_upgrade state");
@@ -305,7 +308,7 @@ pub mod v4 {
old_agendas, new_agendas
),
}
assert_eq!(new_agendas, non_empty_agendas, "Expected to keep all non-empty agendas");
ensure!(new_agendas == non_empty_agendas, "Expected to keep all non-empty agendas");
Ok(())
}
@@ -496,7 +499,7 @@ mod test {
// The pre_upgrade hook fails:
let err = v3::MigrateToV4::<Test>::pre_upgrade().unwrap_err();
assert!(err.contains("Call is too large"));
assert!(err == "Call is too large".into());
// But the migration itself works:
let _w = v3::MigrateToV4::<Test>::on_runtime_upgrade();
+19 -10
View File
@@ -23,6 +23,11 @@ use frame_support::{
traits::OnRuntimeUpgrade,
};
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// Used for release versioning upto v12.
///
/// Obsolete from v13. Keeping around to make encoding/decoding of old migration code easier.
@@ -58,7 +63,7 @@ pub mod v13 {
pub struct MigrateToV13<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV13<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V12_0_0,
"Required v12 before upgrading to v13"
@@ -84,7 +89,7 @@ pub mod v13 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
frame_support::ensure!(
Pallet::<T>::on_chain_storage_version() == 13,
"v13 not applied"
@@ -114,7 +119,7 @@ pub mod v12 {
pub struct MigrateToV12<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV12<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V11_0_0,
"Expected v11 before upgrading to v12"
@@ -146,7 +151,7 @@ pub mod v12 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V12_0_0,
"v12 not applied"
@@ -170,7 +175,7 @@ pub mod v11 {
for MigrateToV11<T, P, N>
{
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V10_0_0,
"must upgrade linearly"
@@ -217,7 +222,7 @@ pub mod v11 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V11_0_0,
"wrong version after the upgrade"
@@ -332,7 +337,7 @@ pub mod v9 {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V8_0_0,
"must upgrade linearly"
@@ -343,17 +348,21 @@ pub mod v9 {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(prev_count: Vec<u8>) -> Result<(), TryRuntimeError> {
let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect(
"the state parameter should be something that was generated by pre_upgrade",
);
let post_count = T::VoterList::count();
let validators = Validators::<T>::count();
assert!(post_count == prev_count + validators);
ensure!(
post_count == prev_count + validators,
"`VoterList` count after the migration must equal to the sum of \
previous count and the current number of validators"
);
frame_support::ensure!(
StorageVersion::<T>::get() == ObsoleteReleases::V9_0_0,
"must upgrade "
"must upgrade"
);
Ok(())
}
+28 -16
View File
@@ -51,6 +51,11 @@ use crate::{
use super::{pallet::*, STAKING_ID};
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
#[cfg(any(test, feature = "try-runtime"))]
use sp_runtime::TryRuntimeError;
/// The maximum number of iterations that we do whilst iterating over `T::VoterList` in
/// `get_npos_voters`.
///
@@ -1467,7 +1472,7 @@ impl<T: Config> SortedListProvider<T::AccountId> for UseValidatorsMap<T> {
0
}
#[cfg(feature = "try-runtime")]
fn try_state() -> Result<(), &'static str> {
fn try_state() -> Result<(), TryRuntimeError> {
Ok(())
}
@@ -1544,7 +1549,7 @@ impl<T: Config> SortedListProvider<T::AccountId> for UseNominatorsAndValidatorsM
}
#[cfg(feature = "try-runtime")]
fn try_state() -> Result<(), &'static str> {
fn try_state() -> Result<(), TryRuntimeError> {
Ok(())
}
@@ -1713,7 +1718,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
#[cfg(any(test, feature = "try-runtime"))]
impl<T: Config> Pallet<T> {
pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), &'static str> {
pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
ensure!(
T::VoterList::iter()
.all(|x| <Nominators<T>>::contains_key(&x) || <Validators<T>>::contains_key(&x)),
@@ -1726,7 +1731,7 @@ impl<T: Config> Pallet<T> {
Self::check_count()
}
fn check_count() -> Result<(), &'static str> {
fn check_count() -> Result<(), TryRuntimeError> {
ensure!(
<T as Config>::VoterList::count() ==
Nominators::<T>::count() + Validators::<T>::count(),
@@ -1739,18 +1744,19 @@ impl<T: Config> Pallet<T> {
ensure!(
ValidatorCount::<T>::get() <=
<T::ElectionProvider as frame_election_provider_support::ElectionProviderBase>::MaxWinners::get(),
"validator count exceeded election max winners"
Error::<T>::TooManyValidators
);
Ok(())
}
fn check_ledgers() -> Result<(), &'static str> {
fn check_ledgers() -> Result<(), TryRuntimeError> {
Bonded::<T>::iter()
.map(|(_, ctrl)| Self::ensure_ledger_consistent(ctrl))
.collect::<Result<_, _>>()
.collect::<Result<Vec<_>, _>>()?;
Ok(())
}
fn check_exposures() -> Result<(), &'static str> {
fn check_exposures() -> Result<(), TryRuntimeError> {
// a check per validator to ensure the exposure struct is always sane.
let era = Self::active_era().unwrap().index;
ErasStakers::<T>::iter_prefix_values(era)
@@ -1766,10 +1772,10 @@ impl<T: Config> Pallet<T> {
);
Ok(())
})
.collect::<Result<_, _>>()
.collect::<Result<(), TryRuntimeError>>()
}
fn check_nominators() -> Result<(), &'static str> {
fn check_nominators() -> Result<(), TryRuntimeError> {
// a check per nominator to ensure their entire stake is correctly distributed. Will only
// kick-in if the nomination was submitted before the current era.
let era = Self::active_era().unwrap().index;
@@ -1783,27 +1789,33 @@ impl<T: Config> Pallet<T> {
}
},
)
.map(|nominator| {
.map(|nominator| -> Result<(), TryRuntimeError> {
// must be bonded.
Self::ensure_is_stash(&nominator)?;
let mut sum = BalanceOf::<T>::zero();
T::SessionInterface::validators()
.iter()
.map(|v| Self::eras_stakers(era, v))
.map(|e| {
.map(|e| -> Result<(), TryRuntimeError> {
let individual =
e.others.iter().filter(|e| e.who == nominator).collect::<Vec<_>>();
let len = individual.len();
match len {
0 => { /* not supporting this validator at all. */ },
1 => sum += individual[0].value,
_ => return Err("nominator cannot back a validator more than once."),
_ =>
return Err(
"nominator cannot back a validator more than once.".into()
),
};
Ok(())
})
.collect::<Result<_, _>>()
.collect::<Result<Vec<_>, _>>()?;
Ok(())
})
.collect::<Result<_, _>>()
.collect::<Result<Vec<_>, _>>()?;
Ok(())
}
fn ensure_is_stash(who: &T::AccountId) -> Result<(), &'static str> {
@@ -1811,7 +1823,7 @@ impl<T: Config> Pallet<T> {
Ok(())
}
fn ensure_ledger_consistent(ctrl: T::AccountId) -> Result<(), &'static str> {
fn ensure_ledger_consistent(ctrl: T::AccountId) -> Result<(), TryRuntimeError> {
// ensures ledger.total == ledger.active + sum(ledger.unlocking).
let ledger = Self::ledger(ctrl.clone()).ok_or("Not a controller.")?;
let real_total: BalanceOf<T> =
+1 -1
View File
@@ -805,7 +805,7 @@ pub mod pallet {
}
#[cfg(feature = "try-runtime")]
fn try_state(n: BlockNumberFor<T>) -> Result<(), &'static str> {
fn try_state(n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
Self::do_try_state(n)
}
}
@@ -105,7 +105,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
current_version,
);
return Err("On chain and current storage version do not match. Missing runtime upgrade?");
return Err("On chain and current storage version do not match. Missing runtime upgrade?".into());
}
}
} else {
@@ -128,7 +128,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
);
return Err("On chain storage version set, while the pallet doesn't \
have the `#[pallet::storage_version(VERSION)]` attribute.");
have the `#[pallet::storage_version(VERSION)]` attribute.".into());
}
}
};
@@ -211,7 +211,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<#frame_support::sp_std::vec::Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<#frame_support::sp_std::vec::Vec<u8>, #frame_support::sp_runtime::TryRuntimeError> {
<
Self
as
@@ -220,7 +220,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: #frame_support::sp_std::vec::Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(state: #frame_support::sp_std::vec::Vec<u8>) -> Result<(), #frame_support::sp_runtime::TryRuntimeError> {
#post_storage_version_check
<
@@ -268,7 +268,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
fn try_state(
n: <T as #frame_system::Config>::BlockNumber,
_s: #frame_support::traits::TryStateSelect
) -> Result<(), &'static str> {
) -> Result<(), #frame_support::sp_runtime::TryRuntimeError> {
#log_try_state
<
Self as #frame_support::traits::Hooks<
+5 -5
View File
@@ -2097,7 +2097,7 @@ macro_rules! decl_module {
fn try_state(
_: <$trait_instance as $system::Config>::BlockNumber,
_: $crate::traits::TryStateSelect,
) -> Result<(), &'static str> {
) -> Result<(), $crate::sp_runtime::TryRuntimeError> {
let pallet_name = <<
$trait_instance
as
@@ -2144,12 +2144,12 @@ macro_rules! decl_module {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec<u8>, $crate::sp_runtime::TryRuntimeError> {
Ok($crate::sp_std::vec::Vec::new())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: $crate::sp_std::vec::Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: $crate::sp_std::vec::Vec<u8>) -> Result<(), $crate::sp_runtime::TryRuntimeError> {
Ok(())
}
}
@@ -2182,12 +2182,12 @@ macro_rules! decl_module {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec<u8>, $crate::sp_runtime::TryRuntimeError> {
Ok($crate::sp_std::vec::Vec::new())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: $crate::sp_std::vec::Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: $crate::sp_std::vec::Vec<u8>) -> Result<(), $crate::sp_runtime::TryRuntimeError> {
Ok(())
}
}
+3 -3
View File
@@ -184,7 +184,7 @@ impl<P: Get<&'static str>, DbWeight: Get<RuntimeDbWeight>> frame_support::traits
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
let hashed_prefix = twox_128(P::get().as_bytes());
match contains_prefixed_key(&hashed_prefix) {
true => log::info!("Found {} keys pre-removal 👀", P::get()),
@@ -197,12 +197,12 @@ impl<P: Get<&'static str>, DbWeight: Get<RuntimeDbWeight>> frame_support::traits
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
let hashed_prefix = twox_128(P::get().as_bytes());
match contains_prefixed_key(&hashed_prefix) {
true => {
log::error!("{} has keys remaining post-removal ❗", P::get());
return Err("Keys remaining post-removal, this should never happen 🚨")
return Err("Keys remaining post-removal, this should never happen 🚨".into())
},
false => log::info!("No {} keys found post-removal 🎉", P::get()),
};
+14 -11
View File
@@ -22,6 +22,9 @@ use impl_trait_for_tuples::impl_for_tuples;
use sp_runtime::traits::AtLeast32BitUnsigned;
use sp_std::prelude::*;
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
/// The block initialization trait.
///
/// Implementing this lets you express what should happen for your pallet when the block is
@@ -136,7 +139,7 @@ pub trait OnRuntimeUpgrade {
/// Same as `on_runtime_upgrade`, but perform the optional `pre_upgrade` and `post_upgrade` as
/// well.
#[cfg(feature = "try-runtime")]
fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, &'static str> {
fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, TryRuntimeError> {
let maybe_state = if checks {
let _guard = frame_support::StorageNoopGuard::default();
let state = Self::pre_upgrade()?;
@@ -167,7 +170,7 @@ pub trait OnRuntimeUpgrade {
/// This hook must not write to any state, as it would make the main `on_runtime_upgrade` path
/// inaccurate.
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
Ok(Vec::new())
}
@@ -182,7 +185,7 @@ pub trait OnRuntimeUpgrade {
/// This hook must not write to any state, as it would make the main `on_runtime_upgrade` path
/// inaccurate.
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
Ok(())
}
}
@@ -201,7 +204,7 @@ impl OnRuntimeUpgrade for Tuple {
/// consecutive migrations for the same pallet without errors. Therefore pre and post upgrade
/// hooks for tuples are a noop.
#[cfg(feature = "try-runtime")]
fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, &'static str> {
fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, TryRuntimeError> {
let mut weight = Weight::zero();
let mut errors = Vec::new();
@@ -224,12 +227,12 @@ impl OnRuntimeUpgrade for Tuple {
errors.iter().for_each(|err| {
log::error!(
target: "try-runtime",
"{}",
"{:?}",
err
);
});
return Err("Detected multiple errors while executing `try_on_runtime_upgrade`, check the logs!")
return Err("Detected multiple errors while executing `try_on_runtime_upgrade`, check the logs!".into())
}
Ok(weight)
@@ -305,7 +308,7 @@ pub trait Hooks<BlockNumber> {
///
/// This hook should not alter any storage.
#[cfg(feature = "try-runtime")]
fn try_state(_n: BlockNumber) -> Result<(), &'static str> {
fn try_state(_n: BlockNumber) -> Result<(), TryRuntimeError> {
Ok(())
}
@@ -317,7 +320,7 @@ pub trait Hooks<BlockNumber> {
///
/// This hook is never meant to be executed on-chain but is meant to be used by testing tools.
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
Ok(Vec::new())
}
@@ -329,7 +332,7 @@ pub trait Hooks<BlockNumber> {
///
/// This hook is never meant to be executed on-chain but is meant to be used by testing tools.
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
Ok(())
}
@@ -411,13 +414,13 @@ mod tests {
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
Pre::mutate(|s| s.push(stringify!($name)));
Ok(Vec::new())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_: Vec<u8>) -> Result<(), &'static str> {
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
Post::mutate(|s| s.push(stringify!($name)));
Ok(())
}
@@ -19,6 +19,7 @@
use impl_trait_for_tuples::impl_for_tuples;
use sp_arithmetic::traits::AtLeast32BitUnsigned;
use sp_runtime::TryRuntimeError;
use sp_std::prelude::*;
/// Which state tests to execute.
@@ -129,7 +130,7 @@ impl core::str::FromStr for UpgradeCheckSelect {
/// This hook should not alter any storage.
pub trait TryState<BlockNumber> {
/// Execute the state checks.
fn try_state(_: BlockNumber, _: Select) -> Result<(), &'static str>;
fn try_state(_: BlockNumber, _: Select) -> Result<(), TryRuntimeError>;
}
#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
@@ -139,7 +140,7 @@ impl<BlockNumber: Clone + sp_std::fmt::Debug + AtLeast32BitUnsigned> TryState<Bl
for Tuple
{
for_tuples!( where #( Tuple: crate::traits::PalletInfoAccess )* );
fn try_state(n: BlockNumber, targets: Select) -> Result<(), &'static str> {
fn try_state(n: BlockNumber, targets: Select) -> Result<(), TryRuntimeError> {
match targets {
Select::None => Ok(()),
Select::All => {
@@ -148,7 +149,7 @@ impl<BlockNumber: Clone + sp_std::fmt::Debug + AtLeast32BitUnsigned> TryState<Bl
result
},
Select::RoundRobin(len) => {
let functions: &[fn(BlockNumber, Select) -> Result<(), &'static str>] =
let functions: &[fn(BlockNumber, Select) -> Result<(), TryRuntimeError>] =
&[for_tuples!(#( Tuple::try_state ),*)];
let skip = n.clone() % (functions.len() as u32).into();
let skip: u32 =
@@ -163,7 +164,7 @@ impl<BlockNumber: Clone + sp_std::fmt::Debug + AtLeast32BitUnsigned> TryState<Bl
Select::Only(ref pallet_names) => {
let try_state_fns: &[(
&'static str,
fn(BlockNumber, Select) -> Result<(), &'static str>,
fn(BlockNumber, Select) -> Result<(), TryRuntimeError>,
)] = &[for_tuples!(
#( (<Tuple as crate::traits::PalletInfoAccess>::name(), Tuple::try_state) ),*
)];
+11 -6
View File
@@ -2110,9 +2110,11 @@ fn post_runtime_upgrade_detects_storage_version_issues() {
// Call `on_genesis` to put the storage version of `Example` into the storage.
Example::on_genesis();
// The version isn't changed, we should detect it.
assert!(Executive::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost)
.unwrap_err()
.contains("On chain and current storage version do not match"));
assert!(
Executive::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost).unwrap_err() ==
"On chain and current storage version do not match. Missing runtime upgrade?"
.into()
);
});
TestExternalities::default().execute_with(|| {
@@ -2138,9 +2140,12 @@ fn post_runtime_upgrade_detects_storage_version_issues() {
// `CustomUpgradePallet4` will set a storage version for `Example4` while this doesn't has
// any storage version "enabled".
assert!(ExecutiveWithUpgradePallet4::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost)
.unwrap_err()
.contains("On chain storage version set, while the pallet doesn't"));
assert!(
ExecutiveWithUpgradePallet4::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost)
.unwrap_err() == "On chain storage version set, while the pallet \
doesn't have the `#[pallet::storage_version(VERSION)]` attribute."
.into()
);
});
}
+3
View File
@@ -784,6 +784,9 @@ pub type ApplyExtrinsicResult =
pub type ApplyExtrinsicResultWithInfo<T> =
Result<DispatchResultWithInfo<T>, transaction_validity::TransactionValidityError>;
/// The error type used as return type in try runtime hooks.
pub type TryRuntimeError = DispatchError;
/// Verify a signature on an encoded value in a lazy manner. This can be
/// an optimization if the signature scheme has an "unsigned" escape hash.
pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(
@@ -122,10 +122,10 @@
//!
//! ```ignore
//! #[cfg(feature = "try-runtime")]
//! fn pre_upgrade() -> Result<Vec<u8>, &'static str> {}
//! fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {}
//!
//! #[cfg(feature = "try-runtime")]
//! fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {}
//! fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {}
//! ```
//!
//! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`).
@@ -141,7 +141,7 @@
//!
//! ```ignore
//! #[cfg(feature = "try-runtime")]
//! fn try_state(_: BlockNumber) -> Result<(), &'static str> {}
//! fn try_state(_: BlockNumber) -> Result<(), TryRuntimeError> {}
//! ```
//!
//! which is called on numerous code paths in the try-runtime tool. These checks should ensure that