Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Tidy Democracy #10867

Merged
merged 7 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions frame/democracy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,12 @@ pub mod pallet {

<NextExternal<T>>::kill();
let now = <frame_system::Pallet<T>>::block_number();
Self::inject_referendum(now + voting_period, proposal_hash, threshold, delay);
Self::inject_referendum(
now.saturating_add(voting_period),
proposal_hash,
threshold,
delay,
);
Ok(())
}

Expand Down Expand Up @@ -871,7 +876,8 @@ pub mod pallet {
existing_vetoers.binary_search(&who).err().ok_or(Error::<T>::AlreadyVetoed)?;

existing_vetoers.insert(insert_position, who.clone());
let until = <frame_system::Pallet<T>>::block_number() + T::CooloffPeriod::get();
let until =
<frame_system::Pallet<T>>::block_number().saturating_add(T::CooloffPeriod::get());
<Blacklist<T>>::insert(&proposal_hash, (until, existing_vetoers));

Self::deposit_event(Event::<T>::Vetoed { who, proposal_hash, until });
Expand Down Expand Up @@ -1089,7 +1095,10 @@ pub mod pallet {
let now = <frame_system::Pallet<T>>::block_number();
let (voting, enactment) = (T::VotingPeriod::get(), T::EnactmentPeriod::get());
let additional = if who == provider { Zero::zero() } else { enactment };
ensure!(now >= since + voting + additional, Error::<T>::TooEarly);
ensure!(
now >= since.saturating_add(voting).saturating_add(additional),
Error::<T>::TooEarly
);
ensure!(expiry.map_or(true, |e| now > e), Error::<T>::Imminent);

let res =
Expand Down Expand Up @@ -1282,7 +1291,7 @@ impl<T: Config> Pallet<T> {
/// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal
/// index.
pub fn backing_for(proposal: PropIndex) -> Option<BalanceOf<T>> {
Self::deposit_of(proposal).map(|(l, d)| d * (l.len() as u32).into())
Self::deposit_of(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into()))
}

/// Get all referenda ready for tally at block `n`.
Expand Down Expand Up @@ -1318,7 +1327,7 @@ impl<T: Config> Pallet<T> {
delay: T::BlockNumber,
) -> ReferendumIndex {
<Pallet<T>>::inject_referendum(
<frame_system::Pallet<T>>::block_number() + T::VotingPeriod::get(),
<frame_system::Pallet<T>>::block_number().saturating_add(T::VotingPeriod::get()),
proposal_hash,
threshold,
delay,
Expand Down Expand Up @@ -1424,7 +1433,9 @@ impl<T: Config> Pallet<T> {
},
Some(ReferendumInfo::Finished { end, approved }) => {
if let Some((lock_periods, balance)) = votes[i].1.locked_if(approved) {
let unlock_at = end + T::VoteLockingPeriod::get() * lock_periods.into();
let unlock_at = end.saturating_add(
T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()),
);
let now = frame_system::Pallet::<T>::block_number();
if now < unlock_at {
ensure!(
Expand Down Expand Up @@ -1513,9 +1524,16 @@ impl<T: Config> Pallet<T> {
};
sp_std::mem::swap(&mut old, voting);
match old {
Voting::Delegating { balance, target, conviction, delegations, prior, .. } => {
Voting::Delegating {
balance, target, conviction, delegations, mut prior, ..
} => {
// remove any delegation votes to our current target.
Self::reduce_upstream_delegation(&target, conviction.votes(balance));
let now = frame_system::Pallet::<T>::block_number();
let lock_periods = conviction.lock_periods().into();
let unlock_block = now
.saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods));
prior.accumulate(unlock_block, balance);
voting.set_common(delegations, prior);
},
Voting::Direct { votes, delegations, prior } => {
Expand Down Expand Up @@ -1548,7 +1566,9 @@ impl<T: Config> Pallet<T> {
Self::reduce_upstream_delegation(&target, conviction.votes(balance));
let now = frame_system::Pallet::<T>::block_number();
let lock_periods = conviction.lock_periods().into();
prior.accumulate(now + T::VoteLockingPeriod::get() * lock_periods, balance);
let unlock_block = now
.saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods));
prior.accumulate(unlock_block, balance);
voting.set_common(delegations, prior);

Ok(votes)
Expand Down Expand Up @@ -1607,7 +1627,7 @@ impl<T: Config> Pallet<T> {
LastTabledWasExternal::<T>::put(true);
Self::deposit_event(Event::<T>::ExternalTabled);
Self::inject_referendum(
now + T::VotingPeriod::get(),
now.saturating_add(T::VotingPeriod::get()),
proposal,
threshold,
T::EnactmentPeriod::get(),
Expand Down Expand Up @@ -1639,7 +1659,7 @@ impl<T: Config> Pallet<T> {
depositors,
});
Self::inject_referendum(
now + T::VotingPeriod::get(),
now.saturating_add(T::VotingPeriod::get()),
proposal,
VoteThreshold::SuperMajorityApprove,
T::EnactmentPeriod::get(),
Expand Down Expand Up @@ -1693,7 +1713,7 @@ impl<T: Config> Pallet<T> {
if status.delay.is_zero() {
let _ = Self::do_enact_proposal(status.proposal_hash, index);
} else {
let when = now + status.delay;
let when = now.saturating_add(status.delay);
// Note that we need the preimage now.
Preimages::<T>::mutate_exists(
&status.proposal_hash,
Expand Down
41 changes: 40 additions & 1 deletion frame/democracy/src/tests/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn conviction_should_be_honored_in_delegation() {
// If transactor voted, delegated vote is overwritten.
new_test_ext().execute_with(|| {
let r = begin_referendum();
// Delegate, undelegate and vote.
// Delegate and vote.
assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20));
assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1)));
// Delegated vote is huge.
Expand All @@ -177,3 +177,42 @@ fn split_vote_delegation_should_be_ignored() {
assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 });
});
}

#[test]
fn redelegation_keeps_lock() {
// If transactor voted, delegated vote is overwritten.
new_test_ext().execute_with(|| {
let r = begin_referendum();
// Delegate and vote.
assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20));
assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1)));
// Delegated vote is huge.
assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 });

let mut prior_lock = vote::PriorLock::default();

// Locked balance of delegator exists
assert_eq!(VotingOf::<Test>::get(2).locked_balance(), 20);
assert_eq!(VotingOf::<Test>::get(2).prior(), &prior_lock);

// Delegate someone else at a lower conviction and amount
assert_ok!(Democracy::delegate(Origin::signed(2), 3, Conviction::None, 10));

// 6x prior should appear w/ locked balance.
prior_lock.accumulate(98, 20);
assert_eq!(VotingOf::<Test>::get(2).prior(), &prior_lock);
assert_eq!(VotingOf::<Test>::get(2).locked_balance(), 20);
// Unlock shouldn't work
assert_ok!(Democracy::unlock(Origin::signed(2), 2));
assert_eq!(VotingOf::<Test>::get(2).prior(), &prior_lock);
assert_eq!(VotingOf::<Test>::get(2).locked_balance(), 20);

fast_forward_to(100);

// Now unlock can remove the prior lock and reduce the locked amount.
assert_eq!(VotingOf::<Test>::get(2).prior(), &prior_lock);
assert_ok!(Democracy::unlock(Origin::signed(2), 2));
assert_eq!(VotingOf::<Test>::get(2).prior(), &vote::PriorLock::default());
assert_eq!(VotingOf::<Test>::get(2).locked_balance(), 10);
});
}
9 changes: 8 additions & 1 deletion frame/democracy/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<Balance: Saturating + Ord + Zero + Copy, BlockNumber: Ord + Copy + Zero, Ac
match self {
Voting::Direct { votes, prior, .. } =>
votes.iter().map(|i| i.1.balance()).fold(prior.locked(), |a, i| a.max(i)),
Voting::Delegating { balance, .. } => *balance,
Voting::Delegating { balance, prior, .. } => *balance.max(&prior.locked()),
}
}

Expand All @@ -199,4 +199,11 @@ impl<Balance: Saturating + Ord + Zero + Copy, BlockNumber: Ord + Copy + Zero, Ac
*d = delegations;
*p = prior;
}

pub fn prior(&self) -> &PriorLock<BlockNumber, Balance> {
match self {
Voting::Direct { prior, .. } => prior,
Voting::Delegating { prior, .. } => prior,
}
}
}