Ver código fonte

Merge pull request #2974 from shamil-gadelshin/olympia_change_quorum_algorithm

Olympia. Change quorum and threshold algorithm - alter effect of abstention.
shamil-gadelshin 3 anos atrás
pai
commit
a1a97df831

+ 129 - 3
runtime-modules/proposals/engine/src/tests/mod.rs

@@ -2179,12 +2179,12 @@ fn proposal_early_rejection_succeeds() {
         let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
 
         let mut vote_generator = VoteGenerator::new(proposal_id);
-        vote_generator.vote_and_assert_ok(VoteKind::Abstain);
-        vote_generator.vote_and_assert_ok(VoteKind::Abstain);
+        vote_generator.vote_and_assert_ok(VoteKind::Reject);
+        vote_generator.vote_and_assert_ok(VoteKind::Reject);
 
         assert_eq!(
             <VoteExistsByProposalByVoter<Test>>::get(&proposal_id, &2),
-            VoteKind::Abstain
+            VoteKind::Reject
         );
 
         run_to_block_and_finalize(1);
@@ -2530,6 +2530,7 @@ fn proposal_status_resolution_approval_quorum_works_correctly() {
         total_voters_count: 500,
         approvals: 3,
         slashes: 3,
+        abstentions: 0,
     };
 
     assert!(!no_approval_proposal_status_resolution.is_approval_quorum_reached());
@@ -2559,6 +2560,7 @@ fn proposal_status_resolution_slashing_quorum_works_correctly() {
         total_voters_count: 500,
         approvals: 3,
         slashes: 3,
+        abstentions: 0,
     };
 
     assert!(!no_slashing_proposal_status_resolution.is_slashing_quorum_reached());
@@ -2588,6 +2590,7 @@ fn proposal_status_resolution_approval_threshold_works_correctly() {
         total_voters_count: 600,
         approvals: 314,
         slashes: 3,
+        abstentions: 0,
     };
 
     assert!(!no_approval_proposal_status_resolution.is_approval_threshold_reached());
@@ -2617,6 +2620,7 @@ fn proposal_status_resolution_slashing_threshold_works_correctly() {
         total_voters_count: 600,
         approvals: 3,
         slashes: 314,
+        abstentions: 0,
     };
 
     assert!(!no_slashing_proposal_status_resolution.is_slashing_threshold_reached());
@@ -2665,6 +2669,7 @@ fn proposal_status_resolution_approval_achievable_works_correctly() {
         total_voters_count: 600,
         approvals: 1,
         slashes: 0,
+        abstentions: 0,
     };
 
     assert!(!not_achievable_proposal_status_resolution.is_approval_threshold_achievable());
@@ -2696,6 +2701,7 @@ fn proposal_status_resolution_is_slashing_achievable_works_correctly() {
         total_voters_count: 600,
         approvals: 0,
         slashes: 1,
+        abstentions: 0,
     };
 
     assert!(!not_achievable_proposal_status_resolution.is_approval_threshold_achievable());
@@ -2709,3 +2715,123 @@ fn proposal_status_resolution_is_slashing_achievable_works_correctly() {
     assert!(slashing_threshold_achievable_resolution.is_slashing_threshold_achievable());
     assert!(!slashing_threshold_achievable_resolution.is_rejection_imminent());
 }
+
+#[test]
+fn proposal_status_resolution_slashing_threshold_works_correctly_with_abstentions() {
+    let no_slashing_threshold_proposal: Proposal<u64, u64, u64, u64> = Proposal {
+        parameters: ProposalParameters {
+            slashing_threshold_percentage: 63,
+            approval_threshold_percentage: 63,
+            ..ProposalParameters::default()
+        },
+        ..Proposal::default()
+    };
+    let no_slashing_proposal_status_resolution = ProposalStatusResolution {
+        proposal: &no_slashing_threshold_proposal,
+        now: 20,
+        votes_count: 500,
+        total_voters_count: 600,
+        approvals: 3,
+        slashes: 314,
+        abstentions: 1,
+    };
+
+    assert!(!no_slashing_proposal_status_resolution.is_slashing_threshold_reached());
+
+    let slashing_threshold_proposal_status_resolution = ProposalStatusResolution {
+        abstentions: 2,
+        ..no_slashing_proposal_status_resolution
+    };
+
+    assert!(slashing_threshold_proposal_status_resolution.is_slashing_threshold_reached());
+}
+
+#[test]
+fn proposal_status_resolution_approval_threshold_works_correctly_with_abstentions() {
+    let no_approval_threshold_proposal: Proposal<u64, u64, u64, u64> = Proposal {
+        parameters: ProposalParameters {
+            slashing_threshold_percentage: 63,
+            approval_threshold_percentage: 63,
+            ..ProposalParameters::default()
+        },
+        ..Proposal::default()
+    };
+    let no_approval_proposal_status_resolution = ProposalStatusResolution {
+        proposal: &no_approval_threshold_proposal,
+        now: 20,
+        votes_count: 500,
+        total_voters_count: 600,
+        approvals: 314,
+        slashes: 3,
+        abstentions: 1,
+    };
+
+    assert!(!no_approval_proposal_status_resolution.is_approval_threshold_reached());
+
+    let approval_threshold_proposal_status_resolution = ProposalStatusResolution {
+        abstentions: 2,
+        ..no_approval_proposal_status_resolution
+    };
+
+    assert!(approval_threshold_proposal_status_resolution.is_approval_threshold_reached());
+}
+
+#[test]
+fn proposal_status_resolution_slashing_quorum_works_correctly_with_abstentions() {
+    let no_slashing_quorum_proposal: Proposal<u64, u64, u64, u64> = Proposal {
+        parameters: ProposalParameters {
+            approval_quorum_percentage: 63,
+            slashing_quorum_percentage: 63,
+            ..ProposalParameters::default()
+        },
+        ..Proposal::default()
+    };
+    let no_slashing_proposal_status_resolution = ProposalStatusResolution {
+        proposal: &no_slashing_quorum_proposal,
+        now: 20,
+        votes_count: 315,
+        total_voters_count: 500,
+        approvals: 3,
+        slashes: 3,
+        abstentions: 1,
+    };
+
+    assert!(!no_slashing_proposal_status_resolution.is_slashing_quorum_reached());
+
+    let slashing_quorum_proposal_status_resolution = ProposalStatusResolution {
+        votes_count: 316,
+        ..no_slashing_proposal_status_resolution
+    };
+
+    assert!(slashing_quorum_proposal_status_resolution.is_slashing_quorum_reached());
+}
+
+#[test]
+fn proposal_status_resolution_approval_quorum_works_correctly_with_abstentions() {
+    let no_approval_quorum_proposal: Proposal<u64, u64, u64, u64> = Proposal {
+        parameters: ProposalParameters {
+            approval_quorum_percentage: 63,
+            slashing_threshold_percentage: 63,
+            ..ProposalParameters::default()
+        },
+        ..Proposal::default()
+    };
+    let no_approval_proposal_status_resolution = ProposalStatusResolution {
+        proposal: &no_approval_quorum_proposal,
+        now: 20,
+        votes_count: 315,
+        total_voters_count: 500,
+        approvals: 3,
+        slashes: 3,
+        abstentions: 1,
+    };
+
+    assert!(!no_approval_proposal_status_resolution.is_approval_quorum_reached());
+
+    let approval_quorum_proposal_status_resolution = ProposalStatusResolution {
+        votes_count: 316,
+        ..no_approval_proposal_status_resolution
+    };
+
+    assert!(approval_quorum_proposal_status_resolution.is_approval_quorum_reached());
+}

+ 29 - 10
runtime-modules/proposals/engine/src/types/mod.rs

@@ -202,6 +202,7 @@ where
             proposal: self,
             approvals: self.voting_results.approvals,
             slashes: self.voting_results.slashes,
+            abstentions: self.voting_results.abstentions,
             now,
             votes_count: self.voting_results.votes_number(),
             total_voters_count,
@@ -262,6 +263,8 @@ pub(crate) struct ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance,
     pub approvals: u32,
     /// Slash votes number
     pub slashes: u32,
+    /// Abstain votes number
+    pub abstentions: u32,
 }
 
 impl<'a, BlockNumber, ProposerId, Balance, AccountId>
@@ -270,6 +273,14 @@ where
     BlockNumber: Add<Output = BlockNumber> + PartialOrd + Copy,
     AccountId: Clone,
 {
+    // Defines vote count during the quorum and threshold calculations.
+    // It subtracts the abstentions from the all votes count.
+    // We alter the `votes count for quorum and threshold calculations` after this issue:
+    // https://github.com/Joystream/joystream/issues/2953
+    pub fn votes_count_without_abstentions(&self) -> u32 {
+        self.votes_count.saturating_sub(self.abstentions)
+    }
+
     // Proposal has been expired and quorum not reached.
     pub fn is_expired(&self) -> bool {
         self.proposal.is_voting_period_expired(self.now)
@@ -278,8 +289,10 @@ where
     // Approval quorum reached for the proposal. Compares predefined parameter with actual
     // votes sum divided by total possible votes number.
     pub(crate) fn is_approval_quorum_reached(&self) -> bool {
-        let actual_votes_fraction =
-            Perbill::from_rational_approximation(self.votes_count, self.total_voters_count);
+        let actual_votes_fraction = Perbill::from_rational_approximation(
+            self.votes_count_without_abstentions(),
+            self.total_voters_count,
+        );
         let approval_quorum_fraction =
             Perbill::from_percent(self.proposal.parameters.approval_quorum_percentage);
 
@@ -292,7 +305,7 @@ where
         let remaining_votes_count = self.total_voters_count - self.votes_count;
         let possible_approval_votes_fraction = Perbill::from_rational_approximation(
             self.approvals + remaining_votes_count,
-            self.votes_count + remaining_votes_count,
+            self.votes_count_without_abstentions() + remaining_votes_count,
         );
 
         let required_threshold_fraction =
@@ -312,7 +325,7 @@ where
         let remaining_votes_count = self.total_voters_count - self.votes_count;
         let possible_slashing_votes_fraction = Perbill::from_rational_approximation(
             self.slashes + remaining_votes_count,
-            self.votes_count + remaining_votes_count,
+            self.votes_count_without_abstentions() + remaining_votes_count,
         );
 
         let required_threshold_fraction =
@@ -324,8 +337,10 @@ where
     // Slashing quorum reached for the proposal. Compares predefined parameter with actual
     // votes sum divided by total possible votes number.
     pub fn is_slashing_quorum_reached(&self) -> bool {
-        let actual_votes_fraction =
-            Perbill::from_rational_approximation(self.votes_count, self.total_voters_count);
+        let actual_votes_fraction = Perbill::from_rational_approximation(
+            self.votes_count_without_abstentions(),
+            self.total_voters_count,
+        );
         let slashing_quorum_fraction =
             Perbill::from_percent(self.proposal.parameters.slashing_quorum_percentage);
 
@@ -335,8 +350,10 @@ where
     // Approval threshold reached for the proposal. Compares predefined parameter with 'approve'
     // votes sum divided by actual votes number.
     pub fn is_approval_threshold_reached(&self) -> bool {
-        let approval_votes_fraction =
-            Perbill::from_rational_approximation(self.approvals, self.votes_count);
+        let approval_votes_fraction = Perbill::from_rational_approximation(
+            self.approvals,
+            self.votes_count_without_abstentions(),
+        );
         let required_threshold_fraction =
             Perbill::from_percent(self.proposal.parameters.approval_threshold_percentage);
 
@@ -346,8 +363,10 @@ where
     // Slashing threshold reached for the proposal. Compares predefined parameter with 'approve'
     // votes sum divided by actual votes count.
     pub fn is_slashing_threshold_reached(&self) -> bool {
-        let slashing_votes_fraction =
-            Perbill::from_rational_approximation(self.slashes, self.votes_count);
+        let slashing_votes_fraction = Perbill::from_rational_approximation(
+            self.slashes,
+            self.votes_count_without_abstentions(),
+        );
         let required_threshold_fraction =
             Perbill::from_percent(self.proposal.parameters.slashing_threshold_percentage);