Browse Source

council - periodic budget refill

ondratra 4 years ago
parent
commit
fe607e4fb0

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

@@ -228,6 +228,11 @@ pub trait Trait: system::Trait {
     /// Interval for automatic reward payments.
     type ElectedMemberRewardPeriod: Get<Self::BlockNumber>;
 
+    /// Amount that will be added to the budget balance on every refill.
+    type BudgetRefillAmount: Get<Balance<Self>>;
+    /// Interval between automatic budget refills.
+    type BudgetRefillPeriod: Get<Self::BlockNumber>;
+
     /// Checks that the user account is indeed associated with the member.
     fn is_council_member_account(
         membership_id: &Self::MembershipId,
@@ -264,8 +269,11 @@ decl_storage! {
         /// Budget for the council's elected members rewards.
         pub Budget get(fn budget): Balance<T>;
 
-        /// The next block in which the budget will be increased.
+        /// The next block in which the elected council member rewards will be payed.
         pub NextRewardPayments get(fn next_reward_payments): T::BlockNumber;
+
+        /// The next block in which the budget will be increased.
+        pub NextBudgetRefill get(fn next_budget_refill): T::BlockNumber;
     }
 }
 
@@ -388,8 +396,8 @@ decl_module! {
             // council stage progress
             Self::try_progress_stage(now);
 
-            // budget reward payment
-            Self::try_reward_payments(now);
+            // budget reward payment + budget refill
+            Self::try_process_budget(now);
         }
 
         /////////////////// Election-related ///////////////////////////////////
@@ -524,7 +532,17 @@ impl<T: Trait> Module<T> {
     }
 
     /// Checkout elected council members reward payments.
-    fn try_reward_payments(now: T::BlockNumber) {
+    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);
+        }
+
         // council members rewards
         if now == NextRewardPayments::<T>::get() {
             Self::pay_elected_member_rewards(now);
@@ -604,7 +622,7 @@ impl<T: Trait> Module<T> {
 
     /////////////////// Budget-related /////////////////////////////////////
 
-    /// pay rewards to elected council members
+    /// Pay rewards to elected council members.
     fn pay_elected_member_rewards(now: T::BlockNumber) {
         let reward_per_block = T::ElectedMemberRewardPerBlock::get();
         let starting_balance = Budget::<T>::get();
@@ -895,6 +913,21 @@ impl<T: Trait> Mutations<T> {
         Budget::<T>::put(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);
+    }
+
+    // Plan next budget refill.
+    fn plan_budget_refill(now: T::BlockNumber) {
+        let refill_period = T::BudgetRefillPeriod::get();
+
+        NextBudgetRefill::<T>::put(now + refill_period);
+    }
+
     /// Pay reward to a single elected council member.
     fn pay_reward(
         member_index: usize,

+ 10 - 0
runtime-modules/council/src/mock.rs

@@ -58,6 +58,8 @@ parameter_types! {
     pub const ElectedMemberLockId: LockIdentifier = *b"council2";
     pub const ElectedMemberRewardPerBlock: u64 = 100;
     pub const ElectedMemberRewardPeriod: u64 = 10;
+    pub const BudgetRefillAmount: u64 = 1000;
+    pub const BudgetRefillPeriod: u64 = 1000; // intentionally high number that prevents side-effecting tests other than  budget refill tests
 }
 
 impl Trait for Runtime {
@@ -78,6 +80,9 @@ impl Trait for Runtime {
     type ElectedMemberRewardPerBlock = ElectedMemberRewardPerBlock;
     type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
 
+    type BudgetRefillAmount = BudgetRefillAmount;
+    type BudgetRefillPeriod = BudgetRefillPeriod;
+
     fn is_council_member_account(
         membership_id: &Self::MembershipId,
         account_id: &<Self as system::Trait>::AccountId,
@@ -343,6 +348,8 @@ pub struct CouncilSettings<T: Trait> {
     pub idle_stage_duration: T::BlockNumber,
     pub election_duration: T::BlockNumber,
     pub cycle_duration: T::BlockNumber,
+    pub budget_refill_amount: Balance<T>,
+    pub budget_refill_period: T::BlockNumber,
 }
 
 impl<T: Trait> CouncilSettings<T>
@@ -378,6 +385,9 @@ where
                 + announcing_stage_duration
                 + voting_stage_duration
                 + idle_stage_duration,
+
+            budget_refill_amount: <T as Trait>::BudgetRefillAmount::get(),
+            budget_refill_period: <T as Trait>::BudgetRefillPeriod::get(),
         }
     }
 }

+ 35 - 1
runtime-modules/council/src/tests.rs

@@ -1,6 +1,8 @@
 #![cfg(test)]
 
-use super::{CouncilMemberOf, CouncilMembers, CouncilStageAnnouncing, Error, Module, Trait};
+use super::{
+    Budget, CouncilMemberOf, CouncilMembers, CouncilStageAnnouncing, Error, Module, Trait,
+};
 use crate::mock::*;
 use crate::staking_handler::mocks::{CANDIDATE_BASE_ID, VOTER_CANDIDATE_OFFSET};
 use crate::staking_handler::StakingHandler2;
@@ -1142,3 +1144,35 @@ fn council_discard_remaining_rewards_on_depose() {
         }
     });
 }
+
+/// Test that budget is periodicly refilled.
+#[test]
+fn council_budget_auto_refill() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let council_settings = CouncilSettings::<Runtime>::extract_settings();
+        let start_balance = Budget::<Runtime>::get();
+
+        // forward before next refill
+        MockUtils::increase_block_number(council_settings.budget_refill_period - 1);
+
+        assert_eq!(Budget::<Runtime>::get(), start_balance,);
+
+        // forward to next filling
+        MockUtils::increase_block_number(1);
+
+        assert_eq!(
+            Budget::<Runtime>::get(),
+            start_balance + council_settings.budget_refill_amount,
+        );
+
+        // forward to next filling
+        MockUtils::increase_block_number(council_settings.budget_refill_period);
+
+        assert_eq!(
+            Budget::<Runtime>::get(),
+            start_balance + 2 * council_settings.budget_refill_amount,
+        );
+    });
+}