From 0e1d9c066a811ec0bcc17c45f49138208d36050e Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 5 Dec 2022 18:15:59 +0000 Subject: [PATCH] OpenGov: Abstentions (#12842) * OpenGov: Abstentions * Tests --- frame/conviction-voting/src/tests.rs | 51 ++++++++++++++++++++++++++++ frame/conviction-voting/src/types.rs | 18 ++++++++++ frame/conviction-voting/src/vote.rs | 6 ++++ 3 files changed, 75 insertions(+) diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 7a3f80442014a..d20dcb66d6198 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -237,6 +237,14 @@ fn nay(amount: u64, conviction: u8) -> AccountVote { AccountVote::Standard { vote, balance: amount } } +fn split(aye: u64, nay: u64) -> AccountVote { + AccountVote::Split { aye, nay } +} + +fn split_abstain(aye: u64, nay: u64, abstain: u64) -> AccountVote { + AccountVote::SplitAbstain { aye, nay, abstain } +} + fn tally(index: u8) -> TallyOf { >>::as_ongoing(index).expect("No poll").0 } @@ -295,6 +303,49 @@ fn basic_voting_works() { }); } +#[test] +fn split_voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(10, 0))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(5, 5))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 5)); + assert_eq!(Balances::usable_balance(1), 0); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + }); +} + +#[test] +fn abstain_voting_works() { + new_test_ext().execute_with(|| { + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split_abstain(0, 0, 10))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(0, 0, 20))); + assert_eq!(tally(3), Tally::from_parts(0, 0, 30)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(10, 0, 10))); + assert_eq!(tally(3), Tally::from_parts(1, 0, 30)); + assert_eq!(Balances::usable_balance(1), 0); + assert_eq!(Balances::usable_balance(2), 0); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + assert_eq!(tally(3), Tally::from_parts(1, 0, 20)); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(2), None, 3)); + assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + assert_eq!(Balances::usable_balance(1), 10); + + assert_ok!(Voting::unlock(RuntimeOrigin::signed(2), class(3), 2)); + assert_eq!(Balances::usable_balance(2), 20); + }); +} + #[test] fn voting_balance_gets_locked() { new_test_ext().execute_with(|| { diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index d6051dff62569..aa2406eef7110 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -147,6 +147,15 @@ impl< self.ayes = self.ayes.checked_add(&aye.votes)?; self.nays = self.nays.checked_add(&nay.votes)?; }, + AccountVote::SplitAbstain { aye, nay, abstain } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + let abstain = Conviction::None.votes(abstain); + self.support = + self.support.checked_add(&aye.capital)?.checked_add(&abstain.capital)?; + self.ayes = self.ayes.checked_add(&aye.votes)?; + self.nays = self.nays.checked_add(&nay.votes)?; + }, } Some(()) } @@ -171,6 +180,15 @@ impl< self.ayes = self.ayes.checked_sub(&aye.votes)?; self.nays = self.nays.checked_sub(&nay.votes)?; }, + AccountVote::SplitAbstain { aye, nay, abstain } => { + let aye = Conviction::None.votes(aye); + let nay = Conviction::None.votes(nay); + let abstain = Conviction::None.votes(abstain); + self.support = + self.support.checked_sub(&aye.capital)?.checked_sub(&abstain.capital)?; + self.ayes = self.ayes.checked_sub(&aye.votes)?; + self.nays = self.nays.checked_sub(&nay.votes)?; + }, } Some(()) } diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index a8e012b6c97a1..1fed70536d246 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -74,6 +74,10 @@ pub enum AccountVote { /// A split vote with balances given for both ways, and with no conviction, useful for /// parachains when voting. Split { aye: Balance, nay: Balance }, + /// A split vote with balances given for both ways as well as abstentions, and with no + /// conviction, useful for parachains when voting, other off-chain aggregate accounts and + /// individuals who wish to abstain. + SplitAbstain { aye: Balance, nay: Balance, abstain: Balance }, } impl AccountVote { @@ -94,6 +98,8 @@ impl AccountVote { match self { AccountVote::Standard { balance, .. } => balance, AccountVote::Split { aye, nay } => aye.saturating_add(nay), + AccountVote::SplitAbstain { aye, nay, abstain } => + aye.saturating_add(nay).saturating_add(abstain), } }