-
Notifications
You must be signed in to change notification settings - Fork 20
Add pallet-fixed-validators-set #1617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2969871
Add pallet-fixed-validators-set
MOZGIII 040c810
Update features snapshot
MOZGIII 0289cf4
Remove redundant clippy allowance (#1619)
dmitrylavrenov 773f0d6
Correct the doc comment at WeightInfo
MOZGIII 3937a27
Correct the test doc-comment
MOZGIII 1b04852
Fix the doc-comment for the update_set call
MOZGIII File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| [package] | ||
| name = "pallet-fixed-validators-set" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| publish = false | ||
|
|
||
| [dependencies] | ||
| codec = { workspace = true, features = ["derive"] } | ||
| frame-benchmarking = { workspace = true, optional = true } | ||
| frame-support = { workspace = true } | ||
| frame-system = { workspace = true } | ||
| scale-info = { workspace = true, features = ["derive"] } | ||
|
|
||
| [features] | ||
| default = ["std"] | ||
| runtime-benchmarks = [ | ||
| "frame-benchmarking/runtime-benchmarks", | ||
| "frame-support/runtime-benchmarks", | ||
| "frame-system/runtime-benchmarks", | ||
| ] | ||
| std = [ | ||
| "codec/std", | ||
| "frame-support/std", | ||
| "frame-system/std", | ||
| "scale-info/std", | ||
| ] | ||
| try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //! The benchmarks for the pallet. | ||
|
|
||
| // Allow integer and float arithmetic in tests. | ||
| #![allow(clippy::float_arithmetic)] | ||
|
|
||
| use frame_benchmarking::benchmarks; | ||
| use frame_support::pallet_prelude::*; | ||
| use frame_system::RawOrigin; | ||
|
|
||
| use crate::*; | ||
|
|
||
| /// The benchmark interface into the environment. | ||
| pub trait Interface: super::Config { | ||
| /// Provide a fixed amount of validator IDs. | ||
| /// | ||
| /// This is used for benchmarking the set update. | ||
| fn provide_validator_id(index: u32) -> <Self as Config>::ValidatorId; | ||
| } | ||
|
|
||
| benchmarks! { | ||
| where_clause { | ||
| where | ||
| T: Interface, | ||
| } | ||
|
|
||
| update_set { | ||
| use frame_support::traits::TryCollect as _; | ||
| let new_set = (0..<T as Config>::MaxValidators::get()) | ||
| .map(|index| <T as Interface>::provide_validator_id(index)) | ||
| .try_collect() | ||
| .unwrap(); | ||
|
|
||
| }: _(RawOrigin::Root, new_set.clone()) | ||
| verify { | ||
| assert_eq!(Validators::<T>::get(), new_set); | ||
| } | ||
|
|
||
| impl_benchmark_test_suite!( | ||
| Pallet, | ||
| crate::mock::new_test_ext(), | ||
| crate::mock::Test, | ||
| ); | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| impl Interface for crate::mock::Test { | ||
| fn provide_validator_id(index: u32) -> <Self as Config>::ValidatorId { | ||
| index.into() | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| //! A substrate pallet for providing a fixed validators set. | ||
|
|
||
| #![cfg_attr(not(feature = "std"), no_std)] | ||
|
|
||
| use frame_support::traits::StorageVersion; | ||
|
|
||
| pub use self::pallet::*; | ||
| pub use self::weights::*; | ||
|
|
||
| #[cfg(feature = "runtime-benchmarks")] | ||
| pub mod benchmarking; | ||
| #[cfg(test)] | ||
| mod mock; | ||
| #[cfg(test)] | ||
| mod tests; | ||
| mod weights; | ||
|
|
||
| /// The current storage version. | ||
| const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); | ||
|
|
||
| // We have to temporarily allow some clippy lints. Later on we'll send patches to substrate to | ||
| // fix them at their end. | ||
| #[allow(clippy::missing_docs_in_private_items)] | ||
| #[frame_support::pallet] | ||
| pub mod pallet { | ||
| use frame_support::{pallet_prelude::*, storage::in_storage_layer}; | ||
| use frame_system::pallet_prelude::*; | ||
|
|
||
| use super::*; | ||
|
|
||
| /// Configure the pallet by specifying the parameters and types on which it depends. | ||
| #[pallet::config] | ||
| pub trait Config: frame_system::Config { | ||
| /// Overarching event type. | ||
| type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; | ||
|
|
||
| /// The maximum number of validators to provide. | ||
| type MaxValidators: Get<u32>; | ||
|
|
||
| /// The type of the validator in the fixed validator set. | ||
| type ValidatorId: Member + Parameter + MaybeSerializeDeserialize + MaxEncodedLen; | ||
|
|
||
| /// The weight information provider type. | ||
| type WeightInfo: WeightInfo; | ||
| } | ||
|
|
||
| #[pallet::pallet] | ||
| #[pallet::storage_version(STORAGE_VERSION)] | ||
| pub struct Pallet<T>(_); | ||
|
|
||
| /// A list of the validators. | ||
| #[pallet::storage] | ||
| #[pallet::getter(fn validators)] | ||
| pub type Validators<T: Config> = | ||
| StorageValue<_, BoundedVec<T::ValidatorId, T::MaxValidators>, ValueQuery>; | ||
|
|
||
| #[pallet::genesis_config] | ||
| #[derive(frame_support::DefaultNoBound)] | ||
| pub struct GenesisConfig<T: Config> { | ||
| /// The set of validators to initialize the chain with. | ||
| pub validators: BoundedVec<T::ValidatorId, T::MaxValidators>, | ||
| } | ||
|
|
||
| // The build of genesis for the pallet. | ||
| #[pallet::genesis_build] | ||
| impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { | ||
| fn build(&self) { | ||
| <Validators<T>>::put(&self.validators); | ||
| } | ||
| } | ||
|
|
||
| #[pallet::event] | ||
| #[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
| pub enum Event<T: Config> { | ||
| /// The fixed validators set has been updated. | ||
| SetUpdated, | ||
| } | ||
|
|
||
| #[pallet::call(weight(T::WeightInfo))] | ||
| impl<T: Config> Pallet<T> { | ||
| /// Update the fixed validators set. | ||
| /// New set extirely replaces the previous state. | ||
| #[pallet::call_index(0)] | ||
| pub fn update_set( | ||
| origin: OriginFor<T>, | ||
| new_set: BoundedVec<T::ValidatorId, T::MaxValidators>, | ||
| ) -> DispatchResult { | ||
| ensure_root(origin)?; | ||
|
|
||
| in_storage_layer(|| { | ||
| Validators::<T>::set(new_set); | ||
| Self::deposit_event(Event::SetUpdated); | ||
| Ok(()) | ||
| }) | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| //! The mock for the pallet. | ||
|
|
||
| use frame_support::{ | ||
| sp_io, | ||
| sp_runtime::{ | ||
| testing::{Header, H256}, | ||
| traits::{BlakeTwo256, IdentityLookup}, | ||
| BuildStorage as _, | ||
| }, | ||
| traits::{ConstU32, ConstU64}, | ||
| }; | ||
|
|
||
| use crate::{self as pallet_fixed_validators_set}; | ||
|
|
||
| type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>; | ||
| type Block = frame_system::mocking::MockBlock<Test>; | ||
|
|
||
| frame_support::construct_runtime!( | ||
| pub struct Test where | ||
| Block = Block, | ||
| NodeBlock = Block, | ||
| UncheckedExtrinsic = UncheckedExtrinsic, | ||
| { | ||
| System: frame_system::{Pallet, Call, Config, Storage, Event<T>}, | ||
| FixedValidatorSet: pallet_fixed_validators_set::{Pallet, Call, Storage, Config<T>, Event<T>}, | ||
| } | ||
| ); | ||
|
|
||
| impl frame_system::Config for Test { | ||
| type BaseCallFilter = frame_support::traits::Everything; | ||
| type BlockWeights = (); | ||
| type BlockLength = (); | ||
| type DbWeight = (); | ||
| type RuntimeOrigin = RuntimeOrigin; | ||
| type RuntimeCall = RuntimeCall; | ||
| type Index = u64; | ||
| type BlockNumber = u64; | ||
| type Hash = H256; | ||
| type Hashing = BlakeTwo256; | ||
| type AccountId = u64; | ||
| type Lookup = IdentityLookup<u64>; | ||
| type Header = Header; | ||
| type RuntimeEvent = RuntimeEvent; | ||
| type BlockHashCount = ConstU64<250>; | ||
| type Version = (); | ||
| type PalletInfo = PalletInfo; | ||
| type AccountData = (); | ||
| type OnNewAccount = (); | ||
| type OnKilledAccount = (); | ||
| type SystemWeightInfo = (); | ||
| type SS58Prefix = (); | ||
| type OnSetCode = (); | ||
| type MaxConsumers = ConstU32<16>; | ||
| } | ||
|
|
||
| impl pallet_fixed_validators_set::Config for Test { | ||
| type RuntimeEvent = RuntimeEvent; | ||
| type WeightInfo = (); | ||
| type MaxValidators = ConstU32<16>; | ||
| type ValidatorId = Self::AccountId; | ||
| } | ||
|
|
||
| pub fn new_test_ext() -> sp_io::TestExternalities { | ||
| let genesis_config = GenesisConfig { | ||
| system: Default::default(), | ||
| fixed_validator_set: FixedValidatorSetConfig { | ||
| validators: Default::default(), | ||
| }, | ||
| }; | ||
| new_test_ext_with(genesis_config) | ||
| } | ||
|
|
||
| // This function basically just builds a genesis storage key/value store according to | ||
| // our desired mockup. | ||
| pub fn new_test_ext_with(genesis_config: GenesisConfig) -> sp_io::TestExternalities { | ||
| let storage = genesis_config.build_storage().unwrap(); | ||
| storage.into() | ||
| } | ||
dmitrylavrenov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| //! The tests for the pallet. | ||
|
|
||
| use frame_support::{assert_noop, assert_ok, BoundedVec}; | ||
|
|
||
| use crate::{ | ||
| mock::{new_test_ext, FixedValidatorSet, RuntimeOrigin, Test}, | ||
| *, | ||
| }; | ||
|
|
||
| /// This test verifies that the test setup for the genesis is adequate. | ||
| #[test] | ||
| fn basic_setup_works() { | ||
| new_test_ext().execute_with(|| { | ||
| // Check the initial set. | ||
| assert_eq!(<Validators<Test>>::get(), vec![]); | ||
| }); | ||
| } | ||
|
|
||
| /// This test verifies that updating the set works in the happy path. | ||
| #[test] | ||
| fn updating_set_works() { | ||
| new_test_ext().execute_with(|| { | ||
| // Check test preconditions. | ||
| assert_eq!(<Validators<Test>>::get(), vec![]); | ||
|
|
||
| // Set block number to enable events. | ||
| mock::System::set_block_number(1); | ||
|
|
||
| // Invoke the function under test. | ||
| assert_ok!(FixedValidatorSet::update_set( | ||
| RuntimeOrigin::root(), | ||
| BoundedVec::try_from(vec![1]).unwrap() | ||
| )); | ||
|
|
||
| // Assert state changes. | ||
| assert_eq!(<Validators<Test>>::get(), vec![1]); | ||
| mock::System::assert_has_event(mock::RuntimeEvent::FixedValidatorSet(Event::SetUpdated)); | ||
| }); | ||
| } | ||
|
|
||
| /// This test verifies that updating the set fails with a non-root origin. | ||
| #[test] | ||
| fn updating_set_requires_root() { | ||
| new_test_ext().execute_with(|| { | ||
| // Check test preconditions. | ||
| assert_eq!(<Validators<Test>>::get(), vec![]); | ||
|
|
||
| // Invoke the function under test and assert it fails. | ||
| assert_noop!( | ||
| FixedValidatorSet::update_set( | ||
| RuntimeOrigin::signed(1), | ||
| BoundedVec::try_from(vec![1]).unwrap() | ||
| ), | ||
| frame_support::dispatch::DispatchError::BadOrigin | ||
| ); | ||
| assert_noop!( | ||
| FixedValidatorSet::update_set( | ||
| RuntimeOrigin::none(), | ||
| BoundedVec::try_from(vec![1]).unwrap(), | ||
| ), | ||
| frame_support::dispatch::DispatchError::BadOrigin | ||
| ); | ||
| }); | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.