Browse Source

Merge pull request #3290 from ignazio-bovo/olympia_feature_MetaProtocolExtrinsics

Olympia feature meta protocol extrinsics
shamil-gadelshin 3 years ago
parent
commit
7239bc7aa6
40 changed files with 3103 additions and 687 deletions
  1. 0 0
      chain-metadata.json
  2. 3 0
      runtime-modules/blog/src/mock.rs
  3. 172 0
      runtime-modules/bounty/src/benchmarking.rs
  4. 181 0
      runtime-modules/bounty/src/lib.rs
  5. 21 0
      runtime-modules/bounty/src/tests/mocks.rs
  6. 359 0
      runtime-modules/bounty/src/tests/mod.rs
  7. 64 0
      runtime-modules/content/src/lib.rs
  8. 505 0
      runtime-modules/content/src/tests/metaprotocol.rs
  9. 137 63
      runtime-modules/content/src/tests/mock.rs
  10. 1 0
      runtime-modules/content/src/tests/mod.rs
  11. 73 1
      runtime-modules/council/src/benchmarking.rs
  12. 64 1
      runtime-modules/council/src/lib.rs
  13. 26 0
      runtime-modules/council/src/mock.rs
  14. 83 1
      runtime-modules/council/src/tests.rs
  15. 9 0
      runtime-modules/forum/src/mock.rs
  16. 17 0
      runtime-modules/membership/src/benchmarking.rs
  17. 27 0
      runtime-modules/membership/src/lib.rs
  18. 8 0
      runtime-modules/membership/src/tests/mock.rs
  19. 51 0
      runtime-modules/membership/src/tests/mod.rs
  20. 19 0
      runtime-modules/proposals/codex/src/tests/mock.rs
  21. 9 0
      runtime-modules/proposals/discussion/src/tests/mock.rs
  22. 17 6
      runtime-modules/proposals/engine/src/benchmarking.rs
  23. 37 0
      runtime-modules/proposals/engine/src/lib.rs
  24. 15 0
      runtime-modules/proposals/engine/src/tests/mock/mod.rs
  25. 3 0
      runtime-modules/referendum/src/mock.rs
  26. 105 61
      runtime-modules/storage/src/lib.rs
  27. 138 67
      runtime-modules/storage/src/tests/mocks.rs
  28. 334 1
      runtime-modules/storage/src/tests/mod.rs
  29. 15 0
      runtime-modules/utility/src/tests/mocks.rs
  30. 39 0
      runtime-modules/working-group/src/benchmarking.rs
  31. 54 0
      runtime-modules/working-group/src/lib.rs
  32. 9 0
      runtime-modules/working-group/src/tests/mock.rs
  33. 3 29
      runtime/src/lib.rs
  34. 121 105
      runtime/src/weights/bounty.rs
  35. 76 64
      runtime/src/weights/council.rs
  36. 97 89
      runtime/src/weights/membership.rs
  37. 69 66
      runtime/src/weights/proposals_engine.rs
  38. 139 130
      runtime/src/weights/working_group.rs
  39. 1 1
      scripts/cargo-build.sh
  40. 2 2
      scripts/generate-weights.sh

File diff suppressed because it is too large
+ 0 - 0
chain-metadata.json


+ 3 - 0
runtime-modules/blog/src/mock.rs

@@ -227,6 +227,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 parameter_types! {

+ 172 - 0
runtime-modules/bounty/src/benchmarking.rs

@@ -973,6 +973,150 @@ benchmarks! {
         );
         assert_last_event::<T>(Event::<T>::BountyRemoved(bounty_id).into());
     }
+
+    entrant_remark {
+        let cherry: BalanceOf<T> = 100u32.into();
+        let funding_amount: BalanceOf<T> = 100u32.into();
+        let stake: BalanceOf<T> = 100u32.into();
+
+        let params = BountyCreationParameters::<T>{
+            work_period: One::one(),
+            judging_period: One::one(),
+            cherry,
+            funding_type: FundingType::Perpetual{ target: funding_amount },
+            entrant_stake: stake,
+            ..Default::default()
+        };
+
+        let bounty_id = create_max_funded_bounty::<T>(params);
+
+        let (account_id, member_id) = member_funded_account::<T>("member1", 1);
+
+        Bounty::<T>::announce_work_entry(
+            RawOrigin::Signed(account_id.clone()).into(),
+            member_id,
+            bounty_id,
+            account_id.clone()
+        ).unwrap();
+
+        let entry_id: T::EntryId = Bounty::<T>::entry_count().into();
+        let msg = b"test".to_vec();
+
+    }: _(RawOrigin::Signed(account_id.clone()), member_id, bounty_id, entry_id, msg.clone())
+    verify {
+        assert_last_event::<T>(
+            Event::<T>::BountyEntrantRemarked(member_id, bounty_id, entry_id, msg).into()
+        );
+    }
+
+    contributor_remark {
+        let funding_period = 1u32;
+        let bounty_amount: BalanceOf<T> = 200u32.into();
+        let cherry: BalanceOf<T> = 100u32.into();
+        let entrant_stake: BalanceOf<T> = T::MinWorkEntrantStake::get();
+
+        T::CouncilBudgetManager::set_budget(cherry);
+
+        let params = BountyCreationParameters::<T>{
+            work_period: One::one(),
+            judging_period: One::one(),
+            funding_type: FundingType::Limited{
+                min_funding_amount: bounty_amount,
+                max_funding_amount: bounty_amount,
+                funding_period: funding_period.into(),
+            },
+            cherry,
+            entrant_stake,
+            ..Default::default()
+        };
+        // should reach default max bounty funding amount
+        let amount: BalanceOf<T> = 100u32.into();
+
+        let (account_id, member_id) = member_funded_account::<T>("member1", 0);
+
+        Bounty::<T>::create_bounty(RawOrigin::Root.into(), params, Vec::new()).unwrap();
+
+        let bounty_id: T::BountyId = Bounty::<T>::bounty_count().into();
+
+        assert!(Bounties::<T>::contains_key(bounty_id));
+
+        let funder = BountyActor::Member(member_id);
+
+        Bounty::<T>::fund_bounty(
+            RawOrigin::Signed(account_id.clone()).into(),
+            funder.clone(),
+            bounty_id,
+            amount
+        ).unwrap();
+
+        run_to_block::<T>((funding_period + 1u32).into());
+        let msg = b"test".to_vec();
+
+    }: _(RawOrigin::Signed(account_id.clone()), funder.clone(), bounty_id, msg.clone())
+    verify {
+        assert_last_event::<T>(
+            Event::<T>::BountyContributorRemarked(funder, bounty_id, msg).into()
+        );
+    }
+
+    oracle_remark {
+        let work_period: T::BlockNumber = One::one();
+        let cherry: BalanceOf<T> = 100u32.into();
+        let funding_amount: BalanceOf<T> = 10000000u32.into();
+        let oracle = BountyActor::Council;
+        let entrant_stake: BalanceOf<T> = T::MinWorkEntrantStake::get();
+        let rationale = b"text".to_vec();
+
+        let params = BountyCreationParameters::<T> {
+            work_period,
+            judging_period: One::one(),
+            creator: BountyActor::Council,
+            cherry,
+            entrant_stake,
+            funding_type: FundingType::Perpetual{ target: funding_amount },
+            oracle: oracle.clone(),
+            ..Default::default()
+        };
+
+        let bounty_id = create_max_funded_bounty::<T>(params);
+        let msg = b"test".to_vec();
+
+    }: _(RawOrigin::Root, oracle.clone(), bounty_id, msg.clone())
+        verify {
+        assert_last_event::<T>(
+            Event::<T>::BountyOracleRemarked(oracle, bounty_id, msg).into()
+        );
+        }
+
+    creator_remark {
+        let work_period: T::BlockNumber = One::one();
+        let cherry: BalanceOf<T> = 100u32.into();
+        let funding_amount: BalanceOf<T> = 10000000u32.into();
+        let oracle = BountyActor::Council;
+        let entrant_stake: BalanceOf<T> = T::MinWorkEntrantStake::get();
+        let rationale = b"text".to_vec();
+        let creator = BountyActor::Council;
+
+        let params = BountyCreationParameters::<T> {
+            work_period,
+            judging_period: One::one(),
+            creator: creator.clone(),
+            cherry,
+            entrant_stake,
+            funding_type: FundingType::Perpetual{ target: funding_amount },
+            oracle: oracle.clone(),
+            ..Default::default()
+        };
+
+        let bounty_id = create_max_funded_bounty::<T>(params);
+        let msg = b"test".to_vec();
+
+    }: _(RawOrigin::Root, creator.clone(), bounty_id, msg.clone())
+        verify {
+        assert_last_event::<T>(
+            Event::<T>::BountyCreatorRemarked(creator, bounty_id, msg).into()
+        );
+        }
 }
 
 #[cfg(test)]
@@ -1099,4 +1243,32 @@ mod tests {
             assert_ok!(test_benchmark_withdraw_work_entrant_funds::<Test>());
         });
     }
+
+    #[test]
+    fn bounty_contributor_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_contributor_remark::<Test>());
+        });
+    }
+
+    #[test]
+    fn bounty_oracle_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_oracle_remark::<Test>());
+        });
+    }
+
+    #[test]
+    fn bounty_entrant_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_entrant_remark::<Test>());
+        });
+    }
+
+    #[test]
+    fn bounty_creator_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_creator_remark::<Test>());
+        });
+    }
 }

+ 181 - 0
runtime-modules/bounty/src/lib.rs

@@ -73,6 +73,10 @@ pub trait WeightInfo {
     fn submit_oracle_judgment_by_member_all_winners(i: u32) -> Weight;
     fn submit_oracle_judgment_by_member_all_rejected(i: u32) -> Weight;
     fn withdraw_work_entrant_funds() -> Weight;
+    fn contributor_remark() -> Weight;
+    fn oracle_remark() -> Weight;
+    fn entrant_remark() -> Weight;
+    fn creator_remark() -> Weight;
 }
 
 type WeightInfoBounty<T> = <T as Trait>::WeightInfo;
@@ -582,6 +586,36 @@ decl_event! {
         /// - entry ID
         /// - entrant member ID
         WorkEntrantFundsWithdrawn(BountyId, EntryId, MemberId),
+
+        /// Bounty contributor made a message remark
+        /// Params:
+        /// - contributor
+        /// - bounty id
+        /// - message
+        BountyContributorRemarked(BountyActor<MemberId>, BountyId, Vec<u8>),
+
+        /// Bounty oracle made a message remark
+        /// Params:
+        /// - oracle
+        /// - bounty id
+        /// - message
+        BountyOracleRemarked(BountyActor<MemberId>, BountyId, Vec<u8>),
+
+        /// Bounty entrant made a message remark
+        /// Params:
+        /// - entrant_id
+        /// - bounty id
+        /// - entry id
+        /// - message
+        BountyEntrantRemarked(MemberId, BountyId, EntryId, Vec<u8>),
+
+        /// Bounty entrant made a message remark
+        /// Params:
+        /// - creator
+        /// - bounty id
+        /// - message
+        BountyCreatorRemarked(BountyActor<MemberId>, BountyId, Vec<u8>),
+
     }
 }
 
@@ -689,6 +723,19 @@ decl_error! {
 
         /// Invalid judgment - all winners should have work submissions.
         WinnerShouldHasWorkSubmission,
+
+        /// Bounty contributor not found
+        InvalidContributorActorSpecified,
+
+        /// Bounty oracle not found
+        InvalidOracleActorSpecified,
+
+        /// Member specified is not an entrant worker
+        InvalidEntrantWorkerSpecified,
+
+        /// Invalid Creator Actor for Bounty specified
+        InvalidCreatorActorSpecified,
+
     }
 }
 
@@ -1252,6 +1299,140 @@ decl_module! {
                 Self::remove_bounty(&bounty_id);
             }
         }
+
+        /// Bounty Contributor made a remark
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoBounty::<T>::contributor_remark()]
+        pub fn contributor_remark(
+            origin,
+            contributor: BountyActor<MemberId<T>>,
+            bounty_id: T::BountyId,
+            msg: Vec<u8>,
+        ) {
+            let _ = BountyActorManager::<T>::ensure_bounty_actor_manager(origin, contributor.clone())?;
+            ensure!(
+                BountyContributions::<T>::contains_key(&bounty_id, &contributor),
+                Error::<T>::InvalidContributorActorSpecified,
+                );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::BountyContributorRemarked(contributor, bounty_id, msg));
+        }
+
+        /// Bounty Oracle made a remark
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoBounty::<T>::oracle_remark()]
+        pub fn oracle_remark(
+            origin,
+            oracle: BountyActor<MemberId<T>>,
+            bounty_id: T::BountyId,
+            msg: Vec<u8>,
+        ) {
+
+            let _ = BountyActorManager::<T>::ensure_bounty_actor_manager(
+                origin,
+                oracle.clone(),
+            )?;
+
+            let bounty = Self::ensure_bounty_exists(&bounty_id)?;
+            ensure!(
+                bounty.creation_params.oracle == oracle,
+                Error::<T>::InvalidOracleActorSpecified,
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+
+            Self::deposit_event(RawEvent::BountyOracleRemarked(oracle, bounty_id, msg));
+        }
+
+        /// Bounty Entrant Worker made a remark
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoBounty::<T>::entrant_remark()]
+        pub fn entrant_remark(
+            origin,
+            entrant_id: MemberId<T>,
+            bounty_id: T::BountyId,
+            entry_id: T::EntryId,
+            msg: Vec<u8>,
+        ) {
+
+            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,
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::BountyEntrantRemarked(entrant_id, bounty_id, entry_id, msg));
+        }
+
+        /// Bounty Oracle made a remark
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoBounty::<T>::creator_remark()]
+        pub fn creator_remark(
+            origin,
+            creator: BountyActor<MemberId<T>>,
+            bounty_id: T::BountyId,
+            msg: Vec<u8>,
+        ) {
+
+            let _ = BountyActorManager::<T>::ensure_bounty_actor_manager(
+                origin,
+                creator.clone(),
+            )?;
+
+            let bounty = Self::ensure_bounty_exists(&bounty_id)?;
+            ensure!(
+                bounty.creation_params.creator == creator,
+                Error::<T>::InvalidCreatorActorSpecified,
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::BountyCreatorRemarked(creator, bounty_id, msg));
+        }
+
     }
 }
 

+ 21 - 0
runtime-modules/bounty/src/tests/mocks.rs

@@ -199,6 +199,18 @@ impl crate::WeightInfo for () {
     fn withdraw_work_entrant_funds() -> u64 {
         0
     }
+    fn contributor_remark() -> u64 {
+        0
+    }
+    fn oracle_remark() -> u64 {
+        0
+    }
+    fn entrant_remark() -> u64 {
+        0
+    }
+    fn creator_remark() -> u64 {
+        0
+    }
 }
 
 impl common::membership::MembershipTypes for Test {
@@ -290,6 +302,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl pallet_timestamp::Trait for Test {
@@ -461,6 +476,12 @@ impl council::WeightInfo for CouncilWeightInfo {
     fn funding_request(_: u32) -> Weight {
         0
     }
+    fn councilor_remark() -> Weight {
+        0
+    }
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 parameter_types! {

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

@@ -5,6 +5,7 @@ pub(crate) mod mocks;
 
 use frame_support::storage::{StorageDoubleMap, StorageMap};
 use frame_support::traits::Currency;
+use frame_support::{assert_err, assert_ok};
 use frame_system::RawOrigin;
 use sp_runtime::DispatchError;
 use sp_std::collections::btree_map::BTreeMap;
@@ -27,6 +28,20 @@ use mocks::{
 
 const DEFAULT_WINNER_REWARD: u64 = 10;
 
+#[macro_export]
+macro_rules! to_origin {
+    ($x: tt) => {
+        RawOrigin::Signed($x as u128 + 100).into()
+    };
+}
+
+#[macro_export]
+macro_rules! to_account {
+    ($x: tt) => {
+        $x as u128 + 100
+    };
+}
+
 #[test]
 fn validate_funding_bounty_stage() {
     build_test_externalities().execute_with(|| {
@@ -3418,3 +3433,347 @@ fn withdraw_work_entrant_funds_fails_with_invalid_stage() {
             ));
     });
 }
+
+fn setup_bounty_environment(oracle_id: u64, creator_id: u64, contributor_id: u64, entrant_id: u64) {
+    let initial_balance = 500;
+    let max_amount = 100;
+    let entrant_stake = 37;
+    let work_period = 10;
+
+    increase_account_balance(&to_account!(creator_id), initial_balance);
+    CreateBountyFixture::default()
+        .with_origin(to_origin!(creator_id))
+        .with_max_funding_amount(max_amount)
+        .with_creator_member_id(creator_id)
+        .with_entrant_stake(entrant_stake)
+        .with_oracle_member_id(oracle_id)
+        .with_work_period(work_period)
+        .call_and_assert(Ok(()));
+
+    let bounty_id = 1;
+
+    increase_account_balance(&to_account!(contributor_id), initial_balance);
+    FundBountyFixture::default()
+        .with_origin(to_origin!(contributor_id))
+        .with_bounty_id(bounty_id)
+        .with_amount(max_amount)
+        .with_member_id(contributor_id)
+        .call_and_assert(Ok(()));
+
+    increase_account_balance(&to_account!(entrant_id), initial_balance);
+
+    AnnounceWorkEntryFixture::default()
+        .with_origin(to_origin!(entrant_id))
+        .with_member_id(entrant_id)
+        .with_staking_account_id(to_account!(entrant_id))
+        .with_bounty_id(bounty_id)
+        .call_and_assert(Ok(()));
+}
+
+#[test]
+fn invalid_bounty_creator_cannot_remark() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_creator_id = creator_id + 1;
+        assert_err!(
+            Bounty::creator_remark(
+                to_origin!(invalid_creator_id),
+                BountyActor::Member(invalid_creator_id),
+                1,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::InvalidCreatorActorSpecified,
+        );
+    })
+}
+
+#[test]
+fn creator_cannot_remark_with_invalid_bounty_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_bounty_id = Bounty::bounty_count() as u64 + 1;
+
+        assert_err!(
+            Bounty::creator_remark(
+                to_origin!(creator_id),
+                BountyActor::Member(creator_id),
+                invalid_bounty_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::BountyDoesntExist,
+        );
+    })
+}
+
+#[test]
+fn creator_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let bounty_id = Bounty::bounty_count() as u64;
+
+        assert_ok!(Bounty::creator_remark(
+            to_origin!(creator_id),
+            BountyActor::Member(creator_id),
+            bounty_id,
+            b"test".to_vec(),
+        ));
+    })
+}
+
+#[test]
+fn invalid_bounty_oracle_cannot_remark() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_oracle_id = oracle_id + 1;
+        assert_err!(
+            Bounty::oracle_remark(
+                to_origin!(invalid_oracle_id),
+                BountyActor::Member(invalid_oracle_id),
+                1,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::InvalidOracleActorSpecified,
+        );
+    })
+}
+
+#[test]
+fn oracle_cannot_remark_with_invalid_bounty_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_bounty_id = Bounty::bounty_count() as u64 + 1;
+
+        assert_err!(
+            Bounty::oracle_remark(
+                to_origin!(oracle_id),
+                BountyActor::Member(oracle_id),
+                invalid_bounty_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::BountyDoesntExist,
+        );
+    })
+}
+
+#[test]
+fn oracle_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let bounty_id = Bounty::bounty_count() as u64;
+
+        assert_ok!(Bounty::oracle_remark(
+            to_origin!(oracle_id),
+            BountyActor::Member(oracle_id),
+            bounty_id,
+            b"test".to_vec(),
+        ));
+    })
+}
+
+#[test]
+fn invalid_bounty_contributor_cannot_remark() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_contributor_id = contributor_id + 1;
+        assert_err!(
+            Bounty::contributor_remark(
+                to_origin!(invalid_contributor_id),
+                BountyActor::Member(invalid_contributor_id),
+                1,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::InvalidContributorActorSpecified,
+        );
+    })
+}
+
+#[test]
+fn contributor_cannot_remark_with_invalid_bounty_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_bounty_id = Bounty::bounty_count() as u64 + 1;
+
+        assert_err!(
+            Bounty::contributor_remark(
+                to_origin!(contributor_id),
+                BountyActor::Member(contributor_id),
+                invalid_bounty_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::InvalidContributorActorSpecified,
+        );
+    })
+}
+
+#[test]
+fn contributor_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let bounty_id = Bounty::bounty_count() as u64;
+
+        assert_ok!(Bounty::contributor_remark(
+            to_origin!(contributor_id),
+            BountyActor::Member(contributor_id),
+            bounty_id,
+            b"test".to_vec(),
+        ));
+    })
+}
+
+#[test]
+fn entrant_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let bounty_id = Bounty::bounty_count() as u64;
+        let entry_id = Bounty::entry_count() as u64;
+
+        assert_ok!(Bounty::entrant_remark(
+            to_origin!(entrant_id),
+            entrant_id,
+            bounty_id,
+            entry_id,
+            b"test".to_vec(),
+        ));
+    })
+}
+
+#[test]
+fn entrant_remark_fails_with_invalid_entrant_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let invalid_entrant_id = entrant_id + 1;
+        let bounty_id = Bounty::bounty_count() as u64;
+        let entry_id = Bounty::entry_count() as u64;
+
+        assert_err!(
+            Bounty::entrant_remark(
+                to_origin!(invalid_entrant_id),
+                invalid_entrant_id,
+                bounty_id,
+                entry_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::InvalidEntrantWorkerSpecified
+        );
+    })
+}
+
+#[test]
+fn entrant_remark_fails_with_invalid_bounty_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let entrant_id = entrant_id;
+        let invalid_bounty_id = Bounty::bounty_count() as u64 + 1;
+        let entry_id = Bounty::entry_count() as u64;
+
+        assert_err!(
+            Bounty::entrant_remark(
+                to_origin!(entrant_id),
+                entrant_id,
+                invalid_bounty_id,
+                entry_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::WorkEntryDoesntExist,
+        );
+    })
+}
+
+#[test]
+fn entrant_remark_fails_with_invalid_entry_id() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let (oracle_id, creator_id, contributor_id, entrant_id) = (1, 2, 3, 4);
+        setup_bounty_environment(oracle_id, creator_id, contributor_id, entrant_id);
+        run_to_block(starting_block + 1);
+
+        let entrant_id = entrant_id;
+        let bounty_id = Bounty::bounty_count() as u64;
+        let invalid_entry_id = Bounty::entry_count() as u64 + 1;
+
+        assert_err!(
+            Bounty::entrant_remark(
+                to_origin!(entrant_id),
+                entrant_id,
+                bounty_id,
+                invalid_entry_id,
+                b"test".to_vec(),
+            ),
+            crate::Error::<Test>::WorkEntryDoesntExist,
+        );
+    })
+}

+ 64 - 0
runtime-modules/content/src/lib.rs

@@ -1890,6 +1890,64 @@ decl_module! {
             // Trigger event
             Self::deposit_event(RawEvent::NftBought(video_id, participant_id));
         }
+
+        /// Channel owner remark
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn channel_owner_remark(origin, actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>, channel_id: T::ChannelId, msg: Vec<u8>) {
+            let sender = ensure_signed(origin)?;
+            let channel = Self::ensure_channel_exists(&channel_id)?;
+            ensure_actor_auth_success::<T>(&sender, &actor)?;
+            ensure_actor_is_channel_owner::<T>(&actor, &channel.owner)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::ChannelOwnerRemarked(actor, channel_id, msg));
+        }
+
+        /// Channel collaborator remark
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn channel_collaborator_remark(origin, actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>, channel_id: T::ChannelId, msg: Vec<u8>) {
+            let sender = ensure_signed(origin)?;
+            let channel = Self::ensure_channel_exists(&channel_id)?;
+            ensure_actor_authorized_to_update_channel_assets::<T>(&sender, &actor, &channel)?;
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::ChannelCollaboratorRemarked(actor, channel_id, msg));
+        }
+
+        /// Channel moderator remark
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn channel_moderator_remark(origin, actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>, channel_id: T::ChannelId, msg: Vec<u8>) {
+            let sender = ensure_signed(origin)?;
+            let channel = Self::ensure_channel_exists(&channel_id)?;
+            ensure_actor_auth_success::<T>(&sender, &actor)?;
+            ensure_actor_is_moderator::<T>(&actor, &channel.moderators)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::ChannelModeratorRemarked(actor, channel_id, msg));
+        }
+
+        /// NFT owner remark
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn nft_owner_remark(origin, actor: ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>, video_id: T::VideoId, msg: Vec<u8>) {
+            let video = Self::ensure_video_exists(&video_id)?;
+            let nft = video.ensure_nft_is_issued::<T>()?;
+            ensure_actor_authorized_to_manage_nft::<T>(origin, &actor, &nft.owner, video.in_channel)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::NftOwnerRemarked(actor, video_id, msg));
+        }
+
     }
 }
 
@@ -2246,5 +2304,11 @@ decl_event!(
         NftBought(VideoId, MemberId),
         BuyNowCanceled(VideoId, ContentActor),
         NftSlingedBackToTheOriginalArtist(VideoId, ContentActor),
+
+        /// Metaprotocols related event
+        ChannelOwnerRemarked(ContentActor, ChannelId, Vec<u8>),
+        ChannelCollaboratorRemarked(ContentActor, ChannelId, Vec<u8>),
+        ChannelModeratorRemarked(ContentActor, ChannelId, Vec<u8>),
+        NftOwnerRemarked(ContentActor, VideoId, Vec<u8>),
     }
 );

+ 505 - 0
runtime-modules/content/src/tests/metaprotocol.rs

@@ -0,0 +1,505 @@
+#![cfg(test)]
+use super::curators;
+use super::fixtures::*;
+use super::mock::*;
+use crate::*;
+use frame_support::{assert_err, assert_ok};
+
+#[test]
+fn successful_collaborator_remark() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_ok!(Content::channel_collaborator_remark(
+            Origin::signed(COLLABORATOR_MEMBER_ACCOUNT_ID),
+            ContentActor::Member(COLLABORATOR_MEMBER_ID),
+            channel_id,
+            msg
+        ));
+    })
+}
+
+#[test]
+fn unsuccessful_collaborator_remark_with_invalid_channel_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let invalid_channel_id = Content::next_channel_id();
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_collaborator_remark(
+                Origin::signed(COLLABORATOR_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(COLLABORATOR_MEMBER_ID),
+                invalid_channel_id,
+                msg
+            ),
+            Error::<Test>::ChannelDoesNotExist
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_collaborator_remark_with_invalid_account_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_collaborator_remark(
+                Origin::signed(UNAUTHORIZED_COLLABORATOR_MEMBER_ACCOUNT_ID + 1),
+                ContentActor::Member(COLLABORATOR_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_collaborator_remark_with_member_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_collaborator_remark(
+                Origin::signed(COLLABORATOR_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_COLLABORATOR_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_collaborator_remark_by_non_collaborator() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_collaborator_remark(
+                Origin::signed(UNAUTHORIZED_COLLABORATOR_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_COLLABORATOR_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::ActorNotAuthorized,
+        );
+    })
+}
+
+#[test]
+fn successful_moderator_remark() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_ok!(Content::channel_moderator_remark(
+            Origin::signed(DEFAULT_MODERATOR_ACCOUNT_ID),
+            ContentActor::Member(DEFAULT_MODERATOR_ID),
+            channel_id,
+            msg
+        ));
+    })
+}
+
+#[test]
+fn unsuccessful_moderator_remark_with_invalid_channel_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let invalid_channel_id = Content::next_channel_id();
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_moderator_remark(
+                Origin::signed(DEFAULT_MODERATOR_ACCOUNT_ID),
+                ContentActor::Member(DEFAULT_MODERATOR_ID),
+                invalid_channel_id,
+                msg
+            ),
+            Error::<Test>::ChannelDoesNotExist
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_moderator_remark_with_invalid_member_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_moderator_remark(
+                Origin::signed(DEFAULT_MODERATOR_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_MODERATOR_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_moderator_remark_with_invalid_account_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_moderator_remark(
+                Origin::signed(UNAUTHORIZED_MODERATOR_ACCOUNT_ID),
+                ContentActor::Member(DEFAULT_MODERATOR_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_moderator_remark_by_non_moderator() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_moderator_remark(
+                Origin::signed(UNAUTHORIZED_MODERATOR_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_MODERATOR_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::ActorNotAuthorized
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_owner_remark_with_invalid_channel_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let invalid_channel_id = Content::next_channel_id();
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_owner_remark(
+                Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(DEFAULT_MEMBER_ID),
+                invalid_channel_id,
+                msg
+            ),
+            Error::<Test>::ChannelDoesNotExist,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_owner_remark_with_invalid_account_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_owner_remark(
+                Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(DEFAULT_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_owner_remark_by_non_owner() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_owner_remark(
+                Origin::signed(UNAUTHORIZED_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::ActorNotAuthorized,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_owner_remark_with_invalid_member_id() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::channel_owner_remark(
+                Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(UNAUTHORIZED_MEMBER_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::MemberAuthFailed,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_owner_remark_with_invalid_curator() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_CURATOR_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_curator_owned_channel();
+
+        let channel_id = Content::next_channel_id() - 1;
+        let msg = b"test".to_vec();
+        let invalid_curator_group_id = curators::add_curator_to_new_group(UNAUTHORIZED_CURATOR_ID);
+
+        assert_err!(
+            Content::channel_owner_remark(
+                Origin::signed(UNAUTHORIZED_CURATOR_ACCOUNT_ID),
+                ContentActor::Curator(invalid_curator_group_id, UNAUTHORIZED_CURATOR_ACCOUNT_ID),
+                channel_id,
+                msg
+            ),
+            Error::<Test>::CuratorAuthFailed,
+        );
+    })
+}
+
+#[test]
+fn unsuccessful_nft_owner_remark_with_nft_not_issued() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        create_initial_storage_buckets_helper();
+        increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+        create_default_member_owned_channel_with_video();
+
+        let video_id = Content::next_video_id() - 1;
+        let msg = b"test".to_vec();
+
+        assert_err!(
+            Content::nft_owner_remark(
+                Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+                ContentActor::Member(DEFAULT_MEMBER_ID),
+                video_id,
+                msg
+            ),
+            Error::<Test>::NftDoesNotExist,
+        );
+    })
+}
+
+fn issue_and_sell_nft() {
+    let video_id = NextVideoId::<Test>::get();
+
+    create_initial_storage_buckets_helper();
+    increase_account_balance_helper(DEFAULT_MEMBER_ACCOUNT_ID, INITIAL_BALANCE);
+    create_default_member_owned_channel_with_video();
+
+    // Issue nft
+    assert_ok!(Content::issue_nft(
+        Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+        ContentActor::Member(DEFAULT_MEMBER_ID),
+        video_id,
+        NftIssuanceParameters::<Test>::default(),
+    ));
+
+    // deposit balance to second member
+    increase_account_balance_helper(SECOND_MEMBER_ACCOUNT_ID, DEFAULT_NFT_PRICE);
+
+    // Sell nft
+    assert_ok!(Content::sell_nft(
+        Origin::signed(DEFAULT_MEMBER_ACCOUNT_ID),
+        video_id,
+        ContentActor::Member(DEFAULT_MEMBER_ID),
+        DEFAULT_NFT_PRICE,
+    ));
+
+    // Buy nft
+    assert_ok!(Content::buy_nft(
+        Origin::signed(SECOND_MEMBER_ACCOUNT_ID),
+        video_id,
+        SECOND_MEMBER_ID,
+    ));
+}
+
+// TODO RHODES: enable after open auction fix
+// #[test]
+// fn successful_nft_owner_remark() {
+//     with_default_mock_builder(|| {
+//         run_to_block(1);
+
+//         let video_id = Content::next_video_id();
+//         let msg = b"test".to_vec();
+
+//         issue_and_sell_nft();
+
+//         assert_ok!(Content::nft_owner_remark(
+//             Origin::signed(SECOND_MEMBER_ACCOUNT_ID),
+//             ContentActor::Member(SECOND_MEMBER_ID),
+//             video_id,
+//             msg
+//         ));
+//     })
+// }
+
+// #[test]
+// fn unsuccessful_nft_owner_with_invalid_video_id() {
+//     with_default_mock_builder(|| {
+//         run_to_block(1);
+
+//         let invalid_video_id = Content::next_video_id() + 1;
+//         let msg = b"test".to_vec();
+
+//         issue_and_sell_nft();
+
+//         assert_err!(
+//             Content::nft_owner_remark(
+//                 Origin::signed(SECOND_MEMBER_ACCOUNT_ID),
+//                 ContentActor::Member(SECOND_MEMBER_ID),
+//                 invalid_video_id,
+//                 msg
+//             ),
+//             Error::<Test>::VideoDoesNotExist
+//         );
+//     })
+// }
+
+// #[test]
+// fn unsuccessful_nft_owner_by_non_authorized_actor() {
+//     with_default_mock_builder(|| {
+//         run_to_block(1);
+
+//         let video_id = Content::next_video_id();
+//         let msg = b"test".to_vec();
+
+//         issue_and_sell_nft();
+
+//         assert_err!(
+//             Content::nft_owner_remark(
+//                 Origin::signed(DEFAULT_MODERATOR_ACCOUNT_ID),
+//                 ContentActor::Member(DEFAULT_MODERATOR_ID),
+//                 video_id,
+//                 msg
+//             ),
+//             Error::<Test>::ActorNotAuthorized
+//         );
+//     })
+// }
+
+// #[test]
+// fn unsuccessful_nft_owner_with_invalid_acount() {
+//     with_default_mock_builder(|| {
+//         run_to_block(1);
+
+//         let video_id = Content::next_video_id();
+//         let msg = b"test".to_vec();
+
+//         issue_and_sell_nft();
+
+//         assert_err!(
+//             Content::nft_owner_remark(
+//                 Origin::signed(DEFAULT_MODERATOR_ACCOUNT_ID),
+//                 ContentActor::Member(SECOND_MEMBER_ID),
+//                 video_id,
+//                 msg
+//             ),
+//             Error::<Test>::MemberAuthFailed
+//         );
+//     })
+// }

+ 137 - 63
runtime-modules/content/src/tests/mock.rs

@@ -315,69 +315,8 @@ impl storage::Trait for Test {
     type ContentId = u64;
     type MaxDataObjectSize = MaxDataObjectSize;
 
-    fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != STORAGE_WG_LEADER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_storage_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_storage_worker_exists(worker_id: &u64) -> DispatchResult {
-        let allowed_storage_providers =
-            vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
-
-        if !allowed_storage_providers.contains(worker_id) {
-            Err(DispatchError::Other("Invalid worker"))
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DISTRIBUTION_WG_LEADER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_worker_exists(worker_id: &u64) -> DispatchResult {
-        let allowed_providers = vec![
-            DEFAULT_DISTRIBUTION_PROVIDER_ID,
-            ANOTHER_DISTRIBUTION_PROVIDER_ID,
-        ];
-
-        if !allowed_providers.contains(worker_id) {
-            Err(DispatchError::Other("Invalid worker"))
-        } else {
-            Ok(())
-        }
-    }
+    type StorageWorkingGroup = StorageWG;
+    type DistributionWorkingGroup = DistributionWG;
 }
 
 // Anyone can upload and delete without restriction
@@ -672,3 +611,138 @@ impl LockComparator<u64> for Test {
         }
     }
 }
+
+// storage & distribution wg auth
+// working group integration
+pub struct StorageWG;
+pub struct DistributionWG;
+
+impl common::working_group::WorkingGroupAuthenticator<Test> for StorageWG {
+    fn ensure_worker_origin(
+        origin: <Test as frame_system::Trait>::Origin,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn ensure_leader_origin(origin: <Test as frame_system::Trait>::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == STORAGE_WG_LEADER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn get_leader_member_id() -> Option<<Test as common::membership::MembershipTypes>::MemberId> {
+        unimplemented!()
+    }
+
+    fn is_leader_account_id(_account_id: &<Test as frame_system::Trait>::AccountId) -> bool {
+        unimplemented!()
+    }
+
+    fn is_worker_account_id(
+        _account_id: &<Test as frame_system::Trait>::AccountId,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> bool {
+        unimplemented!()
+    }
+
+    fn worker_exists(worker_id: &<Test as common::membership::MembershipTypes>::ActorId) -> bool {
+        Self::ensure_worker_exists(worker_id).is_ok()
+    }
+
+    fn ensure_worker_exists(
+        worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let allowed_storage_providers =
+            vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
+        ensure!(
+            allowed_storage_providers.contains(worker_id),
+            DispatchError::Other("Invailid worker"),
+        );
+        Ok(())
+    }
+}
+
+impl common::working_group::WorkingGroupAuthenticator<Test> for DistributionWG {
+    fn ensure_worker_origin(
+        origin: <Test as frame_system::Trait>::Origin,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn ensure_leader_origin(origin: <Test as frame_system::Trait>::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DISTRIBUTION_WG_LEADER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn get_leader_member_id() -> Option<<Test as common::membership::MembershipTypes>::MemberId> {
+        unimplemented!()
+    }
+
+    fn is_leader_account_id(_account_id: &<Test as frame_system::Trait>::AccountId) -> bool {
+        unimplemented!()
+    }
+
+    fn is_worker_account_id(
+        _account_id: &<Test as frame_system::Trait>::AccountId,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> bool {
+        unimplemented!()
+    }
+
+    fn worker_exists(worker_id: &<Test as common::membership::MembershipTypes>::ActorId) -> bool {
+        Self::ensure_worker_exists(worker_id).is_ok()
+    }
+
+    fn ensure_worker_exists(
+        worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let allowed_storage_providers = vec![
+            DEFAULT_DISTRIBUTION_PROVIDER_ID,
+            ANOTHER_DISTRIBUTION_PROVIDER_ID,
+        ];
+        ensure!(
+            allowed_storage_providers.contains(worker_id),
+            DispatchError::Other("Invailid worker"),
+        );
+        Ok(())
+    }
+}
+
+impl common::working_group::WorkingGroupBudgetHandler<Test> for StorageWG {
+    fn get_budget() -> u64 {
+        unimplemented!()
+    }
+
+    fn set_budget(_new_value: u64) {
+        unimplemented!()
+    }
+}
+
+impl common::working_group::WorkingGroupBudgetHandler<Test> for DistributionWG {
+    fn get_budget() -> u64 {
+        unimplemented!()
+    }
+
+    fn set_budget(_new_value: u64) {
+        unimplemented!()
+    }
+}

+ 1 - 0
runtime-modules/content/src/tests/mod.rs

@@ -4,6 +4,7 @@ mod channels;
 mod curators;
 mod fixtures;
 mod merkle;
+mod metaprotocol;
 mod mock;
 // TODO RHODES: enable after open auction fix
 //mod nft;

+ 73 - 1
runtime-modules/council/src/benchmarking.rs

@@ -660,7 +660,7 @@ benchmarks! {
             RawEvent::NewCandidate(
                 member_id,
                 account_id.clone(),
-                account_id.clone(),
+                account_id,
                 T::MinCandidateStake::get()
             ).into()
         );
@@ -735,6 +735,62 @@ benchmarks! {
         );
         assert_last_event::<T>(RawEvent::BudgetRefillPlanned(One::one()).into());
     }
+
+    candidate_remark {
+        let msg = b"test".to_vec();
+        let (account_id, member_id) = start_period_announce_candidacy::<T>(0);
+    }: _(RawOrigin::Signed(account_id.clone()), member_id, msg.clone())
+    verify {
+        assert_last_event::<T>(RawEvent::CandidateRemarked(member_id, msg).into());
+    }
+
+    councilor_remark {
+        // periods easier to calculate
+        let current_block_number = Zero::zero();
+        System::<T>::set_block_number(current_block_number);
+        assert_eq!(System::<T>::block_number(), current_block_number, "Block number not updated");
+
+        // Worst case we have a council elected
+        let (accounts_id, candidates_id) = start_period_announce_multiple_candidates::<T>(
+            T::CouncilSize::get().try_into().unwrap()
+        );
+
+        let winners = candidates_id.iter().map(|candidate_id| {
+            let option_id: T::MemberId = *candidate_id;
+            OptionResult {
+                option_id: option_id.into(),
+                vote_power: Zero::zero(),
+            }
+        }).collect::<Vec<_>>();
+
+        Council::<T>::end_announcement_period(
+            CouncilStageAnnouncing {
+                candidates_count: T::CouncilSize::get(),
+            }
+        );
+
+        Council::<T>::end_election_period(&winners[..]);
+
+        let council = candidates_id.iter().enumerate().map(|(idx, member_id)|
+            CouncilMember{
+                staking_account_id: accounts_id[idx].clone(),
+                reward_account_id: accounts_id[idx].clone(),
+                membership_id: member_id.clone(),
+                stake: T::MinCandidateStake::get(),
+                last_payment_block: Zero::zero(),
+                unpaid_reward: Zero::zero(),
+            }).collect::<Vec<_>>();
+
+        assert_eq!(
+            Council::<T>::council_members(),
+            council,
+            "Council not updated"
+        );
+        let msg = b"test".to_vec();
+    }: _(RawOrigin::Signed(accounts_id[0].clone()), candidates_id[0], msg.clone())
+    verify {
+        assert_last_event::<T>(RawEvent::CouncilorRemarked(candidates_id[0], msg).into());
+    }
 }
 
 #[cfg(test)]
@@ -825,4 +881,20 @@ mod tests {
             assert_ok!(test_benchmark_funding_request::<Runtime>());
         })
     }
+
+    #[test]
+    fn test_councilor_remark() {
+        let config = default_genesis_config();
+        build_test_externalities(config).execute_with(|| {
+            assert_ok!(test_benchmark_councilor_remark::<Runtime>());
+        })
+    }
+
+    #[test]
+    fn test_candidate_remark() {
+        let config = default_genesis_config();
+        build_test_externalities(config).execute_with(|| {
+            assert_ok!(test_benchmark_candidate_remark::<Runtime>());
+        })
+    }
 }

+ 64 - 1
runtime-modules/council/src/lib.rs

@@ -217,6 +217,8 @@ pub trait WeightInfo {
     fn withdraw_candidacy() -> Weight;
     fn set_budget() -> Weight;
     fn plan_budget_refill() -> Weight;
+    fn councilor_remark() -> Weight;
+    fn candidate_remark() -> Weight;
 }
 
 type CouncilWeightInfo<T> = <T as Trait>::WeightInfo;
@@ -401,6 +403,12 @@ decl_event! {
 
         /// Request has been funded
         RequestFunded(AccountId, Balance),
+
+        /// Councilor remark message
+        CouncilorRemarked(MemberId, Vec<u8>),
+
+        /// Candidate remark message
+        CandidateRemarked(MemberId, Vec<u8>),
     }
 }
 
@@ -464,7 +472,10 @@ decl_error! {
         RepeatedFundRequestAccount,
 
         /// Funding requests without recieving accounts
-        EmptyFundingRequests
+        EmptyFundingRequests,
+
+        /// Candidate id not found
+        CandidateDoesNotExist,
     }
 }
 
@@ -855,6 +866,58 @@ decl_module! {
                 Self::deposit_event(RawEvent::RequestFunded(account, amount));
             }
         }
+
+        /// Councilor makes a remark message
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = CouncilWeightInfo::<T>::councilor_remark()]
+        pub fn councilor_remark(
+            origin,
+            councilor_id: T::MemberId,
+            msg: Vec<u8>,
+        ) {
+            Self::ensure_member_consulate(origin, councilor_id)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::CouncilorRemarked(councilor_id, msg));
+        }
+
+        /// Candidate makes a remark message
+        ///
+        /// # <weight>
+        ///
+        /// ## weight
+        /// `O (1)`
+        /// - db:
+        ///    - `O(1)` doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = CouncilWeightInfo::<T>::candidate_remark()]
+        pub fn candidate_remark(
+            origin,
+            candidate_id: T::MemberId,
+            msg: Vec<u8>,
+        ) {
+            EnsureChecks::<T>::ensure_user_membership(origin, &candidate_id)?;
+            ensure!(
+                Self::is_valid_candidate_id(&candidate_id),
+                Error::<T>::CandidateDoesNotExist,
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::CandidateRemarked(candidate_id, msg));
+        }
     }
 }
 

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

@@ -173,6 +173,12 @@ impl WeightInfo for () {
     fn funding_request(_: u32) -> Weight {
         0
     }
+    fn councilor_remark() -> Weight {
+        0
+    }
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 /////////////////// Module implementation //////////////////////////////////////
@@ -427,6 +433,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl balances::Trait for Runtime {
@@ -675,6 +684,23 @@ pub fn default_genesis_config() -> GenesisConfig<Runtime> {
     }
 }
 
+pub fn augmented_genesis_config() -> GenesisConfig<Runtime> {
+    GenesisConfig::<Runtime> {
+        stage: CouncilStageUpdate::default(),
+        council_members: vec![CouncilMemberOf::<Runtime> {
+            membership_id: 1,
+            ..Default::default()
+        }],
+        candidates: vec![(2, Default::default())],
+        announcement_period_nr: 0,
+        budget: 0,
+        next_reward_payments: 0,
+        next_budget_refill: <Runtime as Trait>::BudgetRefillPeriod::get(),
+        budget_increment: 1,
+        councilor_reward: 100,
+    }
+}
+
 pub fn build_test_externalities(config: GenesisConfig<Runtime>) -> sp_io::TestExternalities {
     let mut t = frame_system::GenesisConfig::default()
         .build_storage::<Runtime>()

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

@@ -8,7 +8,7 @@ use crate::mock::*;
 use common::council::CouncilBudgetManager;
 use common::council::CouncilOriginValidator;
 use frame_support::traits::Currency;
-use frame_support::StorageValue;
+use frame_support::{assert_err, assert_ok, StorageValue};
 use frame_system::RawOrigin;
 use staking_handler::StakingHandler;
 
@@ -1805,3 +1805,85 @@ fn test_council_budget_manager_works_correctlyl() {
         );
     });
 }
+
+#[test]
+fn councilor_remark_successful() {
+    let config = augmented_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let account_id = 1;
+        let member_id = 1;
+        let msg = b"test".to_vec();
+        let origin = RawOrigin::Signed(account_id.clone());
+
+        assert_ok!(Council::councilor_remark(origin.into(), member_id, msg));
+    });
+}
+
+#[test]
+fn councilor_remark_unsuccessful_with_invalid_origin() {
+    let config = augmented_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let account_id = 21;
+        let member_id = 1;
+        let msg = b"test".to_vec();
+        let origin = RawOrigin::Signed(account_id.clone());
+
+        assert_err!(
+            Council::councilor_remark(origin.into(), member_id, msg),
+            Error::<Runtime>::MemberIdNotMatchAccount,
+        );
+    });
+}
+
+#[test]
+fn councilor_remark_unsuccessful_with_invalid_councilor() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let account_id = 2;
+        let member_id = 2;
+        let msg = b"test".to_vec();
+        let origin = RawOrigin::Signed(account_id.clone());
+
+        assert_err!(
+            Council::councilor_remark(origin.into(), member_id, msg),
+            Error::<Runtime>::NotCouncilor,
+        );
+    });
+}
+
+#[test]
+fn candidate_remark_unsuccessful_with_invalid_candidate() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let account_id = 2;
+        let member_id = 2;
+        let msg = b"test".to_vec();
+        let origin = RawOrigin::Signed(account_id.clone());
+
+        assert_err!(
+            Council::candidate_remark(origin.into(), member_id, msg),
+            Error::<Runtime>::CandidateDoesNotExist,
+        );
+    });
+}
+
+#[test]
+fn candidate_remark_unsuccessful_with_invalid_origin() {
+    let config = default_genesis_config();
+
+    build_test_externalities(config).execute_with(|| {
+        let account_id = 21;
+        let member_id = 2;
+        let msg = b"test".to_vec();
+        let origin = RawOrigin::Signed(account_id.clone());
+
+        assert_err!(
+            Council::candidate_remark(origin.into(), member_id, msg),
+            Error::<Runtime>::MemberIdNotMatchAccount,
+        );
+    });
+}

+ 9 - 0
runtime-modules/forum/src/mock.rs

@@ -224,6 +224,12 @@ impl working_group::WeightInfo for Weights {
     fn leave_role(_: u32) -> u64 {
         unimplemented!()
     }
+    fn lead_remark() -> u64 {
+        unimplemented!()
+    }
+    fn worker_remark() -> u64 {
+        unimplemented!()
+    }
 }
 
 impl membership::WeightInfo for Weights {
@@ -281,6 +287,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 pub const WORKING_GROUP_BUDGET: u64 = 100;

+ 17 - 0
runtime-modules/membership/src/benchmarking.rs

@@ -16,6 +16,7 @@ use sp_arithmetic::traits::One;
 use sp_arithmetic::Perbill;
 use sp_runtime::traits::Bounded;
 use sp_std::prelude::*;
+use sp_std::vec;
 
 /// Balance alias for `balances` module.
 pub type BalanceOf<T> = <T as balances::Trait>::Balance;
@@ -676,6 +677,15 @@ benchmarks! {
 
         assert_last_event::<T>(RawEvent::StakingAccountRemoved(account_id, member_id).into());
     }
+
+    member_remark{
+        let msg = b"test".to_vec();
+        let member_id = 0;
+        let (account_id, member_id) = member_funded_account::<T>("member", member_id);
+    }: _ (RawOrigin::Signed(account_id.clone()), member_id, msg.clone())
+        verify {
+            assert_last_event::<T>(RawEvent::MemberRemarked(member_id, msg).into());
+        }
 }
 
 #[cfg(test)]
@@ -812,4 +822,11 @@ mod tests {
             assert_ok!(test_benchmark_update_profile_verification::<Test>());
         });
     }
+
+    #[test]
+    fn member_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_member_remark::<Test>());
+        });
+    }
 }

+ 27 - 0
runtime-modules/membership/src/lib.rs

@@ -94,6 +94,7 @@ pub trait WeightInfo {
     fn add_staking_account_candidate() -> Weight;
     fn confirm_staking_account() -> Weight;
     fn remove_staking_account() -> Weight;
+    fn member_remark() -> Weight;
 }
 
 pub trait Trait:
@@ -144,6 +145,7 @@ pub trait Trait:
 pub(crate) const DEFAULT_MEMBER_INVITES_COUNT: u32 = 5;
 
 /// Public membership profile alias.
+
 pub type Membership<T> = MembershipObject<<T as frame_system::Trait>::AccountId>;
 
 #[derive(Encode, PartialEq, Decode, Debug, Default)]
@@ -371,6 +373,7 @@ decl_event! {
         StakingAccountAdded(AccountId, MemberId),
         StakingAccountRemoved(AccountId, MemberId),
         StakingAccountConfirmed(AccountId, MemberId),
+        MemberRemarked(MemberId, Vec<u8>),
     }
 }
 
@@ -987,6 +990,27 @@ decl_module! {
 
             Self::deposit_event(RawEvent::StakingAccountConfirmed(staking_account_id, member_id));
         }
+
+        /// Member makes a remark
+        ///
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (1)`
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoMembership::<T>::member_remark()]
+        pub fn member_remark(origin, member_id: T::MemberId, msg: Vec<u8>) {
+            let sender = ensure_signed(origin)?;
+            Self::ensure_is_controller_account_for_member(&member_id, &sender)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::MemberRemarked(member_id, msg));
+        }
     }
 }
 
@@ -1265,4 +1289,7 @@ impl WeightInfo for () {
     fn remove_staking_account() -> Weight {
         0
     }
+    fn member_remark() -> Weight {
+        0
+    }
 }

+ 8 - 0
runtime-modules/membership/src/tests/mock.rs

@@ -228,6 +228,14 @@ impl working_group::WeightInfo for Weights {
     fn leave_role(_: u32) -> u64 {
         unimplemented!()
     }
+
+    fn lead_remark() -> Weight {
+        unimplemented!()
+    }
+
+    fn worker_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 // impl WeightInfo for () {

+ 51 - 0
runtime-modules/membership/src/tests/mod.rs

@@ -1118,3 +1118,54 @@ fn membership_info_provider_controller_account_id_succeeds() {
         assert_eq!(validation_result, Ok(ALICE_ACCOUNT_ID));
     });
 }
+
+#[test]
+fn unsuccessful_member_remark_with_non_existent_member_profile() {
+    let initial_members = [(ALICE_MEMBER_ID, ALICE_ACCOUNT_ID)];
+
+    build_test_externalities_with_initial_members(initial_members.to_vec()).execute_with(|| {
+        let msg = b"test".to_vec();
+        let validation_result =
+            Membership::member_remark(RawOrigin::Signed(BOB_ACCOUNT_ID).into(), BOB_MEMBER_ID, msg);
+
+        assert_eq!(
+            validation_result,
+            Err(Error::<Test>::MemberProfileNotFound.into())
+        );
+    });
+}
+
+#[test]
+fn unsuccessful_member_remark_with_invalid_origin() {
+    let initial_members = [(ALICE_MEMBER_ID, ALICE_ACCOUNT_ID)];
+
+    build_test_externalities_with_initial_members(initial_members.to_vec()).execute_with(|| {
+        let msg = b"test".to_vec();
+        let validation_result = Membership::member_remark(
+            RawOrigin::Signed(BOB_ACCOUNT_ID).into(),
+            ALICE_MEMBER_ID,
+            msg,
+        );
+
+        assert_eq!(
+            validation_result,
+            Err(Error::<Test>::ControllerAccountRequired.into())
+        );
+    });
+}
+
+#[test]
+fn successful_member_remark() {
+    let initial_members = [(ALICE_MEMBER_ID, ALICE_ACCOUNT_ID)];
+
+    build_test_externalities_with_initial_members(initial_members.to_vec()).execute_with(|| {
+        let msg = b"test".to_vec();
+        let validation_result = Membership::member_remark(
+            RawOrigin::Signed(ALICE_ACCOUNT_ID).into(),
+            ALICE_MEMBER_ID,
+            msg,
+        );
+
+        assert_eq!(validation_result, Ok(()),);
+    });
+}

+ 19 - 0
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -136,6 +136,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl membership::Trait for Test {
@@ -288,6 +291,10 @@ impl proposals_engine::WeightInfo for MockProposalsEngineWeight {
     fn cancel_active_and_pending_proposals(_: u32) -> u64 {
         0
     }
+
+    fn proposer_remark() -> u64 {
+        0
+    }
 }
 
 impl Default for crate::Call<Test> {
@@ -469,6 +476,12 @@ impl working_group::WeightInfo for WorkingGroupWeightInfo {
     fn leave_role(_: u32) -> Weight {
         0
     }
+    fn lead_remark() -> Weight {
+        0
+    }
+    fn worker_remark() -> Weight {
+        0
+    }
 }
 
 impl working_group::Trait<StorageWorkingGroupInstance> for Test {
@@ -706,6 +719,12 @@ impl council::WeightInfo for CouncilWeightInfo {
     fn funding_request(_: u32) -> Weight {
         0
     }
+    fn councilor_remark() -> Weight {
+        0
+    }
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 parameter_types! {

+ 9 - 0
runtime-modules/proposals/discussion/src/tests/mock.rs

@@ -140,6 +140,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl balances::Trait for Test {
@@ -374,6 +377,12 @@ impl council::WeightInfo for CouncilWeightInfo {
     fn funding_request(_: u32) -> Weight {
         0
     }
+    fn councilor_remark() -> Weight {
+        0
+    }
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 pub struct CouncilMock;

+ 17 - 6
runtime-modules/proposals/engine/src/benchmarking.rs

@@ -400,15 +400,9 @@ benchmarks! {
     }
 
     cancel_proposal {
-        let i in 1 .. T::MaxLocks::get();
 
         let (account_id, member_id, proposal_id) = create_proposal::<T>(0, 1, 0, 0);
 
-        for lock_number in 1 .. i {
-            let (locked_account_id, _) = member_funded_account::<T>("locked_member", lock_number);
-            <T as Trait>::StakingHandler::set_stake(&locked_account_id, One::one()).unwrap();
-        }
-
     }: _ (RawOrigin::Signed(account_id.clone()), member_id, proposal_id)
     verify {
         assert!(!Proposals::<T>::contains_key(proposal_id), "Proposal still in storage");
@@ -455,6 +449,16 @@ benchmarks! {
         );
     }
 
+    proposer_remark {
+        let msg = b"test".to_vec();
+        let (proposer_account_id, proposer_id, proposal_id) = create_proposal::<T>(0, 1, 0, 0);
+    }: _ (RawOrigin::Signed(proposer_account_id.clone()), proposal_id, proposer_id, msg.clone())
+    verify {
+        assert_last_event::<T>(
+            RawEvent::ProposerRemarked(proposer_id, proposal_id, msg).into()
+        );
+    }
+
     // We use that branches for decode failing, failing and passing are very similar
     // without any different DB access in each. To use the failing/passing branch
     // we need to include the EncodeProposal trait from codex which depends on engine
@@ -822,4 +826,11 @@ mod tests {
             assert_ok!(test_benchmark_cancel_active_and_pending_proposals::<Test>());
         });
     }
+
+    #[test]
+    fn test_proposer_remark() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_proposer_remark::<Test>());
+        });
+    }
 }

+ 37 - 0
runtime-modules/proposals/engine/src/lib.rs

@@ -169,6 +169,7 @@ pub trait WeightInfo {
     fn on_initialize_rejected(i: u32) -> Weight;
     fn on_initialize_slashed(i: u32) -> Weight;
     fn cancel_active_and_pending_proposals(i: u32) -> Weight;
+    fn proposer_remark() -> Weight;
 }
 
 type WeightInfoEngine<T> = <T as Trait>::WeightInfo;
@@ -296,6 +297,12 @@ decl_event!(
         /// - Member Id of the proposer
         /// - Id of the proposal
         ProposalCancelled(MemberId, ProposalId),
+
+        /// Emits on proposer making a remark
+        /// - proposer id
+        /// - proposal id
+        /// - message
+        ProposerRemarked(MemberId, ProposalId, Vec<u8>),
     }
 );
 
@@ -551,6 +558,36 @@ decl_module! {
 
             Self::finalize_proposal(proposal_id, proposal, ProposalDecision::Vetoed);
         }
+
+        /// Proposer Remark
+        ///
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (1)` doesn't depend on the state or parameters
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoEngine::<T>::proposer_remark()]
+        pub fn proposer_remark(
+            origin,
+            proposal_id: T::ProposalId,
+            proposer_id: MemberId<T>,
+            msg: Vec<u8>,
+        ) {
+            T::ProposerOriginValidator::ensure_member_controller_account_origin(origin, proposer_id)?;
+
+            ensure!(<Proposals<T>>::contains_key(proposal_id), Error::<T>::ProposalNotFound);
+            let proposal = Self::proposals(proposal_id);
+
+            ensure!(proposer_id == proposal.proposer_id, Error::<T>::NotAuthor);
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::ProposerRemarked(proposer_id, proposal_id, msg));
+        }
     }
 }
 

+ 15 - 0
runtime-modules/proposals/engine/src/tests/mock/mod.rs

@@ -248,6 +248,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl membership::Trait for Test {
@@ -373,6 +376,10 @@ impl crate::WeightInfo for () {
     fn cancel_active_and_pending_proposals(_: u32) -> u64 {
         0
     }
+
+    fn proposer_remark() -> Weight {
+        0
+    }
 }
 
 impl ProposalObserver<Test> for () {
@@ -541,6 +548,14 @@ impl council::WeightInfo for CouncilWeightInfo {
     fn funding_request(_: u32) -> Weight {
         0
     }
+
+    fn councilor_remark() -> Weight {
+        0
+    }
+
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 impl LockComparator<<Test as balances::Trait>::Balance> for Test {

+ 3 - 0
runtime-modules/referendum/src/mock.rs

@@ -228,6 +228,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 parameter_types! {

+ 105 - 61
runtime-modules/storage/src/lib.rs

@@ -151,6 +151,7 @@ use sp_std::vec::Vec;
 
 use common::constraints::BoundedValueConstraint;
 use common::working_group::WorkingGroup;
+use common::working_group::WorkingGroupAuthenticator;
 
 use random_buckets::DistributionBucketPicker;
 use random_buckets::StorageBucketPicker;
@@ -350,35 +351,12 @@ pub trait Trait: frame_system::Trait + balances::Trait + common::MembershipTypes
     /// Max data object size in bytes.
     type MaxDataObjectSize: Get<u64>;
 
-    /// Demand the storage working group leader authorization.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult;
+    /// Storage working group pallet integration.
+    type StorageWorkingGroup: common::working_group::WorkingGroupAuthenticator<Self>
+        + common::working_group::WorkingGroupBudgetHandler<Self>;
 
-    /// Validate origin for the storage worker.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_storage_worker_origin(
-        origin: Self::Origin,
-        worker_id: WorkerId<Self>,
-    ) -> DispatchResult;
-
-    /// Validate storage worker existence.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_storage_worker_exists(worker_id: &WorkerId<Self>) -> DispatchResult;
-
-    /// Demand the distribution group leader authorization.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult;
-
-    /// Validate origin for the distribution worker.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_distribution_worker_origin(
-        origin: Self::Origin,
-        worker_id: WorkerId<Self>,
-    ) -> DispatchResult;
-
-    /// Validate distribution worker existence.
-    /// TODO: Refactor after merging with the Olympia release.
-    fn ensure_distribution_worker_exists(worker_id: &WorkerId<Self>) -> DispatchResult;
+    type DistributionWorkingGroup: common::working_group::WorkingGroupAuthenticator<Self>
+        + common::working_group::WorkingGroupBudgetHandler<Self>;
 }
 
 /// Operations with local pallet account.
@@ -1311,6 +1289,30 @@ decl_event! {
             DistributionBucketFamilyId,
             Vec<u8>
         ),
+
+        /// Emits on Storage Operator making a remark
+        /// Params
+        /// - operator's worker id
+        /// - storage bucket id
+        /// - remark message
+        StorageOperatorRemarked(
+            WorkerId,
+            StorageBucketId,
+            Vec<u8>,
+        ),
+
+        /// Emits on Distribution Operator making a remark
+        /// Params
+        /// - operator's worker id
+        /// - distribution bucket id
+        /// - remark message
+        DistributionOperatorRemarked(
+            WorkerId,
+            DistributionBucketId,
+            Vec<u8>,
+        ),
+
+
     }
 }
 
@@ -1544,7 +1546,7 @@ decl_module! {
             origin,
             storage_bucket_id: T::StorageBucketId,
         ){
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1570,7 +1572,7 @@ decl_module! {
         /// Updates global uploading flag.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_uploading_blocked_status(origin, new_status: bool) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             //
             // == MUTATION SAFE ==
@@ -1584,7 +1586,7 @@ decl_module! {
         /// Updates size-based pricing of new objects uploaded.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_data_size_fee(origin, new_data_size_fee: BalanceOf<T>) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             //
             // == MUTATION SAFE ==
@@ -1598,7 +1600,7 @@ decl_module! {
         /// Updates "Storage buckets per bag" number limit.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_storage_buckets_per_bag_limit(origin, new_limit: u64) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             T::StorageBucketsPerBagValueConstraint::get().ensure_valid(
                 new_limit,
@@ -1622,7 +1624,7 @@ decl_module! {
             new_objects_size: u64,
             new_objects_number: u64,
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             //
             // == MUTATION SAFE ==
@@ -1643,7 +1645,7 @@ decl_module! {
             dynamic_bag_type: DynamicBagType,
             number_of_storage_buckets: u64,
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             //
             // == MUTATION SAFE ==
@@ -1670,7 +1672,7 @@ decl_module! {
             remove_hashes: BTreeSet<Cid>,
             add_hashes: BTreeSet<Cid>
         ){
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             // Get only hashes that exist in the blacklist.
             let verified_remove_hashes = Self::get_existing_hashes(&remove_hashes);
@@ -1713,7 +1715,7 @@ decl_module! {
             size_limit: u64,
             objects_limit: u64,
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             let voucher = Voucher {
                 size_limit,
@@ -1763,7 +1765,7 @@ decl_module! {
             add_buckets: BTreeSet<T::StorageBucketId>,
             remove_buckets: BTreeSet<T::StorageBucketId>,
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_bag_exists(&bag_id)?;
 
@@ -1808,7 +1810,7 @@ decl_module! {
         /// Cancel pending storage bucket invite. An invitation must be pending.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn cancel_storage_bucket_operator_invite(origin, storage_bucket_id: T::StorageBucketId){
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1834,7 +1836,7 @@ decl_module! {
             storage_bucket_id: T::StorageBucketId,
             operator_id: WorkerId<T>,
         ){
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1862,7 +1864,7 @@ decl_module! {
             origin,
             storage_bucket_id: T::StorageBucketId,
         ){
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1889,7 +1891,7 @@ decl_module! {
             storage_bucket_id: T::StorageBucketId,
             accepting_new_bags: bool
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1914,7 +1916,7 @@ decl_module! {
             new_objects_size_limit: u64,
             new_objects_number_limit: u64,
         ) {
-            T::ensure_storage_working_group_leader_origin(origin)?;
+            <T as Trait>::StorageWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1961,7 +1963,7 @@ decl_module! {
             storage_bucket_id: T::StorageBucketId,
             transactor_account_id: T::AccountId,
         ) {
-            T::ensure_storage_worker_origin(origin, worker_id)?;
+            <T as Trait>::StorageWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -1996,7 +1998,7 @@ decl_module! {
             storage_bucket_id: T::StorageBucketId,
             metadata: Vec<u8>
         ) {
-            T::ensure_storage_worker_origin(origin, worker_id)?;
+            <T as Trait>::StorageWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
 
             let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
 
@@ -2060,7 +2062,7 @@ decl_module! {
         /// Create a distribution bucket family.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn create_distribution_bucket_family(origin) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             ensure!(
                 Self::distribution_bucket_family_number() <
@@ -2088,7 +2090,7 @@ decl_module! {
         /// Deletes a distribution bucket family.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn delete_distribution_bucket_family(origin, family_id: T::DistributionBucketFamilyId) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_distribution_bucket_family_exists(&family_id)?;
 
@@ -2122,7 +2124,7 @@ decl_module! {
             family_id: T::DistributionBucketFamilyId,
             accepting_new_bags: bool,
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             let family = Self::ensure_distribution_bucket_family_exists(&family_id)?;
 
@@ -2159,7 +2161,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             accepting_new_bags: bool
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2186,7 +2188,7 @@ decl_module! {
             origin,
             bucket_id: DistributionBucketId<T>,
         ){
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2219,7 +2221,7 @@ decl_module! {
             add_buckets_indices: BTreeSet<T::DistributionBucketIndex>,
             remove_buckets_indices: BTreeSet<T::DistributionBucketIndex>,
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::validate_update_distribution_buckets_for_bag_params(
                 &bag_id,
@@ -2264,7 +2266,7 @@ decl_module! {
         /// Updates "Distribution buckets per bag" number limit.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn update_distribution_buckets_per_bag_limit(origin, new_limit: u64) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             T::DistributionBucketsPerBagValueConstraint::get().ensure_valid(
                 new_limit,
@@ -2288,7 +2290,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             distributing: bool
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2316,7 +2318,7 @@ decl_module! {
             dynamic_bag_type: DynamicBagType,
             families: BTreeMap<T::DistributionBucketFamilyId, u32>
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::validate_update_families_in_dynamic_bag_creation_policy_params(&families)?;
 
@@ -2345,7 +2347,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             operator_worker_id: WorkerId<T>
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2375,7 +2377,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             operator_worker_id: WorkerId<T>
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2411,7 +2413,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             operator_worker_id: WorkerId<T>,
         ){
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2445,7 +2447,7 @@ decl_module! {
             family_id: T::DistributionBucketFamilyId,
             metadata: Vec<u8>,
         ) {
-            T::ensure_distribution_working_group_leader_origin(origin)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_leader_origin(origin)?;
 
             Self::ensure_distribution_bucket_family_exists(&family_id)?;
 
@@ -2471,7 +2473,7 @@ decl_module! {
             worker_id: WorkerId<T>,
             bucket_id: DistributionBucketId<T>,
         ) {
-            T::ensure_distribution_worker_origin(origin, worker_id)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2506,7 +2508,7 @@ decl_module! {
             bucket_id: DistributionBucketId<T>,
             metadata: Vec<u8>,
         ) {
-            T::ensure_distribution_worker_origin(origin, worker_id)?;
+            <T as Trait>::DistributionWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
 
             let bucket = Self::ensure_distribution_bucket_exists(&bucket_id)?;
 
@@ -2545,6 +2547,48 @@ decl_module! {
 
             Self::create_dynamic_bag(bag_id, deletion_prize)?;
         }
+
+        /// Create a dynamic bag. Development mode.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn storage_operator_remark(
+            origin,
+            worker_id: WorkerId<T>,
+            storage_bucket_id: T::StorageBucketId,
+            msg: Vec<u8>,
+        ) {
+            <T as Trait>::StorageWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
+            let bucket = Self::ensure_storage_bucket_exists(&storage_bucket_id)?;
+            Self::ensure_bucket_invitation_accepted(&bucket, worker_id)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::StorageOperatorRemarked(worker_id, storage_bucket_id, msg));
+        }
+
+        /// Create a dynamic bag. Development mode.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn distribution_operator_remark(
+            origin,
+            worker_id: WorkerId<T>,
+            distribution_bucket_id: DistributionBucketId<T>,
+            msg: Vec<u8>,
+        ) {
+            <T as Trait>::DistributionWorkingGroup::ensure_worker_origin(origin, &worker_id)?;
+            let bucket = Self::ensure_distribution_bucket_exists(&distribution_bucket_id)?;
+            ensure!(
+                bucket.operators.contains(&worker_id),
+                Error::<T>::MustBeDistributionProviderOperatorForBucket
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::DistributionOperatorRemarked(worker_id, distribution_bucket_id, msg));
+        }
+
     }
 }
 
@@ -3631,7 +3675,7 @@ impl<T: Trait> Module<T> {
     // Verifies storage operator existence.
     fn ensure_storage_provider_operator_exists(operator_id: &WorkerId<T>) -> DispatchResult {
         ensure!(
-            T::ensure_storage_worker_exists(operator_id).is_ok(),
+            <T as Trait>::StorageWorkingGroup::worker_exists(&operator_id),
             Error::<T>::StorageProviderOperatorDoesntExist
         );
 
@@ -3828,7 +3872,7 @@ impl<T: Trait> Module<T> {
         worker_id: &WorkerId<T>,
     ) -> DispatchResult {
         ensure!(
-            T::ensure_distribution_worker_exists(worker_id).is_ok(),
+            <T as Trait>::DistributionWorkingGroup::worker_exists(worker_id),
             Error::<T>::DistributionProviderOperatorDoesntExist
         );
 

+ 138 - 67
runtime-modules/storage/src/tests/mocks.rs

@@ -1,14 +1,13 @@
 #![cfg(test)]
 
-use frame_support::dispatch::{DispatchError, DispatchResult};
 pub use frame_support::traits::LockIdentifier;
-use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
+use frame_support::{ensure, impl_outer_event, impl_outer_origin, parameter_types};
 use frame_system::ensure_signed;
 use sp_core::H256;
 use sp_runtime::{
     testing::Header,
     traits::{BlakeTwo256, IdentityLookup},
-    ModuleId, Perbill,
+    DispatchError, DispatchResult, ModuleId, Perbill,
 };
 
 // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
@@ -107,70 +106,8 @@ impl crate::Trait for Test {
         MaxNumberOfPendingInvitationsPerDistributionBucket;
     type MaxDataObjectSize = MaxDataObjectSize;
     type ContentId = u64;
-
-    fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != STORAGE_WG_LEADER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_storage_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_storage_worker_exists(worker_id: &u64) -> DispatchResult {
-        let allowed_storage_providers =
-            vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
-
-        if !allowed_storage_providers.contains(worker_id) {
-            Err(DispatchError::Other("Invalid worker"))
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DISTRIBUTION_WG_LEADER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
-        let account_id = ensure_signed(origin)?;
-
-        if account_id != DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID {
-            Err(DispatchError::BadOrigin)
-        } else {
-            Ok(())
-        }
-    }
-
-    fn ensure_distribution_worker_exists(worker_id: &u64) -> DispatchResult {
-        let allowed_providers = vec![
-            DEFAULT_DISTRIBUTION_PROVIDER_ID,
-            ANOTHER_DISTRIBUTION_PROVIDER_ID,
-        ];
-
-        if !allowed_providers.contains(worker_id) {
-            Err(DispatchError::Other("Invalid worker"))
-        } else {
-            Ok(())
-        }
-    }
+    type StorageWorkingGroup = StorageWG;
+    type DistributionWorkingGroup = DistributionWG;
 }
 
 pub const DEFAULT_MEMBER_ID: u64 = 100;
@@ -244,3 +181,137 @@ pub type Storage = crate::Module<Test>;
 pub type System = frame_system::Module<Test>;
 pub type Balances = balances::Module<Test>;
 pub type CollectiveFlip = randomness_collective_flip::Module<Test>;
+
+// working group integration
+pub struct StorageWG;
+pub struct DistributionWG;
+
+impl common::working_group::WorkingGroupAuthenticator<Test> for StorageWG {
+    fn ensure_worker_origin(
+        origin: <Test as frame_system::Trait>::Origin,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn ensure_leader_origin(origin: <Test as frame_system::Trait>::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == STORAGE_WG_LEADER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn get_leader_member_id() -> Option<<Test as common::membership::MembershipTypes>::MemberId> {
+        unimplemented!()
+    }
+
+    fn is_leader_account_id(_account_id: &<Test as frame_system::Trait>::AccountId) -> bool {
+        unimplemented!()
+    }
+
+    fn is_worker_account_id(
+        _account_id: &<Test as frame_system::Trait>::AccountId,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> bool {
+        unimplemented!()
+    }
+
+    fn worker_exists(worker_id: &<Test as common::membership::MembershipTypes>::ActorId) -> bool {
+        Self::ensure_worker_exists(worker_id).is_ok()
+    }
+
+    fn ensure_worker_exists(
+        worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let allowed_storage_providers =
+            vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
+        ensure!(
+            allowed_storage_providers.contains(worker_id),
+            DispatchError::Other("Invailid worker"),
+        );
+        Ok(())
+    }
+}
+
+impl common::working_group::WorkingGroupAuthenticator<Test> for DistributionWG {
+    fn ensure_worker_origin(
+        origin: <Test as frame_system::Trait>::Origin,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn ensure_leader_origin(origin: <Test as frame_system::Trait>::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+        ensure!(
+            account_id == DISTRIBUTION_WG_LEADER_ACCOUNT_ID,
+            DispatchError::BadOrigin,
+        );
+        Ok(())
+    }
+
+    fn get_leader_member_id() -> Option<<Test as common::membership::MembershipTypes>::MemberId> {
+        unimplemented!()
+    }
+
+    fn is_leader_account_id(_account_id: &<Test as frame_system::Trait>::AccountId) -> bool {
+        unimplemented!()
+    }
+
+    fn is_worker_account_id(
+        _account_id: &<Test as frame_system::Trait>::AccountId,
+        _worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> bool {
+        unimplemented!()
+    }
+
+    fn worker_exists(worker_id: &<Test as common::membership::MembershipTypes>::ActorId) -> bool {
+        Self::ensure_worker_exists(worker_id).is_ok()
+    }
+
+    fn ensure_worker_exists(
+        worker_id: &<Test as common::membership::MembershipTypes>::ActorId,
+    ) -> DispatchResult {
+        let allowed_storage_providers = vec![
+            DEFAULT_DISTRIBUTION_PROVIDER_ID,
+            ANOTHER_DISTRIBUTION_PROVIDER_ID,
+        ];
+        ensure!(
+            allowed_storage_providers.contains(worker_id),
+            DispatchError::Other("Invailid worker"),
+        );
+        Ok(())
+    }
+}
+
+impl common::working_group::WorkingGroupBudgetHandler<Test> for StorageWG {
+    fn get_budget() -> u64 {
+        unimplemented!()
+    }
+
+    fn set_budget(_new_value: u64) {
+        unimplemented!()
+    }
+}
+
+impl common::working_group::WorkingGroupBudgetHandler<Test> for DistributionWG {
+    fn get_budget() -> u64 {
+        unimplemented!()
+    }
+
+    fn set_budget(_new_value: u64) {
+        unimplemented!()
+    }
+}

+ 334 - 1
runtime-modules/storage/src/tests/mod.rs

@@ -5,7 +5,7 @@ pub(crate) mod mocks;
 
 use frame_support::dispatch::DispatchError;
 use frame_support::traits::Currency;
-use frame_support::{StorageDoubleMap, StorageMap, StorageValue};
+use frame_support::{assert_err, assert_ok, StorageDoubleMap, StorageMap, StorageValue};
 use frame_system::RawOrigin;
 use sp_std::collections::btree_map::BTreeMap;
 use sp_std::collections::btree_set::BTreeSet;
@@ -5640,3 +5640,336 @@ fn unsuccessful_dyn_bag_creation_with_no_bucket_accepting() {
             .call_and_assert(Err(Error::<Test>::StorageBucketIdCollectionsAreEmpty.into()));
     })
 }
+
+#[test]
+fn storage_operator_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+        let storage_provider_id = DEFAULT_STORAGE_PROVIDER_ID;
+        let invite_worker = Some(storage_provider_id);
+        let transactor_id = DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID;
+
+        let bucket_id = CreateStorageBucketFixture::default()
+            .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
+            .with_invite_worker(invite_worker)
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        AcceptStorageBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID))
+            .with_storage_bucket_id(bucket_id)
+            .with_worker_id(storage_provider_id)
+            .with_transactor_account_id(transactor_id)
+            .call_and_assert(Ok(()));
+
+        assert_ok!(Storage::storage_operator_remark(
+            RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID).into(),
+            DEFAULT_STORAGE_PROVIDER_ID,
+            bucket_id,
+            msg
+        ));
+    })
+}
+
+#[test]
+fn storage_operator_remark_unsuccessful_with_invalid_bucket_id() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+        let storage_provider_id = DEFAULT_STORAGE_PROVIDER_ID;
+        let invite_worker = Some(storage_provider_id);
+        let transactor_id = DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID;
+
+        let bucket_id = CreateStorageBucketFixture::default()
+            .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
+            .with_invite_worker(invite_worker)
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let invalid_bucket_id = bucket_id.saturating_add(1);
+
+        AcceptStorageBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID))
+            .with_storage_bucket_id(bucket_id)
+            .with_worker_id(storage_provider_id)
+            .with_transactor_account_id(transactor_id)
+            .call_and_assert(Ok(()));
+
+        assert_err!(
+            Storage::storage_operator_remark(
+                RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID).into(),
+                DEFAULT_STORAGE_PROVIDER_ID,
+                invalid_bucket_id,
+                msg
+            ),
+            Error::<Test>::StorageBucketDoesntExist
+        );
+    })
+}
+
+#[test]
+fn storage_operator_remark_unsuccessful_with_invalid_origin() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+        let storage_provider_id = DEFAULT_STORAGE_PROVIDER_ID;
+        let invite_worker = Some(storage_provider_id);
+        let transactor_id = DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID;
+
+        let bucket_id = CreateStorageBucketFixture::default()
+            .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
+            .with_invite_worker(invite_worker)
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        AcceptStorageBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID))
+            .with_storage_bucket_id(bucket_id)
+            .with_worker_id(storage_provider_id)
+            .with_transactor_account_id(transactor_id)
+            .call_and_assert(Ok(()));
+
+        let invalid_origin = RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID + 100).into();
+        assert_err!(
+            Storage::storage_operator_remark(
+                invalid_origin,
+                DEFAULT_STORAGE_PROVIDER_ID,
+                bucket_id,
+                msg
+            ),
+            DispatchError::BadOrigin,
+        );
+    })
+}
+
+#[test]
+fn storage_operator_remark_unsuccessful_with_invalid_worker_id() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+        let storage_provider_id = DEFAULT_STORAGE_PROVIDER_ID;
+        let invite_worker = Some(storage_provider_id);
+        let transactor_id = DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID;
+
+        let bucket_id = CreateStorageBucketFixture::default()
+            .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
+            .with_invite_worker(invite_worker)
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let invalid_worker_id = DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID.saturating_add(1);
+
+        AcceptStorageBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID))
+            .with_storage_bucket_id(bucket_id)
+            .with_worker_id(storage_provider_id)
+            .with_transactor_account_id(transactor_id)
+            .call_and_assert(Ok(()));
+
+        assert_err!(
+            Storage::storage_operator_remark(
+                RawOrigin::Signed(DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID).into(),
+                invalid_worker_id,
+                bucket_id,
+                msg
+            ),
+            Error::<Test>::InvalidStorageProvider
+        );
+    })
+}
+
+#[test]
+fn distribution_operator_remark_successful() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+
+        let distribution_bucket_family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let distribution_bucket_index = CreateDistributionBucketFixture::default()
+            .with_family_id(distribution_bucket_family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        InviteDistributionBucketOperatorFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_bucket_index(distribution_bucket_index)
+            .with_family_id(distribution_bucket_family_id)
+            .with_operator_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        AcceptDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID))
+            .with_family_id(distribution_bucket_family_id)
+            .with_bucket_index(distribution_bucket_index)
+            .with_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        assert_ok!(Storage::distribution_operator_remark(
+            RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID).into(),
+            DEFAULT_DISTRIBUTION_PROVIDER_ID,
+            DistributionBucketId::<Test> {
+                distribution_bucket_family_id,
+                distribution_bucket_index,
+            },
+            msg
+        ));
+    })
+}
+
+#[test]
+fn distribution_operator_remark_unsuccessful_with_invalid_bucket_id() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let msg = b"test".to_vec();
+
+        let distribution_bucket_family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+        let invalid_distribution_bucket_family_id = distribution_bucket_family_id.saturating_add(1);
+
+        let distribution_bucket_index = CreateDistributionBucketFixture::default()
+            .with_family_id(distribution_bucket_family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        InviteDistributionBucketOperatorFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_bucket_index(distribution_bucket_index)
+            .with_family_id(distribution_bucket_family_id)
+            .with_operator_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        AcceptDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID))
+            .with_family_id(distribution_bucket_family_id)
+            .with_bucket_index(distribution_bucket_index)
+            .with_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        assert_err!(
+            Storage::distribution_operator_remark(
+                RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID).into(),
+                DEFAULT_DISTRIBUTION_PROVIDER_ID,
+                DistributionBucketId::<Test> {
+                    distribution_bucket_family_id: invalid_distribution_bucket_family_id,
+                    distribution_bucket_index,
+                },
+                msg
+            ),
+            Error::<Test>::DistributionBucketDoesntExist
+        );
+    })
+}
+
+#[test]
+fn distribution_operator_remark_unsuccessful_with_invalid_worker_id() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let invalid_distribution_worker_id = DEFAULT_DISTRIBUTION_PROVIDER_ID.saturating_add(1);
+        let msg = b"test".to_vec();
+
+        let distribution_bucket_family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let distribution_bucket_index = CreateDistributionBucketFixture::default()
+            .with_family_id(distribution_bucket_family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        InviteDistributionBucketOperatorFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_bucket_index(distribution_bucket_index)
+            .with_family_id(distribution_bucket_family_id)
+            .with_operator_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        AcceptDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID))
+            .with_family_id(distribution_bucket_family_id)
+            .with_bucket_index(distribution_bucket_index)
+            .with_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        assert_err!(
+            Storage::distribution_operator_remark(
+                RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID).into(),
+                invalid_distribution_worker_id,
+                DistributionBucketId::<Test> {
+                    distribution_bucket_family_id,
+                    distribution_bucket_index,
+                },
+                msg
+            ),
+            Error::<Test>::MustBeDistributionProviderOperatorForBucket,
+        );
+    })
+}
+
+#[test]
+fn distribution_operator_remark_unsuccessful_with_invalid_origin() {
+    build_test_externalities().execute_with(|| {
+        run_to_block(1);
+
+        let invalid_distribution_worker_id = DEFAULT_DISTRIBUTION_PROVIDER_ID.saturating_add(1);
+        let msg = b"test".to_vec();
+
+        let distribution_bucket_family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let distribution_bucket_index = CreateDistributionBucketFixture::default()
+            .with_family_id(distribution_bucket_family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        InviteDistributionBucketOperatorFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_bucket_index(distribution_bucket_index)
+            .with_family_id(distribution_bucket_family_id)
+            .with_operator_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        AcceptDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID))
+            .with_family_id(distribution_bucket_family_id)
+            .with_bucket_index(distribution_bucket_index)
+            .with_worker_id(DEFAULT_DISTRIBUTION_PROVIDER_ID)
+            .call_and_assert(Ok(()));
+
+        let invalid_origin =
+            RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID + 100).into();
+
+        assert_err!(
+            Storage::distribution_operator_remark(
+                invalid_origin,
+                invalid_distribution_worker_id,
+                DistributionBucketId::<Test> {
+                    distribution_bucket_family_id,
+                    distribution_bucket_index,
+                },
+                msg
+            ),
+            DispatchError::BadOrigin,
+        );
+    })
+}

+ 15 - 0
runtime-modules/utility/src/tests/mocks.rs

@@ -359,6 +359,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 parameter_types! {
@@ -450,6 +453,12 @@ impl working_group::WeightInfo for WorkingGroupWeightInfo {
     fn leave_role(_: u32) -> Weight {
         0
     }
+    fn lead_remark() -> Weight {
+        0
+    }
+    fn worker_remark() -> Weight {
+        0
+    }
 }
 
 impl working_group::Trait<StorageWorkingGroupInstance> for Test {
@@ -611,6 +620,12 @@ impl council::WeightInfo for CouncilWeightInfo {
     fn funding_request(_: u32) -> Weight {
         0
     }
+    fn councilor_remark() -> Weight {
+        0
+    }
+    fn candidate_remark() -> Weight {
+        0
+    }
 }
 
 pub type ReferendumInstance = referendum::Instance0;

+ 39 - 0
runtime-modules/working-group/src/benchmarking.rs

@@ -922,6 +922,31 @@ benchmarks_instance! {
             "Worker hasn't started leaving"
         );
     }
+
+    lead_remark {
+        let (caller_id, _) = insert_a_worker::<T, I>(
+            OpeningType::Leader,
+            0,
+            None
+        );
+        let msg = b"test".to_vec();
+    }: _ (RawOrigin::Signed(caller_id), msg.clone())
+        verify {
+            assert_last_event::<T, I>(RawEvent::LeadRemarked(msg).into());
+        }
+
+    worker_remark {
+        let (lead_id, _) =
+            insert_a_worker::<T, I>(OpeningType::Leader, 0, None);
+        let (caller_id, worker_id) = insert_a_worker::<T, I>(
+            OpeningType::Regular,
+            1,
+            Some(lead_id.clone()));
+        let msg = b"test".to_vec();
+    }: _ (RawOrigin::Signed(caller_id), worker_id, msg.clone())
+        verify {
+            assert_last_event::<T, I>(RawEvent::WorkerRemarked(worker_id, msg).into());
+    }
 }
 
 #[cfg(test)]
@@ -1085,4 +1110,18 @@ mod tests {
             assert_ok!(test_benchmark_on_initialize_leaving::<Test>());
         });
     }
+
+    #[test]
+    fn test_lead_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_lead_remark::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_worker_remark() {
+        build_test_externalities().execute_with(|| {
+            assert_ok!(test_benchmark_worker_remark::<Test>());
+        });
+    }
 }

+ 54 - 0
runtime-modules/working-group/src/lib.rs

@@ -91,6 +91,8 @@ pub trait WeightInfo {
     fn set_budget() -> Weight;
     fn add_opening(i: u32) -> Weight;
     fn leave_role(i: u32) -> Weight;
+    fn lead_remark() -> Weight;
+    fn worker_remark() -> Weight;
 }
 
 /// The _Group_ main _Trait_
@@ -288,6 +290,17 @@ decl_event!(
         /// - Id of the worker.
         /// - Raw storage field.
         WorkerStorageUpdated(WorkerId, Vec<u8>),
+
+        /// Emits on Lead making a remark message
+        /// Params:
+        /// - message
+        LeadRemarked(Vec<u8>),
+
+        /// Emits on Lead making a remark message
+        /// Params:
+        /// - worker
+        /// - message
+        WorkerRemarked(WorkerId, Vec<u8>),
     }
 );
 
@@ -1167,6 +1180,47 @@ decl_module! {
             // Trigger event
             Self::deposit_event(RawEvent::WorkerStorageUpdated(worker_id, storage));
         }
+
+        /// Lead remark message
+        ///
+        /// # <weight>
+        ///
+        /// ## Weight
+        /// `O (1)`
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoWorkingGroup::<T,I>::lead_remark()]
+        pub fn lead_remark(origin, msg: Vec<u8>) {
+            let _ = checks::ensure_origin_is_active_leader::<T, I>(origin);
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::LeadRemarked(msg));
+        }
+
+        /// Worker remark message
+        ///
+        /// # <weight>
+        ///
+        /// ## Weight
+        /// `O (1)`
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoWorkingGroup::<T,I>::worker_remark()]
+        pub fn worker_remark(origin, worker_id: WorkerId<T>,msg: Vec<u8>) {
+            let _ = checks::ensure_worker_signed::<T, I>(origin, &worker_id).map(|_| ());
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            Self::deposit_event(RawEvent::WorkerRemarked(worker_id, msg));
+        }
+
     }
 }
 

+ 9 - 0
runtime-modules/working-group/src/tests/mock.rs

@@ -157,6 +157,9 @@ impl membership::WeightInfo for Weights {
     fn remove_staking_account() -> Weight {
         unimplemented!()
     }
+    fn member_remark() -> Weight {
+        unimplemented!()
+    }
 }
 
 impl membership::Trait for Test {
@@ -276,6 +279,12 @@ impl crate::WeightInfo for () {
     fn leave_role(_: u32) -> Weight {
         0
     }
+    fn lead_remark() -> Weight {
+        0
+    }
+    fn worker_remark() -> Weight {
+        0
+    }
 }
 
 pub const ACTOR_ORIGIN_ERROR: &'static str = "Invalid membership";

+ 3 - 29
runtime/src/lib.rs

@@ -38,7 +38,6 @@ mod weights; // Runtime integration tests
 #[macro_use]
 extern crate lazy_static; // for proposals_configuration module
 
-use frame_support::dispatch::DispatchResult;
 use frame_support::traits::{Currency, KeyOwnerProofSystem, LockIdentifier, OnUnbalanced};
 use frame_support::weights::{
     constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
@@ -69,7 +68,7 @@ pub use runtime_api::*;
 
 use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder};
 
-use common::working_group::{WorkingGroup, WorkingGroupAuthenticator, WorkingGroupBudgetHandler};
+use common::working_group::{WorkingGroup, WorkingGroupBudgetHandler};
 use council::ReferendumConnection;
 use referendum::{CastVote, OptionResult};
 use staking_handler::{LockComparator, StakingManager};
@@ -641,33 +640,8 @@ impl storage::Trait for Runtime {
         MaxNumberOfPendingInvitationsPerDistributionBucket;
     type MaxDataObjectSize = MaxDataObjectSize;
     type ContentId = ContentId;
-
-    fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        StorageWorkingGroup::ensure_leader_origin(origin)
-    }
-
-    fn ensure_storage_worker_origin(origin: Self::Origin, worker_id: ActorId) -> DispatchResult {
-        StorageWorkingGroup::ensure_worker_origin(origin, &worker_id)
-    }
-
-    fn ensure_storage_worker_exists(worker_id: &ActorId) -> DispatchResult {
-        StorageWorkingGroup::ensure_worker_exists(&worker_id)
-    }
-
-    fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
-        DistributionWorkingGroup::ensure_leader_origin(origin)
-    }
-
-    fn ensure_distribution_worker_origin(
-        origin: Self::Origin,
-        worker_id: ActorId,
-    ) -> DispatchResult {
-        DistributionWorkingGroup::ensure_worker_origin(origin, &worker_id)
-    }
-
-    fn ensure_distribution_worker_exists(worker_id: &ActorId) -> DispatchResult {
-        DistributionWorkingGroup::ensure_worker_exists(&worker_id)
-    }
+    type StorageWorkingGroup = StorageWorkingGroup;
+    type DistributionWorkingGroup = DistributionWorkingGroup;
 }
 
 impl common::membership::MembershipTypes for Runtime {

+ 121 - 105
runtime/src/weights/bounty.rs

@@ -1,113 +1,129 @@
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1
 
 #![allow(unused_parens)]
 #![allow(unused_imports)]
 
-use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
 
 pub struct WeightInfo;
 impl bounty::WeightInfo for WeightInfo {
-    fn create_bounty_by_council(i: u32, j: u32) -> Weight {
-        (0 as Weight)
-            .saturating_add((194_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add((28_742_000 as Weight).saturating_mul(j as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn create_bounty_by_member(i: u32, j: u32) -> Weight {
-        (843_057_000 as Weight)
-            .saturating_add((174_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add((6_931_000 as Weight).saturating_mul(j as Weight))
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn cancel_bounty_by_council() -> Weight {
-        (527_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn cancel_bounty_by_member() -> Weight {
-        (872_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn veto_bounty() -> Weight {
-        (576_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn fund_bounty_by_member() -> Weight {
-        (866_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn fund_bounty_by_council() -> Weight {
-        (559_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn withdraw_funding_by_member() -> Weight {
-        (939_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn withdraw_funding_by_council() -> Weight {
-        (688_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn announce_work_entry(i: u32) -> Weight {
-        (774_826_000 as Weight)
-            .saturating_add((10_400_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(5 as Weight))
-    }
-    fn withdraw_work_entry() -> Weight {
-        (911_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn submit_work(i: u32) -> Weight {
-        (546_484_000 as Weight)
-            .saturating_add((171_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn submit_oracle_judgment_by_council_all_winners(i: u32) -> Weight {
-        (0 as Weight)
-            .saturating_add((150_234_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn submit_oracle_judgment_by_council_all_rejected(i: u32) -> Weight {
-        (3_192_844_000 as Weight)
-            .saturating_add((552_887_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-            .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
-    }
-    fn submit_oracle_judgment_by_member_all_winners(i: u32) -> Weight {
-        (317_671_000 as Weight)
-            .saturating_add((130_010_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn submit_oracle_judgment_by_member_all_rejected(i: u32) -> Weight {
-        (261_974_000 as Weight)
-            .saturating_add((593_591_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-            .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
-    }
-    fn withdraw_work_entrant_funds() -> Weight {
-        (1_248_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(8 as Weight))
-            .saturating_add(DbWeight::get().writes(6 as Weight))
-    }
+	fn create_bounty_by_council(i: u32, j: u32, ) -> Weight {
+		(652_500_000 as Weight)
+			.saturating_add((247_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add((9_081_000 as Weight).saturating_mul(j as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn create_bounty_by_member(i: u32, j: u32, ) -> Weight {
+		(1_177_497_000 as Weight)
+			.saturating_add((246_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add((3_704_000 as Weight).saturating_mul(j as Weight))
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn cancel_bounty_by_council() -> Weight {
+		(750_529_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn cancel_bounty_by_member() -> Weight {
+		(1_231_951_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn veto_bounty() -> Weight {
+		(750_237_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn fund_bounty_by_member() -> Weight {
+		(1_156_302_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn fund_bounty_by_council() -> Weight {
+		(755_900_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn withdraw_funding_by_member() -> Weight {
+		(1_442_204_000 as Weight)
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn withdraw_funding_by_council() -> Weight {
+		(1_031_991_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn announce_work_entry(i: u32, ) -> Weight {
+		(1_066_657_000 as Weight)
+			.saturating_add((11_895_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(5 as Weight))
+	}
+	fn withdraw_work_entry() -> Weight {
+		(1_339_077_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn submit_work(i: u32, ) -> Weight {
+		(729_723_000 as Weight)
+			.saturating_add((248_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn submit_oracle_judgment_by_council_all_winners(i: u32, ) -> Weight {
+		(614_242_000 as Weight)
+			.saturating_add((197_714_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn submit_oracle_judgment_by_council_all_rejected(i: u32, ) -> Weight {
+		(425_144_000 as Weight)
+			.saturating_add((887_466_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+			.saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
+	}
+	fn submit_oracle_judgment_by_member_all_winners(i: u32, ) -> Weight {
+		(1_179_720_000 as Weight)
+			.saturating_add((193_462_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn submit_oracle_judgment_by_member_all_rejected(i: u32, ) -> Weight {
+		(273_501_000 as Weight)
+			.saturating_add((836_822_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+			.saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
+	}
+	fn withdraw_work_entrant_funds() -> Weight {
+		(1_816_600_000 as Weight)
+			.saturating_add(DbWeight::get().reads(8 as Weight))
+			.saturating_add(DbWeight::get().writes(6 as Weight))
+	}
+	fn entrant_remark() -> Weight {
+		(360_023_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+	}
+	fn contributor_remark() -> Weight {
+		(304_679_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+	}
+	fn oracle_remark() -> Weight {
+		(261_869_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+	}
+	fn creator_remark() -> Weight {
+		(261_289_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+	}
 }

+ 76 - 64
runtime/src/weights/council.rs

@@ -1,72 +1,84 @@
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1
 
 #![allow(unused_parens)]
 #![allow(unused_imports)]
 
-use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
 
 pub struct WeightInfo;
 impl council::WeightInfo for WeightInfo {
-    fn set_budget_increment() -> Weight {
-        (83_923_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_councilor_reward() -> Weight {
-        (82_332_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn funding_request(i: u32) -> Weight {
-        (0 as Weight)
-            .saturating_add((240_865_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn try_process_budget() -> Weight {
-        (1_089_690_000 as Weight)
-            .saturating_add(DbWeight::get().reads(9 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn try_progress_stage_idle() -> Weight {
-        (127_036_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn try_progress_stage_announcing_start_election(i: u32) -> Weight {
-        (213_060_000 as Weight)
-            .saturating_add((316_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn try_progress_stage_announcing_restart() -> Weight {
-        (126_148_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn announce_candidacy() -> Weight {
-        (539_912_000 as Weight)
-            .saturating_add(DbWeight::get().reads(7 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn release_candidacy_stake() -> Weight {
-        (419_221_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn set_candidacy_note(i: u32) -> Weight {
-        (353_199_000 as Weight)
-            .saturating_add((177_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn withdraw_candidacy() -> Weight {
-        (444_837_000 as Weight)
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn set_budget() -> Weight {
-        (71_589_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn plan_budget_refill() -> Weight {
-        (66_611_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
+	fn set_budget_increment() -> Weight {
+		(119_250_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_councilor_reward() -> Weight {
+		(117_702_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn funding_request(i: u32, ) -> Weight {
+		(0 as Weight)
+			.saturating_add((370_110_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn try_process_budget() -> Weight {
+		(1_717_612_000 as Weight)
+			.saturating_add(DbWeight::get().reads(9 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn try_progress_stage_idle() -> Weight {
+		(189_623_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn try_progress_stage_announcing_start_election(i: u32, ) -> Weight {
+		(327_260_000 as Weight)
+			.saturating_add((800_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn try_progress_stage_announcing_restart() -> Weight {
+		(191_622_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn announce_candidacy() -> Weight {
+		(896_118_000 as Weight)
+			.saturating_add(DbWeight::get().reads(7 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn release_candidacy_stake() -> Weight {
+		(589_779_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn set_candidacy_note(i: u32, ) -> Weight {
+		(517_359_000 as Weight)
+			.saturating_add((254_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn withdraw_candidacy() -> Weight {
+		(679_703_000 as Weight)
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn set_budget() -> Weight {
+		(111_817_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn plan_budget_refill() -> Weight {
+		(101_904_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn candidate_remark() -> Weight {
+		(345_043_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+	}
+	fn councilor_remark() -> Weight {
+		(406_707_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+	}
 }

+ 97 - 89
runtime/src/weights/membership.rs

@@ -1,97 +1,105 @@
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1
 
 #![allow(unused_parens)]
 #![allow(unused_imports)]
 
-use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
 
 pub struct WeightInfo;
 impl membership::WeightInfo for WeightInfo {
-    fn buy_membership_without_referrer(i: u32, j: u32) -> Weight {
-        (580_636_000 as Weight)
-            .saturating_add((95_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add((131_000 as Weight).saturating_mul(j as Weight))
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn buy_membership_with_referrer(i: u32, j: u32) -> Weight {
-        (741_433_000 as Weight)
-            .saturating_add((92_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add((131_000 as Weight).saturating_mul(j as Weight))
-            .saturating_add(DbWeight::get().reads(7 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn update_profile(i: u32) -> Weight {
-        (327_665_000 as Weight)
-            .saturating_add((173_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn update_accounts_none() -> Weight {
-        (8_025_000 as Weight)
-    }
-    fn update_accounts_root() -> Weight {
-        (172_444_000 as Weight)
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn update_accounts_controller() -> Weight {
-        (172_544_000 as Weight)
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn update_accounts_both() -> Weight {
-        (172_614_000 as Weight)
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_referral_cut() -> Weight {
-        (65_363_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn transfer_invites() -> Weight {
-        (364_596_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn invite_member(i: u32, j: u32) -> Weight {
-        (800_719_000 as Weight)
-            .saturating_add((97_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add((131_000 as Weight).saturating_mul(j as Weight))
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(6 as Weight))
-    }
-    fn set_membership_price() -> Weight {
-        (66_976_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn update_profile_verification() -> Weight {
-        (274_927_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_leader_invitation_quota() -> Weight {
-        (187_743_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_initial_invitation_balance() -> Weight {
-        (65_533_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_initial_invitation_count() -> Weight {
-        (60_294_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn add_staking_account_candidate() -> Weight {
-        (164_369_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn confirm_staking_account() -> Weight {
-        (242_797_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn remove_staking_account() -> Weight {
-        (185_459_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
+	fn buy_membership_without_referrer(i: u32, j: u32, ) -> Weight {
+		(1_240_241_000 as Weight)
+			.saturating_add((172_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add((250_000 as Weight).saturating_mul(j as Weight))
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn buy_membership_with_referrer(i: u32, j: u32, ) -> Weight {
+		(1_211_185_000 as Weight)
+			.saturating_add((187_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add((267_000 as Weight).saturating_mul(j as Weight))
+			.saturating_add(DbWeight::get().reads(7 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn update_profile(i: u32, ) -> Weight {
+		(506_958_000 as Weight)
+			.saturating_add((344_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn update_accounts_none() -> Weight {
+		(14_899_000 as Weight)
+	}
+	fn update_accounts_root() -> Weight {
+		(338_531_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn update_accounts_controller() -> Weight {
+		(339_930_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn update_accounts_both() -> Weight {
+		(341_573_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_referral_cut() -> Weight {
+		(108_946_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn transfer_invites() -> Weight {
+		(711_865_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn invite_member(i: u32, j: u32, ) -> Weight {
+		(1_753_562_000 as Weight)
+			.saturating_add((180_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add((250_000 as Weight).saturating_mul(j as Weight))
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(6 as Weight))
+	}
+	fn set_membership_price() -> Weight {
+		(112_811_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn update_profile_verification() -> Weight {
+		(545_137_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_leader_invitation_quota() -> Weight {
+		(395_546_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_initial_invitation_balance() -> Weight {
+		(126_112_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_initial_invitation_count() -> Weight {
+		(115_422_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn add_staking_account_candidate() -> Weight {
+		(763_787_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn confirm_staking_account() -> Weight {
+		(509_665_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn remove_staking_account() -> Weight {
+		(723_957_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn member_remark() -> Weight {
+		(248_401_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+	}
 }

+ 69 - 66
runtime/src/weights/proposals_engine.rs

@@ -1,74 +1,77 @@
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1
 
 #![allow(unused_parens)]
 #![allow(unused_imports)]
 
-use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
 
 pub struct WeightInfo;
 impl proposals_engine::WeightInfo for WeightInfo {
-    fn vote(i: u32) -> Weight {
-        (485_352_000 as Weight)
-            .saturating_add((39_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    // WARNING! Some components were not used: ["i"]
-    fn cancel_proposal() -> Weight {
-        (1_126_523_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(8 as Weight))
-    }
-    fn veto_proposal() -> Weight {
-        (479_000_000 as Weight)
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(8 as Weight))
-    }
-    fn on_initialize_immediate_execution_decode_fails(i: u32) -> Weight {
-        (79_260_000 as Weight)
-            .saturating_add((740_840_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().reads((4 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-            .saturating_add(DbWeight::get().writes((7 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_pending_execution_decode_fails(i: u32) -> Weight {
-        (49_200_000 as Weight)
-            .saturating_add((330_580_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-            .saturating_add(DbWeight::get().writes((5 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_approved_pending_constitutionality(i: u32) -> Weight {
-        (67_720_000 as Weight)
-            .saturating_add((363_000_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_rejected(i: u32) -> Weight {
-        (81_920_000 as Weight)
-            .saturating_add((1_041_560_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-            .saturating_add(DbWeight::get().writes((9 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_slashed(i: u32) -> Weight {
-        (0 as Weight)
-            .saturating_add((871_510_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-            .saturating_add(DbWeight::get().writes((9 as Weight).saturating_mul(i as Weight)))
-    }
-    fn cancel_active_and_pending_proposals(i: u32) -> Weight {
-        (120_990_000 as Weight)
-            .saturating_add((505_390_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-            .saturating_add(DbWeight::get().writes((9 as Weight).saturating_mul(i as Weight)))
-    }
+	fn vote(i: u32, ) -> Weight {
+		(674_206_000 as Weight)
+			.saturating_add((261_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn cancel_proposal() -> Weight {
+		(1_471_478_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(7 as Weight))
+	}
+	fn veto_proposal() -> Weight {
+		(643_564_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(7 as Weight))
+	}
+	fn proposer_remark() -> Weight {
+		(364_753_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+	}
+	fn on_initialize_immediate_execution_decode_fails(i: u32, ) -> Weight {
+		(0 as Weight)
+			.saturating_add((1_069_166_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().reads((4 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+			.saturating_add(DbWeight::get().writes((6 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_pending_execution_decode_fails(i: u32, ) -> Weight {
+		(25_079_000 as Weight)
+			.saturating_add((469_174_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+			.saturating_add(DbWeight::get().writes((4 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_approved_pending_constitutionality(i: u32, ) -> Weight {
+		(11_916_000 as Weight)
+			.saturating_add((594_135_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_rejected(i: u32, ) -> Weight {
+		(66_863_000 as Weight)
+			.saturating_add((1_481_979_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+			.saturating_add(DbWeight::get().writes((8 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_slashed(i: u32, ) -> Weight {
+		(279_826_000 as Weight)
+			.saturating_add((1_112_286_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+			.saturating_add(DbWeight::get().writes((8 as Weight).saturating_mul(i as Weight)))
+	}
+	fn cancel_active_and_pending_proposals(i: u32, ) -> Weight {
+		(164_471_000 as Weight)
+			.saturating_add((574_254_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+			.saturating_add(DbWeight::get().writes((8 as Weight).saturating_mul(i as Weight)))
+	}
 }

+ 139 - 130
runtime/src/weights/working_group.rs

@@ -1,138 +1,147 @@
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1
 
 #![allow(unused_parens)]
 #![allow(unused_imports)]
 
-use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
 
 pub struct WeightInfo;
 impl working_group::WeightInfo for WeightInfo {
-    fn on_initialize_leaving(i: u32) -> Weight {
-        (0 as Weight)
-            .saturating_add((496_301_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-            .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_rewarding_with_missing_reward(i: u32) -> Weight {
-        (32_208_000 as Weight)
-            .saturating_add((361_542_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_rewarding_with_missing_reward_cant_pay(i: u32) -> Weight {
-        (129_133_000 as Weight)
-            .saturating_add((233_951_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
-    }
-    fn on_initialize_rewarding_without_missing_reward(i: u32) -> Weight {
-        (82_724_000 as Weight)
-            .saturating_add((222_551_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn apply_on_opening(i: u32) -> Weight {
-        (532_302_000 as Weight)
-            .saturating_add((144_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(4 as Weight))
-    }
-    fn fill_opening_lead() -> Weight {
-        (441_600_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(6 as Weight))
-    }
-    fn fill_opening_worker(i: u32) -> Weight {
-        (145_112_000 as Weight)
-            .saturating_add((257_669_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-            .saturating_add(DbWeight::get().writes((2 as Weight).saturating_mul(i as Weight)))
-    }
-    fn update_role_account() -> Weight {
-        (278_339_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn cancel_opening() -> Weight {
-        (201_764_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn withdraw_application() -> Weight {
-        (291_554_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(3 as Weight))
-    }
-    fn slash_stake(i: u32) -> Weight {
-        (605_562_000 as Weight)
-            .saturating_add((122_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn terminate_role_worker(i: u32) -> Weight {
-        (961_187_000 as Weight)
-            .saturating_add((249_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(7 as Weight))
-            .saturating_add(DbWeight::get().writes(5 as Weight))
-    }
-    fn terminate_role_lead(i: u32) -> Weight {
-        (986_954_000 as Weight)
-            .saturating_add((255_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(6 as Weight))
-            .saturating_add(DbWeight::get().writes(6 as Weight))
-    }
-    fn increase_stake() -> Weight {
-        (393_177_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn decrease_stake() -> Weight {
-        (456_618_000 as Weight)
-            .saturating_add(DbWeight::get().reads(5 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn spend_from_budget() -> Weight {
-        (227_722_000 as Weight)
-            .saturating_add(DbWeight::get().reads(4 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn update_reward_amount() -> Weight {
-        (309_008_000 as Weight)
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_status_text(i: u32) -> Weight {
-        (182_500_000 as Weight)
-            .saturating_add((127_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn update_reward_account() -> Weight {
-        (240_377_000 as Weight)
-            .saturating_add(DbWeight::get().reads(1 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn set_budget() -> Weight {
-        (66_927_000 as Weight).saturating_add(DbWeight::get().writes(1 as Weight))
-    }
-    fn add_opening(i: u32) -> Weight {
-        (233_945_000 as Weight)
-            .saturating_add((127_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(3 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn leave_role(i: u32) -> Weight {
-        (221_051_000 as Weight)
-            .saturating_add((28_000 as Weight).saturating_mul(i as Weight))
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(1 as Weight))
-    }
+	fn on_initialize_leaving(i: u32, ) -> Weight {
+		(9_011_876_000 as Weight)
+			.saturating_add((1_019_158_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().reads((3 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+			.saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_rewarding_with_missing_reward(i: u32, ) -> Weight {
+		(0 as Weight)
+			.saturating_add((1_049_486_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_rewarding_with_missing_reward_cant_pay(i: u32, ) -> Weight {
+		(4_634_959_000 as Weight)
+			.saturating_add((516_394_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
+	}
+	fn on_initialize_rewarding_without_missing_reward(i: u32, ) -> Weight {
+		(973_631_000 as Weight)
+			.saturating_add((506_288_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn apply_on_opening(i: u32, ) -> Weight {
+		(1_030_006_000 as Weight)
+			.saturating_add((255_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn fill_opening_lead() -> Weight {
+		(775_213_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(6 as Weight))
+	}
+	fn fill_opening_worker(i: u32, ) -> Weight {
+		(651_141_000 as Weight)
+			.saturating_add((497_245_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(7 as Weight))
+			.saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
+			.saturating_add(DbWeight::get().writes(5 as Weight))
+			.saturating_add(DbWeight::get().writes((2 as Weight).saturating_mul(i as Weight)))
+	}
+	fn update_role_account() -> Weight {
+		(561_638_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn cancel_opening() -> Weight {
+		(974_307_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn withdraw_application() -> Weight {
+		(529_373_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(3 as Weight))
+	}
+	fn slash_stake(i: u32, ) -> Weight {
+		(1_127_901_000 as Weight)
+			.saturating_add((253_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn terminate_role_worker(i: u32, ) -> Weight {
+		(1_950_392_000 as Weight)
+			.saturating_add((504_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(7 as Weight))
+			.saturating_add(DbWeight::get().writes(5 as Weight))
+	}
+	fn terminate_role_lead(i: u32, ) -> Weight {
+		(1_898_566_000 as Weight)
+			.saturating_add((502_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(6 as Weight))
+			.saturating_add(DbWeight::get().writes(6 as Weight))
+	}
+	fn increase_stake() -> Weight {
+		(804_388_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn decrease_stake() -> Weight {
+		(948_984_000 as Weight)
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(2 as Weight))
+	}
+	fn spend_from_budget() -> Weight {
+		(428_955_000 as Weight)
+			.saturating_add(DbWeight::get().reads(4 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn update_reward_amount() -> Weight {
+		(608_563_000 as Weight)
+			.saturating_add(DbWeight::get().reads(3 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_status_text(i: u32, ) -> Weight {
+		(353_651_000 as Weight)
+			.saturating_add((258_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn update_reward_account() -> Weight {
+		(471_797_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn set_budget() -> Weight {
+		(117_641_000 as Weight)
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn add_opening(i: u32, ) -> Weight {
+		(1_362_228_000 as Weight)
+			.saturating_add((248_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(5 as Weight))
+			.saturating_add(DbWeight::get().writes(4 as Weight))
+	}
+	fn leave_role(i: u32, ) -> Weight {
+		(473_226_000 as Weight)
+			.saturating_add((221_000 as Weight).saturating_mul(i as Weight))
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+			.saturating_add(DbWeight::get().writes(1 as Weight))
+	}
+	fn lead_remark() -> Weight {
+		(279_387_000 as Weight)
+			.saturating_add(DbWeight::get().reads(2 as Weight))
+	}
+	fn worker_remark() -> Weight {
+		(302_419_000 as Weight)
+			.saturating_add(DbWeight::get().reads(1 as Weight))
+	}
 }

+ 1 - 1
scripts/cargo-build.sh

@@ -4,4 +4,4 @@
 
 export WASM_BUILD_TOOLCHAIN=nightly-2021-02-20
 
-cargo +nightly-2021-02-20 build --release
+cargo +nightly-2021-02-20 build --release --features runtime-benchmarks

+ 2 - 2
scripts/generate-weights.sh

@@ -38,7 +38,7 @@ benchmark() {
 # Substrate. This problem has been fixed in this PR: https://github.com/paritytech/substrate/pull/7233
 # So uncomment this when we move to a version that contains that PR.
 # See issue: #1979
-# benchmark frame_system
+benchmark frame_system
 benchmark substrate_utility
 benchmark pallet_session
 benchmark pallet_timestamp
@@ -68,4 +68,4 @@ benchmark membership
 benchmark bounty
 benchmark blog
 benchmark joystream_utility
-# benchmark storage
+#benchmark storage

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