Browse Source

runtime: storage: Add extrinsic.

- add `update_families_in_dynamic_bag_creation_policy ` extrinsic
Shamil Gadelshin 3 years ago
parent
commit
18b5fb67a2

+ 87 - 20
runtime-modules/storage/src/lib.rs

@@ -68,6 +68,8 @@
 //! updates "Distribution buckets per bag" number limit.
 //! - [update_distribution_bucket_mode](./struct.Module.html#method.distribution_buckets_per_bag_limit) -
 //! updates "distributing" flag for the distribution bucket.
+//! - [update_families_in_dynamic_bag_creation_policy](./struct.Module.html#method.update_families_in_dynamic_bag_creation_policy) -
+//!  updates distribution bucket families used in given dynamic bag creation policy.
 //!
 //! #### Public methods
 //! Public integration methods are exposed via the [DataObjectStorage](./trait.DataObjectStorage.html)
@@ -94,6 +96,8 @@
 //! - MaxDistributionBucketNumberPerFamily
 //!
 
+// Compiler demand.
+#![recursion_limit = "256"]
 // Ensure we're `no_std` when compiling for Wasm.
 #![cfg_attr(not(feature = "std"), no_std)]
 #![warn(missing_docs)]
@@ -268,11 +272,11 @@ pub trait Trait: frame_system::Trait + balances::Trait + membership::Trait {
     /// "Distribution buckets per bag" value constraint.
     type DistributionBucketsPerBagValueConstraint: Get<DistributionBucketsPerBagValueConstraint>;
 
-    /// Defines the default dynamic bag creation policy for members.
-    type DefaultMemberDynamicBagCreationPolicy: Get<DynamicBagCreationPolicy>;
+    /// Defines the default dynamic bag creation policy for members (storage bucket number).
+    type DefaultMemberDynamicBagNumberOfStorageBuckets: Get<u64>;
 
-    /// Defines the default dynamic bag creation policy for channels.
-    type DefaultChannelDynamicBagCreationPolicy: Get<DynamicBagCreationPolicy>;
+    /// Defines the default dynamic bag creation policy for channels (storage bucket number).
+    type DefaultChannelDynamicBagNumberOfStorageBuckets: Get<u64>;
 
     /// Defines max random iteration number (eg.: when picking the storage buckets).
     type MaxRandomIterationNumber: Get<u64>;
@@ -368,12 +372,17 @@ impl<T: balances::Trait, ModId: Get<ModuleId>> ModuleAccount<T> for ModuleAccoun
 /// It describes how many storage buckets should store the bag.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct DynamicBagCreationPolicy {
+pub struct DynamicBagCreationPolicy<DistributionBucketFamilyId: Ord> {
     /// The number of storage buckets which should replicate the new bag.
     pub number_of_storage_buckets: u64,
+
+    /// The set of distribution bucket families which should be sampled
+    /// to distribute bag, and for each the number of buckets in that family
+    /// which should be used.
+    pub families: BTreeMap<DistributionBucketFamilyId, u32>,
 }
 
-impl DynamicBagCreationPolicy {
+impl<DistributionBucketFamilyId: Ord> DynamicBagCreationPolicy<DistributionBucketFamilyId> {
     // Verifies non-zero number of storage buckets.
     pub(crate) fn no_storage_buckets_required(&self) -> bool {
         self.number_of_storage_buckets == 0
@@ -826,7 +835,8 @@ decl_storage! {
 
         /// DynamicBagCreationPolicy by bag type storage map.
         pub DynamicBagCreationPolicies get (fn dynamic_bag_creation_policy):
-            map hasher(blake2_128_concat) DynamicBagType => DynamicBagCreationPolicy;
+            map hasher(blake2_128_concat) DynamicBagType =>
+            DynamicBagCreationPolicy<T::DistributionBucketFamilyId>;
 
         /// Distribution bucket family id counter. Starts at zero.
         pub NextDistributionBucketFamilyId get(fn next_distribution_bucket_family_id):
@@ -1065,6 +1075,15 @@ decl_event! {
         /// - distribution bucket ID
         /// - distributing
         DistributionBucketModeUpdated(DistributionBucketFamilyId, DistributionBucketId, bool),
+
+        /// Emits on dynamic bag creation policy update (distribution bucket families).
+        /// Params
+        /// - dynamic bag type
+        /// - families and bucket numbers
+        FamiliesInDynamicBagCreationPolicyUpdated(
+            DynamicBagType,
+            BTreeMap<DistributionBucketFamilyId, u32>
+        ),
     }
 }
 
@@ -1242,13 +1261,15 @@ decl_module! {
         const StorageBucketsPerBagValueConstraint: StorageBucketsPerBagValueConstraint =
             T::StorageBucketsPerBagValueConstraint::get();
 
-        /// Exports const - the default dynamic bag creation policy for members.
-        const DefaultMemberDynamicBagCreationPolicy: DynamicBagCreationPolicy =
-            T::DefaultMemberDynamicBagCreationPolicy::get();
+        /// Exports const - the default dynamic bag creation policy for members (storage bucket
+        /// number).
+        const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 =
+            T::DefaultMemberDynamicBagNumberOfStorageBuckets::get();
 
-        /// Exports const - the default dynamic bag creation policy for channels.
-        const DefaultChannelDynamicBagCreationPolicy: DynamicBagCreationPolicy =
-            T::DefaultChannelDynamicBagCreationPolicy::get();
+        /// Exports const - the default dynamic bag creation policy for channels (storage bucket
+        /// number).
+        const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 =
+            T::DefaultChannelDynamicBagNumberOfStorageBuckets::get();
 
         /// Exports const - max allowed distribution bucket family number.
         const MaxDistributionBucketFamilyNumber: u64 = T::MaxDistributionBucketFamilyNumber::get();
@@ -1377,7 +1398,7 @@ decl_module! {
 
             creation_policy.number_of_storage_buckets = number_of_storage_buckets;
 
-            DynamicBagCreationPolicies::insert(dynamic_bag_type, creation_policy);
+            DynamicBagCreationPolicies::<T>::insert(dynamic_bag_type, creation_policy);
 
             Self::deposit_event(
                 RawEvent::NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated(
@@ -2041,6 +2062,35 @@ decl_module! {
             );
         }
 
+        /// Update number of distributed buckets used in given dynamic bag creation policy.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn update_families_in_dynamic_bag_creation_policy(
+            origin,
+            dynamic_bag_type: DynamicBagType,
+            families: BTreeMap<T::DistributionBucketFamilyId, u32>
+        ) {
+            T::ensure_distribution_working_group_leader_origin(origin)?;
+
+            Self::validate_update_families_in_dynamic_bag_creation_policy_params(&families)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            let mut creation_policy = Self::get_dynamic_bag_creation_policy(dynamic_bag_type);
+
+            creation_policy.families = families.clone();
+
+            DynamicBagCreationPolicies::<T>::insert(dynamic_bag_type, creation_policy);
+
+            Self::deposit_event(
+                RawEvent::FamiliesInDynamicBagCreationPolicyUpdated(
+                    dynamic_bag_type,
+                    families
+                )
+            );
+        }
+
         // ===== Distribution Operator actions =====
 
     }
@@ -2834,18 +2884,23 @@ impl<T: Trait> Module<T> {
     // Get default dynamic bag policy by bag type.
     fn get_default_dynamic_bag_creation_policy(
         bag_type: DynamicBagType,
-    ) -> DynamicBagCreationPolicy {
-        match bag_type {
-            DynamicBagType::Member => T::DefaultMemberDynamicBagCreationPolicy::get(),
-            DynamicBagType::Channel => T::DefaultChannelDynamicBagCreationPolicy::get(),
+    ) -> DynamicBagCreationPolicy<T::DistributionBucketFamilyId> {
+        let number_of_storage_buckets = match bag_type {
+            DynamicBagType::Member => T::DefaultMemberDynamicBagNumberOfStorageBuckets::get(),
+            DynamicBagType::Channel => T::DefaultChannelDynamicBagNumberOfStorageBuckets::get(),
+        };
+
+        DynamicBagCreationPolicy::<T::DistributionBucketFamilyId> {
+            number_of_storage_buckets,
+            ..Default::default()
         }
     }
 
     // Loads dynamic bag creation policy or use default values.
     pub(crate) fn get_dynamic_bag_creation_policy(
         bag_type: DynamicBagType,
-    ) -> DynamicBagCreationPolicy {
-        if DynamicBagCreationPolicies::contains_key(bag_type) {
+    ) -> DynamicBagCreationPolicy<T::DistributionBucketFamilyId> {
+        if DynamicBagCreationPolicies::<T>::contains_key(bag_type) {
             return Self::dynamic_bag_creation_policy(bag_type);
         }
 
@@ -2941,4 +2996,16 @@ impl<T: Trait> Module<T> {
 
         Ok(())
     }
+
+    // Ensures validity of the `update_families_in_dynamic_bag_creation_policy` extrinsic parameters
+    fn validate_update_families_in_dynamic_bag_creation_policy_params(
+        families: &BTreeMap<T::DistributionBucketFamilyId, u32>,
+    ) -> DispatchResult {
+        // TODO: check bucket number? also for storage buckets?
+        for (family_id, _) in families.iter() {
+            Self::ensure_distribution_bucket_family_exists(family_id)?;
+        }
+
+        Ok(())
+    }
 }

+ 51 - 0
runtime-modules/storage/src/tests/fixtures.rs

@@ -2,6 +2,7 @@ use frame_support::dispatch::DispatchResult;
 use frame_support::storage::StorageMap;
 use frame_support::traits::{Currency, OnFinalize, OnInitialize};
 use frame_system::{EventRecord, Phase, RawOrigin};
+use sp_std::collections::btree_map::BTreeMap;
 use sp_std::collections::btree_set::BTreeSet;
 
 use super::mocks::{
@@ -1577,3 +1578,53 @@ impl UpdateDistributionBucketModeFixture {
         assert_eq!(actual_result, expected_result);
     }
 }
+
+pub struct UpdateFamiliesInDynamicBagCreationPolicyFixture {
+    origin: RawOrigin<u64>,
+    dynamic_bag_type: DynamicBagType,
+    families: BTreeMap<u64, u32>,
+}
+
+impl UpdateFamiliesInDynamicBagCreationPolicyFixture {
+    pub fn default() -> Self {
+        Self {
+            origin: RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID),
+            dynamic_bag_type: Default::default(),
+            families: Default::default(),
+        }
+    }
+
+    pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    pub fn with_families(self, families: BTreeMap<u64, u32>) -> Self {
+        Self { families, ..self }
+    }
+
+    pub fn with_dynamic_bag_type(self, dynamic_bag_type: DynamicBagType) -> Self {
+        Self {
+            dynamic_bag_type,
+            ..self
+        }
+    }
+
+    pub fn call_and_assert(&self, expected_result: DispatchResult) {
+        let old_policy = Storage::get_dynamic_bag_creation_policy(self.dynamic_bag_type);
+
+        let actual_result = Storage::update_families_in_dynamic_bag_creation_policy(
+            self.origin.clone().into(),
+            self.dynamic_bag_type,
+            self.families.clone(),
+        );
+
+        assert_eq!(actual_result, expected_result);
+
+        let new_policy = Storage::get_dynamic_bag_creation_policy(self.dynamic_bag_type);
+        if actual_result.is_ok() {
+            assert_eq!(new_policy.families, self.families);
+        } else {
+            assert_eq!(old_policy, new_policy);
+        }
+    }
+}

+ 6 - 10
runtime-modules/storage/src/tests/mocks.rs

@@ -10,8 +10,6 @@ use sp_runtime::{
     ModuleId, Perbill,
 };
 
-use crate::DynamicBagCreationPolicy;
-
 // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct Test;
@@ -63,12 +61,8 @@ parameter_types! {
         crate::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
     pub const InitialStorageBucketsNumberForDynamicBag: u64 = 3;
     pub const MaxRandomIterationNumber: u64 = 3;
-        pub const DefaultMemberDynamicBagCreationPolicy: DynamicBagCreationPolicy = DynamicBagCreationPolicy{
-        number_of_storage_buckets: 3
-    };
-    pub const DefaultChannelDynamicBagCreationPolicy: DynamicBagCreationPolicy = DynamicBagCreationPolicy{
-        number_of_storage_buckets: 4
-    };
+    pub const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 = 3;
+    pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4;
     pub const DistributionBucketsPerBagValueConstraint: crate::DistributionBucketsPerBagValueConstraint =
         crate::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
 }
@@ -94,8 +88,10 @@ impl crate::Trait for Test {
     type ModuleId = StorageModuleId;
     type MemberOriginValidator = ();
     type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint;
-    type DefaultMemberDynamicBagCreationPolicy = DefaultMemberDynamicBagCreationPolicy;
-    type DefaultChannelDynamicBagCreationPolicy = DefaultChannelDynamicBagCreationPolicy;
+    type DefaultMemberDynamicBagNumberOfStorageBuckets =
+        DefaultMemberDynamicBagNumberOfStorageBuckets;
+    type DefaultChannelDynamicBagNumberOfStorageBuckets =
+        DefaultChannelDynamicBagNumberOfStorageBuckets;
     type Randomness = CollectiveFlip;
     type MaxRandomIterationNumber = MaxRandomIterationNumber;
     type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber;

+ 71 - 5
runtime-modules/storage/src/tests/mod.rs

@@ -8,6 +8,7 @@ use frame_support::traits::Currency;
 use frame_support::{StorageMap, StorageValue};
 use frame_system::RawOrigin;
 use sp_runtime::SaturatedConversion;
+use sp_std::collections::btree_map::BTreeMap;
 use sp_std::collections::btree_set::BTreeSet;
 use sp_std::iter::FromIterator;
 
@@ -21,7 +22,7 @@ use crate::{
 
 use mocks::{
     build_test_externalities, Balances, DataObjectDeletionPrize,
-    DefaultChannelDynamicBagCreationPolicy, DefaultMemberDynamicBagCreationPolicy,
+    DefaultChannelDynamicBagNumberOfStorageBuckets, DefaultMemberDynamicBagNumberOfStorageBuckets,
     InitialStorageBucketsNumberForDynamicBag, MaxNumberOfDataObjectsPerBag,
     MaxRandomIterationNumber, MaxStorageBucketNumber, Storage, Test, ANOTHER_STORAGE_PROVIDER_ID,
     DEFAULT_MEMBER_ACCOUNT_ID, DEFAULT_MEMBER_ID, DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID,
@@ -3254,7 +3255,7 @@ fn test_storage_bucket_picking_for_bag_non_random() {
         assert_eq!(bucket_ids, expected_ids);
 
         // No storage buckets required
-        crate::DynamicBagCreationPolicies::insert(
+        crate::DynamicBagCreationPolicies::<Test>::insert(
             DynamicBagType::Member,
             DynamicBagCreationPolicy::default(),
         );
@@ -3336,7 +3337,7 @@ fn test_storage_bucket_picking_for_bag_with_randomness() {
         assert!(!bucket_ids.contains(removed_bucket_id));
 
         // No storage buckets required
-        crate::DynamicBagCreationPolicies::insert(
+        crate::DynamicBagCreationPolicies::<Test>::insert(
             DynamicBagType::Member,
             DynamicBagCreationPolicy::default(),
         );
@@ -3448,7 +3449,10 @@ fn dynamic_bag_creation_policy_defaults_and_updates_succeeded() {
         // Change member dynamic bag creation policy.
         let dynamic_bag_type = DynamicBagType::Member;
         let policy = Storage::get_dynamic_bag_creation_policy(dynamic_bag_type);
-        assert_eq!(policy, DefaultMemberDynamicBagCreationPolicy::get());
+        assert_eq!(
+            policy.number_of_storage_buckets,
+            DefaultMemberDynamicBagNumberOfStorageBuckets::get()
+        );
 
         UpdateNumberOfStorageBucketsInDynamicBagCreationPolicyFixture::default()
             .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
@@ -3462,7 +3466,10 @@ fn dynamic_bag_creation_policy_defaults_and_updates_succeeded() {
         // Change channel dynamic bag creation policy.
         let dynamic_bag_type = DynamicBagType::Channel;
         let policy = Storage::get_dynamic_bag_creation_policy(dynamic_bag_type);
-        assert_eq!(policy, DefaultChannelDynamicBagCreationPolicy::get());
+        assert_eq!(
+            policy.number_of_storage_buckets,
+            DefaultChannelDynamicBagNumberOfStorageBuckets::get()
+        );
 
         UpdateNumberOfStorageBucketsInDynamicBagCreationPolicyFixture::default()
             .with_origin(RawOrigin::Signed(STORAGE_WG_LEADER_ACCOUNT_ID))
@@ -4065,3 +4072,62 @@ fn update_distribution_bucket_mode_fails_with_invalid_distribution_bucket_family
             ));
     });
 }
+
+#[test]
+fn update_families_in_dynamic_bag_creation_policy_succeeded() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let dynamic_bag_type = DynamicBagType::Channel;
+        let new_bucket_number = 40;
+
+        let family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let families = BTreeMap::from_iter(vec![(family_id, new_bucket_number)]);
+
+        UpdateFamiliesInDynamicBagCreationPolicyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_families(families.clone())
+            .with_dynamic_bag_type(dynamic_bag_type)
+            .call_and_assert(Ok(()));
+
+        EventFixture::assert_last_crate_event(RawEvent::FamiliesInDynamicBagCreationPolicyUpdated(
+            dynamic_bag_type,
+            families,
+        ));
+    });
+}
+
+#[test]
+fn update_families_in_dynamic_bag_creation_policy_fails_with_bad_origin() {
+    build_test_externalities().execute_with(|| {
+        let non_leader_id = 1;
+
+        UpdateFamiliesInDynamicBagCreationPolicyFixture::default()
+            .with_origin(RawOrigin::Signed(non_leader_id))
+            .call_and_assert(Err(DispatchError::BadOrigin));
+    });
+}
+
+#[test]
+fn update_families_in_dynamic_bag_creation_policy_fails_with_invalid_family_id() {
+    build_test_externalities().execute_with(|| {
+        let dynamic_bag_type = DynamicBagType::Channel;
+        let new_bucket_number = 40;
+        let invalid_family_id = 111;
+
+        let families = BTreeMap::from_iter(vec![(invalid_family_id, new_bucket_number)]);
+
+        UpdateFamiliesInDynamicBagCreationPolicyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_families(families.clone())
+            .with_dynamic_bag_type(dynamic_bag_type)
+            .call_and_assert(Err(
+                Error::<Test>::DistributionBucketFamilyDoesntExist.into()
+            ));
+    });
+}

+ 6 - 9
runtime/src/lib.rs

@@ -63,7 +63,6 @@ pub use runtime_api::*;
 use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder, MembershipOriginValidator};
 
 use governance::{council, election};
-use storage::DynamicBagCreationPolicy;
 
 // Node dependencies
 pub use common;
@@ -663,12 +662,8 @@ parameter_types! {
     pub const StorageModuleId: ModuleId = ModuleId(*b"mstorage"); // module storage
     pub const StorageBucketsPerBagValueConstraint: storage::StorageBucketsPerBagValueConstraint =
         storage::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7}; //TODO: adjust value
-    pub const DefaultMemberDynamicBagCreationPolicy: DynamicBagCreationPolicy = DynamicBagCreationPolicy{
-        number_of_storage_buckets: 4
-    }; //TODO: adjust value
-    pub const DefaultChannelDynamicBagCreationPolicy: DynamicBagCreationPolicy = DynamicBagCreationPolicy{
-        number_of_storage_buckets: 4
-    }; //TODO: adjust value
+    pub const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 = 4; //TODO: adjust value
+    pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4; //TODO: adjust value
     pub const DistributionBucketsPerBagValueConstraint: storage::DistributionBucketsPerBagValueConstraint =
         storage::DistributionBucketsPerBagValueConstraint {min: 3, max_min_diff: 7}; //TODO: adjust value
 }
@@ -687,8 +682,10 @@ impl storage::Trait for Runtime {
     type ModuleId = StorageModuleId;
     type MemberOriginValidator = MembershipOriginValidator<Self>;
     type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint;
-    type DefaultMemberDynamicBagCreationPolicy = DefaultMemberDynamicBagCreationPolicy;
-    type DefaultChannelDynamicBagCreationPolicy = DefaultChannelDynamicBagCreationPolicy;
+    type DefaultMemberDynamicBagNumberOfStorageBuckets =
+        DefaultMemberDynamicBagNumberOfStorageBuckets;
+    type DefaultChannelDynamicBagNumberOfStorageBuckets =
+        DefaultChannelDynamicBagNumberOfStorageBuckets;
     type Randomness = RandomnessCollectiveFlip;
     type MaxRandomIterationNumber = MaxRandomIterationNumber;
     type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber;