Fix phragmen elections. (#4266)

CC @kianenigma
This commit is contained in:
Gavin Wood
2019-12-02 14:21:32 +01:00
committed by GitHub
parent 2e68c80c20
commit 47721b6b01
+38 -37
View File
@@ -84,9 +84,8 @@
use rstd::prelude::*; use rstd::prelude::*;
use sp_runtime::{print, traits::{Zero, StaticLookup, Bounded, Convert}}; use sp_runtime::{print, traits::{Zero, StaticLookup, Bounded, Convert}};
use support::weights::SimpleDispatchInfo;
use support::{ use support::{
decl_storage, decl_event, ensure, decl_module, dispatch, decl_storage, decl_event, ensure, decl_module, dispatch, weights::SimpleDispatchInfo,
traits::{ traits::{
Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons, Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons,
ChangeMembers, OnUnbalanced, WithdrawReason ChangeMembers, OnUnbalanced, WithdrawReason
@@ -391,11 +390,11 @@ decl_module! {
/// Writes: O(do_phragmen) /// Writes: O(do_phragmen)
/// # </weight> /// # </weight>
#[weight = SimpleDispatchInfo::FixedOperational(2_000_000)] #[weight = SimpleDispatchInfo::FixedOperational(2_000_000)]
fn remove_member(origin, who: <T::Lookup as StaticLookup>::Source) { fn remove_member(origin, who: <T::Lookup as StaticLookup>::Source) -> dispatch::Result {
ensure_root(origin)?; ensure_root(origin)?;
let who = T::Lookup::lookup(who)?; let who = T::Lookup::lookup(who)?;
return Self::remove_and_replace_member(&who).map(|had_replacement| { Self::remove_and_replace_member(&who).map(|had_replacement| {
let (imbalance, _) = T::Currency::slash_reserved(&who, T::CandidacyBond::get()); let (imbalance, _) = T::Currency::slash_reserved(&who, T::CandidacyBond::get());
T::KickedMember::on_unbalanced(imbalance); T::KickedMember::on_unbalanced(imbalance);
Self::deposit_event(RawEvent::MemberKicked(who.clone())); Self::deposit_event(RawEvent::MemberKicked(who.clone()));
@@ -403,8 +402,6 @@ decl_module! {
if !had_replacement { if !had_replacement {
Self::do_phragmen(); Self::do_phragmen();
} }
()
}) })
} }
@@ -452,37 +449,25 @@ impl<T: Trait> Module<T> {
if let Ok(index) = members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(who)) { if let Ok(index) = members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(who)) {
members_with_stake.remove(index); members_with_stake.remove(index);
let mut runners_up = Self::runners_up(); let next_up = <RunnersUp<T>>::mutate(|runners_up| runners_up.pop());
if let Some((replacement, stake)) = runners_up.pop() { let maybe_replacement = next_up.and_then(|(replacement, stake)|
// replace the outgoing with the best runner up. members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(&replacement))
if let Err(index) = members_with_stake .err()
.binary_search_by(|(ref m, ref _s)| m.cmp(&replacement)) .map(|index| {
{ members_with_stake.insert(index, (replacement.clone(), stake));
members_with_stake.insert(index, (replacement.clone(), stake)); replacement
ElectionRounds::mutate(|v| *v += 1); })
T::ChangeMembers::change_members_sorted( );
&[replacement],
&[who.clone()],
&members_with_stake
.iter()
.map(|(m, _)| m.clone())
.collect::<Vec<T::AccountId>>(),
);
}
// else it would mean that the runner up was already a member. This cannot
// happen. If it does, not much that we can do about it.
<Members<T>>::put(members_with_stake); <Members<T>>::put(&members_with_stake);
<RunnersUp<T>>::put(runners_up); let members = members_with_stake.into_iter().map(|m| m.0).collect::<Vec<_>>();
let result = Ok(maybe_replacement.is_some());
Ok(true) let old = [who.clone()];
} else { match maybe_replacement {
// update `Members` storage -- `do_phragmen` adds this to the candidate list. Some(new) => T::ChangeMembers::change_members_sorted(&[new], &old, &members),
<Members<T>>::put(members_with_stake); None => T::ChangeMembers::change_members_sorted(&[], &old, &members),
// signal caller that no replacement has been found.
Ok(false)
} }
result
} else { } else {
Err("not a member") Err("not a member")
} }
@@ -690,7 +675,7 @@ impl<T: Trait> Module<T> {
T::ChangeMembers::change_members_sorted( T::ChangeMembers::change_members_sorted(
&incoming, &incoming,
&outgoing.clone(), &outgoing.clone(),
&Self::members_ids(), &new_members_ids,
); );
// outgoing candidates lose their bond. // outgoing candidates lose their bond.
@@ -826,9 +811,25 @@ mod tests {
fn get() -> u64 { TERM_DURATION.with(|v| *v.borrow()) } fn get() -> u64 { TERM_DURATION.with(|v| *v.borrow()) }
} }
thread_local! {
pub static MEMBERS: RefCell<Vec<u64>> = RefCell::new(vec![]);
}
pub struct TestChangeMembers; pub struct TestChangeMembers;
impl ChangeMembers<u64> for TestChangeMembers { impl ChangeMembers<u64> for TestChangeMembers {
fn change_members_sorted(_: &[u64], _: &[u64], _: &[u64]) {} fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) {
let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec());
old_plus_incoming.extend_from_slice(incoming);
old_plus_incoming.sort();
let mut new_plus_outgoing = new.to_vec();
new_plus_outgoing.extend_from_slice(outgoing);
new_plus_outgoing.sort();
assert_eq!(old_plus_incoming, new_plus_outgoing);
MEMBERS.with(|m| *m.borrow_mut() = new.to_vec());
}
} }
/// Simple structure that exposes how u64 currency can be represented as... u64. /// Simple structure that exposes how u64 currency can be represented as... u64.