diff --git a/substrate/demo/runtime/src/dispatch.rs b/substrate/demo/runtime/src/dispatch.rs index 980025e3ee7ad739aae7d731ba26a9d61b1e1488..bc5a501705dbd3706ca0aced3cc1bc626dca720b 100644 --- a/substrate/demo/runtime/src/dispatch.rs +++ b/substrate/demo/runtime/src/dispatch.rs @@ -43,7 +43,7 @@ pub fn enact_proposal(proposal: Proposal) { staking::privileged::force_new_era() } Proposal::DemocracyCancelReferendum(ref_index) => { - democracy::privileged::clear_referendum(ref_index) + democracy::privileged::cancel_referendum(ref_index) } } } diff --git a/substrate/demo/runtime/src/runtime/council_vote.rs b/substrate/demo/runtime/src/runtime/council_vote.rs index 86f9ecb612cdfa107de5d2837fded238e67074da..1b568c65808cd8643bf896c74f9e9dcdd03bdf87 100644 --- a/substrate/demo/runtime/src/runtime/council_vote.rs +++ b/substrate/demo/runtime/src/runtime/council_vote.rs @@ -190,8 +190,11 @@ pub mod internal { pub fn end_block(now: BlockNumber) { while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) { let tally = take_tally(&proposal_hash); - if let (&Proposal::DemocracyCancelReferendum(ref_index), (_, 0 ,0)) = (&proposal, tally) { - democracy::privileged::clear_referendum(ref_index); + println!("Executing proposal {:?} {:?}", proposal, tally); + if let &Proposal::DemocracyCancelReferendum(ref_index) = &proposal { + if let (_, 0, 0) = tally { + democracy::privileged::cancel_referendum(ref_index); + } } else { if tally.0 > tally.1 + tally.2 { kill_veto_of(&proposal_hash); @@ -211,7 +214,7 @@ pub mod testing { use runtime_io::{twox_128, TestExternalities}; use keyring::Keyring::{Alice, Bob, Charlie}; use codec::Joiner; - use runtime::council; + use runtime::{council, democracy}; pub fn externalities() -> TestExternalities { let expiry: BlockNumber = 10; @@ -222,7 +225,8 @@ pub mod testing { (Charlie.into(), expiry) ]), twox_128(COOLOFF_PERIOD).to_vec() => vec![].and(&2u64), - twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64) + twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64), + twox_128(democracy::VOTING_PERIOD).to_vec() => vec![].and(&3u64) ]; council::testing::externalities() .into_iter().chain(extras.into_iter()).collect() @@ -264,6 +268,68 @@ mod tests { }); } + #[test] + fn referendum_cancellation_should_work_when_unanimous() { + with_externalities(&mut new_test_ext(), || { + with_env(|e| e.block_number = 1); + let proposal = Proposal::StakingSetBondingDuration(42); + democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]); + + let cancellation = Proposal::DemocracyCancelReferendum(0); + let hash = cancellation.blake2_256(); + public::propose(Alice, &cancellation); + public::vote(Bob, &hash, true); + public::vote(Charlie, &hash, true); + assert_eq!(proposals(), vec![(2, hash)]); + internal::end_block(1); + + with_env(|e| e.block_number = 2); + internal::end_block(2); + assert_eq!(democracy::active_referendums(), vec![]); + assert_eq!(staking::bonding_duration(), 0); + }); + } + + #[test] + fn referendum_cancellation_should_fail_when_not_unanimous() { + with_externalities(&mut new_test_ext(), || { + with_env(|e| e.block_number = 1); + let proposal = Proposal::StakingSetBondingDuration(42); + democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + + let cancellation = Proposal::DemocracyCancelReferendum(0); + let hash = cancellation.blake2_256(); + public::propose(Alice, &cancellation); + public::vote(Bob, &hash, true); + public::vote(Charlie, &hash, false); + internal::end_block(1); + + with_env(|e| e.block_number = 2); + internal::end_block(2); + assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]); + }); + } + + #[test] + fn referendum_cancellation_should_fail_when_abstentions() { + with_externalities(&mut new_test_ext(), || { + with_env(|e| e.block_number = 1); + let proposal = Proposal::StakingSetBondingDuration(42); + democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + + let cancellation = Proposal::DemocracyCancelReferendum(0); + let hash = cancellation.blake2_256(); + public::propose(Alice, &cancellation); + public::vote(Bob, &hash, true); + internal::end_block(1); + + with_env(|e| e.block_number = 2); + internal::end_block(2); + assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]); + }); + } + #[test] fn veto_should_work() { with_externalities(&mut new_test_ext(), || { @@ -326,8 +392,7 @@ mod tests { with_env(|e| e.block_number = 4); internal::end_block(4); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); - + assert_eq!(democracy::active_referendums(), vec![(0, 7, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); }); } @@ -390,7 +455,7 @@ mod tests { with_env(|e| e.block_number = 2); internal::end_block(2); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 3, Proposal::StakingSetBondingDuration(42), VoteThreshold::SuperMajorityAgainst)]); + assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SuperMajorityAgainst)]); }); } @@ -407,7 +472,7 @@ mod tests { with_env(|e| e.block_number = 2); internal::end_block(2); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 3, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); + assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); }); } diff --git a/substrate/demo/runtime/src/runtime/democracy.rs b/substrate/demo/runtime/src/runtime/democracy.rs index 31486149996a3ca3054e840c9824442a6654a469..c7cd152f61b48410cf1c7eb63c836470ff9b542d 100644 --- a/substrate/demo/runtime/src/runtime/democracy.rs +++ b/substrate/demo/runtime/src/runtime/democracy.rs @@ -233,11 +233,8 @@ pub mod privileged { } /// Remove a referendum. - pub fn clear_referendum(ref_index: ReferendumIndex) { - for v in voters_for(ref_index) { - storage::kill(&(v, ref_index).to_keyed_vec(VOTE_OF)); - } - storage::kill(&ref_index.to_keyed_vec(VOTERS_FOR)); + pub fn cancel_referendum(ref_index: ReferendumIndex) { + clear_referendum(ref_index); } } @@ -247,9 +244,7 @@ pub mod internal { use dispatch::enact_proposal; /// Current era is ending; we should finish up any proposals. - pub fn end_block() { - let now = system::block_number(); - + pub fn end_block(now: BlockNumber) { // pick out another public referendum if it's time. if now % launch_period() == 0 { let mut public_props = public_props(); @@ -274,7 +269,7 @@ pub mod internal { for (index, _, proposal, vote_threshold) in maturing_referendums_at(now) { let (approve, against) = tally(index); let total_stake = staking::total_stake(); - privileged::clear_referendum(index); + clear_referendum(index); if vote_threshold.approved(approve, against, total_stake) { enact_proposal(proposal); } @@ -299,6 +294,15 @@ fn inject_referendum( ref_index } +/// Remove all info on a referendum. +fn clear_referendum(ref_index: ReferendumIndex) { + storage::kill(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF)); + storage::kill(&ref_index.to_keyed_vec(VOTERS_FOR)); + for v in voters_for(ref_index) { + storage::kill(&(v, ref_index).to_keyed_vec(VOTE_OF)); + } +} + #[cfg(test)] pub mod testing { use super::*; @@ -399,7 +403,7 @@ mod tests { with_externalities(&mut t, || { with_env(|e| e.block_number = 1); public::propose(&alice, &Proposal::StakingSetSessionsPerEra(2), 1u64); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); with_env(|e| e.block_number = 2); let r = 0; @@ -410,7 +414,7 @@ mod tests { assert_eq!(vote_of(&alice, r), Some(true)); assert_eq!(tally(r), (10, 0)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 2u64); @@ -451,7 +455,7 @@ mod tests { public::second(&eve, 0); public::second(&eve, 0); public::second(&eve, 0); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); assert_eq!(staking::balance(&alice), 10u64); assert_eq!(staking::balance(&bob), 20u64); assert_eq!(staking::balance(&eve), 50u64); @@ -506,23 +510,23 @@ mod tests { public::propose(&alice, &Proposal::StakingSetBondingDuration(2), 2u64); public::propose(&alice, &Proposal::StakingSetBondingDuration(4), 4u64); public::propose(&alice, &Proposal::StakingSetBondingDuration(3), 3u64); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); with_env(|e| e.block_number = 1); public::vote(&alice, 0, true); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 4u64); with_env(|e| e.block_number = 2); public::vote(&alice, 1, true); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 3u64); with_env(|e| e.block_number = 3); public::vote(&alice, 2, true); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 2u64); }); @@ -542,13 +546,31 @@ mod tests { assert_eq!(vote_of(&alice, r), Some(true)); assert_eq!(tally(r), (10, 0)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 2u64); }); } + #[test] + fn cancel_referendum_should_work() { + let alice = Keyring::Alice.to_raw_public(); + let mut t = new_test_ext(); + + with_externalities(&mut t, || { + with_env(|e| e.block_number = 1); + let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); + public::vote(&alice, r, true); + privileged::cancel_referendum(r); + + democracy::internal::end_block(system::block_number()); + staking::internal::check_new_era(); + + assert_eq!(staking::era_length(), 1u64); + }); + } + #[test] fn simple_failing_should_work() { let alice = Keyring::Alice.to_raw_public(); @@ -563,7 +585,7 @@ mod tests { assert_eq!(vote_of(&alice, r), Some(false)); assert_eq!(tally(r), (0, 10)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 1u64); @@ -593,7 +615,7 @@ mod tests { assert_eq!(tally(r), (110, 100)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 2u64); @@ -619,7 +641,7 @@ mod tests { assert_eq!(tally(r), (60, 50)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 1u64); @@ -649,7 +671,7 @@ mod tests { assert_eq!(tally(r), (100, 50)); - democracy::internal::end_block(); + democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 2u64);