Skip to content

Commit

Permalink
Merge pull request #866 from galacticcouncil/feat/democracy-force-vot…
Browse files Browse the repository at this point in the history
…e-remove

feat: democracy - allow TC to remove a vote
  • Loading branch information
enthusiastmartin authored Jul 18, 2024
2 parents d86308e + e56444d commit 391e7de
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 13 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pallets/democracy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-democracy"
version = "4.2.1"
version = "4.3.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
license = "Apache-2.0"
Expand Down
51 changes: 46 additions & 5 deletions pallets/democracy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ pub mod pallet {
/// Hooks are actions that are executed on certain events.
/// Eg: on_vote
type DemocracyHooks: DemocracyHooks<Self::AccountId, BalanceOf<Self>>;

/// Origin for anyone able to force remove a vote.
type VoteRemovalOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
}

/// The number of (public) proposals that have been made so far.
Expand Down Expand Up @@ -988,7 +991,7 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::remove_vote(T::MaxVotes::get()))]
pub fn remove_vote(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::try_remove_vote(&who, index, UnvoteScope::Any)
Self::try_remove_vote(&who, index, UnvoteScope::Any, false)
}

/// Remove a vote for a referendum.
Expand Down Expand Up @@ -1020,7 +1023,7 @@ pub mod pallet {
} else {
UnvoteScope::OnlyExpired
};
Self::try_remove_vote(&target, index, scope)?;
Self::try_remove_vote(&target, index, scope, false)?;
Ok(())
}

Expand Down Expand Up @@ -1165,6 +1168,39 @@ pub mod pallet {
}
Ok(())
}

/// Allow to force remove a vote for a referendum.
///
/// Same as `remove_other_vote`, except the scope is overriden by forced flag.
/// The dispatch origin of this call must be `VoteRemovalOrigin`.
///
/// Only allowed if the referendum is finished.
///
/// The dispatch origin of this call must be _Signed_.
///
/// - `target`: The account of the vote to be removed; this account must have voted for
/// referendum `index`.
/// - `index`: The index of referendum of the vote to be removed.
///
/// Weight: `O(R + log R)` where R is the number of referenda that `target` has voted on.
/// Weight is calculated for the maximum number of vote.
#[pallet::call_index(19)]
#[pallet::weight(T::WeightInfo::remove_other_vote(T::MaxVotes::get()))]
pub fn force_remove_vote(
origin: OriginFor<T>,
target: crate::AccountIdLookupOf<T>,
index: crate::types::ReferendumIndex,
) -> DispatchResult {
let who = T::VoteRemovalOrigin::ensure_origin(origin)?;
let target = T::Lookup::lookup(target)?;
let scope = if target == who {
crate::types::UnvoteScope::Any
} else {
crate::types::UnvoteScope::OnlyExpired
};
Self::try_remove_vote(&target, index, scope, true)?;
Ok(())
}
}
}

Expand Down Expand Up @@ -1332,7 +1368,12 @@ impl<T: Config> Pallet<T> {
/// - The referendum has finished and the voter's lock period is up.
///
/// This will generally be combined with a call to `unlock`.
fn try_remove_vote(who: &T::AccountId, ref_index: ReferendumIndex, scope: UnvoteScope) -> DispatchResult {
fn try_remove_vote(
who: &T::AccountId,
ref_index: ReferendumIndex,
scope: UnvoteScope,
forced: bool,
) -> DispatchResult {
let info = ReferendumInfoOf::<T>::get(ref_index);
VotingOf::<T>::try_mutate(who, |voting| -> DispatchResult {
if let Voting::Direct {
Expand Down Expand Up @@ -1361,7 +1402,7 @@ impl<T: Config> Pallet<T> {
end.saturating_add(T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()));
let now = frame_system::Pallet::<T>::block_number();
if now < unlock_at {
ensure!(matches!(scope, UnvoteScope::Any), Error::<T>::NoPermission);
ensure!(forced || matches!(scope, UnvoteScope::Any), Error::<T>::NoPermission);
prior.accumulate(unlock_at, balance)
}
} else {
Expand All @@ -1375,7 +1416,7 @@ impl<T: Config> Pallet<T> {
);
let now = frame_system::Pallet::<T>::block_number();
if now < unlock_at {
ensure!(matches!(scope, UnvoteScope::Any), Error::<T>::NoPermission);
ensure!(forced || matches!(scope, UnvoteScope::Any), Error::<T>::NoPermission);
prior.accumulate(unlock_at, to_lock)
}
}
Expand Down
2 changes: 2 additions & 0 deletions pallets/democracy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ ord_parameter_types! {
pub const Four: u64 = 4;
pub const Five: u64 = 5;
pub const Six: u64 = 6;
pub const Seven: u64 = 7;
}
pub struct OneToFive;
impl SortedMembers<u64> for OneToFive {
Expand Down Expand Up @@ -211,6 +212,7 @@ impl Config for Test {
type MaxProposals = ConstU32<100>;
type Preimages = Preimage;
type DemocracyHooks = HooksHandler;
type VoteRemovalOrigin = EnsureSignedBy<Seven, u64>;
}

pub fn new_test_ext() -> sp_io::TestExternalities {
Expand Down
58 changes: 58 additions & 0 deletions pallets/democracy/src/tests/voting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,61 @@ fn passing_low_turnout_voting_should_work() {
assert_eq!(Balances::free_balance(42), 2);
});
}

#[test]
fn force_remove_vote_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance(1, 2, 1));
let r = 0;
assert!(Democracy::referendum_info(r).is_none());

// start of 2 => next referendum scheduled.
fast_forward_to(2);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, big_aye(1)));

assert_eq!(Democracy::referendum_count(), 1);
assert_eq!(
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally {
ayes: 10,
nays: 0,
turnout: 10
},
})
);

fast_forward_to(3);

// referendum still running
assert_ok!(Democracy::referendum_status(0));

// not allowed to force remove a vote when referendum is ongoing
assert_noop!(
Democracy::force_remove_vote(RuntimeOrigin::signed(7), 1, 0),
Error::<Test>::NoPermission
);

// referendum runs during 2 and 3, ends @ start of 4.
fast_forward_to(4);

assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_some());

// referendum passes and wait another two blocks for enactment.
fast_forward_to(6);

assert_eq!(Balances::free_balance(42), 2);

// Not allowed origin
assert_noop!(Democracy::force_remove_vote(RuntimeOrigin::signed(4), 1, 0), BadOrigin);

// Allowed origin
assert_ok!(Democracy::force_remove_vote(RuntimeOrigin::signed(7), 1, 0));
});
}
2 changes: 1 addition & 1 deletion runtime/hydradx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hydradx-runtime"
version = "247.0.0"
version = "248.0.0"
authors = ["GalacticCouncil"]
edition = "2021"
license = "Apache 2.0"
Expand Down
2 changes: 2 additions & 0 deletions runtime/hydradx/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ impl pallet_democracy::Config for Runtime {
type PalletsOrigin = OriginCaller;
type Slash = Treasury;
type DemocracyHooks = pallet_staking::integrations::democracy::StakingDemocracy<Runtime>;
// Any single technical committee member may remove a vote.
type VoteRemovalOrigin = frame_system::EnsureSignedBy<TechCommAccounts, AccountId>;
}

parameter_types! {
Expand Down
2 changes: 1 addition & 1 deletion runtime/hydradx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("hydradx"),
impl_name: create_runtime_str!("hydradx"),
authoring_version: 1,
spec_version: 247,
spec_version: 248,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down

0 comments on commit 391e7de

Please sign in to comment.