Fix Collective <-> Elections initialization. (#5454)

* A patch

* Fix

* Better approach.

* Fix grumbles
This commit is contained in:
Kian Paimani
2020-03-31 22:40:28 +02:00
committed by GitHub
parent 21c92dfd29
commit 63e6f81776
7 changed files with 149 additions and 75 deletions
+85 -7
View File
@@ -91,7 +91,7 @@ use frame_support::{
weights::{SimpleDispatchInfo, Weight, WeighData}, storage::{StorageMap, IterableStorageMap},
traits::{
Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons,
ChangeMembers, OnUnbalanced, WithdrawReason, Contains, BalanceStatus
ChangeMembers, OnUnbalanced, WithdrawReason, Contains, BalanceStatus, InitializeMembers,
}
};
use sp_phragmen::{build_support_map, ExtendedBalance};
@@ -118,6 +118,9 @@ pub trait Trait: frame_system::Trait {
/// What to do when the members change.
type ChangeMembers: ChangeMembers<Self::AccountId>;
/// What to do with genesis members
type InitializeMembers: InitializeMembers<Self::AccountId>;
/// Convert a balance into a number used for election calculation.
/// This must fit into a `u64` but is allowed to be sensibly lossy.
type CurrencyToVote: Convert<BalanceOf<Self>, u64> + Convert<u128, BalanceOf<Self>>;
@@ -160,11 +163,44 @@ decl_storage! {
pub ElectionRounds get(fn election_rounds): u32 = Zero::zero();
/// Votes and locked stake of a particular voter.
pub Voting: map hasher(twox_64_concat) T::AccountId => (BalanceOf<T>, Vec<T::AccountId>);
pub Voting get(fn voting): map hasher(twox_64_concat) T::AccountId => (BalanceOf<T>, Vec<T::AccountId>);
/// The present candidate list. Sorted based on account-id. A current member or runner-up
/// can never enter this vector and is always implicitly assumed to be a candidate.
pub Candidates get(fn candidates): Vec<T::AccountId>;
} add_extra_genesis {
config(members): Vec<(T::AccountId, BalanceOf<T>)>;
build(|config: &GenesisConfig<T>| {
let members = config.members.iter().map(|(ref member, ref stake)| {
// make sure they have enough stake
assert!(
T::Currency::free_balance(member) >= *stake,
"Genesis member does not have enough stake",
);
// reserve candidacy bond and set as members.
T::Currency::reserve(&member, T::CandidacyBond::get())
.expect("Genesis member does not have enough balance to be a candidate");
// Note: all members will only vote for themselves, hence they must be given exactly
// their own stake as total backing. Any sane election should behave as such.
// Nonetheless, stakes will be updated for term 1 onwards according to the election.
<Members<T>>::append(&[(member.clone(), *stake)])
.expect("Failed to append genesis members.");
// set self-votes to make persistent.
<Module<T>>::vote(
T::Origin::from(Some(member.clone()).into()),
vec![member.clone()],
*stake,
).expect("Genesis member could not vote.");
member.clone()
}).collect::<Vec<T::AccountId>>();
// report genesis members to upstream, if any.
T::InitializeMembers::initialize_members(&members);
})
}
}
@@ -844,7 +880,7 @@ mod tests {
Perbill, testing::Header, BuildStorage,
traits::{BlakeTwo256, IdentityLookup, Block as BlockT},
};
use crate as elections;
use crate as elections_phragmen;
use frame_system as system;
parameter_types! {
@@ -980,6 +1016,7 @@ mod tests {
type Currency = Balances;
type CurrencyToVote = CurrencyToVoteHandler;
type ChangeMembers = TestChangeMembers;
type InitializeMembers = ();
type CandidacyBond = CandidacyBond;
type VotingBond = VotingBond;
type TermDuration = TermDuration;
@@ -1001,11 +1038,12 @@ mod tests {
{
System: system::{Module, Call, Event<T>},
Balances: pallet_balances::{Module, Call, Event<T>, Config<T>},
Elections: elections::{Module, Call, Event<T>},
Elections: elections_phragmen::{Module, Call, Event<T>, Config<T>},
}
);
pub struct ExtBuilder {
genesis_members: Vec<(u64, u64)>,
balance_factor: u64,
voter_bond: u64,
term_duration: u64,
@@ -1015,6 +1053,7 @@ mod tests {
impl Default for ExtBuilder {
fn default() -> Self {
Self {
genesis_members: vec![],
balance_factor: 1,
voter_bond: 2,
desired_runners_up: 0,
@@ -1036,10 +1075,15 @@ mod tests {
self.term_duration = duration;
self
}
pub fn genesis_members(mut self, members: Vec<(u64, u64)>) -> Self {
self.genesis_members = members;
self
}
pub fn build(self) -> sp_io::TestExternalities {
VOTING_BOND.with(|v| *v.borrow_mut() = self.voter_bond);
TERM_DURATION.with(|v| *v.borrow_mut() = self.term_duration);
DESIRED_RUNNERS_UP.with(|v| *v.borrow_mut() = self.desired_runners_up);
MEMBERS.with(|m| *m.borrow_mut() = self.genesis_members.iter().map(|(m, _)| m.clone()).collect::<Vec<_>>());
let mut ext: sp_io::TestExternalities = GenesisConfig {
pallet_balances: Some(pallet_balances::GenesisConfig::<Test>{
balances: vec![
@@ -1051,6 +1095,9 @@ mod tests {
(6, 60 * self.balance_factor)
],
}),
elections_phragmen: Some(elections_phragmen::GenesisConfig::<Test> {
members: self.genesis_members
}),
}.build_storage().unwrap().into();
ext.execute_with(|| System::set_block_number(1));
ext
@@ -1090,6 +1137,37 @@ mod tests {
});
}
#[test]
fn genesis_members_should_work() {
ExtBuilder::default().genesis_members(vec![(1, 10), (2, 20)]).build().execute_with(|| {
System::set_block_number(1);
assert_eq!(Elections::members(), vec![(1, 10), (2, 20)]);
assert_eq!(Elections::voting(1), (10, vec![1]));
assert_eq!(Elections::voting(2), (20, vec![2]));
// they will persist since they have self vote.
System::set_block_number(5);
assert_ok!(Elections::end_block(System::block_number()));
assert_eq!(Elections::members_ids(), vec![1, 2]);
})
}
#[test]
#[should_panic = "Genesis member does not have enough stake"]
fn genesis_members_cannot_over_stake_0() {
// 10 cannot lock 20 as their stake and extra genesis will panic.
ExtBuilder::default().genesis_members(vec![(1, 20), (2, 20)]).build();
}
#[test]
#[should_panic]
fn genesis_members_cannot_over_stake_1() {
// 10 cannot reserve 20 as voting bond and extra genesis will panic.
ExtBuilder::default().voter_bond(20).genesis_members(vec![(1, 10), (2, 20)]).build();
}
#[test]
fn term_duration_zero_is_passive() {
ExtBuilder::default()
@@ -1538,7 +1616,7 @@ mod tests {
assert_ok!(Elections::report_defunct_voter(Origin::signed(5), 3));
assert!(System::events().iter().any(|event| {
event.event == Event::elections(RawEvent::VoterReported(3, 5, true))
event.event == Event::elections_phragmen(RawEvent::VoterReported(3, 5, true))
}));
assert_eq!(balances(&3), (28, 0));
@@ -1566,7 +1644,7 @@ mod tests {
assert_ok!(Elections::report_defunct_voter(Origin::signed(5), 4));
assert!(System::events().iter().any(|event| {
event.event == Event::elections(RawEvent::VoterReported(4, 5, false))
event.event == Event::elections_phragmen(RawEvent::VoterReported(4, 5, false))
}));
assert_eq!(balances(&4), (35, 5));
@@ -1976,7 +2054,7 @@ mod tests {
assert_eq!(balances(&5), (45, 2));
assert!(System::events().iter().any(|event| {
event.event == Event::elections(RawEvent::NewTerm(vec![(4, 40), (5, 50)]))
event.event == Event::elections_phragmen(RawEvent::NewTerm(vec![(4, 40), (5, 50)]))
}));
})
}