diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 909ff931756ad..eba64f52f63f5 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -620,6 +620,7 @@ impl pallet_democracy::Config for Runtime { type EnactmentPeriod = EnactmentPeriod; type LaunchPeriod = LaunchPeriod; type VotingPeriod = VotingPeriod; + type VoteLockingPeriod = EnactmentPeriod; // Same as EnactmentPeriod type MinimumDeposit = MinimumDeposit; /// A straight majority of the council can decide what their next motion is. type ExternalOrigin = diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 9a1dd503b7991..473ac964692cf 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -263,8 +263,7 @@ pub mod pallet { type Currency: ReservableCurrency + LockableCurrency; - /// The minimum period of locking and the period between a proposal being approved and - /// enacted. + /// The period between a proposal being approved and enacted. /// /// It should generally be a little more than the unstake period to ensure that /// voting stakers have an opportunity to remove themselves from the system in the case @@ -280,6 +279,13 @@ pub mod pallet { #[pallet::constant] type VotingPeriod: Get; + /// The minimum period of vote locking. + /// + /// It should be no shorter than enactment period to ensure that in the case of an approval, + /// those successful voters are locked into the consequences that their votes entail. + #[pallet::constant] + type VoteLockingPeriod: Get; + /// The minimum amount to be used as a deposit for a public referendum proposal. #[pallet::constant] type MinimumDeposit: Get>; @@ -1429,7 +1435,7 @@ impl Pallet { }, Some(ReferendumInfo::Finished { end, approved }) => { if let Some((lock_periods, balance)) = votes[i].1.locked_if(approved) { - let unlock_at = end + T::EnactmentPeriod::get() * lock_periods.into(); + let unlock_at = end + T::VoteLockingPeriod::get() * lock_periods.into(); let now = frame_system::Pallet::::block_number(); if now < unlock_at { ensure!( @@ -1553,7 +1559,7 @@ impl Pallet { Self::reduce_upstream_delegation(&target, conviction.votes(balance)); let now = frame_system::Pallet::::block_number(); let lock_periods = conviction.lock_periods().into(); - prior.accumulate(now + T::EnactmentPeriod::get() * lock_periods, balance); + prior.accumulate(now + T::VoteLockingPeriod::get() * lock_periods, balance); voting.set_common(delegations, prior); Ok(votes) diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 46d3cade36eb1..9a5e47c89ac77 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -140,6 +140,7 @@ parameter_types! { pub const FastTrackVotingPeriod: u64 = 2; pub const MinimumDeposit: u64 = 1; pub const EnactmentPeriod: u64 = 2; + pub const VoteLockingPeriod: u64 = 3; pub const CooloffPeriod: u64 = 2; pub const MaxVotes: u32 = 100; pub const MaxProposals: u32 = MAX_PROPOSALS; @@ -170,6 +171,7 @@ impl Config for Test { type EnactmentPeriod = EnactmentPeriod; type LaunchPeriod = LaunchPeriod; type VotingPeriod = VotingPeriod; + type VoteLockingPeriod = VoteLockingPeriod; type FastTrackVotingPeriod = FastTrackVotingPeriod; type MinimumDeposit = MinimumDeposit; type ExternalOrigin = EnsureSignedBy; diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index c1a27400fe557..8b80b39c14aab 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -85,7 +85,7 @@ fn lock_voting_should_work() { assert_eq!(Balances::locks(5), vec![]); assert_eq!(Balances::free_balance(42), 2); - fast_forward_to(5); + fast_forward_to(7); // No change yet... assert_noop!( Democracy::remove_other_vote(Origin::signed(1), 4, r), @@ -93,29 +93,29 @@ fn lock_voting_should_work() { ); assert_ok!(Democracy::unlock(Origin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![the_lock(40)]); - fast_forward_to(6); + fast_forward_to(8); // 4 should now be able to reap and unlock assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 4, r)); assert_ok!(Democracy::unlock(Origin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![]); - fast_forward_to(9); + fast_forward_to(13); assert_noop!( Democracy::remove_other_vote(Origin::signed(1), 3, r), Error::::NoPermission ); assert_ok!(Democracy::unlock(Origin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![the_lock(30)]); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 3, r)); assert_ok!(Democracy::unlock(Origin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![]); // 2 doesn't need to reap_vote here because it was already done before. - fast_forward_to(17); + fast_forward_to(25); assert_ok!(Democracy::unlock(Origin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![the_lock(20)]); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::unlock(Origin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![]); }); @@ -201,40 +201,40 @@ fn setup_three_referenda() -> (u32, u32, u32) { fn prior_lockvotes_should_be_enforced() { new_test_ext().execute_with(|| { let r = setup_three_referenda(); - // r.0 locked 10 until #18. - // r.1 locked 20 until #10. - // r.2 locked 50 until #6. + // r.0 locked 10 until 2 + 8 * 3 = #26 + // r.1 locked 20 until 2 + 4 * 3 = #14 + // r.2 locked 50 until 2 + 2 * 3 = #8 - fast_forward_to(5); + fast_forward_to(7); assert_noop!( Democracy::remove_other_vote(Origin::signed(1), 5, r.2), Error::::NoPermission ); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); - fast_forward_to(6); + fast_forward_to(8); assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.2)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); - fast_forward_to(9); + fast_forward_to(13); assert_noop!( Democracy::remove_other_vote(Origin::signed(1), 5, r.1), Error::::NoPermission ); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.1)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); - fast_forward_to(17); + fast_forward_to(25); assert_noop!( Democracy::remove_other_vote(Origin::signed(1), 5, r.0), Error::::NoPermission ); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.0)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); @@ -245,31 +245,31 @@ fn prior_lockvotes_should_be_enforced() { fn single_consolidation_of_lockvotes_should_work_as_before() { new_test_ext().execute_with(|| { let r = setup_three_referenda(); - // r.0 locked 10 until #18. - // r.1 locked 20 until #10. - // r.2 locked 50 until #6. + // r.0 locked 10 until 2 + 8 * 3 = #26 + // r.1 locked 20 until 2 + 4 * 3 = #14 + // r.2 locked 50 until 2 + 2 * 3 = #8 - fast_forward_to(5); + fast_forward_to(7); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); - fast_forward_to(6); + fast_forward_to(8); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); - fast_forward_to(9); + fast_forward_to(13); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); - fast_forward_to(17); + fast_forward_to(25); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); @@ -279,23 +279,23 @@ fn single_consolidation_of_lockvotes_should_work_as_before() { fn multi_consolidation_of_lockvotes_should_be_conservative() { new_test_ext().execute_with(|| { let r = setup_three_referenda(); - // r.0 locked 10 until #18. - // r.1 locked 20 until #10. - // r.2 locked 50 until #6. + // r.0 locked 10 until 2 + 8 * 3 = #26 + // r.1 locked 20 until 2 + 4 * 3 = #14 + // r.2 locked 50 until 2 + 2 * 3 = #8 assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); - fast_forward_to(6); + fast_forward_to(8); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); @@ -314,28 +314,28 @@ fn locks_should_persist_from_voting_to_delegation() { assert_ok!(Democracy::vote(Origin::signed(5), r, aye(4, 10))); fast_forward_to(2); assert_ok!(Democracy::remove_vote(Origin::signed(5), r)); - // locked 10 until #18. + // locked 10 until #26. assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked3x, 20)); // locked 20. assert!(Balances::locks(5)[0].amount == 20); assert_ok!(Democracy::undelegate(Origin::signed(5))); - // locked 20 until #10 + // locked 20 until #14 - fast_forward_to(9); + fast_forward_to(13); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount == 20); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); - fast_forward_to(17); + fast_forward_to(25); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); @@ -347,30 +347,30 @@ fn locks_should_persist_from_delegation_to_voting() { System::set_block_number(0); assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked5x, 5)); assert_ok!(Democracy::undelegate(Origin::signed(5))); - // locked 5 until #32 + // locked 5 until 16 * 3 = #48 let r = setup_three_referenda(); - // r.0 locked 10 until #18. - // r.1 locked 20 until #10. - // r.2 locked 50 until #6. + // r.0 locked 10 until 2 + 8 * 3 = #26 + // r.1 locked 20 until 2 + 4 * 3 = #14 + // r.2 locked 50 until 2 + 2 * 3 = #8 assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); - fast_forward_to(6); + fast_forward_to(8); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); - fast_forward_to(10); + fast_forward_to(14); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); - fast_forward_to(18); + fast_forward_to(26); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 5); - fast_forward_to(32); + fast_forward_to(48); assert_ok!(Democracy::unlock(Origin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); });