Skip to content
Snippets Groups Projects
Unverified Commit 11191abe authored by brettkolodny's avatar brettkolodny Committed by GitHub
Browse files

Add BoundedVec to gradually-update (#498)

* Converted Vec storage to BoundedVec

* Test for exceeding max gradually updates

* Converted storage key and value to BoundedVec
parent 7c9fd1c7
No related branches found
No related tags found
No related merge requests found
......@@ -25,11 +25,12 @@ use frame_support::{
ensure,
pallet_prelude::*,
storage,
traits::{EnsureOrigin, Get},
traits::{EnsureOrigin, Get, MaxEncodedLen},
BoundedVec,
};
use frame_system::pallet_prelude::*;
use sp_runtime::{traits::SaturatedConversion, DispatchResult, RuntimeDebug};
use sp_std::prelude::Vec;
use sp_std::convert::TryInto;
mod default_weight;
mod mock;
......@@ -38,14 +39,11 @@ mod tests;
/// Gradually update a value stored at `key` to `target_value`,
/// change `per_block` * `T::UpdateFrequency` per `T::UpdateFrequency`
/// blocks.
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct GraduallyUpdate {
/// The storage key of the value to update
pub key: StorageKeyBytes,
/// The target value
pub target_value: StorageValueBytes,
/// The amount of the value to update per one block
pub per_block: StorageValueBytes,
#[derive(Encode, Decode, Clone, Eq, PartialEq, MaxEncodedLen, RuntimeDebug)]
pub struct GraduallyUpdate<Key, Value> {
pub key: Key,
pub target_value: Value,
pub per_block: Value,
}
pub use module::*;
......@@ -60,8 +58,10 @@ pub mod module {
fn on_finalize(u: u32) -> Weight;
}
pub(crate) type StorageKeyBytes = Vec<u8>;
pub(crate) type StorageValueBytes = Vec<u8>;
pub(crate) type StorageKeyBytes<T> = BoundedVec<u8, <T as Config>::MaxStorageKeyBytes>;
pub(crate) type StorageValueBytes<T> = BoundedVec<u8, <T as Config>::MaxStorageValueBytes>;
type GraduallyUpdateOf<T> = GraduallyUpdate<StorageKeyBytes<T>, StorageValueBytes<T>>;
#[pallet::config]
pub trait Config: frame_system::Config {
......@@ -76,6 +76,15 @@ pub mod module {
/// Weight information for extrinsics in this module.
type WeightInfo: WeightInfo;
/// Maximum active gradual updates
type MaxGraduallyUpdate: Get<u32>;
/// Maximum size of storage key
type MaxStorageKeyBytes: Get<u32>;
/// Maximum size of storage value
type MaxStorageValueBytes: Get<u32>;
}
#[pallet::error]
......@@ -88,23 +97,30 @@ pub mod module {
GraduallyUpdateHasExisted,
/// No update exists to cancel.
GraduallyUpdateNotFound,
/// Maximum updates exceeded
MaxGraduallyUpdateExceeded,
/// Maximum key size exceeded
MaxStorageKeyBytesExceeded,
/// Maximum value size exceeded
MaxStorageValueBytesExceeded,
}
#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
/// Gradually update added. [key, per_block, target_value]
GraduallyUpdateAdded(StorageKeyBytes, StorageValueBytes, StorageValueBytes),
GraduallyUpdateAdded(StorageKeyBytes<T>, StorageValueBytes<T>, StorageValueBytes<T>),
/// Gradually update cancelled. [key]
GraduallyUpdateCancelled(StorageKeyBytes),
GraduallyUpdateCancelled(StorageKeyBytes<T>),
/// Gradually update applied. [block_number, key, target_value]
Updated(T::BlockNumber, StorageKeyBytes, StorageValueBytes),
Updated(T::BlockNumber, StorageKeyBytes<T>, StorageValueBytes<T>),
}
/// All the on-going updates
#[pallet::storage]
#[pallet::getter(fn gradually_updates)]
pub(crate) type GraduallyUpdates<T: Config> = StorageValue<_, Vec<GraduallyUpdate>, ValueQuery>;
pub(crate) type GraduallyUpdates<T: Config> =
StorageValue<_, BoundedVec<GraduallyUpdateOf<T>, T::MaxGraduallyUpdate>, ValueQuery>;
/// The last updated block number
#[pallet::storage]
......@@ -135,7 +151,7 @@ pub mod module {
impl<T: Config> Pallet<T> {
/// Add gradually_update to adjust numeric parameter.
#[pallet::weight(T::WeightInfo::gradually_update())]
pub fn gradually_update(origin: OriginFor<T>, update: GraduallyUpdate) -> DispatchResultWithPostInfo {
pub fn gradually_update(origin: OriginFor<T>, update: GraduallyUpdateOf<T>) -> DispatchResultWithPostInfo {
T::DispatchOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
// Support max value is u128, ensure per_block and target_value <= 16 bytes.
......@@ -145,7 +161,7 @@ pub mod module {
);
if storage::unhashed::exists(&update.key) {
let current_value = storage::unhashed::get::<StorageValueBytes>(&update.key).unwrap();
let current_value = storage::unhashed::get::<StorageValueBytes<T>>(&update.key).unwrap();
ensure!(
current_value.len() == update.target_value.len(),
Error::<T>::InvalidTargetValue
......@@ -158,7 +174,9 @@ pub mod module {
Error::<T>::GraduallyUpdateHasExisted
);
gradually_updates.push(update.clone());
gradually_updates
.try_push(update.clone())
.map_err(|_| Error::<T>::MaxGraduallyUpdateExceeded)?;
Ok(())
})?;
......@@ -173,7 +191,7 @@ pub mod module {
/// Cancel gradually_update to adjust numeric parameter.
#[pallet::weight(T::WeightInfo::cancel_gradually_update())]
pub fn cancel_gradually_update(origin: OriginFor<T>, key: StorageKeyBytes) -> DispatchResultWithPostInfo {
pub fn cancel_gradually_update(origin: OriginFor<T>, key: StorageKeyBytes<T>) -> DispatchResultWithPostInfo {
T::DispatchOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
GraduallyUpdates::<T>::try_mutate(|gradually_updates| -> DispatchResult {
......@@ -206,7 +224,7 @@ impl<T: Config> Pallet<T> {
gradually_updates.retain(|update| {
let mut keep = true;
let current_value = storage::unhashed::get::<StorageValueBytes>(&update.key).unwrap_or_default();
let current_value = storage::unhashed::get::<StorageValueBytes<T>>(&update.key).unwrap_or_default();
let current_value_u128 = u128::from_le_bytes(Self::convert_vec_to_u8(&current_value));
let frequency_u128: u128 = T::UpdateFrequency::get().saturated_into();
......@@ -232,7 +250,9 @@ impl<T: Config> Pallet<T> {
storage::unhashed::put(&update.key, &value);
Self::deposit_event(Event::Updated(now, update.key.clone(), value));
let bounded_value: StorageValueBytes<T> = value.to_vec().try_into().unwrap();
Self::deposit_event(Event::Updated(now, update.key.clone(), bounded_value));
keep
});
......@@ -246,7 +266,7 @@ impl<T: Config> Pallet<T> {
}
#[allow(clippy::ptr_arg)]
fn convert_vec_to_u8(input: &StorageValueBytes) -> [u8; 16] {
fn convert_vec_to_u8(input: &StorageValueBytes<T>) -> [u8; 16] {
let mut array: [u8; 16] = [0; 16];
for (i, v) in input.iter().enumerate() {
array[i] = *v;
......
......@@ -44,6 +44,9 @@ impl frame_system::Config for Runtime {
parameter_types! {
pub const UpdateFrequency: BlockNumber = 10;
pub MaxGraduallyUpdate: u32 = 3;
pub MaxStorageKeyBytes: u32 = 100_000;
pub MaxStorageValueBytes: u32 = 100_000;
}
impl Config for Runtime {
......@@ -51,6 +54,9 @@ impl Config for Runtime {
type UpdateFrequency = UpdateFrequency;
type DispatchOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = ();
type MaxGraduallyUpdate = MaxGraduallyUpdate;
type MaxStorageKeyBytes = MaxStorageKeyBytes;
type MaxStorageValueBytes = MaxStorageValueBytes;
}
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
......
......@@ -7,13 +7,17 @@ use codec::Encode;
use frame_support::{assert_noop, assert_ok};
use mock::{Event, *};
use sp_runtime::{FixedPointNumber, FixedU128, Permill};
use sp_std::convert::TryInto;
fn storage_set(key: &Vec<u8>, value: &Vec<u8>) {
// let bounded_key: StorageValueBytes<Runtime> =
// key.to_vec().try_into().unwrap(); let bounded_value:
// StorageValueBytes<Runtime> = key.to_vec().try_into().unwrap();
frame_support::storage::unhashed::put(key, value);
}
fn storage_get(key: &Vec<u8>) -> Vec<u8> {
frame_support::storage::unhashed::get::<StorageValueBytes>(key).unwrap_or_default()
fn storage_get(key: &Vec<u8>) -> StorageValueBytes<Runtime> {
frame_support::storage::unhashed::get::<StorageValueBytes<Runtime>>(key).unwrap_or_default()
}
#[test]
......@@ -21,10 +25,10 @@ fn gradually_update_should_work() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update = GraduallyUpdate {
key: vec![1],
target_value: vec![9],
per_block: vec![1],
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: vec![9].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
......@@ -42,29 +46,29 @@ fn gradually_update_should_work() {
#[test]
fn gradually_update_should_fail() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: 9u32.encode(),
per_block: 1u64.encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: 9u32.encode().try_into().unwrap(),
per_block: 1u64.encode().try_into().unwrap(),
};
assert_noop!(
GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()),
Error::<Runtime>::InvalidPerBlockOrTargetValue
);
let update = GraduallyUpdate {
key: vec![1],
target_value: 90u32.encode(),
per_block: 1u32.encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: 90u32.encode().try_into().unwrap(),
per_block: 1u32.encode().try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
GraduallyUpdateModule::on_finalize(20);
let new_update = GraduallyUpdate {
key: vec![1],
target_value: 9u64.encode(),
per_block: 1u64.encode(),
key: vec![1].try_into().unwrap(),
target_value: 9u64.encode().try_into().unwrap(),
per_block: 1u64.encode().try_into().unwrap(),
};
assert_noop!(
GraduallyUpdateModule::gradually_update(Origin::root(), new_update.clone()),
......@@ -83,10 +87,10 @@ fn cancel_gradually_update_should_work() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update = GraduallyUpdate {
key: vec![1],
target_value: vec![9],
per_block: vec![1],
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: vec![9].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
let gradually_update_event = Event::gradually_update(crate::Event::GraduallyUpdateAdded(
......@@ -102,7 +106,8 @@ fn cancel_gradually_update_should_work() {
Origin::root(),
update.key.clone()
));
let cancel_gradually_update_event = Event::gradually_update(crate::Event::GraduallyUpdateCancelled(update.key));
let cancel_gradually_update_event =
Event::gradually_update(crate::Event::GraduallyUpdateCancelled(update.key.clone()));
assert!(System::events()
.iter()
.any(|record| record.event == cancel_gradually_update_event));
......@@ -112,10 +117,10 @@ fn cancel_gradually_update_should_work() {
#[test]
fn cancel_gradually_update_should_fail() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: 9u32.encode(),
per_block: 1u32.encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: 9u32.encode().try_into().unwrap(),
per_block: 1u32.encode().try_into().unwrap(),
};
assert_noop!(
GraduallyUpdateModule::cancel_gradually_update(Origin::root(), update.key.clone()),
......@@ -136,21 +141,26 @@ fn add_on_finalize_should_work() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update = GraduallyUpdate {
key: vec![1],
target_value: vec![30],
per_block: vec![1],
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: vec![30].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_eq!(storage_get(&update.key), Vec::<u8>::new());
GraduallyUpdateModule::on_finalize(10);
assert_eq!(storage_get(&update.key), vec![10]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(10, update.key.clone(), vec![10]));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
10,
update.key.clone(),
vec![10].try_into().unwrap(),
));
println!("Length {}", System::events().len());
assert!(System::events().iter().any(|record| {
println!("{:?}", record.event);
record.event == gradually_update_blocknumber_event
}));
assert_eq!(System::events().len(), 2);
GraduallyUpdateModule::on_finalize(15);
......@@ -159,8 +169,11 @@ fn add_on_finalize_should_work() {
GraduallyUpdateModule::on_finalize(20);
assert_eq!(storage_get(&update.key), vec![20]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(20, update.key.clone(), vec![20]));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
20,
update.key.clone(),
vec![20].try_into().unwrap(),
));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
......@@ -168,8 +181,11 @@ fn add_on_finalize_should_work() {
GraduallyUpdateModule::on_finalize(40);
assert_eq!(storage_get(&update.key), vec![30]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(40, update.key.clone(), vec![30]));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
40,
update.key.clone(),
vec![30].try_into().unwrap(),
));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
......@@ -181,10 +197,10 @@ fn sub_on_finalize_should_work() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update = GraduallyUpdate {
key: vec![1],
target_value: vec![5],
per_block: vec![1],
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: vec![5].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
storage_set(&update.key, &vec![30]);
......@@ -193,8 +209,11 @@ fn sub_on_finalize_should_work() {
GraduallyUpdateModule::on_finalize(10);
assert_eq!(storage_get(&update.key), vec![20]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(10, update.key.clone(), vec![20]));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
10,
update.key.clone(),
vec![20].try_into().unwrap(),
));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
......@@ -206,8 +225,11 @@ fn sub_on_finalize_should_work() {
GraduallyUpdateModule::on_finalize(20);
assert_eq!(storage_get(&update.key), vec![10]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(20, update.key.clone(), vec![10]));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
20,
update.key.clone(),
vec![10].try_into().unwrap(),
));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
......@@ -215,8 +237,11 @@ fn sub_on_finalize_should_work() {
GraduallyUpdateModule::on_finalize(40);
assert_eq!(storage_get(&update.key), vec![5]);
let gradually_update_blocknumber_event =
Event::gradually_update(crate::Event::Updated(40, update.key.clone(), vec![5]));
let gradually_update_blocknumber_event = Event::gradually_update(crate::Event::Updated(
40,
update.key.clone(),
vec![5].try_into().unwrap(),
));
assert!(System::events()
.iter()
.any(|record| record.event == gradually_update_blocknumber_event));
......@@ -226,10 +251,10 @@ fn sub_on_finalize_should_work() {
#[test]
fn u32_should_work() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: 30u32.encode(),
per_block: 1u32.encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: 30u32.encode().try_into().unwrap(),
per_block: 1u32.encode().try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_eq!(storage_get(&update.key), Vec::<u8>::new());
......@@ -247,10 +272,10 @@ fn u32_should_work() {
#[test]
fn u128_should_work() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: 30u128.encode(),
per_block: 1u128.encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: 30u128.encode().try_into().unwrap(),
per_block: 1u128.encode().try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_eq!(storage_get(&update.key), Vec::<u8>::new());
......@@ -280,10 +305,10 @@ fn u128_should_work() {
#[test]
fn permill_should_work() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: Permill::from_percent(30).encode(),
per_block: Permill::from_percent(1).encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: Permill::from_percent(30).encode().try_into().unwrap(),
per_block: Permill::from_percent(1).encode().try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_eq!(storage_get(&update.key), Vec::<u8>::new());
......@@ -301,10 +326,10 @@ fn permill_should_work() {
#[test]
fn fixedu128_should_work() {
ExtBuilder::default().build().execute_with(|| {
let update = GraduallyUpdate {
key: vec![1],
target_value: FixedU128::saturating_from_rational(30, 1).encode(),
per_block: FixedU128::saturating_from_rational(1, 1).encode(),
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![1].try_into().unwrap(),
target_value: FixedU128::saturating_from_rational(30, 1).encode().try_into().unwrap(),
per_block: FixedU128::saturating_from_rational(1, 1).encode().try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_eq!(storage_get(&update.key), Vec::<u8>::new());
......@@ -336,20 +361,20 @@ fn finish_multiple_on_finalize_should_work() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update = GraduallyUpdate {
key: vec![10],
target_value: vec![30],
per_block: vec![1],
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![10].try_into().unwrap(),
target_value: vec![30].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
let update2 = GraduallyUpdate {
key: vec![20],
target_value: vec![60],
per_block: vec![2],
let update2: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![20].try_into().unwrap(),
target_value: vec![60].try_into().unwrap(),
per_block: vec![2].try_into().unwrap(),
};
let update3 = GraduallyUpdate {
key: vec![30],
target_value: vec![100],
per_block: vec![3],
let update3: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![30].try_into().unwrap(),
target_value: vec![100].try_into().unwrap(),
per_block: vec![3].try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update2.clone()));
......@@ -381,3 +406,50 @@ fn finish_multiple_on_finalize_should_work() {
assert_eq!(storage_get(&update3.key), vec![100]);
});
}
#[test]
fn exceeding_max_gradually_updates_should_fail() {
ExtBuilder::default().build().execute_with(|| {
System::set_block_number(1);
let update: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![10].try_into().unwrap(),
target_value: vec![30].try_into().unwrap(),
per_block: vec![1].try_into().unwrap(),
};
let update2: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![20].try_into().unwrap(),
target_value: vec![60].try_into().unwrap(),
per_block: vec![2].try_into().unwrap(),
};
let update3: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![30].try_into().unwrap(),
target_value: vec![100].try_into().unwrap(),
per_block: vec![3].try_into().unwrap(),
};
let update4: GraduallyUpdate<StorageKeyBytes<Runtime>, StorageValueBytes<Runtime>> = GraduallyUpdate {
key: vec![40].try_into().unwrap(),
target_value: vec![120].try_into().unwrap(),
per_block: vec![4].try_into().unwrap(),
};
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update.clone()));
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update2.clone()));
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update3.clone()));
assert_noop!(
GraduallyUpdateModule::gradually_update(Origin::root(), update4.clone()),
Error::<Runtime>::MaxGraduallyUpdateExceeded
);
GraduallyUpdateModule::on_finalize(10);
GraduallyUpdateModule::on_finalize(20);
GraduallyUpdateModule::on_finalize(30);
assert_ok!(GraduallyUpdateModule::gradually_update(Origin::root(), update4.clone()));
GraduallyUpdateModule::on_finalize(40);
GraduallyUpdateModule::on_finalize(50);
GraduallyUpdateModule::on_finalize(60);
assert_eq!(storage_get(&update.key), vec![30]);
assert_eq!(storage_get(&update2.key), vec![60]);
assert_eq!(storage_get(&update3.key), vec![100]);
assert_eq!(storage_get(&update4.key), vec![120]);
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment