Skip to content

Commit f0e6d2a

Browse files
authored
Adding try_state hook for Treasury pallet (#1820)
This PR adds a `try_state` hook for the `Treasury` pallet. Part of #239.
1 parent 70d4907 commit f0e6d2a

File tree

3 files changed

+308
-40
lines changed

3 files changed

+308
-40
lines changed

substrate/frame/treasury/src/benchmarking.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,5 +336,9 @@ mod benchmarks {
336336
Ok(())
337337
}
338338

339-
impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test);
339+
impl_benchmark_test_suite!(
340+
Treasury,
341+
crate::tests::ExtBuilder::default().build(),
342+
crate::tests::Test
343+
);
340344
}

substrate/frame/treasury/src/lib.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ use sp_runtime::{
8989
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
9090

9191
use frame_support::{
92-
print,
92+
dispatch::{DispatchResult, DispatchResultWithPostInfo},
93+
ensure, print,
9394
traits::{
9495
tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced,
9596
ReservableCurrency, WithdrawReasons,
@@ -456,6 +457,14 @@ pub mod pallet {
456457
Weight::zero()
457458
}
458459
}
460+
461+
#[cfg(feature = "try-runtime")]
462+
fn try_state(
463+
_: frame_system::pallet_prelude::BlockNumberFor<T>,
464+
) -> Result<(), sp_runtime::TryRuntimeError> {
465+
Self::do_try_state()?;
466+
Ok(())
467+
}
459468
}
460469

461470
#[derive(Default)]
@@ -1020,6 +1029,85 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
10201029
// Must never be less than 0 but better be safe.
10211030
.saturating_sub(T::Currency::minimum_balance())
10221031
}
1032+
1033+
/// Ensure the correctness of the state of this pallet.
1034+
#[cfg(any(feature = "try-runtime", test))]
1035+
fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
1036+
Self::try_state_proposals()?;
1037+
Self::try_state_spends()?;
1038+
1039+
Ok(())
1040+
}
1041+
1042+
/// ### Invariants of proposal storage items
1043+
///
1044+
/// 1. [`ProposalCount`] >= Number of elements in [`Proposals`].
1045+
/// 2. Each entry in [`Proposals`] should be saved under a key stricly less than current
1046+
/// [`ProposalCount`].
1047+
/// 3. Each [`ProposalIndex`] contained in [`Approvals`] should exist in [`Proposals`].
1048+
/// Note, that this automatically implies [`Approvals`].count() <= [`Proposals`].count().
1049+
#[cfg(any(feature = "try-runtime", test))]
1050+
fn try_state_proposals() -> Result<(), sp_runtime::TryRuntimeError> {
1051+
let current_proposal_count = ProposalCount::<T, I>::get();
1052+
ensure!(
1053+
current_proposal_count as usize >= Proposals::<T, I>::iter().count(),
1054+
"Actual number of proposals exceeds `ProposalCount`."
1055+
);
1056+
1057+
Proposals::<T, I>::iter_keys().try_for_each(|proposal_index| -> DispatchResult {
1058+
ensure!(
1059+
current_proposal_count as u32 > proposal_index,
1060+
"`ProposalCount` should by strictly greater than any ProposalIndex used as a key for `Proposals`."
1061+
);
1062+
Ok(())
1063+
})?;
1064+
1065+
Approvals::<T, I>::get()
1066+
.iter()
1067+
.try_for_each(|proposal_index| -> DispatchResult {
1068+
ensure!(
1069+
Proposals::<T, I>::contains_key(proposal_index),
1070+
"Proposal indices in `Approvals` must also be contained in `Proposals`."
1071+
);
1072+
Ok(())
1073+
})?;
1074+
1075+
Ok(())
1076+
}
1077+
1078+
/// ## Invariants of spend storage items
1079+
///
1080+
/// 1. [`SpendCount`] >= Number of elements in [`Spends`].
1081+
/// 2. Each entry in [`Spends`] should be saved under a key stricly less than current
1082+
/// [`SpendCount`].
1083+
/// 3. For each spend entry contained in [`Spends`] we should have spend.expire_at
1084+
/// > spend.valid_from.
1085+
#[cfg(any(feature = "try-runtime", test))]
1086+
fn try_state_spends() -> Result<(), sp_runtime::TryRuntimeError> {
1087+
let current_spend_count = SpendCount::<T, I>::get();
1088+
ensure!(
1089+
current_spend_count as usize >= Spends::<T, I>::iter().count(),
1090+
"Actual number of spends exceeds `SpendCount`."
1091+
);
1092+
1093+
Spends::<T, I>::iter_keys().try_for_each(|spend_index| -> DispatchResult {
1094+
ensure!(
1095+
current_spend_count > spend_index,
1096+
"`SpendCount` should by strictly greater than any SpendIndex used as a key for `Spends`."
1097+
);
1098+
Ok(())
1099+
})?;
1100+
1101+
Spends::<T, I>::iter().try_for_each(|(_index, spend)| -> DispatchResult {
1102+
ensure!(
1103+
spend.valid_from < spend.expire_at,
1104+
"Spend cannot expire before it becomes valid."
1105+
);
1106+
Ok(())
1107+
})?;
1108+
1109+
Ok(())
1110+
}
10231111
}
10241112

10251113
impl<T: Config<I>, I: 'static> OnUnbalanced<NegativeImbalanceOf<T, I>> for Pallet<T, I> {

0 commit comments

Comments
 (0)