Participating in Council Governance is Free for First Time Voters and Successful Closing (#7661)

* wk2049 | D5 | addition-motions first free vote for members | p1

* Update frame/collective/src/lib.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* wk2049 | D6 | addition-motions first free vote for members | p2

* Update frame/collective/src/lib.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* wk2049 | D7 | addition-motions first free vote for members | p3

* Update frame/collective/src/lib.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* wk2049 | D7 | addition-motions first free vote for members | p4

* wk2049 | D7 | addition-motions first free vote for members | p6

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/collective/src/lib.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* wk2050 | D3 | addition-motions first free vote for members | p7

* wk2050 | D3 | addition-motions first free vote for members | p8

* update comment

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
RK
2020-12-15 23:59:11 +05:30
committed by GitHub
parent 9706023ec7
commit c79fde5fae
+127 -14
View File
@@ -56,7 +56,7 @@ use frame_support::{
},
ensure,
traits::{ChangeMembers, EnsureOrigin, Get, InitializeMembers},
weights::{DispatchClass, GetDispatchInfo, Weight},
weights::{DispatchClass, GetDispatchInfo, Weight, Pays},
};
use frame_system::{self as system, ensure_signed, ensure_root};
@@ -488,6 +488,8 @@ decl_module! {
///
/// Requires the sender to be a member.
///
/// Transaction fees will be waived if the member is voting on any particular proposal
/// for the first time and the call is successful. Subsequent vote changes will charge a fee.
/// # <weight>
/// ## Weight
/// - `O(M)` where `M` is members-count (code- and governance-bounded)
@@ -515,6 +517,9 @@ decl_module! {
let position_yes = voting.ayes.iter().position(|a| a == &who);
let position_no = voting.nays.iter().position(|a| a == &who);
// Detects first vote of the member in the motion
let is_account_voting_first_time = position_yes.is_none() && position_no.is_none();
if approve {
if position_yes.is_none() {
voting.ayes.push(who.clone());
@@ -541,7 +546,17 @@ decl_module! {
Voting::<T, I>::insert(&proposal, voting);
Ok(Some(T::WeightInfo::vote(members.len() as u32)).into())
if is_account_voting_first_time {
Ok((
Some(T::WeightInfo::vote(members.len() as u32)),
Pays::No,
).into())
} else {
Ok((
Some(T::WeightInfo::vote(members.len() as u32)),
Pays::Yes,
).into())
}
}
/// Close a vote that is either approved, disapproved or whose voting period has ended.
@@ -554,6 +569,9 @@ decl_module! {
/// If called after the end of the voting period abstentions are counted as rejections
/// unless there is a prime member set and the prime member cast an approval.
///
/// If the close operation completes successfully with disapproval, the transaction fee will
/// be waived. Otherwise execution of the approved operation will be charged to the caller.
///
/// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed proposal.
/// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via
/// `storage::read` so it is `size_of::<u32>() == 4` larger than the pure length.
@@ -606,20 +624,23 @@ decl_module! {
let (proposal, len) = Self::validate_and_get_proposal(
&proposal_hash,
length_bound,
proposal_weight_bound
proposal_weight_bound,
)?;
Self::deposit_event(RawEvent::Closed(proposal_hash, yes_votes, no_votes));
let (proposal_weight, proposal_count) =
Self::do_approve_proposal(seats, voting, proposal_hash, proposal);
return Ok(Some(
T::WeightInfo::close_early_approved(len as u32, seats, proposal_count)
.saturating_add(proposal_weight)
return Ok((
Some(T::WeightInfo::close_early_approved(len as u32, seats, proposal_count)
.saturating_add(proposal_weight)),
Pays::Yes,
).into());
} else if disapproved {
Self::deposit_event(RawEvent::Closed(proposal_hash, yes_votes, no_votes));
let proposal_count = Self::do_disapprove_proposal(proposal_hash);
return Ok(Some(
T::WeightInfo::close_early_disapproved(seats, proposal_count)
return Ok((
Some(T::WeightInfo::close_early_disapproved(seats, proposal_count)),
Pays::No,
).into());
}
@@ -642,20 +663,22 @@ decl_module! {
let (proposal, len) = Self::validate_and_get_proposal(
&proposal_hash,
length_bound,
proposal_weight_bound
proposal_weight_bound,
)?;
Self::deposit_event(RawEvent::Closed(proposal_hash, yes_votes, no_votes));
let (proposal_weight, proposal_count) =
Self::do_approve_proposal(seats, voting, proposal_hash, proposal);
return Ok(Some(
T::WeightInfo::close_approved(len as u32, seats, proposal_count)
.saturating_add(proposal_weight)
return Ok((
Some(T::WeightInfo::close_approved(len as u32, seats, proposal_count)
.saturating_add(proposal_weight)),
Pays::Yes,
).into());
} else {
Self::deposit_event(RawEvent::Closed(proposal_hash, yes_votes, no_votes));
let proposal_count = Self::do_disapprove_proposal(proposal_hash);
return Ok(Some(
T::WeightInfo::close_disapproved(seats, proposal_count)
return Ok((
Some(T::WeightInfo::close_disapproved(seats, proposal_count)),
Pays::No,
).into());
}
}
@@ -1436,6 +1459,96 @@ mod tests {
});
}
#[test]
fn motions_all_first_vote_free_works() {
new_test_ext().execute_with(|| {
let proposal = make_proposal(42);
let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32);
let hash: H256 = proposal.blake2_256().into();
let end = 4;
assert_ok!(
Collective::propose(
Origin::signed(1),
2,
Box::new(proposal.clone()),
proposal_len,
)
);
assert_eq!(
Collective::voting(&hash),
Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![], end })
);
// For the motion, acc 2's first vote, expecting Ok with Pays::No.
let vote_rval: DispatchResultWithPostInfo = Collective::vote(
Origin::signed(2),
hash.clone(),
0,
true,
);
assert_eq!(vote_rval.unwrap().pays_fee, Pays::No);
// Duplicate vote, expecting error with Pays::Yes.
let vote_rval: DispatchResultWithPostInfo = Collective::vote(
Origin::signed(2),
hash.clone(),
0,
true,
);
assert_eq!(vote_rval.unwrap_err().post_info.pays_fee, Pays::Yes);
// Modifying vote, expecting ok with Pays::Yes.
let vote_rval: DispatchResultWithPostInfo = Collective::vote(
Origin::signed(2),
hash.clone(),
0,
false,
);
assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes);
// For the motion, acc 3's first vote, expecting Ok with Pays::No.
let vote_rval: DispatchResultWithPostInfo = Collective::vote(
Origin::signed(3),
hash.clone(),
0,
true,
);
assert_eq!(vote_rval.unwrap().pays_fee, Pays::No);
// acc 3 modify the vote, expecting Ok with Pays::Yes.
let vote_rval: DispatchResultWithPostInfo = Collective::vote(
Origin::signed(3),
hash.clone(),
0,
false,
);
assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes);
// Test close() Extrincis | Check DispatchResultWithPostInfo with Pay Info
let proposal_weight = proposal.get_dispatch_info().weight;
let close_rval: DispatchResultWithPostInfo = Collective::close(
Origin::signed(2),
hash.clone(),
0,
proposal_weight,
proposal_len,
);
assert_eq!(close_rval.unwrap().pays_fee, Pays::No);
// trying to close the proposal, which is already closed.
// Expecting error "ProposalMissing" with Pays::Yes
let close_rval: DispatchResultWithPostInfo = Collective::close(
Origin::signed(2),
hash.clone(),
0,
proposal_weight,
proposal_len,
);
assert_eq!(close_rval.unwrap_err().post_info.pays_fee, Pays::Yes);
});
}
#[test]
fn motions_reproposing_disapproved_works() {
new_test_ext().execute_with(|| {