Browse Source

Merge pull request #3425 from shamil-gadelshin/olympia-fix-bounty-bug

runtime: content: Fix missing member_id check.
Bedeho Mender 3 years ago
parent
commit
9bcbb5955d
2 changed files with 196 additions and 6 deletions
  1. 21 6
      runtime-modules/bounty/src/lib.rs
  2. 175 0
      runtime-modules/bounty/src/tests/mod.rs

+ 21 - 6
runtime-modules/bounty/src/lib.rs

@@ -735,7 +735,6 @@ decl_error! {
 
         /// Invalid Creator Actor for Bounty specified
         InvalidCreatorActorSpecified,
-
     }
 }
 
@@ -1102,6 +1101,8 @@ decl_module! {
 
             let entry = Self::ensure_work_entry_exists(&bounty_id, &entry_id)?;
 
+            Self::ensure_work_entry_ownership(&entry, &member_id)?;
+
             //
             // == MUTATION SAFE ==
             //
@@ -1138,7 +1139,9 @@ decl_module! {
 
             Self::ensure_bounty_stage(current_bounty_stage, BountyStage::WorkSubmission)?;
 
-            Self::ensure_work_entry_exists(&bounty_id, &entry_id)?;
+            let entry = Self::ensure_work_entry_exists(&bounty_id, &entry_id)?;
+
+            Self::ensure_work_entry_ownership(&entry, &member_id)?;
 
             //
             // == MUTATION SAFE ==
@@ -1272,6 +1275,8 @@ decl_module! {
 
             let entry = Self::ensure_work_entry_exists(&bounty_id, &entry_id)?;
 
+            Self::ensure_work_entry_ownership(&entry, &member_id)?;
+
             //
             // == MUTATION SAFE ==
             //
@@ -1386,10 +1391,7 @@ decl_module! {
             T::Membership::ensure_member_controller_account_origin(origin, entrant_id)?;
 
             let entry = Self::ensure_work_entry_exists(&bounty_id, &entry_id)?;
-            ensure!(
-                entry.member_id == entrant_id,
-                Error::<T>::InvalidEntrantWorkerSpecified,
-            );
+            Self::ensure_work_entry_ownership(&entry, &entrant_id)?;
 
             //
             // == MUTATION SAFE ==
@@ -1728,6 +1730,19 @@ impl<T: Trait> Module<T> {
         Ok(entry)
     }
 
+    // Ensures entry record ownership for a member.
+    fn ensure_work_entry_ownership(
+        entry: &Entry<T>,
+        owner_member_id: &MemberId<T>,
+    ) -> DispatchResult {
+        ensure!(
+            entry.member_id == *owner_member_id,
+            Error::<T>::InvalidEntrantWorkerSpecified
+        );
+
+        Ok(())
+    }
+
     // Unlocks the work entry stake.
     // It also calculates and slashes the stake on work entry withdrawal.
     // The slashing amount depends on the entry active period.

+ 175 - 0
runtime-modules/bounty/src/tests/mod.rs

@@ -1911,6 +1911,56 @@ fn withdraw_work_entry_succeeded() {
     });
 }
 
+#[test]
+fn withdraw_work_entry_fails_with_invalid_owner() {
+    build_test_externalities().execute_with(|| {
+        let initial_balance = 500;
+        let max_amount = 100;
+        let entrant_stake = 37;
+
+        set_council_budget(initial_balance);
+
+        CreateBountyFixture::default()
+            .with_max_funding_amount(max_amount)
+            .with_entrant_stake(entrant_stake)
+            .call_and_assert(Ok(()));
+
+        let bounty_id = 1;
+        let member_id = 1;
+        let account_id = 1;
+
+        FundBountyFixture::default()
+            .with_bounty_id(bounty_id)
+            .with_amount(max_amount)
+            .with_council()
+            .with_origin(RawOrigin::Root)
+            .call_and_assert(Ok(()));
+
+        increase_account_balance(&account_id, initial_balance);
+
+        AnnounceWorkEntryFixture::default()
+            .with_origin(RawOrigin::Signed(account_id))
+            .with_member_id(member_id)
+            .with_staking_account_id(account_id)
+            .with_bounty_id(bounty_id)
+            .call_and_assert(Ok(()));
+
+        assert_eq!(
+            Balances::usable_balance(&account_id),
+            initial_balance - entrant_stake
+        );
+
+        let entry_id = 1;
+        let invalid_member_id = 10;
+
+        WithdrawWorkEntryFixture::default()
+            .with_origin(RawOrigin::Signed(account_id))
+            .with_member_id(invalid_member_id)
+            .with_entry_id(entry_id)
+            .call_and_assert(Err(Error::<Test>::InvalidEntrantWorkerSpecified.into()));
+    });
+}
+
 #[test]
 fn withdraw_work_slashes_successfully1() {
     build_test_externalities().execute_with(|| {
@@ -2308,6 +2358,53 @@ fn submit_work_succeeded() {
     });
 }
 
+#[test]
+fn submit_work_failed_with_invalid_ownership() {
+    build_test_externalities().execute_with(|| {
+        let initial_balance = 500;
+        let max_amount = 100;
+        let entrant_stake = 37;
+
+        set_council_budget(initial_balance);
+
+        CreateBountyFixture::default()
+            .with_max_funding_amount(max_amount)
+            .with_entrant_stake(entrant_stake)
+            .call_and_assert(Ok(()));
+
+        let bounty_id = 1;
+        let member_id = 1;
+        let account_id = 1;
+
+        FundBountyFixture::default()
+            .with_bounty_id(bounty_id)
+            .with_amount(max_amount)
+            .with_council()
+            .with_origin(RawOrigin::Root)
+            .call_and_assert(Ok(()));
+
+        increase_account_balance(&account_id, initial_balance);
+
+        AnnounceWorkEntryFixture::default()
+            .with_origin(RawOrigin::Signed(account_id))
+            .with_member_id(member_id)
+            .with_staking_account_id(account_id)
+            .with_bounty_id(bounty_id)
+            .call_and_assert(Ok(()));
+
+        let entry_id = 1;
+        let invalid_member_id = 11;
+
+        let work_data = b"Work submitted".to_vec();
+        SubmitWorkFixture::default()
+            .with_origin(RawOrigin::Signed(account_id))
+            .with_member_id(invalid_member_id)
+            .with_entry_id(entry_id)
+            .with_work_data(work_data.clone())
+            .call_and_assert(Err(Error::<Test>::InvalidEntrantWorkerSpecified.into()));
+    });
+}
+
 #[test]
 fn submit_work_fails_with_invalid_bounty_id() {
     build_test_externalities().execute_with(|| {
@@ -3288,6 +3385,84 @@ fn withdraw_work_entrant_funds_succeeded() {
     });
 }
 
+#[test]
+fn withdraw_work_entrant_funds_fails_with_invalid_entry_ownership() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let initial_balance = 500;
+        let max_amount = 100;
+        let winner_reward = max_amount;
+        let entrant_stake = 37;
+        let work_period = 1;
+
+        set_council_budget(initial_balance);
+
+        CreateBountyFixture::default()
+            .with_max_funding_amount(max_amount)
+            .with_work_period(work_period)
+            .with_entrant_stake(entrant_stake)
+            .call_and_assert(Ok(()));
+
+        let bounty_id = 1;
+
+        FundBountyFixture::default()
+            .with_bounty_id(bounty_id)
+            .with_amount(max_amount)
+            .with_council()
+            .with_origin(RawOrigin::Root)
+            .call_and_assert(Ok(()));
+
+        let member_id1 = 1;
+        let account_id1 = 1;
+        increase_account_balance(&account_id1, initial_balance);
+
+        AnnounceWorkEntryFixture::default()
+            .with_origin(RawOrigin::Signed(account_id1))
+            .with_member_id(member_id1)
+            .with_staking_account_id(account_id1)
+            .with_bounty_id(bounty_id)
+            .call_and_assert(Ok(()));
+
+        assert_eq!(
+            Balances::usable_balance(&account_id1),
+            initial_balance - entrant_stake
+        );
+
+        let entry_id1 = 1;
+        SubmitWorkFixture::default()
+            .with_origin(RawOrigin::Signed(account_id1))
+            .with_member_id(member_id1)
+            .with_entry_id(entry_id1)
+            .call_and_assert(Ok(()));
+
+        // Judgment
+        let mut judgment = BTreeMap::new();
+        judgment.insert(
+            entry_id1,
+            OracleWorkEntryJudgment::Winner {
+                reward: winner_reward,
+            },
+        );
+
+        run_to_block(starting_block + work_period + 1);
+
+        SubmitJudgmentFixture::default()
+            .with_bounty_id(bounty_id)
+            .with_judgment(judgment)
+            .call_and_assert(Ok(()));
+
+        // Withdraw work entrant.
+        let invalid_member_id = 111;
+        WithdrawWorkEntrantFundsFixture::default()
+            .with_origin(RawOrigin::Signed(account_id1))
+            .with_member_id(invalid_member_id)
+            .with_entry_id(entry_id1)
+            .call_and_assert(Err(Error::<Test>::InvalidEntrantWorkerSpecified.into()));
+    });
+}
+
 #[test]
 fn withdraw_work_entrant_funds_fails_with_invalid_bounty_id() {
     build_test_externalities().execute_with(|| {