Переглянути джерело

Restore commented code in fill_worker_opening()

Shamil Gadelshin 4 роки тому
батько
коміт
96d6cf4e1f

+ 1 - 0
Cargo.lock

@@ -4479,6 +4479,7 @@ dependencies = [
  "substrate-hiring-module",
  "substrate-membership-module",
  "substrate-primitives",
+ "substrate-recurring-reward-module",
  "substrate-stake-module",
  "substrate-token-mint-module",
 ]

+ 6 - 0
runtime-modules/bureaucracy/Cargo.toml

@@ -17,6 +17,7 @@ std = [
     'stake/std',
     'membership/std',
     'minting/std',
+    'recurringrewards/std',
 ]
 
 [dependencies.primitives]
@@ -80,6 +81,11 @@ default_features = false
 package = 'substrate-token-mint-module'
 path = '../token-minting'
 
+[dependencies.recurringrewards]
+default_features = false
+package = 'substrate-recurring-reward-module'
+path = '../recurring-reward'
+
 [dev-dependencies.runtime-io]
 default_features = false
 git = 'https://github.com/paritytech/substrate.git'

+ 4 - 0
runtime-modules/bureaucracy/src/errors.rs

@@ -24,6 +24,10 @@ pub mod bureaucracy_errors {
     pub static MSG_WORKER_APPLICATION_DOES_NOT_EXIST: &str = "Worker application does not exist";
     pub static MSG_SUCCESSFUL_WORKER_APPLICATION_DOES_NOT_EXIST: &str =
         "Successful worker application does not exist";
+    pub static MSG_FILL_WORKER_OPENING_INVALID_NEXT_PAYMENT_BLOCK: &str =
+        "Reward policy has invalid next payment block number";
+    pub static MSG_FILL_WORKER_OPENING_MINT_DOES_NOT_EXIST: &str =
+        "Working group mint does not exist";
 }
 /*
  * The errors below, while in many cases encoding similar outcomes,

+ 66 - 80
runtime-modules/bureaucracy/src/lib.rs

@@ -21,11 +21,14 @@ use constraints::InputValidationLengthConstraint;
 use errors::bureaucracy_errors::*;
 use errors::WrappedError;
 use types::{
-    Lead, OpeningPolicyCommitment, Worker, WorkerApplication, WorkerOpening, WorkerRoleStakeProfile,
+    Lead, OpeningPolicyCommitment, RewardPolicy, Worker, WorkerApplication, WorkerOpening,
+    WorkerRoleStage, WorkerRoleStakeProfile,
 };
 
 //TODO: docs
 //TODO: migrate to decl_error
+//TODO: 'roles' extrinsics
+//TODO: initialize a mint!
 
 /// Alias for the _Lead_ type
 pub type LeadOf<T> =
@@ -99,18 +102,23 @@ type WorkerApplicationInfo<T> = (
     >,
 );
 
+// Type simplification
 type WorkerOf<T> = Worker<
     <T as system::Trait>::AccountId,
-    //    T::RewardRelationshipId,
-    //    T::StakeId,
-    //    <T as system::Trait>::BlockNumber,
-    //    LeadId<T>,
-    //    WorkerApplicationId<T>,
-    //    PrincipalId<T>,
+    <T as recurringrewards::Trait>::RewardRelationshipId,
+    <T as stake::Trait>::StakeId,
+    <T as system::Trait>::BlockNumber,
 >;
 
 /// The bureaucracy main _Trait_
-pub trait Trait<I: Instance>: system::Trait + membership::members::Trait + hiring::Trait {
+pub trait Trait<I: Instance>:
+    system::Trait
+    + membership::members::Trait
+    + hiring::Trait
+    + minting::Trait
+    + stake::Trait
+    + recurringrewards::Trait
+{
     /// Engine event type.
     type Event: From<Event<Self, I>> + Into<<Self as system::Trait>::Event>;
 }
@@ -165,6 +173,9 @@ decl_event!(
 
 decl_storage! {
     trait Store for Module<T: Trait<I>, I: Instance> as Bureaucracy {
+        /// The mint currently funding the rewards for this module.
+        pub Mint get(mint) : <T as minting::Trait>::MintId;
+
         /// The current lead.
         pub CurrentLead get(current_lead) : Option<LeadOf<T>>;
 
@@ -469,7 +480,7 @@ decl_module! {
             origin,
             worker_opening_id: WorkerOpeningId<T>,
             successful_worker_application_ids: WorkerApplicationIdSet<T>,
-//            reward_policy: Option<RewardPolicy<minting::BalanceOf<T>, T::BlockNumber>>
+            reward_policy: Option<RewardPolicy<minting::BalanceOf<T>, T::BlockNumber>>
         ) {
             // Ensure lead is set and is origin signer
             Self::ensure_origin_is_set_lead(origin)?;
@@ -515,70 +526,60 @@ decl_module! {
                 )
             )?;
 
-            // TODO: should we implement this?
-            // let create_reward_settings = if let Some(policy) = reward_policy {
-            //     // A reward will need to be created so ensure our configured mint exists
-            //     let mint_id = Self::mint();
-            //
-            //     ensure!(<minting::Mints<T>>::exists(mint_id), MSG_FILL_WORKER_OPENING_MINT_DOES_NOT_EXIST);
-            //
-            //     // Make sure valid parameters are selected for next payment at block number
-            //     ensure!(policy.next_payment_at_block > <system::Module<T>>::block_number(), MSG_FILL_WORKER_OPENING_INVALID_NEXT_PAYMENT_BLOCK);
-            //
-            //     // The verified reward settings to use
-            //     Some((mint_id, policy))
-            // } else {
-            //     None
-            // };
-
-            //
-            // == MUTATION SAFE ==
-            //
-
-            let _current_block = <system::Module<T>>::block_number();
-
-            // For each successful application
-            // - create and hold on to worker
-            // - register role with membership module
+            let create_reward_settings = if let Some(policy) = reward_policy {
+                // A reward will need to be created so ensure our configured mint exists
+                let mint_id = Self::mint();
+
+                ensure!(<minting::Mints<T>>::exists(mint_id), MSG_FILL_WORKER_OPENING_MINT_DOES_NOT_EXIST);
+
+                // Make sure valid parameters are selected for next payment at block number
+                ensure!(policy.next_payment_at_block > <system::Module<T>>::block_number(), MSG_FILL_WORKER_OPENING_INVALID_NEXT_PAYMENT_BLOCK);
+
+                // The verified reward settings to use
+                Some((mint_id, policy))
+            } else {
+                None
+            };
+
+            // mutation
 
             let mut worker_application_id_to_worker_id = BTreeMap::new();
 
             successful_iter
             .clone()
             .for_each(|(successful_worker_application, id, _)| {
-                // TODO: should we implement this?
-                // // Create a reward relationship
-                // let reward_relationship = if let Some((mint_id, checked_policy)) = create_reward_settings.clone() {
-                //
-                //     // Create a new recipient for the new relationship
-                //     let recipient = <recurringrewards::Module<T>>::add_recipient();
-                //
-                //     // member must exist, since it was checked that it can enter the role
-                //     let member_profile = <members::Module<T>>::member_profile(successful_worker_application.member_id).unwrap();
-                //
-                //     // rewards are deposited in the member's root account
-                //     let reward_destination_account = member_profile.root_account;
-                //
-                //     // values have been checked so this should not fail!
-                //     let relationship_id = <recurringrewards::Module<T>>::add_reward_relationship(
-                //         mint_id,
-                //         recipient,
-                //         reward_destination_account,
-                //         checked_policy.amount_per_payout,
-                //         checked_policy.next_payment_at_block,
-                //         checked_policy.payout_interval,
-                //     ).expect("Failed to create reward relationship!");
-                //
-                //     Some(relationship_id)
-                // } else {
-                //     None
-                // };
+                // Create a reward relationship
+                let reward_relationship = if let Some((mint_id, checked_policy)) = create_reward_settings.clone() {
+
+                    // Create a new recipient for the new relationship
+                    let recipient = <recurringrewards::Module<T>>::add_recipient();
+
+                    // member must exist, since it was checked that it can enter the role
+                    let member_profile = <membership::members::Module<T>>::member_profile(successful_worker_application.member_id).unwrap();
+
+                    // rewards are deposited in the member's root account
+                    let reward_destination_account = member_profile.root_account;
+
+                    // values have been checked so this should not fail!
+                    let relationship_id = <recurringrewards::Module<T>>::add_reward_relationship(
+                        mint_id,
+                        recipient,
+                        reward_destination_account,
+                        checked_policy.amount_per_payout,
+                        checked_policy.next_payment_at_block,
+                        checked_policy.payout_interval,
+                    ).expect("Failed to create reward relationship!");
+
+                    Some(relationship_id)
+                } else {
+                    None
+                };
 
                 // Get possible stake for role
                 let application = hiring::ApplicationById::<T>::get(successful_worker_application.application_id);
 
                 // Staking profile for worker
-                let _stake_profile =
+                let stake_profile =
                     if let Some(ref stake_id) = application.active_role_staking_id {
 
                         Some(
@@ -595,32 +596,17 @@ decl_module! {
                 // Get worker id
                 let new_worker_id = <NextWorkerId<T, I>>::get();
 
-                // Make and add new principal
- //               let principal_id = Self::add_new_principal(&Principal::Worker(new_worker_id));
-
-                // TODO: should we implement this?
                 // Construct worker
                 let worker = Worker::new(
                     &(successful_worker_application.role_account),
-//                    &reward_relationship,
-//                    &stake_profile,
-//                    &WorkerRoleStage::Active,
-//                    &WorkerInduction::new(&lead_id, &id, &current_block),
-//                    &principal_id
+                   &reward_relationship,
+                   &stake_profile,
+                   &WorkerRoleStage::Active,
                 );
 
                 // Store worker
                 <WorkerById<T, I>>::insert(new_worker_id, worker);
 
-                // TODO: should we implement this?
-                // // Register role on member
-                // let registered_role = members::Module::<T>::register_role_on_member(
-                //     successful_worker_application.member_id,
-                //     &role_types::ActorInRole::new(role_types::Role::Worker, new_worker_id)
-                // ).is_ok();
-
-                //assert!(registered_role);
-
                 // Update next worker id
                 <NextWorkerId<T, I>>::mutate(|id| *id += <WorkerId<T> as One>::one());
 

+ 6 - 0
runtime-modules/bureaucracy/src/tests/mock.rs

@@ -115,6 +115,12 @@ impl balances::Trait for Test {
     type CreationFee = CreationFee;
 }
 
+impl recurringrewards::Trait for Test {
+    type PayoutStatusHandler = ();
+    type RecipientId = u64;
+    type RewardRelationshipId = u64;
+}
+
 pub type Balances = balances::Module<Test>;
 pub type System = system::Module<Test>;
 

+ 11 - 1
runtime-modules/bureaucracy/src/tests/mod.rs

@@ -1,7 +1,10 @@
 mod mock;
 
 use crate::constraints::InputValidationLengthConstraint;
-use crate::types::{Lead, OpeningPolicyCommitment, Worker, WorkerApplication, WorkerOpening};
+use crate::types::{
+    Lead, OpeningPolicyCommitment, RewardPolicy, Worker, WorkerApplication, WorkerOpening,
+    WorkerRoleStage,
+};
 use crate::{Instance1, RawEvent};
 use mock::{build_test_externalities, Balances, Bureaucracy1, Membership, System, TestEvent};
 use srml_support::StorageValue;
@@ -13,6 +16,7 @@ struct FillWorkerOpeningFixture {
     opening_id: u64,
     successful_worker_application_ids: BTreeSet<u64>,
     role_account: u64,
+    reward_policy: Option<RewardPolicy<u64, u64>>,
 }
 
 impl FillWorkerOpeningFixture {
@@ -24,6 +28,7 @@ impl FillWorkerOpeningFixture {
             opening_id,
             successful_worker_application_ids: application_ids,
             role_account: 1,
+            reward_policy: None,
         }
     }
 
@@ -37,6 +42,7 @@ impl FillWorkerOpeningFixture {
             self.origin.clone().into(),
             self.opening_id,
             self.successful_worker_application_ids.clone(),
+            self.reward_policy.clone(),
         );
         assert_eq!(actual_result.clone(), expected_result);
 
@@ -48,6 +54,10 @@ impl FillWorkerOpeningFixture {
 
             let expected_worker = Worker {
                 role_account: self.role_account,
+
+                reward_relationship: None,
+                role_stake_profile: None,
+                stage: WorkerRoleStage::Active,
             };
 
             assert_eq!(actual_worker, expected_worker);

+ 89 - 51
runtime-modules/bureaucracy/src/types.rs

@@ -1,5 +1,8 @@
 use codec::{Decode, Encode};
+use rstd::borrow::ToOwned;
 use rstd::collections::btree_set::BTreeSet;
+use rstd::vec::Vec;
+
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
 
@@ -168,65 +171,100 @@ impl<StakeId: Clone, BlockNumber: Clone> WorkerRoleStakeProfile<StakeId, BlockNu
 /// This role can be staked, have reward and be inducted through the hiring module.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
-pub struct Worker<
-    AccountId,
-    //    RewardRelationshipId,
-    //    StakeId,
-    //    BlockNumber,
-    //    LeadId,
-    //    WorkerApplicationId,
-    //    PrincipalId,
-> {
+pub struct Worker<AccountId, RewardRelationshipId, StakeId, BlockNumber> {
     /// Account used to authenticate in this role,
     pub role_account: AccountId,
-    // /// Whether the role has recurring reward, and if so an identifier for this.
-    // pub reward_relationship: Option<RewardRelationshipId>,
-    // /// When set, describes role stake of worker.
-    // pub role_stake_profile: Option<WorkerRoleStakeProfile<StakeId, BlockNumber>>,
-    // /// The stage of this worker in the working group.
-    // pub stage: WorkerRoleStage<BlockNumber>,
-    //
-    // /// How the worker was inducted into the working group.
-    // pub induction: WorkerInduction<LeadId, WorkerApplicationId, BlockNumber>,
-    //
-    // /// Permissions module principal id
-    // pub principal_id: PrincipalId,
-}
-
-impl<
-        AccountId: Clone,
-        //    RewardRelationshipId: Clone,
-        //        StakeId: Clone,
-        //        BlockNumber: Clone,
-        //    LeadId: Clone,
-        //    ApplicationId: Clone,
-        //    PrincipalId: Clone,
-    >
-    Worker<
-        AccountId,
-        //    RewardRelationshipId,
-        //        StakeId,
-        //        BlockNumber,
-        //    LeadId,
-        //    ApplicationId,
-        //    PrincipalId,
-    >
+    /// Whether the role has recurring reward, and if so an identifier for this.
+    pub reward_relationship: Option<RewardRelationshipId>,
+    /// When set, describes role stake of worker.
+    pub role_stake_profile: Option<WorkerRoleStakeProfile<StakeId, BlockNumber>>,
+    /// The stage of this worker in the working group.
+    pub stage: WorkerRoleStage<BlockNumber>,
+}
+
+impl<AccountId: Clone, RewardRelationshipId: Clone, StakeId: Clone, BlockNumber: Clone>
+    Worker<AccountId, RewardRelationshipId, StakeId, BlockNumber>
 {
     pub fn new(
         role_account: &AccountId,
-        //        reward_relationship: &Option<RewardRelationshipId>,
-        //        role_stake_profile: &Option<WorkerRoleStakeProfile<StakeId, BlockNumber>>,
-        //        stage: &WorkerRoleStage<BlockNumber>,
-        //        induction: &WorkerInduction<LeadId, ApplicationId, BlockNumber>,
-        //        principal_id: &PrincipalId,
+        reward_relationship: &Option<RewardRelationshipId>,
+        role_stake_profile: &Option<WorkerRoleStakeProfile<StakeId, BlockNumber>>,
+        stage: &WorkerRoleStage<BlockNumber>,
     ) -> Self {
         Worker {
             role_account: (*role_account).clone(),
-            //            reward_relationship: (*reward_relationship).clone(),
-            //            role_stake_profile: (*role_stake_profile).clone(),
-            //            stage: (*stage).clone(),
-            //            induction: (*induction).clone(),
-            //            principal_id: (*principal_id).clone(),
+            reward_relationship: (*reward_relationship).clone(),
+            role_stake_profile: (*role_stake_profile).clone(),
+            stage: (*stage).clone(),
         }
     }
 }
+
+// The stage of the involvement of a curator in the working group.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Debug, Clone, PartialEq)]
+pub enum WorkerRoleStage<BlockNumber> {
+    /// Currently active.
+    Active,
+
+    /// Currently unstaking
+    Unstaking(CuratorExitSummary<BlockNumber>),
+
+    /// No longer active and unstaked
+    Exited(CuratorExitSummary<BlockNumber>),
+}
+
+/// Must be default constructible because it indirectly is a value in a storage map.
+/// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
+impl<BlockNumber> Default for WorkerRoleStage<BlockNumber> {
+    fn default() -> Self {
+        WorkerRoleStage::Active
+    }
+}
+
+/// The exit stage of a curators involvement in the working group.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Debug, Clone, PartialEq)]
+pub struct CuratorExitSummary<BlockNumber> {
+    /// Origin for exit.
+    pub origin: CuratorExitInitiationOrigin,
+
+    /// When exit was initiated.
+    pub initiated_at_block_number: BlockNumber,
+
+    /// Explainer for why exit was initited.
+    pub rationale_text: Vec<u8>,
+}
+
+impl<BlockNumber: Clone> CuratorExitSummary<BlockNumber> {
+    pub fn new(
+        origin: &CuratorExitInitiationOrigin,
+        initiated_at_block_number: &BlockNumber,
+        rationale_text: &[u8],
+    ) -> Self {
+        CuratorExitSummary {
+            origin: (*origin).clone(),
+            initiated_at_block_number: (*initiated_at_block_number).clone(),
+            rationale_text: rationale_text.to_owned(),
+        }
+    }
+}
+
+/// Origin of exit initiation on behalf of a curator.'
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Debug, Clone, PartialEq)]
+pub enum CuratorExitInitiationOrigin {
+    /// Lead is origin.
+    Lead,
+
+    /// The curator exiting is the origin.
+    Curator,
+}
+
+/// The recurring reward if any to be assigned to an actor when filling in the position.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct RewardPolicy<Balance, BlockNumber> {
+    pub amount_per_payout: Balance,
+    pub next_payment_at_block: BlockNumber,
+    pub payout_interval: Option<BlockNumber>,
+}