Browse Source

Merge branch 'council_rework' into council_olympia

ondratra 4 years ago
parent
commit
420a209a59

+ 83 - 43
runtime-modules/council/src/lib.rs

@@ -31,11 +31,12 @@
 //! - [release_candidacy_stake](./struct.Module.html#method.release_candidacy_stake)
 //! - [release_candidacy_stake](./struct.Module.html#method.release_candidacy_stake)
 //! - [set_candidacy_note](./struct.Module.html#method.set_candidacy_note)
 //! - [set_candidacy_note](./struct.Module.html#method.set_candidacy_note)
 //! - [set_budget](./struct.Module.html#method.set_budget)
 //! - [set_budget](./struct.Module.html#method.set_budget)
+//! - [plan_budget_refill](./struct.Module.html#method.plan_budget_refill)
 //!
 //!
 //! ## Important functions
 //! ## Important functions
 //! These functions have to be called by the runtime for the council to work properly.
 //! These functions have to be called by the runtime for the council to work properly.
 //! - [recieve_referendum_results](./trait.ReferendumConnection.html#method.recieve_referendum_results)
 //! - [recieve_referendum_results](./trait.ReferendumConnection.html#method.recieve_referendum_results)
-//! - [can_release_vote_stake](./trait.ReferendumConnection.html#method.can_release_vote_stake)
+//! - [can_unlock_vote_stake](./trait.ReferendumConnection.html#method.can_unlock_vote_stake)
 //!
 //!
 //! ## Dependencies:
 //! ## Dependencies:
 //! - [referendum](../referendum/index.html)
 //! - [referendum](../referendum/index.html)
@@ -248,10 +249,7 @@ pub trait ReferendumConnection<T: Trait> {
     fn recieve_referendum_results(winners: &[OptionResult<VotePowerOf<T>>]);
     fn recieve_referendum_results(winners: &[OptionResult<VotePowerOf<T>>]);
 
 
     /// Process referendum results. This function MUST be called in runtime's implementation of referendum's `can_release_voting_stake()`.
     /// Process referendum results. This function MUST be called in runtime's implementation of referendum's `can_release_voting_stake()`.
-    fn can_release_vote_stake(
-        vote: &CastVoteOf<T>,
-        current_voting_cycle_id: &u64,
-    ) -> Result<(), Error<T>>;
+    fn can_unlock_vote_stake(vote: &CastVoteOf<T>) -> Result<(), Error<T>>;
 
 
     /// Checks that user is indeed candidating. This function MUST be called in runtime's implementation of referendum's `is_valid_option_id()`.
     /// Checks that user is indeed candidating. This function MUST be called in runtime's implementation of referendum's `is_valid_option_id()`.
     fn is_valid_candidate_id(membership_id: &T::MembershipId) -> bool;
     fn is_valid_candidate_id(membership_id: &T::MembershipId) -> bool;
@@ -272,13 +270,13 @@ decl_storage! {
         pub AnnouncementPeriodNr get(fn announcement_period_nr) config(): u64;
         pub AnnouncementPeriodNr get(fn announcement_period_nr) config(): u64;
 
 
         /// Budget for the council's elected members rewards.
         /// Budget for the council's elected members rewards.
-        pub Budget get(fn budget): Balance<T>;
+        pub Budget get(fn budget) config(): Balance<T>;
 
 
         /// The next block in which the elected council member rewards will be payed.
         /// The next block in which the elected council member rewards will be payed.
-        pub NextRewardPayments get(fn next_reward_payments): T::BlockNumber;
+        pub NextRewardPayments get(fn next_reward_payments) config(): T::BlockNumber;
 
 
         /// The next block in which the budget will be increased.
         /// The next block in which the budget will be increased.
-        pub NextBudgetRefill get(fn next_budget_refill): T::BlockNumber;
+        pub NextBudgetRefill get(fn next_budget_refill) config(): T::BlockNumber;
     }
     }
 }
 }
 
 
@@ -286,6 +284,7 @@ decl_event! {
     pub enum Event<T>
     pub enum Event<T>
     where
     where
         Balance = Balance::<T>,
         Balance = Balance::<T>,
+        <T as system::Trait>::BlockNumber,
         <T as Trait>::MembershipId,
         <T as Trait>::MembershipId,
         <T as frame_system::Trait>::AccountId,
         <T as frame_system::Trait>::AccountId,
     {
     {
@@ -321,6 +320,12 @@ decl_event! {
 
 
         /// Budget balance was changed by the root.
         /// Budget balance was changed by the root.
         BudgetBalanceSet(Balance),
         BudgetBalanceSet(Balance),
+
+        /// Budget balance was increased by automatic refill.
+        BudgetRefill(Balance),
+
+        /// The next budget refill was planned.
+        BudgetRefillPlanned(BlockNumber),
     }
     }
 }
 }
 
 
@@ -528,6 +533,25 @@ decl_module! {
 
 
             Ok(())
             Ok(())
         }
         }
+
+        /// Plan the next budget refill.
+        #[weight = 10_000_000]
+        pub fn plan_budget_refill(origin, next_refill: T::BlockNumber) -> Result<(), Error<T>> {
+            // ensure action can be started
+            EnsureChecks::<T>::can_plan_budget_refill(origin)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            // update state
+            Mutations::<T>::plan_budget_refill(&next_refill);
+
+            // emit event
+            Self::deposit_event(RawEvent::BudgetRefillPlanned(next_refill));
+
+            Ok(())
+        }
     }
     }
 }
 }
 
 
@@ -559,13 +583,8 @@ impl<T: Trait> Module<T> {
     /// Checkout elected council members reward payments.
     /// Checkout elected council members reward payments.
     fn try_process_budget(now: T::BlockNumber) {
     fn try_process_budget(now: T::BlockNumber) {
         // budget autorefill
         // budget autorefill
-        let next_refill = NextBudgetRefill::<T>::get();
-        if next_refill == 0.into() {
-            // budget automatic refill initialization (this condition will be true only first time autorefill is planned)
-            Mutations::<T>::plan_budget_refill(now);
-        } else if next_refill == now {
-            // budget automatic refill
-            Mutations::<T>::refill_budget(now);
+        if now == NextBudgetRefill::<T>::get() {
+            Self::refill_budget(now);
         }
         }
 
 
         // council members rewards
         // council members rewards
@@ -647,6 +666,26 @@ impl<T: Trait> Module<T> {
 
 
     /////////////////// Budget-related /////////////////////////////////////
     /////////////////// Budget-related /////////////////////////////////////
 
 
+    /// Refill (increase) the budget's balance.
+    fn refill_budget(now: T::BlockNumber) {
+        // get refill amount
+        let refill_amount = T::BudgetRefillAmount::get();
+
+        // refill budget
+        Mutations::<T>::refill_budget(&refill_amount);
+
+        // calculate next refill block number
+        let refill_period = T::BudgetRefillPeriod::get();
+        let next_refill = now + refill_period;
+
+        // plan next budget refill
+        Mutations::<T>::plan_budget_refill(&next_refill);
+
+        // emit events
+        Self::deposit_event(RawEvent::BudgetRefill(refill_amount));
+        Self::deposit_event(RawEvent::BudgetRefillPlanned(next_refill));
+    }
+
     /// Pay rewards to elected council members.
     /// Pay rewards to elected council members.
     fn pay_elected_member_rewards(now: T::BlockNumber) {
     fn pay_elected_member_rewards(now: T::BlockNumber) {
         let reward_per_block = T::ElectedMemberRewardPerBlock::get();
         let reward_per_block = T::ElectedMemberRewardPerBlock::get();
@@ -660,18 +699,10 @@ impl<T: Trait> Module<T> {
                 let unpaid_reward =
                 let unpaid_reward =
                     Calculations::<T>::get_current_reward(&council_member, reward_per_block, now);
                     Calculations::<T>::get_current_reward(&council_member, reward_per_block, now);
 
 
-                if unpaid_reward == 0.into() {
-                    Self::deposit_event(RawEvent::RewardPayment(
-                        council_member.membership_id,
-                        council_member.reward_account_id.clone(),
-                        0.into(),
-                        0.into(),
-                    ));
-                    return balance;
-                }
+                // depleted budget or no accumulated reward to be paid?
+                if balance == 0.into() || unpaid_reward == 0.into() {
+                    // no need to update council member record here; their unpaid reward will be recalculated next time rewards are paid
 
 
-                // stop iterating if budget is completely depleted
-                if balance == 0.into() {
                     // emit event
                     // emit event
                     Self::deposit_event(RawEvent::RewardPayment(
                     Self::deposit_event(RawEvent::RewardPayment(
                         council_member.membership_id,
                         council_member.membership_id,
@@ -742,22 +773,28 @@ impl<T: Trait> ReferendumConnection<T> for Module<T> {
     }
     }
 
 
     /// Check that it is a proper time to release stake.
     /// Check that it is a proper time to release stake.
-    fn can_release_vote_stake(
-        vote: &CastVoteOf<T>,
-        current_voting_cycle_id: &u64,
-    ) -> Result<(), Error<T>> {
+    fn can_unlock_vote_stake(vote: &CastVoteOf<T>) -> Result<(), Error<T>> {
+        let current_voting_cycle_id = AnnouncementPeriodNr::get();
+
         // allow release for very old votes
         // allow release for very old votes
-        if vote.cycle_id > current_voting_cycle_id + 1 {
+        if current_voting_cycle_id > vote.cycle_id + 1 {
             return Ok(());
             return Ok(());
         }
         }
 
 
+        // allow release for current cycle only in idle stage
+        if current_voting_cycle_id == vote.cycle_id
+            && !matches!(Stage::<T>::get().stage, CouncilStage::Idle)
+        {
+            return Err(Error::CantReleaseStakeNow);
+        }
+
         let voting_for_winner = CouncilMembers::<T>::get()
         let voting_for_winner = CouncilMembers::<T>::get()
             .iter()
             .iter()
             .map(|council_member| council_member.membership_id)
             .map(|council_member| council_member.membership_id)
             .any(|membership_id| vote.vote_for == Some(membership_id.into()));
             .any(|membership_id| vote.vote_for == Some(membership_id.into()));
 
 
         // allow release for vote from previous elections only when not voted for winner
         // allow release for vote from previous elections only when not voted for winner
-        if vote.cycle_id == current_voting_cycle_id + 1 {
+        if current_voting_cycle_id == vote.cycle_id + 1 {
             // ensure vote was not cast for the one of winning candidates / council members
             // ensure vote was not cast for the one of winning candidates / council members
             if voting_for_winner {
             if voting_for_winner {
                 return Err(Error::CantReleaseStakeNow);
                 return Err(Error::CantReleaseStakeNow);
@@ -768,7 +805,8 @@ impl<T: Trait> ReferendumConnection<T> for Module<T> {
 
 
         // at this point vote.cycle_id == current_voting_cycle_id
         // at this point vote.cycle_id == current_voting_cycle_id
 
 
-        if voting_for_winner {
+        // ensure election has ended and voter haven't voted for winner
+        if voting_for_winner || !matches!(Stage::<T>::get().stage, CouncilStage::Idle) {
             return Err(Error::CantReleaseStakeNow);
             return Err(Error::CantReleaseStakeNow);
         }
         }
 
 
@@ -859,7 +897,7 @@ impl<T: Trait> Mutations<T> {
         let extra_winning_target_count = T::CouncilSize::get() - 1;
         let extra_winning_target_count = T::CouncilSize::get() - 1;
 
 
         // start referendum
         // start referendum
-        T::Referendum::force_start(extra_winning_target_count);
+        T::Referendum::force_start(extra_winning_target_count, AnnouncementPeriodNr::get());
 
 
         let block_number = <frame_system::Module<T>>::block_number();
         let block_number = <frame_system::Module<T>>::block_number();
 
 
@@ -962,18 +1000,13 @@ impl<T: Trait> Mutations<T> {
     }
     }
 
 
     /// Refill budget's balance.
     /// Refill budget's balance.
-    fn refill_budget(now: T::BlockNumber) {
-        let refill_amount = T::BudgetRefillAmount::get();
-
-        Budget::<T>::mutate(|balance| *balance += refill_amount);
-        Self::plan_budget_refill(now);
+    fn refill_budget(refill_amount: &Balance<T>) {
+        Budget::<T>::mutate(|balance| *balance += *refill_amount);
     }
     }
 
 
     // Plan next budget refill.
     // Plan next budget refill.
-    fn plan_budget_refill(now: T::BlockNumber) {
-        let refill_period = T::BudgetRefillPeriod::get();
-
-        NextBudgetRefill::<T>::put(now + refill_period);
+    fn plan_budget_refill(refill_at: &T::BlockNumber) {
+        NextBudgetRefill::<T>::put(refill_at);
     }
     }
 
 
     /// Pay reward to a single elected council member.
     /// Pay reward to a single elected council member.
@@ -1181,4 +1214,11 @@ impl<T: Trait> EnsureChecks<T> {
 
 
         Ok(())
         Ok(())
     }
     }
+
+    // Ensures there is no problem in planning next budget refill.
+    fn can_plan_budget_refill(origin: T::Origin) -> Result<(), Error<T>> {
+        ensure_root(origin)?;
+
+        Ok(())
+    }
 }
 }

+ 47 - 13
runtime-modules/council/src/mock.rs

@@ -4,7 +4,8 @@
 use crate::{
 use crate::{
     AnnouncementPeriodNr, Balance, Budget, CandidateOf, Candidates, CouncilMemberOf,
     AnnouncementPeriodNr, Balance, Budget, CandidateOf, Candidates, CouncilMemberOf,
     CouncilMembers, CouncilStage, CouncilStageAnnouncing, CouncilStageElection, CouncilStageUpdate,
     CouncilMembers, CouncilStage, CouncilStageAnnouncing, CouncilStageElection, CouncilStageUpdate,
-    CouncilStageUpdateOf, Error, GenesisConfig, Module, ReferendumConnection, Stage, Trait,
+    CouncilStageUpdateOf, Error, GenesisConfig, Module, NextBudgetRefill, ReferendumConnection,
+    Stage, Trait,
 };
 };
 
 
 use balances;
 use balances;
@@ -15,8 +16,8 @@ use frame_support::{
 use frame_system::{EnsureOneOf, EnsureRoot, EnsureSigned, RawOrigin};
 use frame_system::{EnsureOneOf, EnsureRoot, EnsureSigned, RawOrigin};
 use rand::Rng;
 use rand::Rng;
 use referendum::{
 use referendum::{
-    Balance as BalanceReferendum, CastVote, CurrentCycleId, OptionResult, ReferendumManager,
-    ReferendumStage, ReferendumStageRevealing,
+    Balance as BalanceReferendum, CastVote, OptionResult, ReferendumManager, ReferendumStage,
+    ReferendumStageRevealing,
 };
 };
 use sp_core::H256;
 use sp_core::H256;
 use sp_io;
 use sp_io;
@@ -213,20 +214,15 @@ impl referendum::Trait<ReferendumInstance> for RuntimeReferendum {
         stake
         stake
     }
     }
 
 
-    fn can_release_vote_stake(
+    fn can_unlock_vote_stake(
         vote: &CastVote<Self::Hash, BalanceReferendum<Self, ReferendumInstance>>,
         vote: &CastVote<Self::Hash, BalanceReferendum<Self, ReferendumInstance>>,
-        current_voting_cycle_id: &u64,
     ) -> bool {
     ) -> bool {
         // trigger fail when requested to do so
         // trigger fail when requested to do so
         if !IS_UNSTAKE_ENABLED.with(|value| value.borrow().0) {
         if !IS_UNSTAKE_ENABLED.with(|value| value.borrow().0) {
             return false;
             return false;
         }
         }
 
 
-        <Module<Runtime> as ReferendumConnection<Runtime>>::can_release_vote_stake(
-            vote,
-            current_voting_cycle_id,
-        )
-        .is_ok()
+        <Module<Runtime> as ReferendumConnection<Runtime>>::can_unlock_vote_stake(vote).is_ok()
     }
     }
 
 
     fn process_results(winners: &[OptionResult<Self::VotePower>]) {
     fn process_results(winners: &[OptionResult<Self::VotePower>]) {
@@ -447,6 +443,9 @@ pub fn default_genesis_config() -> GenesisConfig<Runtime> {
         council_members: vec![],
         council_members: vec![],
         candidates: vec![],
         candidates: vec![],
         announcement_period_nr: 0,
         announcement_period_nr: 0,
+        budget: 0,
+        next_reward_payments: 0,
+        next_budget_refill: <Runtime as Trait>::BudgetRefillPeriod::get(),
     }
     }
 }
 }
 
 
@@ -525,10 +524,16 @@ where
         }
         }
     }
     }
 
 
-    pub fn generate_voter(index: u64, stake: Balance<T>, vote_for_index: u64) -> VoterInfo<T> {
+    pub fn generate_voter(
+        index: u64,
+        stake: Balance<T>,
+        vote_for_index: u64,
+        cycle_id: u64,
+    ) -> VoterInfo<T> {
         let account_id = VOTER_BASE_ID + index;
         let account_id = VOTER_BASE_ID + index;
         let origin = OriginType::Signed(account_id.into());
         let origin = OriginType::Signed(account_id.into());
-        let (commitment, salt) = Self::vote_commitment(&account_id.into(), &vote_for_index.into());
+        let (commitment, salt) =
+            Self::vote_commitment(&account_id.into(), &vote_for_index.into(), &cycle_id);
 
 
         Self::topup_account(account_id.into(), stake);
         Self::topup_account(account_id.into(), stake);
 
 
@@ -551,8 +556,8 @@ where
     pub fn vote_commitment(
     pub fn vote_commitment(
         account_id: &<T as frame_system::Trait>::AccountId,
         account_id: &<T as frame_system::Trait>::AccountId,
         vote_option_index: &u64,
         vote_option_index: &u64,
+        cycle_id: &u64,
     ) -> (T::Hash, Vec<u8>) {
     ) -> (T::Hash, Vec<u8>) {
-        let cycle_id = CurrentCycleId::<ReferendumInstance>::get();
         let salt = Self::generate_salt();
         let salt = Self::generate_salt();
 
 
         (
         (
@@ -654,6 +659,7 @@ where
                         vote_power: item.vote_power.into(),
                         vote_power: item.vote_power.into(),
                     })
                     })
                     .collect(),
                     .collect(),
+                current_cycle_id: AnnouncementPeriodNr::get(),
             }),
             }),
         );
         );
 
 
@@ -685,6 +691,11 @@ where
         assert_eq!(Candidates::<T>::get(membership_id).note_hash, note_hash,);
         assert_eq!(Candidates::<T>::get(membership_id).note_hash, note_hash,);
     }
     }
 
 
+    pub fn check_budget_refill(expected_balance: Balance<T>, expected_next_refill: T::BlockNumber) {
+        assert_eq!(Budget::<T>::get(), expected_balance,);
+        assert_eq!(NextBudgetRefill::<T>::get(), expected_next_refill,);
+    }
+
     pub fn set_candidacy_note(
     pub fn set_candidacy_note(
         origin: OriginType<T::AccountId>,
         origin: OriginType<T::AccountId>,
         membership_id: T::MembershipId,
         membership_id: T::MembershipId,
@@ -796,6 +807,28 @@ where
         assert_eq!(Budget::<T>::get(), amount,);
         assert_eq!(Budget::<T>::get(), amount,);
     }
     }
 
 
+    pub fn plan_budget_refill(
+        origin: OriginType<T::AccountId>,
+        next_refill: T::BlockNumber,
+        expected_result: Result<(), ()>,
+    ) {
+        // check method returns expected result
+        assert_eq!(
+            Module::<T>::plan_budget_refill(
+                InstanceMockUtils::<T>::mock_origin(origin),
+                next_refill,
+            )
+            .is_ok(),
+            expected_result.is_ok(),
+        );
+
+        if expected_result.is_err() {
+            return;
+        }
+
+        assert_eq!(NextBudgetRefill::<T>::get(), next_refill,);
+    }
+
     /// simulate one council's election cycle
     /// simulate one council's election cycle
     pub fn simulate_council_cycle(params: CouncilCycleParams<T>) {
     pub fn simulate_council_cycle(params: CouncilCycleParams<T>) {
         let settings = params.council_settings;
         let settings = params.council_settings;
@@ -970,6 +1003,7 @@ where
                     index as u64 + users_offset,
                     index as u64 + users_offset,
                     vote_stake.into(),
                     vote_stake.into(),
                     CANDIDATE_BASE_ID + votes_map[index] + users_offset,
                     CANDIDATE_BASE_ID + votes_map[index] + users_offset,
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();

+ 40 - 2
runtime-modules/council/src/tests.rs

@@ -1,7 +1,8 @@
 #![cfg(test)]
 #![cfg(test)]
 
 
 use super::{
 use super::{
-    Budget, CouncilMemberOf, CouncilMembers, CouncilStageAnnouncing, Error, Module, Trait,
+    AnnouncementPeriodNr, Budget, CouncilMemberOf, CouncilMembers, CouncilStageAnnouncing, Error,
+    Module, Trait,
 };
 };
 use crate::mock::*;
 use crate::mock::*;
 use crate::staking_handler::mocks::{CANDIDATE_BASE_ID, VOTER_CANDIDATE_OFFSET};
 use crate::staking_handler::mocks::{CANDIDATE_BASE_ID, VOTER_CANDIDATE_OFFSET};
@@ -133,6 +134,7 @@ fn council_can_vote_for_yourself() {
             VOTER_CANDIDATE_OFFSET,
             VOTER_CANDIDATE_OFFSET,
             vote_stake,
             vote_stake,
             self_voting_candidate_index,
             self_voting_candidate_index,
+            AnnouncementPeriodNr::get(),
         );
         );
         Mocks::vote_for_candidate(
         Mocks::vote_for_candidate(
             voter.origin.clone(),
             voter.origin.clone(),
@@ -162,7 +164,7 @@ fn council_vote_for_winner_stakes_longer() {
         let council_settings = CouncilSettings::<Runtime>::extract_settings();
         let council_settings = CouncilSettings::<Runtime>::extract_settings();
 
 
         // run first election round
         // run first election round
-        let params = Mocks::run_full_council_cycle(0, &vec![], 0);
+        let params = Mocks::run_full_council_cycle(0, &[], 0);
         let second_round_user_offset = 100; // some number higher than the number of voters
         let second_round_user_offset = 100; // some number higher than the number of voters
 
 
         let voter_for_winner = params.voters[0].clone();
         let voter_for_winner = params.voters[0].clone();
@@ -283,6 +285,7 @@ fn council_announcement_reset_on_not_enough_winners() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -374,6 +377,7 @@ fn council_two_consecutive_rounds() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -399,6 +403,7 @@ fn council_two_consecutive_rounds() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map2[index],
                     CANDIDATE_BASE_ID + votes_map2[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -563,6 +568,7 @@ fn council_candidate_stake_can_be_unlocked() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -669,6 +675,7 @@ fn council_candidate_stake_automaticly_converted() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -759,6 +766,7 @@ fn council_member_stake_is_locked() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -816,6 +824,7 @@ fn council_member_stake_automaticly_unlocked() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map2[index],
                     CANDIDATE_BASE_ID + votes_map2[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -897,6 +906,7 @@ fn council_candidacy_set_note() {
                     index as u64,
                     index as u64,
                     vote_stake,
                     vote_stake,
                     CANDIDATE_BASE_ID + votes_map[index],
                     CANDIDATE_BASE_ID + votes_map[index],
+                    AnnouncementPeriodNr::get(),
                 )
                 )
             })
             })
             .collect();
             .collect();
@@ -1033,6 +1043,34 @@ fn council_budget_can_be_set() {
     })
     })
 }
 }
 
 
+/// Test that budget balance can be set from external source.
+#[test]
+fn council_budget_refill_can_be_planned() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let origin = OriginType::Root;
+        let next_refill = 1000;
+
+        Mocks::plan_budget_refill(origin.clone(), next_refill, Ok(()));
+
+        // forward to one block before refill
+        MockUtils::increase_block_number(next_refill - 1);
+
+        // check no refill happened yet
+        Mocks::check_budget_refill(0, next_refill);
+
+        // forward to after block refill
+        MockUtils::increase_block_number(1);
+
+        // check budget was increased
+        Mocks::check_budget_refill(
+            <Runtime as Trait>::BudgetRefillAmount::get(),
+            next_refill + <Runtime as Trait>::BudgetRefillPeriod::get(),
+        );
+    })
+}
+
 /// Test that rewards for council members are paid.
 /// Test that rewards for council members are paid.
 #[test]
 #[test]
 fn council_rewards_are_paid() {
 fn council_rewards_are_paid() {

+ 44 - 47
runtime-modules/referendum/src/lib.rs

@@ -73,6 +73,7 @@ impl<BlockNumber, VotePower: Encode + Decode> Default for ReferendumStage<BlockN
 pub struct ReferendumStageVoting<BlockNumber> {
 pub struct ReferendumStageVoting<BlockNumber> {
     pub started: BlockNumber,      // block in which referendum started
     pub started: BlockNumber,      // block in which referendum started
     pub winning_target_count: u64, // target number of winners
     pub winning_target_count: u64, // target number of winners
+    pub current_cycle_id: u64,     // index of current election
 }
 }
 
 
 /// Representation for revealing stage state.
 /// Representation for revealing stage state.
@@ -81,6 +82,7 @@ pub struct ReferendumStageRevealing<BlockNumber, VotePower> {
     pub started: BlockNumber,      // block in which referendum started
     pub started: BlockNumber,      // block in which referendum started
     pub winning_target_count: u64, // target number of winners
     pub winning_target_count: u64, // target number of winners
     pub intermediate_winners: Vec<OptionResult<VotePower>>, // intermediate winning options
     pub intermediate_winners: Vec<OptionResult<VotePower>>, // intermediate winning options
+    pub current_cycle_id: u64,     // index of current election
 }
 }
 
 
 #[derive(Encode, Decode, PartialEq, Eq, Debug, Default, Clone)]
 #[derive(Encode, Decode, PartialEq, Eq, Debug, Default, Clone)]
@@ -137,11 +139,15 @@ pub trait ReferendumManager<Origin, AccountId, Hash> {
     type Currency: LockableCurrency<AccountId>;
     type Currency: LockableCurrency<AccountId>;
 
 
     /// Start a new referendum.
     /// Start a new referendum.
-    fn start_referendum(origin: Origin, extra_winning_target_count: u64) -> Result<(), ()>;
+    fn start_referendum(
+        origin: Origin,
+        extra_winning_target_count: u64,
+        cycle_id: u64,
+    ) -> Result<(), ()>;
 
 
     /// Start referendum independent of the current state.
     /// Start referendum independent of the current state.
     /// If an election is running before calling this function, it will be discontinued without any winners selected.
     /// If an election is running before calling this function, it will be discontinued without any winners selected.
-    fn force_start(extra_winning_target_count: u64);
+    fn force_start(extra_winning_target_count: u64, cycle_id: u64);
 
 
     /// Calculate commitment for a vote.
     /// Calculate commitment for a vote.
     fn calculate_commitment(
     fn calculate_commitment(
@@ -195,10 +201,7 @@ pub trait Trait<I: Instance>: frame_system::Trait {
 
 
     /// Checks if user can unlock his stake from the given vote.
     /// Checks if user can unlock his stake from the given vote.
     /// Gives runtime an ability to penalize user for not revealing stake, etc.
     /// Gives runtime an ability to penalize user for not revealing stake, etc.
-    fn can_release_vote_stake(
-        vote: &CastVote<Self::Hash, Balance<Self, I>>,
-        current_voting_cycle_id: &u64,
-    ) -> bool;
+    fn can_unlock_vote_stake(vote: &CastVote<Self::Hash, Balance<Self, I>>) -> bool;
 
 
     /// Gives runtime an ability to react on referendum result.
     /// Gives runtime an ability to react on referendum result.
     fn process_results(winners: &[OptionResult<Self::VotePower>]);
     fn process_results(winners: &[OptionResult<Self::VotePower>]);
@@ -223,9 +226,6 @@ decl_storage! {
         /// A record is finally removed when the user unstakes, which can happen during a voting stage or after the current cycle ends.
         /// A record is finally removed when the user unstakes, which can happen during a voting stage or after the current cycle ends.
         /// A stake for a vote can be reused in future referendum cycles.
         /// A stake for a vote can be reused in future referendum cycles.
         pub Votes get(fn votes) config(): map hasher(blake2_128_concat) T::AccountId => CastVoteOf<T, I>;
         pub Votes get(fn votes) config(): map hasher(blake2_128_concat) T::AccountId => CastVoteOf<T, I>;
-
-        /// Index of the current referendum cycle. It is incremented everytime referendum ends.
-        pub CurrentCycleId get(fn current_cycle_id) config(): u64;
     }
     }
 }
 }
 
 
@@ -347,14 +347,14 @@ decl_module! {
         #[weight = 10_000_000]
         #[weight = 10_000_000]
         pub fn vote(origin, commitment: T::Hash, stake: Balance<T, I>) -> Result<(), Error<T, I>> {
         pub fn vote(origin, commitment: T::Hash, stake: Balance<T, I>) -> Result<(), Error<T, I>> {
             // ensure action can be started
             // ensure action can be started
-            let account_id = EnsureChecks::<T, I>::can_vote(origin, &stake)?;
+            let (current_cycle_id, account_id) = EnsureChecks::<T, I>::can_vote(origin, &stake)?;
 
 
             //
             //
             // == MUTATION SAFE ==
             // == MUTATION SAFE ==
             //
             //
 
 
             // start revealing phase - it can return error when stake fails to lock
             // start revealing phase - it can return error when stake fails to lock
-            Mutations::<T, I>::vote(&account_id, &commitment, &stake)?;
+            Mutations::<T, I>::vote(&account_id, &commitment, &stake, &current_cycle_id)?;
 
 
             // emit event
             // emit event
             Self::deposit_event(RawEvent::VoteCast(account_id, commitment, stake));
             Self::deposit_event(RawEvent::VoteCast(account_id, commitment, stake));
@@ -451,7 +451,11 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Has
     type Currency = T::Currency;
     type Currency = T::Currency;
 
 
     /// Start new referendum run.
     /// Start new referendum run.
-    fn start_referendum(origin: T::Origin, extra_winning_target_count: u64) -> Result<(), ()> {
+    fn start_referendum(
+        origin: T::Origin,
+        extra_winning_target_count: u64,
+        cycle_id: u64,
+    ) -> Result<(), ()> {
         let winning_target_count = extra_winning_target_count + 1;
         let winning_target_count = extra_winning_target_count + 1;
 
 
         // ensure action can be started
         // ensure action can be started
@@ -462,7 +466,7 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Has
         //
         //
 
 
         // update state
         // update state
-        Mutations::<T, I>::start_voting_period(&winning_target_count);
+        Mutations::<T, I>::start_voting_period(&winning_target_count, &cycle_id);
 
 
         // emit event
         // emit event
         Self::deposit_event(RawEvent::ReferendumStarted(winning_target_count));
         Self::deposit_event(RawEvent::ReferendumStarted(winning_target_count));
@@ -472,14 +476,14 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Has
 
 
     /// Start referendum independent of the current state.
     /// Start referendum independent of the current state.
     /// If an election is running before calling this function, it will be discontinued without any winners selected.
     /// If an election is running before calling this function, it will be discontinued without any winners selected.
-    fn force_start(extra_winning_target_count: u64) {
+    fn force_start(extra_winning_target_count: u64, cycle_id: u64) {
         let winning_target_count = extra_winning_target_count + 1;
         let winning_target_count = extra_winning_target_count + 1;
 
 
         // remember if referendum is running
         // remember if referendum is running
         let referendum_running = !matches!(Stage::<T, I>::get(), ReferendumStage::Inactive);
         let referendum_running = !matches!(Stage::<T, I>::get(), ReferendumStage::Inactive);
 
 
         // update state
         // update state
-        Mutations::<T, I>::start_voting_period(&winning_target_count);
+        Mutations::<T, I>::start_voting_period(&winning_target_count, &cycle_id);
 
 
         // emit event
         // emit event
         if referendum_running {
         if referendum_running {
@@ -517,13 +521,14 @@ struct Mutations<T: Trait<I>, I: Instance> {
 
 
 impl<T: Trait<I>, I: Instance> Mutations<T, I> {
 impl<T: Trait<I>, I: Instance> Mutations<T, I> {
     /// Change the referendum stage from inactive to voting stage.
     /// Change the referendum stage from inactive to voting stage.
-    fn start_voting_period(winning_target_count: &u64) {
+    fn start_voting_period(winning_target_count: &u64, cycle_id: &u64) {
         // change referendum state
         // change referendum state
         Stage::<T, I>::put(ReferendumStage::Voting(ReferendumStageVoting::<
         Stage::<T, I>::put(ReferendumStage::Voting(ReferendumStageVoting::<
             T::BlockNumber,
             T::BlockNumber,
         > {
         > {
             started: <frame_system::Module<T>>::block_number() + 1.into(),
             started: <frame_system::Module<T>>::block_number() + 1.into(),
             winning_target_count: *winning_target_count,
             winning_target_count: *winning_target_count,
+            current_cycle_id: *cycle_id,
         }));
         }));
     }
     }
 
 
@@ -537,6 +542,7 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
             started: <frame_system::Module<T>>::block_number() + 1.into(),
             started: <frame_system::Module<T>>::block_number() + 1.into(),
             winning_target_count: old_stage.winning_target_count,
             winning_target_count: old_stage.winning_target_count,
             intermediate_winners: vec![],
             intermediate_winners: vec![],
+            current_cycle_id: old_stage.current_cycle_id,
         }));
         }));
     }
     }
 
 
@@ -545,23 +551,18 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
         revealing_stage: ReferendumStageRevealingOf<T, I>,
         revealing_stage: ReferendumStageRevealingOf<T, I>,
     ) -> Vec<OptionResult<<T as Trait<I>>::VotePower>> {
     ) -> Vec<OptionResult<<T as Trait<I>>::VotePower>> {
         // reset referendum state
         // reset referendum state
-        Self::reset_referendum();
+        Stage::<T, I>::put(ReferendumStage::Inactive);
 
 
         // return winning option
         // return winning option
         revealing_stage.intermediate_winners
         revealing_stage.intermediate_winners
     }
     }
 
 
-    /// Change the referendum stage from revealing to the inactive stage.
-    fn reset_referendum() {
-        Stage::<T, I>::put(ReferendumStage::Inactive);
-        CurrentCycleId::<I>::put(CurrentCycleId::<I>::get() + 1);
-    }
-
     /// Cast a user's sealed vote for the current referendum cycle.
     /// Cast a user's sealed vote for the current referendum cycle.
     fn vote(
     fn vote(
         account_id: &<T as frame_system::Trait>::AccountId,
         account_id: &<T as frame_system::Trait>::AccountId,
         commitment: &T::Hash,
         commitment: &T::Hash,
         stake: &Balance<T, I>,
         stake: &Balance<T, I>,
+        current_cycle_id: &u64,
     ) -> Result<(), Error<T, I>> {
     ) -> Result<(), Error<T, I>> {
         // lock stake amount
         // lock stake amount
         T::Currency::set_lock(
         T::Currency::set_lock(
@@ -577,7 +578,7 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
             CastVote {
             CastVote {
                 commitment: *commitment,
                 commitment: *commitment,
                 stake: *stake,
                 stake: *stake,
-                cycle_id: CurrentCycleId::<I>::get(),
+                cycle_id: *current_cycle_id,
                 vote_for: None,
                 vote_for: None,
             },
             },
         );
         );
@@ -746,8 +747,12 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
         Ok(())
         Ok(())
     }
     }
 
 
-    fn can_vote(origin: T::Origin, stake: &Balance<T, I>) -> Result<T::AccountId, Error<T, I>> {
+    fn can_vote(
+        origin: T::Origin,
+        stake: &Balance<T, I>,
+    ) -> Result<(u64, T::AccountId), Error<T, I>> {
         fn prevent_repeated_vote<T: Trait<I>, I: Instance>(
         fn prevent_repeated_vote<T: Trait<I>, I: Instance>(
+            cycle_id: &u64,
             account_id: &T::AccountId,
             account_id: &T::AccountId,
         ) -> Result<(), Error<T, I>> {
         ) -> Result<(), Error<T, I>> {
             if !Votes::<T, I>::contains_key(&account_id) {
             if !Votes::<T, I>::contains_key(&account_id) {
@@ -757,7 +762,7 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
             let existing_vote = Votes::<T, I>::get(&account_id);
             let existing_vote = Votes::<T, I>::get(&account_id);
 
 
             // don't allow repeated vote
             // don't allow repeated vote
-            if existing_vote.cycle_id == CurrentCycleId::<I>::get() {
+            if existing_vote.cycle_id == *cycle_id {
                 return Err(Error::<T, I>::AlreadyVotedThisCycle);
                 return Err(Error::<T, I>::AlreadyVotedThisCycle);
             }
             }
 
 
@@ -767,16 +772,14 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
         // ensure superuser requested action
         // ensure superuser requested action
         let account_id = Self::ensure_regular_user(origin)?;
         let account_id = Self::ensure_regular_user(origin)?;
 
 
-        let stage = Stage::<T, I>::get();
-
         // ensure referendum is running
         // ensure referendum is running
-        match stage {
-            ReferendumStage::Voting(_) => (),
+        let current_cycle_id = match Stage::<T, I>::get() {
+            ReferendumStage::Voting(tmp_stage_data) => tmp_stage_data.current_cycle_id,
             _ => return Err(Error::ReferendumNotRunning),
             _ => return Err(Error::ReferendumNotRunning),
         };
         };
 
 
         // prevent repeated vote
         // prevent repeated vote
-        prevent_repeated_vote::<T, I>(&account_id)?;
+        prevent_repeated_vote::<T, I>(&current_cycle_id, &account_id)?;
 
 
         // ensure stake is enough for voting
         // ensure stake is enough for voting
         if stake < &T::MinimumStake::get() {
         if stake < &T::MinimumStake::get() {
@@ -788,7 +791,7 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
             return Err(Error::InsufficientBalanceToStakeCurrency);
             return Err(Error::InsufficientBalanceToStakeCurrency);
         }
         }
 
 
-        Ok(account_id)
+        Ok((current_cycle_id, account_id))
     }
     }
 
 
     fn can_reveal_vote<R: ReferendumManager<T::Origin, T::AccountId, T::Hash>>(
     fn can_reveal_vote<R: ReferendumManager<T::Origin, T::AccountId, T::Hash>>(
@@ -796,15 +799,11 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
         salt: &[u8],
         salt: &[u8],
         vote_option_id: &u64,
         vote_option_id: &u64,
     ) -> Result<CanRevealResult<T, I>, Error<T, I>> {
     ) -> Result<CanRevealResult<T, I>, Error<T, I>> {
-        let cycle_id = CurrentCycleId::<I>::get();
-
         // ensure superuser requested action
         // ensure superuser requested action
         let account_id = Self::ensure_regular_user(origin)?;
         let account_id = Self::ensure_regular_user(origin)?;
 
 
-        let stage = Stage::<T, I>::get();
-
         // ensure referendum is running
         // ensure referendum is running
-        let stage_data = match stage {
+        let stage_data = match Stage::<T, I>::get() {
             ReferendumStage::Revealing(tmp_stage_data) => tmp_stage_data,
             ReferendumStage::Revealing(tmp_stage_data) => tmp_stage_data,
             _ => return Err(Error::RevealingNotInProgress),
             _ => return Err(Error::RevealingNotInProgress),
         };
         };
@@ -817,7 +816,7 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
         }
         }
 
 
         // ensure vote was cast for the running referendum
         // ensure vote was cast for the running referendum
-        if cycle_id != cast_vote.cycle_id {
+        if stage_data.current_cycle_id != cast_vote.cycle_id {
             return Err(Error::InvalidVote);
             return Err(Error::InvalidVote);
         }
         }
 
 
@@ -827,7 +826,12 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
         }
         }
 
 
         // ensure commitment corresponds to salt and vote option
         // ensure commitment corresponds to salt and vote option
-        let commitment = R::calculate_commitment(&account_id, salt, &cycle_id, vote_option_id);
+        let commitment = R::calculate_commitment(
+            &account_id,
+            salt,
+            &stage_data.current_cycle_id,
+            vote_option_id,
+        );
         if commitment != cast_vote.commitment {
         if commitment != cast_vote.commitment {
             return Err(Error::InvalidReveal);
             return Err(Error::InvalidReveal);
         }
         }
@@ -836,20 +840,13 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
     }
     }
 
 
     fn can_release_vote_stake(origin: T::Origin) -> Result<T::AccountId, Error<T, I>> {
     fn can_release_vote_stake(origin: T::Origin) -> Result<T::AccountId, Error<T, I>> {
-        let cycle_id = CurrentCycleId::<I>::get();
-
         // ensure superuser requested action
         // ensure superuser requested action
         let account_id = Self::ensure_regular_user(origin)?;
         let account_id = Self::ensure_regular_user(origin)?;
 
 
         let cast_vote = Self::ensure_vote_exists(&account_id)?;
         let cast_vote = Self::ensure_vote_exists(&account_id)?;
 
 
-        // allow release only for past cycles
-        if cycle_id == cast_vote.cycle_id {
-            return Err(Error::UnstakingVoteInSameCycle);
-        }
-
         // ask runtime if stake can be released
         // ask runtime if stake can be released
-        if !T::can_release_vote_stake(&cast_vote, &cycle_id) {
+        if !T::can_unlock_vote_stake(&cast_vote) {
             return Err(Error::UnstakingForbidden);
             return Err(Error::UnstakingForbidden);
         }
         }
 
 

+ 21 - 15
runtime-modules/referendum/src/mock.rs

@@ -2,9 +2,8 @@
 
 
 /////////////////// Configuration //////////////////////////////////////////////
 /////////////////// Configuration //////////////////////////////////////////////
 use crate::{
 use crate::{
-    Balance, CastVote, CurrentCycleId, Error, Instance, Module, OptionResult, RawEvent,
-    ReferendumManager, ReferendumStage, ReferendumStageRevealing, ReferendumStageVoting, Stage,
-    Trait, Votes,
+    Balance, CastVote, Error, Instance, Module, OptionResult, RawEvent, ReferendumManager,
+    ReferendumStage, ReferendumStageRevealing, ReferendumStageVoting, Stage, Trait, Votes,
 };
 };
 
 
 use frame_support::traits::{Currency, LockIdentifier, OnFinalize};
 use frame_support::traits::{Currency, LockIdentifier, OnFinalize};
@@ -91,10 +90,7 @@ impl Trait<Instance0> for Runtime {
         stake
         stake
     }
     }
 
 
-    fn can_release_vote_stake(
-        _vote: &CastVote<Self::Hash, Balance<Self, Instance0>>,
-        _current_voting_cycle_id: &u64,
-    ) -> bool {
+    fn can_unlock_vote_stake(_vote: &CastVote<Self::Hash, Balance<Self, Instance0>>) -> bool {
         // trigger fail when requested to do so
         // trigger fail when requested to do so
         if !IS_UNSTAKE_ENABLED.with(|value| value.borrow().0) {
         if !IS_UNSTAKE_ENABLED.with(|value| value.borrow().0) {
             return false;
             return false;
@@ -241,7 +237,6 @@ pub fn default_genesis_config() -> GenesisConfig<Runtime, Instance0> {
     GenesisConfig::<Runtime, Instance0> {
     GenesisConfig::<Runtime, Instance0> {
         stage: ReferendumStage::default(),
         stage: ReferendumStage::default(),
         votes: vec![],
         votes: vec![],
-        current_cycle_id: 0,
     }
     }
 }
 }
 
 
@@ -322,8 +317,8 @@ where
     pub fn calculate_commitment(
     pub fn calculate_commitment(
         account_id: &<T as frame_system::Trait>::AccountId,
         account_id: &<T as frame_system::Trait>::AccountId,
         vote_option_index: &u64,
         vote_option_index: &u64,
+        cycle_id: &u64,
     ) -> (T::Hash, Vec<u8>) {
     ) -> (T::Hash, Vec<u8>) {
-        let cycle_id = CurrentCycleId::<I>::get();
         Self::calculate_commitment_for_cycle(account_id, &cycle_id, vote_option_index, None)
         Self::calculate_commitment_for_cycle(account_id, &cycle_id, vote_option_index, None)
     }
     }
 
 
@@ -331,8 +326,8 @@ where
         account_id: &<T as frame_system::Trait>::AccountId,
         account_id: &<T as frame_system::Trait>::AccountId,
         vote_option_index: &u64,
         vote_option_index: &u64,
         custom_salt: &[u8],
         custom_salt: &[u8],
+        cycle_id: &u64,
     ) -> (T::Hash, Vec<u8>) {
     ) -> (T::Hash, Vec<u8>) {
-        let cycle_id = CurrentCycleId::<I>::get();
         Self::calculate_commitment_for_cycle(
         Self::calculate_commitment_for_cycle(
             account_id,
             account_id,
             &cycle_id,
             &cycle_id,
@@ -390,6 +385,7 @@ impl InstanceMocks<Runtime, Instance0> {
     pub fn start_referendum_extrinsic(
     pub fn start_referendum_extrinsic(
         origin: OriginType<<Runtime as frame_system::Trait>::AccountId>,
         origin: OriginType<<Runtime as frame_system::Trait>::AccountId>,
         winning_target_count: u64,
         winning_target_count: u64,
+        cycle_id: u64,
         expected_result: Result<(), ()>,
         expected_result: Result<(), ()>,
     ) -> () {
     ) -> () {
         let extra_winning_target_count = winning_target_count - 1;
         let extra_winning_target_count = winning_target_count - 1;
@@ -399,15 +395,17 @@ impl InstanceMocks<Runtime, Instance0> {
             Module::<Runtime, Instance0>::start_referendum(
             Module::<Runtime, Instance0>::start_referendum(
                 InstanceMockUtils::<Runtime, Instance0>::mock_origin(origin),
                 InstanceMockUtils::<Runtime, Instance0>::mock_origin(origin),
                 extra_winning_target_count,
                 extra_winning_target_count,
+                cycle_id,
             ),
             ),
             expected_result,
             expected_result,
         );
         );
 
 
-        Self::start_referendum_inner(extra_winning_target_count, expected_result)
+        Self::start_referendum_inner(extra_winning_target_count, cycle_id, expected_result)
     }
     }
 
 
     pub fn start_referendum_manager(
     pub fn start_referendum_manager(
         winning_target_count: u64,
         winning_target_count: u64,
+        cycle_id: u64,
         expected_result: Result<(), ()>,
         expected_result: Result<(), ()>,
     ) -> () {
     ) -> () {
         let extra_winning_target_count = winning_target_count - 1;
         let extra_winning_target_count = winning_target_count - 1;
@@ -421,15 +419,20 @@ impl InstanceMocks<Runtime, Instance0> {
             >>::start_referendum(
             >>::start_referendum(
                 InstanceMockUtils::<Runtime, Instance0>::mock_origin(OriginType::Root),
                 InstanceMockUtils::<Runtime, Instance0>::mock_origin(OriginType::Root),
                 extra_winning_target_count,
                 extra_winning_target_count,
+                cycle_id,
             )
             )
             .is_ok(),
             .is_ok(),
             expected_result.is_ok(),
             expected_result.is_ok(),
         );
         );
 
 
-        Self::start_referendum_inner(extra_winning_target_count, expected_result)
+        Self::start_referendum_inner(extra_winning_target_count, cycle_id, expected_result)
     }
     }
 
 
-    fn start_referendum_inner(extra_winning_target_count: u64, expected_result: Result<(), ()>) {
+    fn start_referendum_inner(
+        extra_winning_target_count: u64,
+        cycle_id: u64,
+        expected_result: Result<(), ()>,
+    ) {
         if expected_result.is_err() {
         if expected_result.is_err() {
             return;
             return;
         }
         }
@@ -442,6 +445,7 @@ impl InstanceMocks<Runtime, Instance0> {
             ReferendumStage::Voting(ReferendumStageVoting {
             ReferendumStage::Voting(ReferendumStageVoting {
                 started: block_number + 1, // actual voting starts in the next block (thats why +1)
                 started: block_number + 1, // actual voting starts in the next block (thats why +1)
                 winning_target_count,
                 winning_target_count,
+                current_cycle_id: cycle_id,
             }),
             }),
         );
         );
 
 
@@ -456,7 +460,7 @@ impl InstanceMocks<Runtime, Instance0> {
         );
         );
     }
     }
 
 
-    pub fn check_voting_finished(winning_target_count: u64) {
+    pub fn check_voting_finished(winning_target_count: u64, cycle_id: u64) {
         let block_number = frame_system::Module::<Runtime>::block_number();
         let block_number = frame_system::Module::<Runtime>::block_number();
 
 
         assert_eq!(
         assert_eq!(
@@ -465,6 +469,7 @@ impl InstanceMocks<Runtime, Instance0> {
                 started: block_number,
                 started: block_number,
                 winning_target_count,
                 winning_target_count,
                 intermediate_winners: vec![],
                 intermediate_winners: vec![],
+                current_cycle_id: cycle_id,
             }),
             }),
         );
         );
 
 
@@ -504,6 +509,7 @@ impl InstanceMocks<Runtime, Instance0> {
         account_id: <Runtime as frame_system::Trait>::AccountId,
         account_id: <Runtime as frame_system::Trait>::AccountId,
         commitment: <Runtime as frame_system::Trait>::Hash,
         commitment: <Runtime as frame_system::Trait>::Hash,
         stake: Balance<Runtime, Instance0>,
         stake: Balance<Runtime, Instance0>,
+        cycle_id: u64,
         expected_result: Result<(), Error<Runtime, Instance0>>,
         expected_result: Result<(), Error<Runtime, Instance0>>,
     ) -> () {
     ) -> () {
         // check method returns expected result
         // check method returns expected result
@@ -524,7 +530,7 @@ impl InstanceMocks<Runtime, Instance0> {
             Votes::<Runtime, Instance0>::get(account_id),
             Votes::<Runtime, Instance0>::get(account_id),
             CastVote {
             CastVote {
                 commitment,
                 commitment,
-                cycle_id: CurrentCycleId::<Instance0>::get(),
+                cycle_id: cycle_id.clone(),
                 stake,
                 stake,
                 vote_for: None,
                 vote_for: None,
             },
             },

+ 265 - 65
runtime-modules/referendum/src/tests.rs

@@ -13,8 +13,9 @@ type MockUtils = InstanceMockUtils<Runtime, Instance0>;
 fn referendum_start() {
 fn referendum_start() {
     MockUtils::origin_access(USER_ADMIN, |origin| {
     MockUtils::origin_access(USER_ADMIN, |origin| {
         let winning_target_count = 1;
         let winning_target_count = 1;
+        let cycle_id = 1;
 
 
-        Mocks::start_referendum_extrinsic(origin, winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(origin, winning_target_count, cycle_id, Ok(()));
     });
     });
 }
 }
 
 
@@ -25,8 +26,14 @@ fn referendum_start_access_restricted() {
 
 
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let winning_target_count = 1;
         let winning_target_count = 1;
+        let cycle_id = 1;
 
 
-        Mocks::start_referendum_extrinsic(OriginType::None, winning_target_count, Err(()));
+        Mocks::start_referendum_extrinsic(
+            OriginType::None,
+            winning_target_count,
+            cycle_id,
+            Err(()),
+        );
     });
     });
 }
 }
 
 
@@ -39,9 +46,15 @@ fn referendum_start_forbidden_after_start() {
         let origin = OriginType::Signed(USER_ADMIN);
         let origin = OriginType::Signed(USER_ADMIN);
         let options = 1;
         let options = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
+        let cycle_id = 1;
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::start_referendum_extrinsic(origin.clone(), options.clone(), Err(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::start_referendum_extrinsic(origin.clone(), options.clone(), cycle_id, Err(()));
     });
     });
 }
 }
 
 
@@ -55,15 +68,29 @@ fn voting() {
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
 
 
         let winning_target_count = 1;
         let winning_target_count = 1;
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, _) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, _) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count,
+            cycle_id.clone(),
+            Ok(()),
+        );
 
 
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
     });
     });
 }
 }
 
 
@@ -75,11 +102,13 @@ fn voting_referendum_not_running() {
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
 
 
         let winning_target_count = 1;
         let winning_target_count = 1;
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, _) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, _) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
         // try to vote before referendum starts
         // try to vote before referendum starts
         Mocks::vote(
         Mocks::vote(
@@ -87,10 +116,16 @@ fn voting_referendum_not_running() {
             account_id,
             account_id,
             commitment,
             commitment,
             stake,
             stake,
+            cycle_id.clone(),
             Err(Error::ReferendumNotRunning),
             Err(Error::ReferendumNotRunning),
         );
         );
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count,
+            cycle_id.clone(),
+            Ok(()),
+        );
 
 
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         MockUtils::increase_block_number(voting_stage_duration + 1);
         MockUtils::increase_block_number(voting_stage_duration + 1);
@@ -101,6 +136,7 @@ fn voting_referendum_not_running() {
             account_id,
             account_id,
             commitment,
             commitment,
             stake,
             stake,
+            cycle_id.clone(),
             Err(Error::ReferendumNotRunning),
             Err(Error::ReferendumNotRunning),
         );
         );
     });
     });
@@ -114,18 +150,26 @@ fn voting_stake_too_low() {
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
 
 
         let winning_target_count = 1;
         let winning_target_count = 1;
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get() - 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get() - 1;
-        let (commitment, _) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, _) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count,
+            cycle_id.clone(),
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
             commitment,
             commitment,
             stake,
             stake,
+            cycle_id.clone(),
             Err(Error::InsufficientStake),
             Err(Error::InsufficientStake),
         );
         );
     });
     });
@@ -139,19 +183,27 @@ fn voting_user_repeated_vote() {
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
 
 
         let winning_target_count = 1;
         let winning_target_count = 1;
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let different_stake = stake * 2;
         let different_stake = stake * 2;
-        let (commitment, _) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, _) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count,
+            cycle_id.clone(),
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
             commitment,
             commitment,
             stake.clone(),
             stake.clone(),
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
 
 
@@ -160,6 +212,7 @@ fn voting_user_repeated_vote() {
             account_id,
             account_id,
             commitment,
             commitment,
             different_stake.clone(),
             different_stake.clone(),
+            cycle_id.clone(),
             Err(Error::AlreadyVotedThisCycle),
             Err(Error::AlreadyVotedThisCycle),
         );
         );
     });
     });
@@ -172,14 +225,20 @@ fn voting_user_repeated_vote() {
 fn finish_voting() {
 fn finish_voting() {
     MockUtils::origin_access(USER_ADMIN, |origin| {
     MockUtils::origin_access(USER_ADMIN, |origin| {
         let winning_target_count = 1;
         let winning_target_count = 1;
+        let cycle_id = 1;
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count,
+            cycle_id.clone(),
+            Ok(()),
+        );
 
 
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
 
 
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id.clone());
     });
     });
 }
 }
 
 
@@ -194,17 +253,31 @@ fn reveal() {
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for = 1;
         let option_to_vote_for = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -225,13 +298,20 @@ fn reveal_reveal_stage_not_running() {
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for = 1;
         let option_to_vote_for = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
 
 
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
@@ -241,10 +321,17 @@ fn reveal_reveal_stage_not_running() {
             Err(Error::RevealingNotInProgress),
             Err(Error::RevealingNotInProgress),
         );
         );
 
 
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         MockUtils::increase_block_number(reveal_stage_duration);
         MockUtils::increase_block_number(reveal_stage_duration);
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
 
 
@@ -268,12 +355,18 @@ fn reveal_no_vote() {
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         MockUtils::increase_block_number(reveal_stage_duration);
         MockUtils::increase_block_number(reveal_stage_duration);
 
 
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
@@ -290,6 +383,7 @@ fn reveal_salt_too_long() {
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let mut salt = vec![];
         let mut salt = vec![];
@@ -299,14 +393,30 @@ fn reveal_salt_too_long() {
 
 
         let option_to_vote_for = 1;
         let option_to_vote_for = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, _) =
-            MockUtils::calculate_commitment_custom_salt(&account_id, &option_to_vote_for, &salt);
+        let (commitment, _) = MockUtils::calculate_commitment_custom_salt(
+            &account_id,
+            &option_to_vote_for,
+            &salt,
+            &cycle_id,
+        );
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -326,20 +436,34 @@ fn reveal_invalid_vote() {
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let invalid_option = 1000;
         let invalid_option = 1000;
         let option_to_vote_for = 1;
         let option_to_vote_for = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
         Runtime::feature_option_id_valid(false);
         Runtime::feature_option_id_valid(false);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -359,18 +483,32 @@ fn reveal_invalid_commitment_proof() {
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let invalid_option = option_to_vote_for + 1;
         let invalid_option = option_to_vote_for + 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -393,17 +531,31 @@ fn finish_revealing_period() {
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
-        Mocks::vote(origin.clone(), account_id, commitment, stake, Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
+        Mocks::vote(
+            origin.clone(),
+            account_id,
+            commitment,
+            stake,
+            cycle_id.clone(),
+            Ok(()),
+        );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -437,6 +589,7 @@ fn finish_revealing_period_vote_power() {
         let origin = OriginType::Signed(account_superuser);
         let origin = OriginType::Signed(account_superuser);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter2 = OriginType::Signed(account_id2);
         let origin_voter2 = OriginType::Signed(account_id2);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for1 = 0;
         let option_to_vote_for1 = 0;
@@ -444,16 +597,22 @@ fn finish_revealing_period_vote_power() {
         let stake_bigger = <Runtime as Trait<Instance0>>::MinimumStake::get() * 2;
         let stake_bigger = <Runtime as Trait<Instance0>>::MinimumStake::get() * 2;
         let stake_smaller = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake_smaller = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let (commitment1, salt1) =
         let (commitment1, salt1) =
-            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1);
+            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1, &cycle_id);
         let (commitment2, salt2) =
         let (commitment2, salt2) =
-            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for2);
+            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for2, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
             commitment1,
             commitment1,
             stake_bigger,
             stake_bigger,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         ); // vote for first option by regular user
         ); // vote for first option by regular user
         Mocks::vote(
         Mocks::vote(
@@ -461,11 +620,12 @@ fn finish_revealing_period_vote_power() {
             account_id2,
             account_id2,
             commitment2,
             commitment2,
             stake_smaller,
             stake_smaller,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         ); // vote for second option by prominent user
         ); // vote for second option by prominent user
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
@@ -508,11 +668,12 @@ fn winners_no_vote_revealed() {
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let voting_stage_duration = <Runtime as Trait<Instance0>>::VoteStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let origin = OriginType::Signed(USER_ADMIN);
         let origin = OriginType::Signed(USER_ADMIN);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, Ok(()));
+        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count, cycle_id, Ok(()));
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         MockUtils::increase_block_number(reveal_stage_duration);
         MockUtils::increase_block_number(reveal_stage_duration);
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
         Mocks::check_revealing_finished(vec![], MockUtils::transform_results(vec![]));
     });
     });
@@ -534,24 +695,31 @@ fn winners_multiple_winners() {
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter2 = OriginType::Signed(account_id2);
         let origin_voter2 = OriginType::Signed(account_id2);
         let origin_voter3 = OriginType::Signed(account_id3);
         let origin_voter3 = OriginType::Signed(account_id3);
+        let cycle_id = 1;
         let winning_target_count = 2;
         let winning_target_count = 2;
 
 
         let option_to_vote_for1 = 0;
         let option_to_vote_for1 = 0;
         let option_to_vote_for2 = 1;
         let option_to_vote_for2 = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let (commitment1, salt1) =
         let (commitment1, salt1) =
-            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1);
+            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1, &cycle_id);
         let (commitment2, salt2) =
         let (commitment2, salt2) =
-            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for1);
+            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for1, &cycle_id);
         let (commitment3, salt3) =
         let (commitment3, salt3) =
-            MockUtils::calculate_commitment(&account_id3, &option_to_vote_for2);
+            MockUtils::calculate_commitment(&account_id3, &option_to_vote_for2, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
             commitment1,
             commitment1,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         Mocks::vote(
         Mocks::vote(
@@ -559,6 +727,7 @@ fn winners_multiple_winners() {
             account_id2,
             account_id2,
             commitment2,
             commitment2,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         Mocks::vote(
         Mocks::vote(
@@ -566,11 +735,12 @@ fn winners_multiple_winners() {
             account_id3,
             account_id3,
             commitment3,
             commitment3,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
 
 
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
@@ -626,22 +796,29 @@ fn winners_multiple_winners_extra() {
         let origin = OriginType::Signed(account_superuser);
         let origin = OriginType::Signed(account_superuser);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter2 = OriginType::Signed(account_id2);
         let origin_voter2 = OriginType::Signed(account_id2);
+        let cycle_id = 1;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for1 = 0;
         let option_to_vote_for1 = 0;
         let option_to_vote_for2 = 1;
         let option_to_vote_for2 = 1;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let (commitment1, salt1) =
         let (commitment1, salt1) =
-            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1);
+            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for1, &cycle_id);
         let (commitment2, salt2) =
         let (commitment2, salt2) =
-            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for2);
+            MockUtils::calculate_commitment(&account_id2, &option_to_vote_for2, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
             commitment1,
             commitment1,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         Mocks::vote(
         Mocks::vote(
@@ -649,11 +826,12 @@ fn winners_multiple_winners_extra() {
             account_id2,
             account_id2,
             commitment2,
             commitment2,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
@@ -694,24 +872,31 @@ fn winners_multiple_not_enough() {
         let account_id1 = USER_REGULAR;
         let account_id1 = USER_REGULAR;
         let origin = OriginType::Signed(account_superuser);
         let origin = OriginType::Signed(account_superuser);
         let origin_voter1 = OriginType::Signed(account_id1);
         let origin_voter1 = OriginType::Signed(account_id1);
+        let cycle_id = 1;
         let winning_target_count = 3;
         let winning_target_count = 3;
 
 
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let (commitment1, salt1) =
         let (commitment1, salt1) =
-            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for);
+            MockUtils::calculate_commitment(&account_id1, &option_to_vote_for, &cycle_id);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id,
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
             commitment1,
             commitment1,
             stake,
             stake,
+            cycle_id.clone(),
             Ok(()),
             Ok(()),
         );
         );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin_voter1.clone(),
             origin_voter1.clone(),
             account_id1,
             account_id1,
@@ -745,23 +930,32 @@ fn referendum_release_stake() {
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let reveal_stage_duration = <Runtime as Trait<Instance0>>::RevealStageDuration::get();
         let account_id = USER_ADMIN;
         let account_id = USER_ADMIN;
         let origin = OriginType::Signed(account_id);
         let origin = OriginType::Signed(account_id);
+        let cycle_id1 = 1;
+        let cycle_id2 = 2;
         let winning_target_count = 1;
         let winning_target_count = 1;
 
 
         let option_to_vote_for = 0;
         let option_to_vote_for = 0;
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
         let stake = <Runtime as Trait<Instance0>>::MinimumStake::get();
-        let (commitment, salt) = MockUtils::calculate_commitment(&account_id, &option_to_vote_for);
+        let (commitment, salt) =
+            MockUtils::calculate_commitment(&account_id, &option_to_vote_for, &cycle_id1);
 
 
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id1,
+            Ok(()),
+        );
         Mocks::vote(
         Mocks::vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
             commitment,
             commitment,
             stake.clone(),
             stake.clone(),
+            cycle_id1.clone(),
             Ok(()),
             Ok(()),
         );
         );
         MockUtils::increase_block_number(voting_stage_duration);
         MockUtils::increase_block_number(voting_stage_duration);
 
 
-        Mocks::check_voting_finished(winning_target_count);
+        Mocks::check_voting_finished(winning_target_count, cycle_id1);
         Mocks::reveal_vote(
         Mocks::reveal_vote(
             origin.clone(),
             origin.clone(),
             account_id,
             account_id,
@@ -784,7 +978,12 @@ fn referendum_release_stake() {
         Runtime::feature_stack_lock(true);
         Runtime::feature_stack_lock(true);
 
 
         // since `account_id` voted for the winner, he can unlock stake only after inactive stage ends
         // since `account_id` voted for the winner, he can unlock stake only after inactive stage ends
-        Mocks::start_referendum_extrinsic(origin.clone(), winning_target_count.clone(), Ok(()));
+        Mocks::start_referendum_extrinsic(
+            origin.clone(),
+            winning_target_count.clone(),
+            cycle_id2,
+            Ok(()),
+        );
 
 
         Mocks::release_stake(origin.clone(), account_id, Ok(()));
         Mocks::release_stake(origin.clone(), account_id, Ok(()));
     });
     });
@@ -799,7 +998,8 @@ fn referendum_manager_referendum_start() {
 
 
     build_test_externalities(config).execute_with(|| {
     build_test_externalities(config).execute_with(|| {
         let winning_target_count = 1;
         let winning_target_count = 1;
+        let cycle_id = 1;
 
 
-        Mocks::start_referendum_manager(winning_target_count, Ok(()));
+        Mocks::start_referendum_manager(winning_target_count, cycle_id, Ok(()));
     });
     });
 }
 }