Browse Source

runtime: working-group: add opening to application and require stake

conectado 4 years ago
parent
commit
3f254a2a8a

+ 26 - 112
runtime-modules/working-group/src/benchmarking.rs

@@ -18,11 +18,6 @@ use membership::Module as Membership;
 const SEED: u32 = 0;
 const MAX_BYTES: u32 = 16384;
 
-pub enum StakingRole {
-    WithStakes,
-    WithoutStakes,
-}
-
 fn assert_last_event<T: Trait<I>, I: Instance>(generic_event: <T as Trait<I>>::Event) {
     let events = System::<T>::events();
     let system_event: <T as frame_system::Trait>::Event = generic_event.into();
@@ -38,15 +33,11 @@ fn get_byte(num: u32, byte_number: u8) -> u8 {
 fn add_opening_helper<T: Trait<I>, I: Instance>(
     id: u32,
     add_opening_origin: &T::Origin,
-    staking_role: &StakingRole,
     job_opening_type: &OpeningType,
 ) -> OpeningId {
-    let staking_policy = match staking_role {
-        StakingRole::WithStakes => Some(StakePolicy {
-            stake_amount: One::one(),
-            leaving_unstaking_period: T::MinUnstakingPeriodLimit::get() + One::one(),
-        }),
-        StakingRole::WithoutStakes => None,
+    let staking_policy = StakePolicy {
+        stake_amount: T::MinimumStakeForOpening::get(),
+        leaving_unstaking_period: T::MinUnstakingPeriodLimit::get() + One::one(),
     };
 
     WorkingGroup::<T, _>::add_opening(
@@ -70,18 +61,14 @@ fn add_opening_helper<T: Trait<I>, I: Instance>(
 
 fn apply_on_opening_helper<T: Trait<I>, I: Instance>(
     id: u32,
-    staking_role: &StakingRole,
     applicant_id: &T::AccountId,
     member_id: &T::MemberId,
     opening_id: &OpeningId,
 ) -> ApplicationId {
-    let stake_parameters = match staking_role {
-        StakingRole::WithStakes => Some(StakeParameters {
-            // Due to mock implementation of StakingHandler we can't go over 1000
-            stake: min(BalanceOf::<T>::max_value(), BalanceOf::<T>::from(1000)),
-            staking_account_id: applicant_id.clone(),
-        }),
-        StakingRole::WithoutStakes => None,
+    let stake_parameters = StakeParameters {
+        // Due to mock implementation of StakingHandler we can't go over 1000
+        stake: min(BalanceOf::<T>::max_value(), BalanceOf::<T>::from(1000)),
+        staking_account_id: applicant_id.clone(),
     };
 
     WorkingGroup::<T, _>::apply_on_opening(
@@ -110,11 +97,9 @@ fn apply_on_opening_helper<T: Trait<I>, I: Instance>(
 fn add_opening_and_apply_with_multiple_ids<T: Trait<I> + membership::Trait, I: Instance>(
     ids: &Vec<u32>,
     add_opening_origin: &T::Origin,
-    staking_role: &StakingRole,
     job_opening_type: &OpeningType,
 ) -> (OpeningId, BTreeSet<ApplicationId>, Vec<T::AccountId>) {
-    let opening_id =
-        add_opening_helper::<T, I>(1, add_opening_origin, &staking_role, job_opening_type);
+    let opening_id = add_opening_helper::<T, I>(1, add_opening_origin, job_opening_type);
 
     let mut successful_application_ids = BTreeSet::new();
 
@@ -124,7 +109,6 @@ fn add_opening_and_apply_with_multiple_ids<T: Trait<I> + membership::Trait, I: I
             member_funded_account::<T, I>("member", *id);
         let application_id = apply_on_opening_helper::<T, I>(
             *id,
-            &staking_role,
             &applicant_account_id,
             &applicant_member_id,
             &opening_id,
@@ -140,16 +124,13 @@ fn add_opening_and_apply_with_multiple_ids<T: Trait<I> + membership::Trait, I: I
 fn add_and_apply_opening<T: Trait<I>, I: Instance>(
     id: u32,
     add_opening_origin: &T::Origin,
-    staking_role: &StakingRole,
     applicant_id: &T::AccountId,
     member_id: &T::MemberId,
     job_opening_type: &OpeningType,
 ) -> (OpeningId, ApplicationId) {
-    let opening_id =
-        add_opening_helper::<T, I>(id, add_opening_origin, staking_role, job_opening_type);
+    let opening_id = add_opening_helper::<T, I>(id, add_opening_origin, job_opening_type);
 
-    let application_id =
-        apply_on_opening_helper::<T, I>(id, staking_role, applicant_id, member_id, &opening_id);
+    let application_id = apply_on_opening_helper::<T, I>(id, applicant_id, member_id, &opening_id);
 
     (opening_id, application_id)
 }
@@ -220,7 +201,6 @@ fn force_missed_reward<T: Trait<I>, I: Instance>() {
 }
 
 pub fn insert_a_worker<T: Trait<I> + membership::Trait, I: Instance>(
-    staking_role: StakingRole,
     job_opening_type: OpeningType,
     id: u32,
     lead_id: Option<T::AccountId>,
@@ -230,20 +210,12 @@ where
 {
     let (caller_id, member_id) = member_funded_account::<T, I>("member", id);
 
-    let worker_id = complete_opening::<T, I>(
-        staking_role,
-        job_opening_type,
-        id,
-        lead_id,
-        &caller_id,
-        member_id,
-    );
+    let worker_id = complete_opening::<T, I>(job_opening_type, id, lead_id, &caller_id, member_id);
 
     (caller_id, worker_id)
 }
 
 pub fn complete_opening<T: Trait<I> + membership::Trait, I: Instance>(
-    staking_role: StakingRole,
     job_opening_type: OpeningType,
     id: u32,
     lead_id: Option<T::AccountId>,
@@ -258,7 +230,6 @@ pub fn complete_opening<T: Trait<I> + membership::Trait, I: Instance>(
     let (opening_id, application_id) = add_and_apply_opening::<T, I>(
         id,
         &T::Origin::from(add_worker_origin.clone()),
-        &staking_role,
         caller_id,
         &member_id,
         &job_opening_type,
@@ -295,7 +266,6 @@ benchmarks_instance! {
         let i in 2 .. T::MaxWorkerNumberLimit::get();
 
         let (lead_id, lead_worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Leader,
             0,
             None
@@ -305,7 +275,6 @@ benchmarks_instance! {
             add_opening_and_apply_with_multiple_ids::<T, I>(
                 &(1..i).collect(),
                 &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-                &StakingRole::WithStakes,
                 &OpeningType::Regular
             );
 
@@ -382,7 +351,6 @@ benchmarks_instance! {
         let i in 2 .. T::MaxWorkerNumberLimit::get();
 
         let (lead_id, _) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Leader,
             0,
             None
@@ -392,7 +360,6 @@ benchmarks_instance! {
             add_opening_and_apply_with_multiple_ids::<T, I>(
                 &(1..i).collect(),
                 &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-                &StakingRole::WithStakes,
                 &OpeningType::Regular
             );
 
@@ -444,7 +411,6 @@ benchmarks_instance! {
         let i in 2 .. T::MaxWorkerNumberLimit::get();
 
         let (lead_id, _) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Leader,
             0,
             None
@@ -454,7 +420,6 @@ benchmarks_instance! {
             add_opening_and_apply_with_multiple_ids::<T, I>(
                 &(1..i).collect(),
                 &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-                &StakingRole::WithStakes,
                 &OpeningType::Regular
             );
 
@@ -495,7 +460,6 @@ benchmarks_instance! {
         let i in 2 .. T::MaxWorkerNumberLimit::get();
 
         let (lead_id, _) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Leader,
             0,
             None
@@ -505,7 +469,6 @@ benchmarks_instance! {
             add_opening_and_apply_with_multiple_ids::<T, I>(
                 &(1..i).collect(),
                 &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-                &StakingRole::WithStakes,
                 &OpeningType::Regular
             );
 
@@ -553,7 +516,6 @@ benchmarks_instance! {
         let opening_id = add_opening_helper::<T, I>(
             0,
             &T::Origin::from(RawOrigin::Root),
-            &StakingRole::WithStakes,
             &OpeningType::Leader
         );
 
@@ -563,14 +525,11 @@ benchmarks_instance! {
             role_account_id: lead_account_id.clone(),
             reward_account_id: lead_account_id.clone(),
             description: vec![0u8; i.try_into().unwrap()],
-            stake_parameters: Some(
-                // Make sure to keep consistency with the StakePolicy in add_opening_helper
-                // (we are safe as long as we are using max_value for stake)
+            stake_parameters:
                 StakeParameters {
-                    stake: One::one(),
+                    stake: T::MinimumStakeForOpening::get(),
                     staking_account_id: lead_account_id.clone(),
                 }
-            ),
         };
 
     }: _ (RawOrigin::Signed(lead_account_id.clone()), apply_on_opening_params.clone())
@@ -590,7 +549,6 @@ benchmarks_instance! {
         let (opening_id, application_id) = add_and_apply_opening::<T, I>(
             0,
             &RawOrigin::Root.into(),
-            &StakingRole::WithoutStakes,
             &lead_account_id,
             &lead_member_id,
             &OpeningType::Leader
@@ -624,7 +582,6 @@ benchmarks_instance! {
     fill_opening_worker {
         let i in 1 .. T::MaxWorkerNumberLimit::get() - 1;
         let (lead_id, lead_worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithoutStakes,
             OpeningType::Leader,
             0,
             None
@@ -634,7 +591,6 @@ benchmarks_instance! {
             add_opening_and_apply_with_multiple_ids::<T, I>(
                 &(1..i+1).collect(),
                 &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-                &StakingRole::WithoutStakes,
                 &OpeningType::Regular
             );
     }: fill_opening(
@@ -665,7 +621,7 @@ benchmarks_instance! {
 
     update_role_account{
         let (lead_id, lead_worker_id) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let new_account_id = account::<T::AccountId>("new_lead_account", 1, SEED);
     }: _ (RawOrigin::Signed(lead_id), lead_worker_id, new_account_id.clone())
     verify {
@@ -682,11 +638,10 @@ benchmarks_instance! {
 
     cancel_opening {
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let opening_id = add_opening_helper::<T, I>(
             1,
             &T::Origin::from(RawOrigin::Signed(lead_id.clone())),
-            &StakingRole::WithoutStakes,
             &OpeningType::Regular
         );
 
@@ -701,7 +656,6 @@ benchmarks_instance! {
         let (caller_id, member_id) = member_funded_account::<T, I>("lead", 0);
         let (_, application_id) = add_and_apply_opening::<T, I>(0,
             &RawOrigin::Root.into(),
-            &StakingRole::WithStakes,
             &caller_id,
             &member_id,
             &OpeningType::Leader
@@ -719,9 +673,8 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
 
         let (lead_id, lead_worker_id) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let (caller_id, worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Regular,
             1,
             Some(lead_id.clone())
@@ -748,9 +701,8 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
 
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let (caller_id, worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Regular,
             1,
             Some(lead_id.clone())
@@ -775,7 +727,7 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
 
         let (_, lead_worker_id) =
-            insert_a_worker::<T, I>(StakingRole::WithStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let current_budget = BalanceOf::<T>::max_value();
         // To be able to pay unpaid reward
         WorkingGroup::<T, _>::set_budget(RawOrigin::Root.into(), current_budget).unwrap();
@@ -798,9 +750,8 @@ benchmarks_instance! {
     // require access to the storage whilist that's not the case with a lead opening
     increase_stake {
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let (caller_id, worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Regular,
             1,
             Some(lead_id.clone())
@@ -819,9 +770,8 @@ benchmarks_instance! {
     // require access to the storage whilist that's not the case with a lead opening
     decrease_stake {
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let (_, worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Regular,
             1,
             Some(lead_id.clone())
@@ -836,7 +786,6 @@ benchmarks_instance! {
 
     spend_from_budget {
         let (lead_id, _) = insert_a_worker::<T, I>(
-            StakingRole::WithoutStakes,
             OpeningType::Leader,
             0,
             None
@@ -854,9 +803,8 @@ benchmarks_instance! {
     // require access to the storage whilist that's not the case with a lead opening
     update_reward_amount {
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let (_, worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithoutStakes,
             OpeningType::Regular,
             1,
             Some(lead_id.clone())
@@ -880,7 +828,7 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
 
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let status_text = Some(vec![0u8; i.try_into().unwrap()]);
 
     }: _ (RawOrigin::Signed(lead_id), status_text.clone())
@@ -900,7 +848,7 @@ benchmarks_instance! {
 
     update_reward_account {
         let (caller_id, worker_id) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
         let new_id = account::<T::AccountId>("new_id", 1, 0);
 
     }: _ (RawOrigin::Signed(caller_id), worker_id, new_id.clone())
@@ -929,7 +877,7 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
 
         let (lead_id, _) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
 
         let stake_policy = StakePolicy {
             stake_amount: BalanceOf::<T>::max_value(),
@@ -942,7 +890,7 @@ benchmarks_instance! {
             RawOrigin::Signed(lead_id),
             description.clone(),
             OpeningType::Regular,
-            Some(stake_policy.clone()),
+            stake_policy.clone(),
             Some(BalanceOf::<T>::max_value())
         )
     verify {
@@ -951,38 +899,12 @@ benchmarks_instance! {
                 1,
                 description,
                 OpeningType::Regular,
-                Some(stake_policy),
+                stake_policy,
                 Some(BalanceOf::<T>::max_value())
             ).into()
         );
     }
 
-    // This is always worse than leave_role_immediatly
-    leave_role_immediatly {
-        let i in 0 .. MAX_BYTES;
-        // Worst case scenario there is a lead(this requires **always** more steps)
-        // could separate into new branch to tighten weight
-        // Also, workers without stake can leave immediatly
-        let (caller_id, lead_worker_id) =
-            insert_a_worker::<T, I>(StakingRole::WithoutStakes, OpeningType::Leader, 0, None);
-
-        // To be able to pay unpaid reward
-        WorkingGroup::<T, _>::set_budget(
-            RawOrigin::Root.into(),
-            BalanceOf::<T>::max_value()
-        ).unwrap();
-        let rationale = Some(vec![0u8; i.try_into().unwrap()]);
-
-    }: leave_role(
-            RawOrigin::Signed(caller_id),
-            lead_worker_id,
-            rationale.clone()
-        )
-    verify {
-        assert!(!WorkerById::<T, I>::contains_key(lead_worker_id), "Worker hasn't left");
-        assert_last_event::<T, I>(RawEvent::WorkerLeft(lead_worker_id, rationale).into());
-    }
-
     // Generally speaking this seems to be always the best case scenario
     // but since it's so obviously a different branch I think it's a good idea
     // to leave this branch and use tha max between these 2
@@ -990,7 +912,6 @@ benchmarks_instance! {
         let i in 0 .. MAX_BYTES;
         // Workers with stake can't leave immediatly
         let (caller_id, caller_worker_id) = insert_a_worker::<T, I>(
-            StakingRole::WithStakes,
             OpeningType::Leader,
             0,
             None
@@ -1022,13 +943,6 @@ mod tests {
         });
     }
 
-    #[test]
-    fn test_leave_role_immediatly() {
-        build_test_externalities().execute_with(|| {
-            assert_ok!(test_benchmark_leave_role_immediatly::<Test>());
-        });
-    }
-
     #[test]
     fn test_add_opening() {
         build_test_externalities().execute_with(|| {

+ 15 - 24
runtime-modules/working-group/src/checks.rs

@@ -34,7 +34,7 @@ pub(crate) fn ensure_origin_for_opening_type<T: Trait<I>, I: Instance>(
 
 // Check opening: returns the opening by id if it is exists.
 pub(crate) fn ensure_opening_exists<T: Trait<I>, I: Instance>(
-    opening_id: &OpeningId,
+    opening_id: OpeningId,
 ) -> Result<Opening<T::BlockNumber, BalanceOf<T>>, Error<T, I>> {
     ensure!(
         <crate::OpeningById::<T, I>>::contains_key(opening_id),
@@ -188,19 +188,17 @@ pub(crate) fn ensure_origin_for_worker_operation<T: Trait<I>, I: Instance>(
 
 // Check opening: verifies stake policy for the opening.
 pub(crate) fn ensure_valid_stake_policy<T: Trait<I>, I: Instance>(
-    stake_policy: &Option<StakePolicy<T::BlockNumber, BalanceOf<T>>>,
+    stake_policy: &StakePolicy<T::BlockNumber, BalanceOf<T>>,
 ) -> Result<(), DispatchError> {
-    if let Some(stake_policy) = stake_policy {
-        ensure!(
-            stake_policy.stake_amount != Zero::zero(),
-            Error::<T, I>::CannotStakeZero
-        );
+    ensure!(
+        stake_policy.stake_amount >= T::MinimumStakeForOpening::get(),
+        Error::<T, I>::BelowMinimumStakes
+    );
 
-        ensure!(
-            stake_policy.leaving_unstaking_period > T::MinUnstakingPeriodLimit::get(),
-            Error::<T, I>::UnstakingPeriodLessThanMinimum
-        );
-    }
+    ensure!(
+        stake_policy.leaving_unstaking_period > T::MinUnstakingPeriodLimit::get(),
+        Error::<T, I>::UnstakingPeriodLessThanMinimum
+    );
 
     Ok(())
 }
@@ -222,19 +220,12 @@ pub(crate) fn ensure_valid_reward_per_block<T: Trait<I>, I: Instance>(
 // Check application: verifies that proposed stake is enough for the opening.
 pub(crate) fn ensure_application_stake_match_opening<T: Trait<I>, I: Instance>(
     opening: &Opening<T::BlockNumber, BalanceOf<T>>,
-    stake_parameters: &Option<StakeParameters<T::AccountId, BalanceOf<T>>>,
+    stake_parameters: &StakeParameters<T::AccountId, BalanceOf<T>>,
 ) -> DispatchResult {
-    let opening_stake_balance = opening
-        .stake_policy
-        .clone()
-        .unwrap_or_default()
-        .stake_amount;
-
-    let application_stake_balance = stake_parameters.clone().unwrap_or_default().stake;
-
-    if application_stake_balance < opening_stake_balance {
-        return Err(Error::<T, I>::ApplicationStakeDoesntMatchOpening.into());
-    }
+    ensure!(
+        opening.stake_policy.stake_amount <= stake_parameters.stake,
+        Error::<T, I>::ApplicationStakeDoesntMatchOpening
+    );
 
     Ok(())
 }

+ 5 - 5
runtime-modules/working-group/src/errors.rs

@@ -42,8 +42,8 @@ decl_error! {
         /// Signer is not worker role account.
         SignerIsNotWorkerRoleAccount,
 
-        /// Cannot stake zero.
-        CannotStakeZero,
+        /// Staking less than the lower bound.
+        BelowMinimumStakes,
 
         /// Insufficient balance to cover stake.
         InsufficientBalanceToCoverStake,
@@ -72,9 +72,6 @@ decl_error! {
         /// Specified unstaking period is less then minimum set for the group.
         UnstakingPeriodLessThanMinimum,
 
-        /// Requested operation with stake is impossible because of stake was not defined for the role.
-        CannotChangeStakeWithoutStakingAccount,
-
         /// Invalid spending amount.
         CannotSpendZero,
 
@@ -86,5 +83,8 @@ decl_error! {
 
         /// Cannot decrease stake - stake delta greater than initial stake.
         CannotDecreaseStakeDeltaGreaterThanStake,
+
+        /// Trying to fill opening with an application for other opening
+        ApplicationsNotForOpening,
     }
 }

+ 80 - 104
runtime-modules/working-group/src/lib.rs

@@ -118,6 +118,9 @@ pub trait Trait<I: Instance = DefaultInstance>:
 
     /// Weight information for extrinsics in this pallet.
     type WeightInfo: WeightInfo;
+
+    /// Minimum stake required for an opening
+    type MinimumStakeForOpening: Get<Self::Balance>;
 }
 
 decl_event!(
@@ -141,7 +144,7 @@ decl_event!(
         /// - Opening Type(Lead or Worker)
         /// - Stake Policy for the opening
         /// - Reward per block
-        OpeningAdded(OpeningId, Vec<u8>, OpeningType, Option<StakePolicy>, Option<Balance>),
+        OpeningAdded(OpeningId, Vec<u8>, OpeningType, StakePolicy, Option<Balance>),
 
         /// Emits on adding the application for the worker opening.
         /// Params:
@@ -358,7 +361,7 @@ decl_module! {
             origin,
             description: Vec<u8>,
             opening_type: OpeningType,
-            stake_policy: Option<StakePolicy<T::BlockNumber, BalanceOf<T>>>,
+            stake_policy: StakePolicy<T::BlockNumber, BalanceOf<T>>,
             reward_per_block: Option<BalanceOf<T>>
         ){
             checks::ensure_origin_for_opening_type::<T, I>(origin, opening_type)?;
@@ -414,39 +417,38 @@ decl_module! {
             T::MemberOriginValidator::ensure_member_controller_account_origin(origin, p.member_id)?;
 
             // Ensure job opening exists.
-            let opening = checks::ensure_opening_exists::<T, I>(&p.opening_id)?;
+            let opening = checks::ensure_opening_exists::<T, I>(p.opening_id)?;
 
             // Ensure that proposed stake is enough for the opening.
             checks::ensure_application_stake_match_opening::<T, I>(&opening, &p.stake_parameters)?;
 
             // Checks external conditions for staking.
-            if let Some(sp) = p.stake_parameters.clone() {
-                ensure!(
-                    T::StakingAccountValidator::is_member_staking_account(
-                        &p.member_id,
-                        &sp.staking_account_id
-                    ),
-                    Error::<T, I>::InvalidStakingAccountForMember
-                );
+            ensure!(
+                  T::StakingAccountValidator::is_member_staking_account(
+                      &p.member_id,
+                      &p.stake_parameters.staking_account_id
+                  ),
+                  Error::<T, I>::InvalidStakingAccountForMember
+            );
 
-                ensure!(
-                    T::StakingHandler::is_account_free_of_conflicting_stakes(&sp.staking_account_id),
-                    Error::<T, I>::ConflictStakesOnAccount
-                );
+              ensure!(
+                  T::StakingHandler::is_account_free_of_conflicting_stakes(&p.stake_parameters.staking_account_id),
+                  Error::<T, I>::ConflictStakesOnAccount
+              );
 
-                ensure!(
-                    T::StakingHandler::is_enough_balance_for_stake(&sp.staking_account_id, sp.stake),
-                    Error::<T, I>::InsufficientBalanceToCoverStake
-                );
-            }
+              ensure!(
+                  T::StakingHandler::is_enough_balance_for_stake(
+                    &p.stake_parameters.staking_account_id,
+                    p.stake_parameters.stake
+                  ),
+                  Error::<T, I>::InsufficientBalanceToCoverStake
+              );
 
             //
             // == MUTATION SAFE ==
             //
 
-            if let Some(sp) = p.stake_parameters.clone() {
-                T::StakingHandler::lock(&sp.staking_account_id, sp.stake);
-            }
+            T::StakingHandler::lock(&p.stake_parameters.staking_account_id, p.stake_parameters.stake);
 
             let hashed_description = T::Hashing::hash(&p.description);
 
@@ -454,8 +456,9 @@ decl_module! {
             let application = Application::<T>::new(
                 &p.role_account_id,
                 &p.reward_account_id,
-                &p.stake_parameters.as_ref().map(|sp| sp.staking_account_id.clone()),
+                &p.stake_parameters.staking_account_id,
                 &p.member_id,
+                p.opening_id,
                 hashed_description.as_ref().to_vec(),
             );
 
@@ -483,7 +486,9 @@ decl_module! {
         ///    - O(A)
         /// # </weight>
         #[weight =
-            WeightInfoWorkingGroup::<T, I>::fill_opening_worker(successful_application_ids.len().saturated_into())
+            WeightInfoWorkingGroup::<T, I>::fill_opening_worker(
+                successful_application_ids.len().saturated_into()
+            )
             .max(WeightInfoWorkingGroup::<T, I>::fill_opening_lead())
         ]
         pub fn fill_opening(
@@ -492,13 +497,14 @@ decl_module! {
             successful_application_ids: BTreeSet<ApplicationId>,
         ) {
             // Ensure job opening exists.
-            let opening = checks::ensure_opening_exists::<T, I>(&opening_id)?;
+            let opening = checks::ensure_opening_exists::<T, I>(opening_id)?;
 
             checks::ensure_origin_for_opening_type::<T, I>(origin, opening.opening_type)?;
 
             // Ensure we're not exceeding the maximum worker number.
             let potential_worker_number =
                 Self::active_worker_count() + (successful_application_ids.len() as u32);
+
             ensure!(
                 potential_worker_number <= T::MaxWorkerNumberLimit::get(),
                 Error::<T, I>::MaxActiveWorkerNumberExceeded
@@ -506,14 +512,27 @@ decl_module! {
 
             // Cannot hire a lead when another leader exists.
             if matches!(opening.opening_type, OpeningType::Leader) {
-                ensure!(!<CurrentLead<T,I>>::exists(), Error::<T, I>::CannotHireLeaderWhenLeaderExists);
+                ensure!(
+                    !<CurrentLead<T,I>>::exists(),
+                    Error::<T, I>::CannotHireLeaderWhenLeaderExists
+                );
             }
 
-            let checked_applications_info = checks::ensure_succesful_applications_exist::<T, I>(&successful_application_ids)?;
+            let checked_applications_info =
+                checks::ensure_succesful_applications_exist::<T, I>(&successful_application_ids)?;
+
+            // Check that all applications are for the intended opening
+            if !checked_applications_info.iter()
+                .all(|info| info.application.opening_id == opening_id) {
+                return Err(Error::<T, I>::ApplicationsNotForOpening.into());
+            }
 
             // Check for a single application for a leader.
             if matches!(opening.opening_type, OpeningType::Leader) {
-                ensure!(successful_application_ids.len() == 1, Error::<T, I>::CannotHireMultipleLeaders);
+                ensure!(
+                    successful_application_ids.len() == 1,
+                    Error::<T, I>::CannotHireMultipleLeaders
+                );
             }
 
             //
@@ -635,22 +654,12 @@ decl_module! {
             // Ensuring worker actually exists.
             let worker = checks::ensure_worker_exists::<T,I>(&worker_id)?;
 
-            if penalty.is_some() {
-                // Ensure worker has a stake.
-                ensure!(
-                    worker.staking_account_id.is_some(),
-                    Error::<T, I>::CannotChangeStakeWithoutStakingAccount
-                );
-            }
-
             //
             // == MUTATION SAFE ==
             //
 
             if let Some(penalty) = penalty {
-                if let Some(staking_account_id) = worker.staking_account_id.clone() {
-                    Self::slash(worker_id, &staking_account_id, penalty, rationale.clone());
-                }
+                Self::slash(worker_id, &worker.staking_account_id, penalty, rationale.clone());
             }
 
             // Trigger the event
@@ -687,12 +696,6 @@ decl_module! {
             // Ensuring worker actually exists.
             let worker = checks::ensure_worker_exists::<T,I>(&worker_id)?;
 
-            // Ensure worker has a stake.
-            ensure!(
-                worker.staking_account_id.is_some(),
-                Error::<T, I>::CannotChangeStakeWithoutStakingAccount
-            );
-
             ensure!(
                 penalty != <BalanceOf<T>>::zero(),
                 Error::<T, I>::StakeBalanceCannotBeZero
@@ -702,9 +705,7 @@ decl_module! {
             // == MUTATION SAFE ==
             //
 
-            if let Some(staking_account_id) = worker.staking_account_id {
-                Self::slash(worker_id, &staking_account_id, penalty, rationale)
-            }
+            Self::slash(worker_id, &worker.staking_account_id, penalty, rationale)
         }
 
         /// Decreases the regular worker/lead stake and returns the remainder to the
@@ -726,12 +727,6 @@ decl_module! {
 
             let worker = checks::ensure_worker_exists::<T,I>(&worker_id)?;
 
-            // Ensure worker has a stake.
-            ensure!(
-                worker.staking_account_id.is_some(),
-                Error::<T, I>::CannotChangeStakeWithoutStakingAccount
-            );
-
             // Ensure the worker is active.
             ensure!(!worker.is_leaving(), Error::<T, I>::WorkerIsLeaving);
 
@@ -742,30 +737,26 @@ decl_module! {
             );
 
             // Ensure enough stake to decrease.
-            if let Some(staking_account_id) = worker.staking_account_id.clone(){
-                let current_stake = T::StakingHandler::current_stake(&staking_account_id);
+            let current_stake = T::StakingHandler::current_stake(&worker.staking_account_id);
 
-                ensure!(
-                    current_stake > stake_balance_delta,
-                    Error::<T, I>::CannotDecreaseStakeDeltaGreaterThanStake
-                );
-            }
+            ensure!(
+                current_stake > stake_balance_delta,
+                Error::<T, I>::CannotDecreaseStakeDeltaGreaterThanStake
+            );
 
             //
             // == MUTATION SAFE ==
             //
 
-             if let Some(staking_account_id) = worker.staking_account_id{
-                let current_stake = T::StakingHandler::current_stake(&staking_account_id);
+            let current_stake = T::StakingHandler::current_stake(&worker.staking_account_id);
 
-                // Cannot possibly overflow because of the already performed check.
-                let new_stake = current_stake.saturating_sub(stake_balance_delta);
+            // Cannot possibly overflow because of the already performed check.
+            let new_stake = current_stake.saturating_sub(stake_balance_delta);
 
-                // This external module call both checks and mutates the state.
-                T::StakingHandler::set_stake(&staking_account_id, new_stake)?;
+            // This external module call both checks and mutates the state.
+            T::StakingHandler::set_stake(&worker.staking_account_id, new_stake)?;
 
-                Self::deposit_event(RawEvent::StakeDecreased(worker_id, stake_balance_delta));
-            }
+            Self::deposit_event(RawEvent::StakeDecreased(worker_id, stake_balance_delta));
         }
 
         /// Increases the regular worker/lead stake, demands a worker origin.
@@ -786,38 +777,31 @@ decl_module! {
             // Ensure the worker is active.
             ensure!(!worker.is_leaving(), Error::<T, I>::WorkerIsLeaving);
 
-            // Ensure worker has a stake.
-            ensure!(
-                worker.staking_account_id.is_some(),
-                Error::<T, I>::CannotChangeStakeWithoutStakingAccount
-            );
-
             ensure!(
                 stake_balance_delta != <BalanceOf<T>>::zero(),
                 Error::<T, I>::StakeBalanceCannotBeZero
             );
 
-            if let Some(staking_account_id) = worker.staking_account_id.clone() {
-                ensure!(
-                    T::StakingHandler::is_enough_balance_for_stake(&staking_account_id, stake_balance_delta),
-                    Error::<T, I>::InsufficientBalanceToCoverStake
-                );
-            }
+            ensure!(
+                T::StakingHandler::is_enough_balance_for_stake(
+                    &worker.staking_account_id,
+                    stake_balance_delta
+                ),
+                Error::<T, I>::InsufficientBalanceToCoverStake
+            );
 
             //
             // == MUTATION SAFE ==
             //
 
-            if let Some(staking_account_id) = worker.staking_account_id {
-                let current_stake = T::StakingHandler::current_stake(&staking_account_id);
+            let current_stake = T::StakingHandler::current_stake(&worker.staking_account_id);
 
-                let new_stake = current_stake.saturating_add(stake_balance_delta);
+            let new_stake = current_stake.saturating_add(stake_balance_delta);
 
-                // This external module call both checks and mutates the state.
-                T::StakingHandler::set_stake(&staking_account_id, new_stake)?;
+            // This external module call both checks and mutates the state.
+            T::StakingHandler::set_stake(&worker.staking_account_id, new_stake)?;
 
-                Self::deposit_event(RawEvent::StakeIncreased(worker_id, stake_balance_delta));
-            }
+            Self::deposit_event(RawEvent::StakeIncreased(worker_id, stake_balance_delta));
         }
 
         /// Withdraw the worker application. Can be done by the worker only.
@@ -850,9 +834,8 @@ decl_module! {
             // == MUTATION SAFE ==
             //
 
-            if let Some(staking_account_id) = application_info.application.staking_account_id.clone() {
-                T::StakingHandler::unlock(&staking_account_id);
-            }
+            T::StakingHandler::unlock(&application_info.application.staking_account_id);
+
             // Remove an application.
             <ApplicationById<T, I>>::remove(application_info.application_id);
 
@@ -876,7 +859,7 @@ decl_module! {
             opening_id: OpeningId,
         ) {
             // Ensure job opening exists.
-            let opening = checks::ensure_opening_exists::<T, I>(&opening_id)?;
+            let opening = checks::ensure_opening_exists::<T, I>(opening_id)?;
 
             checks::ensure_origin_for_opening_type::<T, I>(origin, opening.opening_type)?;
 
@@ -1174,10 +1157,7 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
             &application_info.application.role_account_id,
             &application_info.application.reward_account_id,
             &application_info.application.staking_account_id,
-            opening
-                .stake_policy
-                .as_ref()
-                .map_or(Zero::zero(), |sp| sp.leaving_unstaking_period),
+            opening.stake_policy.leaving_unstaking_period,
             opening.reward_per_block,
             Self::current_block(),
         );
@@ -1231,9 +1211,7 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
         WorkerById::<T, I>::remove(worker_id);
         Self::decrease_active_worker_counter();
 
-        if let Some(staking_account_id) = worker.staking_account_id.clone() {
-            T::StakingHandler::unlock(&staking_account_id);
-        }
+        T::StakingHandler::unlock(&worker.staking_account_id);
 
         Self::deposit_event(event);
     }
@@ -1388,10 +1366,8 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
             return true;
         }
 
-        if let Some(staking_account_id) = worker.staking_account_id.clone() {
-            if T::StakingHandler::current_stake(&staking_account_id) == Zero::zero() {
-                return true;
-            }
+        if T::StakingHandler::current_stake(&worker.staking_account_id) == Zero::zero() {
+            return true;
         }
 
         false

+ 135 - 79
runtime-modules/working-group/src/tests/fixtures.rs

@@ -1,5 +1,6 @@
 #![cfg(test)]
 use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::Currency;
 use frame_support::StorageMap;
 use frame_system::{EventRecord, Phase, RawOrigin};
 use sp_runtime::traits::Hash;
@@ -10,7 +11,7 @@ use super::mock::{Balances, LockId, System, Test, TestEvent, TestWorkingGroup};
 use crate::types::StakeParameters;
 use crate::{
     Application, ApplyOnOpeningParameters, DefaultInstance, Opening, OpeningType, RawEvent,
-    StakePolicy, Worker,
+    StakePolicy, Trait, Worker,
 };
 
 pub struct EventFixture;
@@ -50,7 +51,7 @@ pub struct AddOpeningFixture {
     pub description: Vec<u8>,
     pub opening_type: OpeningType,
     pub starting_block: u64,
-    pub stake_policy: Option<StakePolicy<u64, u64>>,
+    pub stake_policy: StakePolicy<u64, u64>,
     pub reward_per_block: Option<u64>,
 }
 
@@ -61,7 +62,10 @@ impl Default for AddOpeningFixture {
             description: b"human_text".to_vec(),
             opening_type: OpeningType::Regular,
             starting_block: 0,
-            stake_policy: None,
+            stake_policy: StakePolicy {
+                stake_amount: <Test as Trait>::MinimumStakeForOpening::get(),
+                leaving_unstaking_period: <Test as Trait>::MinUnstakingPeriodLimit::get() + 1,
+            },
             reward_per_block: None,
         }
     }
@@ -129,7 +133,7 @@ impl AddOpeningFixture {
         }
     }
 
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
+    pub fn with_stake_policy(self, stake_policy: StakePolicy<u64, u64>) -> Self {
         Self {
             stake_policy,
             ..self
@@ -151,7 +155,8 @@ pub struct ApplyOnOpeningFixture {
     role_account_id: u64,
     reward_account_id: u64,
     description: Vec<u8>,
-    stake_parameters: Option<StakeParameters<u64, u64>>,
+    stake_parameters: StakeParameters<u64, u64>,
+    initial_balance: u64,
 }
 
 impl ApplyOnOpeningFixture {
@@ -162,33 +167,47 @@ impl ApplyOnOpeningFixture {
         }
     }
 
-    pub fn with_origin(self, origin: RawOrigin<u64>, member_id: u64) -> Self {
+    pub fn with_origin(self, origin: RawOrigin<u64>, id: u64) -> Self {
         Self {
             origin,
-            member_id,
+            stake_parameters: StakeParameters {
+                staking_account_id: id,
+                ..self.stake_parameters
+            },
+            member_id: id,
+            role_account_id: id,
+            reward_account_id: id,
             ..self
         }
     }
 
-    pub fn with_stake_parameters(
-        self,
-        stake_parameters: Option<StakeParameters<u64, u64>>,
-    ) -> Self {
+    pub fn with_stake_parameters(self, stake_parameters: StakeParameters<u64, u64>) -> Self {
         Self {
             stake_parameters,
             ..self
         }
     }
 
+    pub fn with_initial_balance(self, initial_balance: u64) -> Self {
+        Self {
+            initial_balance,
+            ..self
+        }
+    }
+
     pub fn default_for_opening_id(opening_id: u64) -> Self {
         Self {
-            origin: RawOrigin::Signed(1),
-            member_id: 1,
+            origin: RawOrigin::Signed(2),
+            member_id: 2,
             opening_id,
-            role_account_id: 1,
-            reward_account_id: 1,
+            role_account_id: 2,
+            reward_account_id: 2,
             description: b"human_text".to_vec(),
-            stake_parameters: None,
+            stake_parameters: StakeParameters {
+                stake: <Test as Trait>::MinimumStakeForOpening::get(),
+                staking_account_id: 2,
+            },
+            initial_balance: <Test as Trait>::MinimumStakeForOpening::get(),
         }
     }
 
@@ -204,6 +223,11 @@ impl ApplyOnOpeningFixture {
     }
 
     pub fn call(&self) -> Result<u64, DispatchError> {
+        balances::Module::<Test>::make_free_balance_be(
+            &self.stake_parameters.staking_account_id,
+            self.initial_balance,
+        );
+
         let saved_application_next_id = TestWorkingGroup::next_application_id();
         TestWorkingGroup::apply_on_opening(
             self.origin.clone().into(),
@@ -212,6 +236,7 @@ impl ApplyOnOpeningFixture {
 
         Ok(saved_application_next_id)
     }
+
     pub fn call_and_assert(&self, expected_result: DispatchResult) -> u64 {
         let saved_application_next_id = TestWorkingGroup::next_application_id();
 
@@ -231,12 +256,10 @@ impl ApplyOnOpeningFixture {
             let expected_application = Application::<Test> {
                 role_account_id: self.role_account_id,
                 reward_account_id: self.reward_account_id,
-                staking_account_id: self
-                    .stake_parameters
-                    .clone()
-                    .map(|sp| sp.staking_account_id),
+                staking_account_id: self.stake_parameters.staking_account_id,
                 member_id: self.member_id,
                 description_hash: expected_hash.as_ref().to_vec(),
+                opening_id: 1,
             };
 
             assert_eq!(actual_application, expected_application);
@@ -252,8 +275,8 @@ pub struct FillOpeningFixture {
     pub successful_application_ids: BTreeSet<u64>,
     role_account_id: u64,
     reward_account_id: u64,
-    staking_account_id: Option<u64>,
-    stake_policy: Option<StakePolicy<u64, u64>>,
+    staking_account_id: u64,
+    stake_policy: StakePolicy<u64, u64>,
     reward_per_block: Option<u64>,
     created_at: u64,
 }
@@ -266,10 +289,13 @@ impl FillOpeningFixture {
             origin: RawOrigin::Signed(1),
             opening_id,
             successful_application_ids: application_ids,
-            role_account_id: 1,
-            reward_account_id: 1,
-            staking_account_id: None,
-            stake_policy: None,
+            role_account_id: 2,
+            reward_account_id: 2,
+            staking_account_id: 2,
+            stake_policy: StakePolicy {
+                stake_amount: <Test as Trait>::MinimumStakeForOpening::get(),
+                leaving_unstaking_period: <Test as Trait>::MinUnstakingPeriodLimit::get() + 1,
+            },
             reward_per_block: None,
             created_at: 0,
         }
@@ -283,14 +309,14 @@ impl FillOpeningFixture {
         Self { created_at, ..self }
     }
 
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
+    pub fn with_stake_policy(self, stake_policy: StakePolicy<u64, u64>) -> Self {
         Self {
             stake_policy,
             ..self
         }
     }
 
-    pub fn with_staking_account_id(self, staking_account_id: Option<u64>) -> Self {
+    pub fn with_staking_account_id(self, staking_account_id: u64) -> Self {
         Self {
             staking_account_id,
             ..self
@@ -336,15 +362,12 @@ impl FillOpeningFixture {
             }
 
             let expected_worker = Worker::<Test> {
-                member_id: 1,
+                member_id: 2,
                 role_account_id: self.role_account_id,
                 reward_account_id: self.reward_account_id,
                 staking_account_id: self.staking_account_id,
                 started_leaving_at: None,
-                job_unstaking_period: self
-                    .stake_policy
-                    .as_ref()
-                    .map_or(0, |sp| sp.leaving_unstaking_period),
+                job_unstaking_period: self.stake_policy.leaving_unstaking_period,
                 reward_per_block: self.reward_per_block,
                 missed_reward: None,
                 created_at: self.created_at,
@@ -369,20 +392,34 @@ impl FillOpeningFixture {
 
 pub struct HireLeadFixture {
     setup_environment: bool,
-    stake_policy: Option<StakePolicy<u64, u64>>,
+    stake_policy: StakePolicy<u64, u64>,
     reward_per_block: Option<u64>,
+    lead_id: u64,
+    initial_balance: u64,
 }
 
 impl Default for HireLeadFixture {
     fn default() -> Self {
         Self {
             setup_environment: true,
-            stake_policy: None,
+            stake_policy: StakePolicy {
+                stake_amount: <Test as Trait>::MinimumStakeForOpening::get(),
+                leaving_unstaking_period: <Test as Trait>::MinUnstakingPeriodLimit::get() + 1,
+            },
             reward_per_block: None,
+            lead_id: 1,
+            initial_balance: <Test as Trait>::MinimumStakeForOpening::get() + 1,
         }
     }
 }
 impl HireLeadFixture {
+    pub fn with_initial_balance(self, initial_balance: u64) -> Self {
+        Self {
+            initial_balance,
+            ..self
+        }
+    }
+
     pub fn with_setup_environment(self, setup_environment: bool) -> Self {
         Self {
             setup_environment,
@@ -390,7 +427,7 @@ impl HireLeadFixture {
         }
     }
 
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
+    pub fn with_stake_policy(self, stake_policy: StakePolicy<u64, u64>) -> Self {
         Self {
             stake_policy,
             ..self
@@ -404,46 +441,59 @@ impl HireLeadFixture {
         }
     }
 
-    pub fn hire_lead(self) -> u64 {
+    fn get_hiring_workflow(self) -> HiringWorkflow {
         HiringWorkflow::default()
             .with_setup_environment(self.setup_environment)
             .with_opening_type(OpeningType::Leader)
             .with_stake_policy(self.stake_policy)
             .with_reward_per_block(self.reward_per_block)
-            .add_application(b"leader".to_vec())
-            .execute()
-            .unwrap()
+            .with_initial_balance(self.initial_balance)
+            .add_application_full(
+                b"leader".to_vec(),
+                RawOrigin::Signed(self.lead_id),
+                self.lead_id,
+                self.lead_id,
+            )
+    }
+
+    pub fn hire_lead(self) -> u64 {
+        self.get_hiring_workflow().execute().unwrap()
     }
 
     pub fn expect(self, error: DispatchError) {
-        HiringWorkflow::default()
-            .with_setup_environment(self.setup_environment)
-            .with_opening_type(OpeningType::Leader)
-            .with_stake_policy(self.stake_policy)
-            .with_reward_per_block(self.reward_per_block)
-            .add_application(b"leader".to_vec())
-            .expect(Err(error))
-            .execute();
+        self.get_hiring_workflow().expect(Err(error)).execute();
     }
 }
 
 pub struct HireRegularWorkerFixture {
     setup_environment: bool,
-    stake_policy: Option<StakePolicy<u64, u64>>,
+    stake_policy: StakePolicy<u64, u64>,
     reward_per_block: Option<u64>,
+    initial_balance: u64,
 }
 
 impl Default for HireRegularWorkerFixture {
     fn default() -> Self {
         Self {
             setup_environment: true,
-            stake_policy: None,
+            stake_policy: StakePolicy {
+                stake_amount: <Test as Trait>::MinimumStakeForOpening::get(),
+                leaving_unstaking_period: <Test as Trait>::MinUnstakingPeriodLimit::get() + 1,
+            },
             reward_per_block: None,
+            initial_balance: <Test as Trait>::MinimumStakeForOpening::get(),
         }
     }
 }
 impl HireRegularWorkerFixture {
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
+    pub fn with_initial_balance(self, initial_balance: u64) -> Self {
+        Self {
+            initial_balance,
+            ..self
+        }
+    }
+
+    pub fn with_stake_policy(self, stake_policy: StakePolicy<u64, u64>) -> Self {
         Self {
             stake_policy,
             ..self
@@ -463,6 +513,7 @@ impl HireRegularWorkerFixture {
             .with_opening_type(OpeningType::Regular)
             .with_stake_policy(self.stake_policy)
             .with_reward_per_block(self.reward_per_block)
+            .with_initial_balance(self.initial_balance)
             .add_application(b"worker".to_vec())
             .execute()
             .unwrap()
@@ -506,44 +557,33 @@ impl UpdateWorkerRoleAccountFixture {
 pub(crate) struct LeaveWorkerRoleFixture {
     worker_id: u64,
     origin: RawOrigin<u64>,
-    stake_policy: Option<StakePolicy<u64, u64>>,
 }
 
 impl LeaveWorkerRoleFixture {
     pub fn default_for_worker_id(worker_id: u64) -> Self {
         Self {
             worker_id,
-            origin: RawOrigin::Signed(1),
-            stake_policy: None,
+            origin: RawOrigin::Signed(2),
         }
     }
     pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
         Self { origin, ..self }
     }
 
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
-        Self {
-            stake_policy,
-            ..self
-        }
-    }
-
     pub fn call_and_assert(&self, expected_result: DispatchResult) {
         let actual_result =
             TestWorkingGroup::leave_role(self.origin.clone().into(), self.worker_id, None);
         assert_eq!(actual_result, expected_result);
 
         if actual_result.is_ok() {
-            if self.stake_policy.is_some() {
-                let worker = TestWorkingGroup::worker_by_id(self.worker_id);
-
-                if worker.job_unstaking_period > 0 {
-                    assert_eq!(
-                        worker.started_leaving_at,
-                        Some(<frame_system::Module<Test>>::block_number())
-                    );
-                    return;
-                }
+            let worker = TestWorkingGroup::worker_by_id(self.worker_id);
+
+            if worker.job_unstaking_period > 0 {
+                assert_eq!(
+                    worker.started_leaving_at,
+                    Some(<frame_system::Module<Test>>::block_number())
+                );
+                return;
             }
 
             assert!(!<crate::WorkerById<Test, DefaultInstance>>::contains_key(
@@ -611,7 +651,7 @@ pub struct SlashWorkerStakeFixture {
 
 impl SlashWorkerStakeFixture {
     pub fn default_for_worker_id(worker_id: u64) -> Self {
-        let account_id = 1;
+        let account_id = 2;
 
         let lead_account_id = get_current_lead_account_id();
 
@@ -631,6 +671,10 @@ impl SlashWorkerStakeFixture {
         Self { penalty, ..self }
     }
 
+    pub fn with_account_id(self, account_id: u64) -> Self {
+        Self { account_id, ..self }
+    }
+
     pub fn call_and_assert(&self, expected_result: DispatchResult) {
         let old_balance = Balances::usable_balance(&self.account_id);
         let old_stake = get_stake_balance(&self.account_id);
@@ -686,7 +730,7 @@ pub struct DecreaseWorkerStakeFixture {
 
 impl DecreaseWorkerStakeFixture {
     pub fn default_for_worker_id(worker_id: u64) -> Self {
-        let account_id = 1;
+        let account_id = 2;
 
         let lead_account_id = get_current_lead_account_id();
 
@@ -697,6 +741,11 @@ impl DecreaseWorkerStakeFixture {
             account_id,
         }
     }
+
+    pub fn with_account_id(self, account_id: u64) -> Self {
+        Self { account_id, ..self }
+    }
+
     pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
         Self { origin, ..self }
     }
@@ -718,7 +767,10 @@ impl DecreaseWorkerStakeFixture {
 
         if actual_result.is_ok() {
             // new stake was set
-            assert_eq!(self.balance, get_stake_balance(&self.account_id));
+            assert_eq!(
+                old_stake - self.balance,
+                get_stake_balance(&self.account_id)
+            );
 
             let new_balance = Balances::usable_balance(&self.account_id);
 
@@ -737,9 +789,9 @@ pub struct IncreaseWorkerStakeFixture {
 
 impl IncreaseWorkerStakeFixture {
     pub fn default_for_worker_id(worker_id: u64) -> Self {
-        let account_id = 1;
+        let account_id = 2;
         Self {
-            origin: RawOrigin::Signed(1),
+            origin: RawOrigin::Signed(account_id),
             worker_id,
             balance: 10,
             account_id,
@@ -749,6 +801,10 @@ impl IncreaseWorkerStakeFixture {
         Self { origin, ..self }
     }
 
+    pub fn with_account_id(self, account_id: u64) -> Self {
+        Self { account_id, ..self }
+    }
+
     pub fn with_balance(self, balance: u64) -> Self {
         Self { balance, ..self }
     }
@@ -809,10 +865,10 @@ impl WithdrawApplicationFixture {
 
     pub fn default_for_application_id(application_id: u64) -> Self {
         Self {
-            origin: RawOrigin::Signed(1),
+            origin: RawOrigin::Signed(2),
             application_id,
             stake: false,
-            account_id: 1,
+            account_id: 2,
         }
     }
     pub fn call_and_assert(&self, expected_result: DispatchResult) {
@@ -936,7 +992,7 @@ impl UpdateRewardAccountFixture {
         Self {
             worker_id,
             new_reward_account_id,
-            origin: RawOrigin::Signed(1),
+            origin: RawOrigin::Signed(2),
         }
     }
     pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {

+ 29 - 15
runtime-modules/working-group/src/tests/hiring_workflow.rs

@@ -1,16 +1,17 @@
 use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::Currency;
 use frame_system::RawOrigin;
 
 use crate::tests::fixtures::{
     AddOpeningFixture, ApplyOnOpeningFixture, FillOpeningFixture, HireLeadFixture,
 };
-use crate::tests::mock::TestWorkingGroup;
+use crate::tests::mock::{Test, TestWorkingGroup};
 use crate::types::StakeParameters;
-use crate::{OpeningType, StakePolicy};
+use crate::{OpeningType, StakePolicy, Trait};
 
 #[derive(Clone)]
 struct HiringWorkflowApplication {
-    stake_parameters: Option<StakeParameters<u64, u64>>,
+    stake_parameters: StakeParameters<u64, u64>,
     worker_handle: Vec<u8>,
     origin: RawOrigin<u64>,
     member_id: u64,
@@ -19,10 +20,11 @@ struct HiringWorkflowApplication {
 pub struct HiringWorkflow {
     opening_type: OpeningType,
     expected_result: DispatchResult,
-    stake_policy: Option<StakePolicy<u64, u64>>,
+    stake_policy: StakePolicy<u64, u64>,
     reward_per_block: Option<u64>,
     applications: Vec<HiringWorkflowApplication>,
     setup_environment: bool,
+    initial_balance: u64,
 }
 
 impl Default for HiringWorkflow {
@@ -30,16 +32,27 @@ impl Default for HiringWorkflow {
         Self {
             opening_type: OpeningType::Regular,
             expected_result: Ok(()),
-            stake_policy: None,
+            stake_policy: StakePolicy {
+                stake_amount: <Test as Trait>::MinimumStakeForOpening::get(),
+                leaving_unstaking_period: <Test as Trait>::MinUnstakingPeriodLimit::get() + 1,
+            },
             reward_per_block: None,
             applications: Vec::new(),
             setup_environment: true,
+            initial_balance: <Test as Trait>::MinimumStakeForOpening::get() + 1,
         }
     }
 }
 
 impl HiringWorkflow {
-    pub fn with_stake_policy(self, stake_policy: Option<StakePolicy<u64, u64>>) -> Self {
+    pub fn with_initial_balance(self, initial_balance: u64) -> Self {
+        Self {
+            initial_balance,
+            ..self
+        }
+    }
+
+    pub fn with_stake_policy(self, stake_policy: StakePolicy<u64, u64>) -> Self {
         Self {
             stake_policy,
             ..self
@@ -81,7 +94,7 @@ impl HiringWorkflow {
     }
 
     pub fn add_application(self, worker_handle: Vec<u8>) -> Self {
-        self.add_application_full(worker_handle, RawOrigin::Signed(1), 1, Some(1))
+        self.add_application_full(worker_handle, RawOrigin::Signed(2), 2, 2)
     }
 
     pub fn add_application_full(
@@ -89,16 +102,12 @@ impl HiringWorkflow {
         worker_handle: Vec<u8>,
         origin: RawOrigin<u64>,
         member_id: u64,
-        staking_account_id: Option<u64>,
+        staking_account_id: u64,
     ) -> Self {
-        let stake_parameters = staking_account_id.map(|staking_account_id| StakeParameters {
-            stake: self
-                .stake_policy
-                .clone()
-                .map(|policy| policy.stake_amount)
-                .unwrap_or_default(),
+        let stake_parameters = StakeParameters {
+            stake: self.stake_policy.stake_amount,
             staking_account_id,
-        });
+        };
 
         let mut applications = self.applications;
         applications.push(HiringWorkflowApplication {
@@ -118,6 +127,10 @@ impl HiringWorkflow {
         if matches!(self.opening_type, OpeningType::Regular) {
             HireLeadFixture::default().hire_lead();
         } else {
+            balances::Module::<Test>::make_free_balance_be(
+                &1,
+                <Test as Trait>::MinimumStakeForOpening::get() + 1,
+            );
             //         setup_members(6);
         }
     }
@@ -164,6 +177,7 @@ impl HiringWorkflow {
                 ApplyOnOpeningFixture::default_for_opening_id(opening_id)
                     .with_stake_parameters(application.stake_parameters)
                     .with_text(application.worker_handle)
+                    .with_initial_balance(self.initial_balance)
                     .with_origin(application.origin, application.member_id);
 
             let application_id = apply_on_worker_opening_fixture.call()?;

+ 2 - 1
runtime-modules/working-group/src/tests/mock.rs

@@ -178,6 +178,7 @@ parameter_types! {
     pub const RewardPeriod: u32 = 2;
     pub const MaxWorkerNumberLimit: u32 = 3;
     pub const MinUnstakingPeriodLimit: u64 = 3;
+    pub const MinimumStakeForOpening: u64 = 50;
     pub const LockId: [u8; 8] = [1; 8];
 }
 
@@ -190,6 +191,7 @@ impl Trait for Test {
     type MinUnstakingPeriodLimit = MinUnstakingPeriodLimit;
     type RewardPeriod = RewardPeriod;
     type WeightInfo = ();
+    type MinimumStakeForOpening = MinimumStakeForOpening;
 }
 
 impl common::StakingAccountValidator<Test> for () {
@@ -295,7 +297,6 @@ pub type TestWorkingGroup = Module<Test, DefaultInstance>;
 
 pub const STAKING_ACCOUNT_ID_NOT_BOUND_TO_MEMBER: u64 = 222;
 pub const STAKING_ACCOUNT_ID_FOR_CONFLICTING_STAKES: u64 = 333;
-pub const STAKING_ACCOUNT_ID_FOR_ZERO_STAKE: u64 = 444;
 
 pub fn build_test_externalities() -> sp_io::TestExternalities {
     let t = frame_system::GenesisConfig::default()

File diff suppressed because it is too large
+ 157 - 300
runtime-modules/working-group/src/tests/mod.rs


+ 12 - 6
runtime-modules/working-group/src/types.rs

@@ -68,7 +68,7 @@ pub struct Opening<BlockNumber: Ord, Balance> {
     pub description_hash: Vec<u8>,
 
     /// Stake policy for the job opening.
-    pub stake_policy: Option<StakePolicy<BlockNumber, Balance>>,
+    pub stake_policy: StakePolicy<BlockNumber, Balance>,
 
     /// Reward per block for the job opening.
     pub reward_per_block: Option<Balance>,
@@ -104,13 +104,16 @@ pub struct JobApplication<AccountId, MemberId> {
     pub reward_account_id: AccountId,
 
     /// Account used to stake in this role.
-    pub staking_account_id: Option<AccountId>,
+    pub staking_account_id: AccountId,
 
     /// Member applying.
     pub member_id: MemberId,
 
     /// Hash of the application description.
     pub description_hash: Vec<u8>,
+
+    /// Opening ID for the application
+    pub opening_id: OpeningId,
 }
 
 impl<AccountId: Clone, MemberId: Clone> JobApplication<AccountId, MemberId> {
@@ -118,8 +121,9 @@ impl<AccountId: Clone, MemberId: Clone> JobApplication<AccountId, MemberId> {
     pub fn new(
         role_account_id: &AccountId,
         reward_account_id: &AccountId,
-        staking_account_id: &Option<AccountId>,
+        staking_account_id: &AccountId,
         member_id: &MemberId,
+        opening_id: OpeningId,
         description_hash: Vec<u8>,
     ) -> Self {
         JobApplication {
@@ -127,6 +131,7 @@ impl<AccountId: Clone, MemberId: Clone> JobApplication<AccountId, MemberId> {
             reward_account_id: reward_account_id.clone(),
             staking_account_id: staking_account_id.clone(),
             member_id: member_id.clone(),
+            opening_id,
             description_hash,
         }
     }
@@ -143,7 +148,7 @@ pub struct GroupWorker<AccountId, MemberId, BlockNumber, Balance> {
     pub role_account_id: AccountId,
 
     /// Account used to stake in this role.
-    pub staking_account_id: Option<AccountId>,
+    pub staking_account_id: AccountId,
 
     /// Reward account id.
     pub reward_account_id: AccountId,
@@ -152,6 +157,7 @@ pub struct GroupWorker<AccountId, MemberId, BlockNumber, Balance> {
     pub started_leaving_at: Option<BlockNumber>,
 
     /// Unstaking period when the worker chooses to leave the role.
+    ///
     /// It is defined by the job opening.
     pub job_unstaking_period: BlockNumber,
 
@@ -173,7 +179,7 @@ impl<AccountId: Clone, MemberId: Clone, BlockNumber, Balance>
         member_id: &MemberId,
         role_account_id: &AccountId,
         reward_account_id: &AccountId,
-        staking_account_id: &Option<AccountId>,
+        staking_account_id: &AccountId,
         job_unstaking_period: BlockNumber,
         reward_per_block: Option<Balance>,
         created_at: BlockNumber,
@@ -228,7 +234,7 @@ pub struct ApplyOnOpeningParams<MemberId, OpeningId, AccountId, Balance> {
     pub description: Vec<u8>,
 
     /// Stake information for the application.
-    pub stake_parameters: Option<StakeParameters<AccountId, Balance>>,
+    pub stake_parameters: StakeParameters<AccountId, Balance>,
 }
 
 /// Contains information for the stakes when applying for opening.

Some files were not shown because too many files changed in this diff