Browse Source

runtime: proposals: fix council proposals

This fixes the proposals for:
* Set Council Budget Increment
* Set Councilor Reward

Furthermore this neccesitated updating council for having councilor_reward
and budget increment to be stored as part of the module's storage
conectado 4 years ago
parent
commit
9a3ea5620a

+ 1 - 0
node/src/chain_spec/council_config.rs

@@ -12,6 +12,7 @@ pub fn create_council_config() -> CouncilConfig {
         next_reward_payments: 0,
         next_budget_refill: <Runtime as CouncilTrait>::BudgetRefillPeriod::get(),
         budget_increment: 1,
+        councilor_reward: 100,
     }
 }
 

+ 1 - 1
runtime-modules/council/src/benchmarking.rs

@@ -395,7 +395,7 @@ benchmarks! {
             .collect::<Vec<_>>();
     }: { Council::<T>::try_process_budget(target); }
     verify {
-        let reward_per_block: Balance<T> = T::ElectedMemberRewardPerBlock::get();
+        let reward_per_block: Balance<T> = Council::<T>::councilor_reward();
 
         let reward_per_councillor: Balance<T> =
             reward_period

+ 38 - 5
runtime-modules/council/src/lib.rs

@@ -242,8 +242,6 @@ pub trait Trait: frame_system::Trait + common::Trait + balances::Trait {
     /// Duration of idle period
     type IdlePeriodDuration: Get<Self::BlockNumber>;
 
-    /// The value elected members will be awarded each block of their reign.
-    type ElectedMemberRewardPerBlock: Get<Balance<Self>>;
     /// Interval for automatic reward payments.
     type ElectedMemberRewardPeriod: Get<Self::BlockNumber>;
 
@@ -315,6 +313,9 @@ decl_storage! {
 
         /// Amount of balance to be refilled every budget period
         pub BudgetIncrement get(fn budget_increment) config(): Balance::<T>;
+
+        /// Councilor reward per block
+        pub CouncilorReward get(fn councilor_reward) config(): Balance::<T>;
     }
 }
 
@@ -367,6 +368,9 @@ decl_event! {
 
         /// Budget increment has been updated.
         BudgetIncrementUpdated(Balance),
+
+        /// Councilor reward has been updated.
+        CouncilorRewardUpdated(Balance),
     }
 }
 
@@ -455,8 +459,6 @@ decl_module! {
         const AnnouncingPeriodDuration: T::BlockNumber = T::AnnouncingPeriodDuration::get();
         /// Duration of idle period
         const IdlePeriodDuration: T::BlockNumber = T::IdlePeriodDuration::get();
-        /// The value elected members will be awarded each block of their reign.
-        const ElectedMemberRewardPerBlock: Balance<T> = T::ElectedMemberRewardPerBlock::get();
         /// Interval for automatic reward payments.
         const ElectedMemberRewardPeriod: T::BlockNumber = T::ElectedMemberRewardPeriod::get();
         /// Interval between automatic budget refills.
@@ -686,6 +688,25 @@ decl_module! {
 
             Ok(())
         }
+
+        #[weight = 10_000_000]
+        pub fn set_councilor_reward(origin, councilor_reward: Balance::<T>) -> Result<(), Error<T>> {
+            // ensure action can be started
+            EnsureChecks::<T>::can_set_councilor_reward(origin)?;
+
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            // update state
+            Mutations::<T>::set_councilor_reward(&councilor_reward);
+
+            // emit event
+            Self::deposit_event(RawEvent::CouncilorRewardUpdated(councilor_reward));
+
+            Ok(())
+        }
     }
 }
 
@@ -831,7 +852,7 @@ impl<T: Trait> Module<T> {
 
     // Pay rewards to elected council members.
     fn pay_elected_member_rewards(now: T::BlockNumber) {
-        let reward_per_block = T::ElectedMemberRewardPerBlock::get();
+        let reward_per_block = Self::councilor_reward();
         let starting_balance = Budget::<T>::get();
 
         // pay reward to all council members
@@ -1206,6 +1227,11 @@ impl<T: Trait> Mutations<T> {
         BudgetIncrement::<T>::put(budget_increment);
     }
 
+    // Set councilor reward.
+    fn set_councilor_reward(councilor_reward: &Balance<T>) {
+        CouncilorReward::<T>::put(councilor_reward);
+    }
+
     // Pay reward to a single elected council member.
     fn pay_reward(
         member_index: usize,
@@ -1418,6 +1444,13 @@ impl<T: Trait> EnsureChecks<T> {
 
         Ok(())
     }
+
+    // Ensures there is no problem in setting the councilor reward.
+    fn can_set_councilor_reward(origin: T::Origin) -> Result<(), Error<T>> {
+        ensure_root(origin)?;
+
+        Ok(())
+    }
 }
 
 impl<T: Trait + common::Trait> CouncilOriginValidator<T::Origin, T::MemberId, T::AccountId>

+ 33 - 4
runtime-modules/council/src/mock.rs

@@ -4,8 +4,8 @@
 use crate::{
     AnnouncementPeriodNr, Balance, Budget, BudgetIncrement, CandidateOf, Candidates,
     CouncilMemberOf, CouncilMembers, CouncilStage, CouncilStageAnnouncing, CouncilStageElection,
-    CouncilStageUpdate, CouncilStageUpdateOf, Error, GenesisConfig, Module, NextBudgetRefill,
-    RawEvent, ReferendumConnection, Stage, Trait, WeightInfo,
+    CouncilStageUpdate, CouncilStageUpdateOf, CouncilorReward, Error, GenesisConfig, Module,
+    NextBudgetRefill, RawEvent, ReferendumConnection, Stage, Trait, WeightInfo,
 };
 
 use balances;
@@ -64,7 +64,6 @@ parameter_types! {
     pub const MinCandidateStake: u64 = 11000;
     pub const CandidacyLockId: LockIdentifier = *b"council1";
     pub const CouncilorLockId: LockIdentifier = *b"council2";
-    pub const ElectedMemberRewardPerBlock: u64 = 100;
     pub const ElectedMemberRewardPeriod: u64 = 10;
     // intentionally high number that prevents side-effecting tests other than  budget refill tests
     pub const BudgetRefillPeriod: u64 = 1000;
@@ -89,7 +88,6 @@ impl Trait for Runtime {
     type CandidacyLock = StakingManager<Self, CandidacyLockId>;
     type CouncilorLock = StakingManager<Self, CouncilorLockId>;
 
-    type ElectedMemberRewardPerBlock = ElectedMemberRewardPerBlock;
     type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
 
     type StakingAccountValidator = ();
@@ -585,6 +583,7 @@ pub fn default_genesis_config() -> GenesisConfig<Runtime> {
         next_reward_payments: 0,
         next_budget_refill: <Runtime as Trait>::BudgetRefillPeriod::get(),
         budget_increment: 1,
+        councilor_reward: 100,
     }
 }
 
@@ -1100,6 +1099,36 @@ where
         );
     }
 
+    pub fn set_councilor_reward(
+        origin: OriginType<T::AccountId>,
+        councilor_reward: T::Balance,
+        expected_result: Result<(), ()>,
+    ) {
+        // check method returns expected result
+        assert_eq!(
+            Module::<T>::set_councilor_reward(
+                InstanceMockUtils::<T>::mock_origin(origin),
+                councilor_reward,
+            )
+            .is_ok(),
+            expected_result.is_ok(),
+        );
+
+        if expected_result.is_err() {
+            return;
+        }
+
+        assert_eq!(CouncilorReward::<T>::get(), councilor_reward);
+
+        assert_eq!(
+            frame_system::Module::<Runtime>::events()
+                .last()
+                .unwrap()
+                .event,
+            TestEvent::event_mod(RawEvent::CouncilorRewardUpdated(councilor_reward.into())),
+        );
+    }
+
     pub fn set_budget_increment(
         origin: OriginType<T::AccountId>,
         budget_increment: T::Balance,

+ 75 - 0
runtime-modules/council/src/tests.rs

@@ -1147,6 +1147,35 @@ fn council_budget_increment_can_be_upddated() {
     })
 }
 
+// Test that budget increment can be set from external source.
+#[test]
+fn council_budget_increment_can_be_updated() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let origin = OriginType::Root;
+        let budget_increment = 1000;
+        let next_refill = <Runtime as Trait>::BudgetRefillPeriod::get();
+
+        Mocks::set_budget_increment(origin.clone(), budget_increment, Ok(()));
+
+        // forward to one block before refill
+        MockUtils::increase_block_number(next_refill - 1);
+
+        // Check budget currently is 0
+        Mocks::check_budget_refill(0, next_refill);
+
+        // forward to after block refill
+        MockUtils::increase_block_number(1);
+
+        // check budget was increased with the expected increment
+        Mocks::check_budget_refill(
+            budget_increment,
+            next_refill + <Runtime as Trait>::BudgetRefillPeriod::get(),
+        );
+    })
+}
+
 // Test that rewards for council members are paid.
 #[test]
 fn council_rewards_are_paid() {
@@ -1187,6 +1216,52 @@ fn council_rewards_are_paid() {
     });
 }
 
+// Test that can set councilor reward correctly.
+#[test]
+fn councilor_reward_can_be_set() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let council_settings = CouncilSettings::<Runtime>::extract_settings();
+        let origin = OriginType::Root;
+
+        let sufficient_balance = 10000000;
+
+        Mocks::set_budget(origin.clone(), sufficient_balance, Ok(()));
+        Mocks::set_councilor_reward(origin.clone(), 1, Ok(()));
+
+        // run 1st council cycle
+        let params = Mocks::run_full_council_cycle(0, &[], 0);
+
+        // calculate council member last reward block
+        let last_payment_block = council_settings.cycle_duration
+            + (<Runtime as Trait>::ElectedMemberRewardPeriod::get()
+                - (council_settings.idle_stage_duration
+                    % <Runtime as Trait>::ElectedMemberRewardPeriod::get()))
+            - 1; // -1 because current block is not finalized yet
+
+        let start_rewarding_block = council_settings.reveal_stage_duration
+            + council_settings.announcing_stage_duration
+            + council_settings.voting_stage_duration
+            - 1;
+
+        let councilor_initial_balance = council_settings.min_candidate_stake * TOPUP_MULTIPLIER;
+        let current_council_balance =
+            (last_payment_block - start_rewarding_block) + councilor_initial_balance;
+
+        // Check that reward was correctly paid out
+        params
+            .expected_final_council_members
+            .iter()
+            .for_each(|council_member| {
+                assert_eq!(
+                    balances::Module::<Runtime>::free_balance(council_member.reward_account_id),
+                    current_council_balance
+                )
+            });
+    });
+}
+
 // Test that any rewards missed due to insufficient budget balance will be paid off eventually.
 #[test]
 fn council_missed_rewards_are_paid_later() {

+ 0 - 2
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -491,7 +491,6 @@ parameter_types! {
     pub const MinCandidateStake: u64 = 11000;
     pub const CandidacyLockId: LockIdentifier = *b"council1";
     pub const CouncilorLockId: LockIdentifier = *b"council2";
-    pub const ElectedMemberRewardPerBlock: u64 = 100;
     pub const ElectedMemberRewardPeriod: u64 = 10;
     pub const BudgetRefillAmount: u64 = 1000;
     // intentionally high number that prevents side-effecting tests other than  budget refill tests
@@ -514,7 +513,6 @@ impl council::Trait for Test {
     type CandidacyLock = StakingManager<Self, CandidacyLockId>;
     type CouncilorLock = StakingManager<Self, CouncilorLockId>;
 
-    type ElectedMemberRewardPerBlock = ElectedMemberRewardPerBlock;
     type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
 
     type BudgetRefillPeriod = BudgetRefillPeriod;

+ 0 - 2
runtime-modules/proposals/engine/src/tests/mock/mod.rs

@@ -376,7 +376,6 @@ parameter_types! {
     pub const MinCandidateStake: u64 = 11000;
     pub const CandidacyLockId: LockIdentifier = *b"council1";
     pub const CouncilorLockId: LockIdentifier = *b"council2";
-    pub const ElectedMemberRewardPerBlock: u64 = 100;
     pub const ElectedMemberRewardPeriod: u64 = 10;
     pub const BudgetRefillAmount: u64 = 1000;
     // intentionally high number that prevents side-effecting tests other than  budget refill tests
@@ -399,7 +398,6 @@ impl council::Trait for Test {
     type CandidacyLock = StakingManager<Self, CandidacyLockId>;
     type CouncilorLock = StakingManager<Self, CouncilorLockId>;
 
-    type ElectedMemberRewardPerBlock = ElectedMemberRewardPerBlock;
     type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
 
     type BudgetRefillPeriod = BudgetRefillPeriod;

+ 2 - 3
runtime/src/integration/proposals/proposal_encoder.rs

@@ -107,9 +107,8 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
                 Call::Council(council::Call::set_budget_increment(budget_increment))
             }
 
-            ProposalDetails::SetCouncilorReward(_councilor_reward) => {
-                // TODO: replace stub
-                Call::ProposalsCodex(proposals_codex::Call::execute_signal_proposal(Vec::new()))
+            ProposalDetails::SetCouncilorReward(councilor_reward) => {
+                Call::Council(council::Call::set_councilor_reward(councilor_reward))
             }
 
             ProposalDetails::SetInitialInvitationBalance(initial_invitation_balance) => {

+ 0 - 2
runtime/src/lib.rs

@@ -474,7 +474,6 @@ parameter_types! {
     pub const IdlePeriodDuration: BlockNumber = 27;
     pub const CouncilSize: u64 = 3;
     pub const MinCandidateStake: u64 = 11000;
-    pub const ElectedMemberRewardPerBlock: u64 = 100;
     pub const ElectedMemberRewardPeriod: BlockNumber = 10;
     pub const DefaultBudgetIncrement: u64 = 1000;
     pub const BudgetRefillPeriod: BlockNumber = 1000;
@@ -554,7 +553,6 @@ impl council::Trait for Runtime {
 
     type StakingAccountValidator = Members;
 
-    type ElectedMemberRewardPerBlock = ElectedMemberRewardPerBlock;
     type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
 
     type BudgetRefillPeriod = BudgetRefillPeriod;

+ 1 - 1
runtime/src/proposals_configuration/defaults.rs

@@ -223,7 +223,7 @@ pub(crate) fn set_council_budget_increment_proposal() -> ProposalParameters<Bloc
 pub(crate) fn set_councilor_reward_proposal() -> ProposalParameters<BlockNumber, Balance> {
     ProposalParameters {
         voting_period: 72200,
-        grace_period: 72200,
+        grace_period: 0,
         approval_quorum_percentage: 80,
         approval_threshold_percentage: 100,
         slashing_quorum_percentage: 60,

+ 30 - 0
runtime/src/tests/proposals_integration/mod.rs

@@ -836,6 +836,36 @@ fn set_budget_increment_proposal_succeds() {
     });
 }
 
+#[test]
+fn set_councilor_reward_proposal_succeds() {
+    initial_test_ext().execute_with(|| {
+        let member_id = 10;
+        let account_id: [u8; 32] = [member_id; 32];
+        let councilor_reward = 100;
+
+        let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
+            let general_proposal_parameters = GeneralProposalParameters::<Runtime> {
+                member_id: member_id.into(),
+                title: b"title".to_vec(),
+                description: b"body".to_vec(),
+                staking_account_id: Some(account_id.into()),
+                exact_execution_block: None,
+            };
+
+            ProposalCodex::create_proposal(
+                RawOrigin::Signed(account_id.into()).into(),
+                general_proposal_parameters,
+                ProposalDetails::SetCouncilorReward(councilor_reward),
+            )
+        })
+        .with_member_id(member_id as u64);
+
+        codex_extrinsic_test_fixture.call_extrinsic_and_assert();
+
+        assert_eq!(Council::councilor_reward(), councilor_reward);
+    });
+}
+
 #[test]
 fn proposal_reactivation_succeeds() {
     initial_test_ext().execute_with(|| {