mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 23:31:07 +00:00
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:
@@ -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(|| {
|
||||
|
||||
Reference in New Issue
Block a user