Browse Source

council - budget refill initialization rework

ondratra 4 years ago
parent
commit
223763067e

+ 63 - 19
runtime-modules/council/src/lib.rs

@@ -31,6 +31,7 @@
 //! - [release_candidacy_stake](./struct.Module.html#method.release_candidacy_stake)
 //! - [set_candidacy_note](./struct.Module.html#method.set_candidacy_note)
 //! - [set_budget](./struct.Module.html#method.set_budget)
+//! - [plan_budget_refill](./struct.Module.html#method.plan_budget_refill)
 //!
 //! ## Important functions
 //! These functions have to be called by the runtime for the council to work properly.
@@ -267,13 +268,13 @@ decl_storage! {
         pub AnnouncementPeriodNr get(fn announcement_period_nr) config(): u64;
 
         /// 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.
-        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.
-        pub NextBudgetRefill get(fn next_budget_refill): T::BlockNumber;
+        pub NextBudgetRefill get(fn next_budget_refill) config(): T::BlockNumber;
     }
 }
 
@@ -281,6 +282,7 @@ decl_event! {
     pub enum Event<T>
     where
         Balance = Balance::<T>,
+        <T as system::Trait>::BlockNumber,
         <T as Trait>::MembershipId,
         <T as system::Trait>::AccountId,
     {
@@ -316,6 +318,12 @@ decl_event! {
 
         /// Budget balance was changed by the root.
         BudgetBalanceSet(Balance),
+
+        /// Budget balance was increased by automatic refill.
+        BudgetRefill(Balance),
+
+        /// The next budget refill was planned.
+        BudgetRefillPlanned(BlockNumber),
     }
 }
 
@@ -503,6 +511,25 @@ decl_module! {
 
             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(())
+        }
     }
 }
 
@@ -534,13 +561,8 @@ impl<T: Trait> Module<T> {
     /// Checkout elected council members reward payments.
     fn try_process_budget(now: T::BlockNumber) {
         // 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
@@ -622,6 +644,26 @@ impl<T: Trait> Module<T> {
 
     /////////////////// 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.
     fn pay_elected_member_rewards(now: T::BlockNumber) {
         let reward_per_block = T::ElectedMemberRewardPerBlock::get();
@@ -914,18 +956,13 @@ impl<T: Trait> Mutations<T> {
     }
 
     /// 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.
-    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.
@@ -1133,4 +1170,11 @@ impl<T: Trait> EnsureChecks<T> {
 
         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(())
+    }
 }

+ 32 - 1
runtime-modules/council/src/mock.rs

@@ -4,7 +4,8 @@
 use crate::{
     AnnouncementPeriodNr, Balance, Budget, CandidateOf, Candidates, CouncilMemberOf,
     CouncilMembers, CouncilStage, CouncilStageAnnouncing, CouncilStageElection, CouncilStageUpdate,
-    CouncilStageUpdateOf, Error, GenesisConfig, Module, ReferendumConnection, Stage, Trait,
+    CouncilStageUpdateOf, Error, GenesisConfig, Module, NextBudgetRefill, ReferendumConnection,
+    Stage, Trait,
 };
 
 use balances;
@@ -437,6 +438,9 @@ pub fn default_genesis_config() -> GenesisConfig<Runtime> {
         council_members: vec![],
         candidates: vec![],
         announcement_period_nr: 0,
+        budget: 0,
+        next_reward_payments: 0,
+        next_budget_refill: <Runtime as Trait>::BudgetRefillPeriod::get(),
     }
 }
 
@@ -675,6 +679,11 @@ where
         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(
         origin: OriginType<T::AccountId>,
         membership_id: T::MembershipId,
@@ -772,6 +781,28 @@ where
         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
     pub fn simulate_council_cycle(params: CouncilCycleParams<T>) {
         let settings = params.council_settings;

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

@@ -999,6 +999,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]
 fn council_rewards_are_paid() {