|
@@ -1,26 +1,3 @@
|
|
|
-//! Council Elections Manager
|
|
|
-//!
|
|
|
-//! # Election Parameters:
|
|
|
-//! We don't currently handle zero periods, zero council term, zero council size and candidacy
|
|
|
-//! limit in any special way. The behaviour in such cases:
|
|
|
-//!
|
|
|
-//! - Setting any period to 0 will mean the election getting stuck in that stage, until force changing
|
|
|
-//! the state.
|
|
|
-//!
|
|
|
-//! - Council Size of 0 - no limit to size of council, all applicants that move beyond
|
|
|
-//! announcing stage would become council members, so effectively the candidacy limit will
|
|
|
-//! be the size of the council, voting and revealing have no impact on final results.
|
|
|
-//!
|
|
|
-//! - If candidacy limit is zero and council size > 0, council_size number of applicants will reach the voting stage.
|
|
|
-//! and become council members, voting will have no impact on final results.
|
|
|
-//!
|
|
|
-//! - If both candidacy limit and council size are zero then all applicant become council members
|
|
|
-//! since no filtering occurs at end of announcing stage.
|
|
|
-//!
|
|
|
-//! We only guard against these edge cases in the [`set_election_parameters`] call.
|
|
|
-//!
|
|
|
-//! [`set_election_parameters`]: struct.Module.html#method.set_election_parameters
|
|
|
-
|
|
|
use rstd::prelude::*;
|
|
|
use srml_support::traits::{Currency, ReservableCurrency};
|
|
|
use srml_support::{decl_event, decl_module, decl_storage, dispatch::Result, ensure};
|
|
@@ -37,7 +14,6 @@ use super::sealed_vote::SealedVote;
|
|
|
use super::stake::Stake;
|
|
|
|
|
|
use super::council;
|
|
|
-use crate::election_params::ElectionParameters;
|
|
|
pub use common::currency::{BalanceOf, GovernanceCurrency};
|
|
|
|
|
|
pub trait Trait:
|
|
@@ -48,8 +24,6 @@ pub trait Trait:
|
|
|
type CouncilElected: CouncilElected<Seats<Self::AccountId, BalanceOf<Self>>, Self::BlockNumber>;
|
|
|
}
|
|
|
|
|
|
-pub static MSG_CANNOT_CHANGE_PARAMS_DURING_ELECTION: &str = "CannotChangeParamsDuringElection";
|
|
|
-
|
|
|
#[derive(Clone, Copy, Encode, Decode)]
|
|
|
pub enum ElectionStage<BlockNumber> {
|
|
|
Announcing(BlockNumber),
|
|
@@ -132,25 +106,16 @@ decl_storage! {
|
|
|
// TODO value type of this map looks scary, is there any way to simplify the notation?
|
|
|
Votes get(votes): map T::Hash => SealedVote<T::AccountId, ElectionStake<T>, T::Hash, T::AccountId>;
|
|
|
|
|
|
- // Current Election Parameters.
|
|
|
- // Should we replace all the individual values with a single ElectionParameters type?
|
|
|
- // Having them individually makes it more flexible to add and remove new parameters in future
|
|
|
- // without dealing with migration issues.
|
|
|
- AnnouncingPeriod get(announcing_period): T::BlockNumber;
|
|
|
- VotingPeriod get(voting_period): T::BlockNumber;
|
|
|
- RevealingPeriod get(revealing_period): T::BlockNumber;
|
|
|
- CouncilSize get(council_size): u32;
|
|
|
- CandidacyLimit get (candidacy_limit): u32;
|
|
|
- MinCouncilStake get(min_council_stake): BalanceOf<T>;
|
|
|
- NewTermDuration get(new_term_duration): T::BlockNumber;
|
|
|
- MinVotingStake get(min_voting_stake): BalanceOf<T>;
|
|
|
- }
|
|
|
- add_extra_genesis {
|
|
|
- config(election_parameters): ElectionParameters<BalanceOf<T>, T::BlockNumber>;
|
|
|
- build(|config: &GenesisConfig<T>| {
|
|
|
- config.election_parameters.ensure_valid().expect("Invalid Election Parameters");
|
|
|
- Module::<T>::set_verified_election_parameters(config.election_parameters);
|
|
|
- });
|
|
|
+ // Current Election Parameters - default "zero" values are not meaningful. Running an election without
|
|
|
+ // settings reasonable values is a bad idea. Parameters can be set in the TriggerElection hook.
|
|
|
+ AnnouncingPeriod get(announcing_period) config(): T::BlockNumber = T::BlockNumber::from(100);
|
|
|
+ VotingPeriod get(voting_period) config(): T::BlockNumber = T::BlockNumber::from(100);
|
|
|
+ RevealingPeriod get(revealing_period) config(): T::BlockNumber = T::BlockNumber::from(100);
|
|
|
+ CouncilSize get(council_size) config(): u32 = 10;
|
|
|
+ CandidacyLimit get (candidacy_limit) config(): u32 = 20;
|
|
|
+ MinCouncilStake get(min_council_stake) config(): BalanceOf<T> = BalanceOf::<T>::from(100);
|
|
|
+ NewTermDuration get(new_term_duration) config(): T::BlockNumber = T::BlockNumber::from(1000);
|
|
|
+ MinVotingStake get(min_voting_stake) config(): BalanceOf<T> = BalanceOf::<T>::from(10);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -191,7 +156,7 @@ impl<T: Trait> Module<T> {
|
|
|
}
|
|
|
|
|
|
fn can_participate(sender: &T::AccountId) -> bool {
|
|
|
- !<T as GovernanceCurrency>::Currency::free_balance(sender).is_zero()
|
|
|
+ !T::Currency::free_balance(sender).is_zero()
|
|
|
&& <membership::members::Module<T>>::is_member_account(sender)
|
|
|
}
|
|
|
|
|
@@ -230,7 +195,7 @@ impl<T: Trait> Module<T> {
|
|
|
|
|
|
// Take snapshot of seat and backing stakes of an existing council
|
|
|
// Its important to note that the election system takes ownership of these stakes, and is responsible
|
|
|
- // to return any unused stake to original owners at the end of the election.
|
|
|
+ // to return any unused stake to original owners and the end of the election.
|
|
|
Self::initialize_transferable_stakes(current_council);
|
|
|
|
|
|
Self::deposit_event(RawEvent::ElectionStarted());
|
|
@@ -391,10 +356,7 @@ impl<T: Trait> Module<T> {
|
|
|
for stakeholder in Self::existing_stake_holders().iter() {
|
|
|
let stake = Self::transferable_stakes(stakeholder);
|
|
|
if !stake.seat.is_zero() || !stake.backing.is_zero() {
|
|
|
- <T as GovernanceCurrency>::Currency::unreserve(
|
|
|
- stakeholder,
|
|
|
- stake.seat + stake.backing,
|
|
|
- );
|
|
|
+ T::Currency::unreserve(stakeholder, stake.seat + stake.backing);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -419,7 +381,7 @@ impl<T: Trait> Module<T> {
|
|
|
|
|
|
// return new stake to account's free balance
|
|
|
if !stake.new.is_zero() {
|
|
|
- <T as GovernanceCurrency>::Currency::unreserve(applicant, stake.new);
|
|
|
+ T::Currency::unreserve(applicant, stake.new);
|
|
|
}
|
|
|
|
|
|
// return unused transferable stake
|
|
@@ -473,7 +435,7 @@ impl<T: Trait> Module<T> {
|
|
|
// return new stake to account's free balance
|
|
|
let SealedVote { voter, stake, .. } = sealed_vote;
|
|
|
if !stake.new.is_zero() {
|
|
|
- <T as GovernanceCurrency>::Currency::unreserve(voter, stake.new);
|
|
|
+ T::Currency::unreserve(voter, stake.new);
|
|
|
}
|
|
|
|
|
|
// return unused transferable stake
|
|
@@ -664,12 +626,12 @@ impl<T: Trait> Module<T> {
|
|
|
let new_stake = Self::new_stake_reusing_transferable(&mut transferable_stake.seat, stake);
|
|
|
|
|
|
ensure!(
|
|
|
- <T as GovernanceCurrency>::Currency::can_reserve(&applicant, new_stake.new),
|
|
|
+ T::Currency::can_reserve(&applicant, new_stake.new),
|
|
|
"not enough free balance to reserve"
|
|
|
);
|
|
|
|
|
|
ensure!(
|
|
|
- <T as GovernanceCurrency>::Currency::reserve(&applicant, new_stake.new).is_ok(),
|
|
|
+ T::Currency::reserve(&applicant, new_stake.new).is_ok(),
|
|
|
"failed to reserve applicant stake!"
|
|
|
);
|
|
|
|
|
@@ -700,12 +662,12 @@ impl<T: Trait> Module<T> {
|
|
|
Self::new_stake_reusing_transferable(&mut transferable_stake.backing, stake);
|
|
|
|
|
|
ensure!(
|
|
|
- <T as GovernanceCurrency>::Currency::can_reserve(&voter, vote_stake.new),
|
|
|
+ T::Currency::can_reserve(&voter, vote_stake.new),
|
|
|
"not enough free balance to reserve"
|
|
|
);
|
|
|
|
|
|
ensure!(
|
|
|
- <T as GovernanceCurrency>::Currency::reserve(&voter, vote_stake.new).is_ok(),
|
|
|
+ T::Currency::reserve(&voter, vote_stake.new).is_ok(),
|
|
|
"failed to reserve voting stake!"
|
|
|
);
|
|
|
|
|
@@ -751,17 +713,6 @@ impl<T: Trait> Module<T> {
|
|
|
|
|
|
Ok(())
|
|
|
}
|
|
|
-
|
|
|
- fn set_verified_election_parameters(params: ElectionParameters<BalanceOf<T>, T::BlockNumber>) {
|
|
|
- <AnnouncingPeriod<T>>::put(params.announcing_period);
|
|
|
- <VotingPeriod<T>>::put(params.voting_period);
|
|
|
- <RevealingPeriod<T>>::put(params.revealing_period);
|
|
|
- <MinCouncilStake<T>>::put(params.min_council_stake);
|
|
|
- <NewTermDuration<T>>::put(params.new_term_duration);
|
|
|
- CouncilSize::put(params.council_size);
|
|
|
- CandidacyLimit::put(params.candidacy_limit);
|
|
|
- <MinVotingStake<T>>::put(params.min_voting_stake);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
decl_module! {
|
|
@@ -852,16 +803,52 @@ decl_module! {
|
|
|
<Stage<T>>::put(ElectionStage::Voting(ends_at));
|
|
|
}
|
|
|
|
|
|
- /// Sets new election parameters. Some combination of parameters that are not desirable, so
|
|
|
- /// the parameters are checked for validity.
|
|
|
- /// The call will fail if an election is in progress. If a council is not being elected for some
|
|
|
- /// reaon after multiple rounds, force_stop_election() can be called to stop elections and followed by
|
|
|
- /// set_election_parameters().
|
|
|
- pub fn set_election_parameters(origin, params: ElectionParameters<BalanceOf<T>, T::BlockNumber>) {
|
|
|
+ fn set_param_announcing_period(origin, period: T::BlockNumber) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(!period.is_zero(), "period cannot be zero");
|
|
|
+ <AnnouncingPeriod<T>>::put(period);
|
|
|
+ }
|
|
|
+ fn set_param_voting_period(origin, period: T::BlockNumber) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(!period.is_zero(), "period cannot be zero");
|
|
|
+ <VotingPeriod<T>>::put(period);
|
|
|
+ }
|
|
|
+ fn set_param_revealing_period(origin, period: T::BlockNumber) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(!period.is_zero(), "period cannot be zero");
|
|
|
+ <RevealingPeriod<T>>::put(period);
|
|
|
+ }
|
|
|
+ fn set_param_min_council_stake(origin, amount: BalanceOf<T>) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ <MinCouncilStake<T>>::put(amount);
|
|
|
+ }
|
|
|
+ fn set_param_new_term_duration(origin, duration: T::BlockNumber) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(!duration.is_zero(), "new term duration cannot be zero");
|
|
|
+ <NewTermDuration<T>>::put(duration);
|
|
|
+ }
|
|
|
+ fn set_param_council_size(origin, council_size: u32) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(council_size > 0, "council size cannot be zero");
|
|
|
+ ensure!(council_size <= Self::candidacy_limit(), "council size cannot greater than candidacy limit");
|
|
|
+ CouncilSize::put(council_size);
|
|
|
+ }
|
|
|
+ fn set_param_candidacy_limit(origin, limit: u32) {
|
|
|
+ ensure_root(origin)?;
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ ensure!(limit >= Self::council_size(), "candidacy limit cannot be less than council size");
|
|
|
+ CandidacyLimit::put(limit);
|
|
|
+ }
|
|
|
+ fn set_param_min_voting_stake(origin, amount: BalanceOf<T>) {
|
|
|
ensure_root(origin)?;
|
|
|
- ensure!(!Self::is_election_running(), MSG_CANNOT_CHANGE_PARAMS_DURING_ELECTION);
|
|
|
- params.ensure_valid()?;
|
|
|
- Self::set_verified_election_parameters(params);
|
|
|
+ ensure!(!Self::is_election_running(), "cannot change params during election");
|
|
|
+ <MinVotingStake<T>>::put(amount);
|
|
|
}
|
|
|
|
|
|
fn force_stop_election(origin) {
|
|
@@ -2055,53 +2042,4 @@ mod tests {
|
|
|
assert_ok!(Election::start_election(vec![]));
|
|
|
});
|
|
|
}
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn setting_election_parameters() {
|
|
|
- initial_test_ext().execute_with(|| {
|
|
|
- let default_parameters: ElectionParameters<u64, u64> = ElectionParameters::default();
|
|
|
- // default all zeros is invalid
|
|
|
- assert!(default_parameters.ensure_valid().is_err());
|
|
|
-
|
|
|
- let new_parameters = ElectionParameters {
|
|
|
- announcing_period: 1,
|
|
|
- voting_period: 2,
|
|
|
- revealing_period: 3,
|
|
|
- council_size: 4,
|
|
|
- candidacy_limit: 5,
|
|
|
- min_voting_stake: 6,
|
|
|
- min_council_stake: 7,
|
|
|
- new_term_duration: 8,
|
|
|
- };
|
|
|
-
|
|
|
- assert_ok!(Election::set_election_parameters(
|
|
|
- Origin::ROOT,
|
|
|
- new_parameters
|
|
|
- ));
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- <AnnouncingPeriod<Test>>::get(),
|
|
|
- new_parameters.announcing_period
|
|
|
- );
|
|
|
- assert_eq!(<VotingPeriod<Test>>::get(), new_parameters.voting_period);
|
|
|
- assert_eq!(
|
|
|
- <RevealingPeriod<Test>>::get(),
|
|
|
- new_parameters.revealing_period
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- <MinCouncilStake<Test>>::get(),
|
|
|
- new_parameters.min_council_stake
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- <NewTermDuration<Test>>::get(),
|
|
|
- new_parameters.new_term_duration
|
|
|
- );
|
|
|
- assert_eq!(CouncilSize::get(), new_parameters.council_size);
|
|
|
- assert_eq!(CandidacyLimit::get(), new_parameters.candidacy_limit);
|
|
|
- assert_eq!(
|
|
|
- <MinVotingStake<Test>>::get(),
|
|
|
- new_parameters.min_voting_stake
|
|
|
- );
|
|
|
- });
|
|
|
- }
|
|
|
}
|