diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index d5fdf37d42..37f8f30e28 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1727,7 +1727,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2864,7 +2864,7 @@ dependencies = [ "fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-codec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5617,7 +5617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uint" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6501,7 +6501,7 @@ dependencies = [ "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" -"checksum uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8f0f47ed099f0db671ce82c66548c5de012e3c0cba3963514d1db15c7588701" +"checksum uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5375d2c574f89adad4108ad525c93e39669853a602560bf5ed4ca9943b10799" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 6c965e7a8f..7fa848a0d6 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -81,7 +81,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 146, - impl_version: 146, + impl_version: 147, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/elections/src/lib.rs b/substrate/srml/elections/src/lib.rs index a96588e84a..58ad47a4ed 100644 --- a/substrate/srml/elections/src/lib.rs +++ b/substrate/srml/elections/src/lib.rs @@ -892,9 +892,17 @@ impl Module { count += 1; } for (old, new) in candidates.iter().zip(new_candidates.iter()) { + // candidate is not a runner up. if old != new { // removed - kill it >::remove(old); + + // and candidate is not a winner. + if incoming.iter().find(|e| *e == old).is_none() { + // slash the bond. + let (imbalance, _) = T::Currency::slash_reserved(&old, T::CandidacyBond::get()); + T::LoserCandidate::on_unbalanced(imbalance); + } } } // discard any superfluous slots. @@ -1253,6 +1261,7 @@ mod tests { pub struct ExtBuilder { balance_factor: u64, decay_ratio: u32, + desired_seats: u32, voting_fee: u64, voter_bond: u64, bad_presentation_punishment: u64, @@ -1263,6 +1272,7 @@ mod tests { Self { balance_factor: 1, decay_ratio: 24, + desired_seats: 2, voting_fee: 0, voter_bond: 0, bad_presentation_punishment: 1, @@ -1291,6 +1301,10 @@ mod tests { self.voter_bond = fee; self } + pub fn desired_seats(mut self, seats: u32) -> Self { + self.desired_seats = seats; + self + } pub fn build(self) -> runtime_io::TestExternalities { VOTER_BOND.with(|v| *v.borrow_mut() = self.voter_bond); VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); @@ -1310,7 +1324,7 @@ mod tests { }), elections: Some(elections::GenesisConfig::{ members: vec![], - desired_seats: 2, + desired_seats: self.desired_seats, presentation_duration: 2, term_duration: 5, }), @@ -1341,6 +1355,10 @@ mod tests { ::VotingBond::get() } + fn balances(who: &u64) -> (u64, u64) { + (Balances::free_balance(who), Balances::reserved_balance(who)) + } + #[test] fn bool_to_flag_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { @@ -2471,8 +2489,6 @@ mod tests { assert_eq!(voter_ids(), vec![0, 5]); assert_eq!(Elections::all_approvals_of(&2).len(), 0); - assert_eq!(Balances::total_balance(&2), 18); - assert_eq!(Balances::total_balance(&5), 52); }); } @@ -2873,4 +2889,41 @@ mod tests { assert_eq!(Elections::candidate_reg_info(4), Some((0, 3))); }); } + + #[test] + fn loser_candidates_bond_gets_slashed() { + with_externalities(&mut ExtBuilder::default().desired_seats(1).build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); + + assert_eq!(balances(&2), (17, 3)); + + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, true, true, true], 0, 0)); + + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(4), 4, 10, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(3), 3, 10, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(2), 2, 10, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 50, 0), Ok(())); + + + // winner + carry + assert_eq!(Elections::leaderboard(), Some(vec![(10, 3), (10, 4), (50, 1)])); + assert_ok!(Elections::end_block(System::block_number())); + assert!(!Elections::presentation_active()); + assert_eq!(Elections::members(), vec![(1, 11)]); + + // account 2 is not a runner up or in leaderboard. + assert_eq!(balances(&2), (17, 0)); + }); + } }