Browse Source

runtime: storage: Add extrinsic.

- add `cancel_distribution_bucket_operator_invite`
Shamil Gadelshin 3 years ago
parent
commit
de918d9e2c

+ 59 - 2
runtime-modules/storage/src/lib.rs

@@ -67,11 +67,13 @@
 //! - [distribution_buckets_per_bag_limit](./struct.Module.html#method.distribution_buckets_per_bag_limit) -
 //! 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.
+//! updates "distributing" flag for a 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.
 //! - [invite_distribution_bucket_operator](./struct.Module.html#method.invite_distribution_bucket_operator) -
 //!  invites a distribution bucket operator.
+//! - [cancel_distribution_bucket_operator_invite](./struct.Module.html#method.cancel_distribution_bucket_operator_invite) -
+//!  Cancels pending invite for a distribution bucket.
 //!
 //! #### Public methods
 //! Public integration methods are exposed via the [DataObjectStorage](./trait.DataObjectStorage.html)
@@ -1122,15 +1124,27 @@ decl_event! {
             BTreeMap<DistributionBucketFamilyId, u32>
         ),
 
-        /// Emits on dynamic bag creation policy update (distribution bucket families).
+        /// Emits on creating a distribution bucket invitation for the operator.
         /// Params
         /// - distribution bucket family ID
         /// - distribution bucket ID
+        /// - worker ID
         DistributionBucketOperatorInvited(
             DistributionBucketFamilyId,
             DistributionBucketId,
             WorkerId,
         ),
+
+        /// Emits on canceling a distribution bucket invitation for the operator.
+        /// Params
+        /// - distribution bucket family ID
+        /// - distribution bucket ID
+        /// - worker ID
+        DistributionBucketInvitationCancelled(
+            DistributionBucketFamilyId,
+            DistributionBucketId,
+            WorkerId,
+        ),
     }
 }
 
@@ -1289,6 +1303,9 @@ decl_error! {
 
         /// Distribution provider operator already set.
         DistributionProviderOperatorAlreadySet,
+
+        /// No distribution bucket invitation.
+        NoDistributionBucketInvitation,
     }
 }
 
@@ -2184,6 +2201,46 @@ decl_module! {
             );
         }
 
+        /// Cancel pending invite. Must be pending.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn cancel_distribution_bucket_operator_invite(
+            origin,
+            distribution_bucket_family_id: T::DistributionBucketFamilyId,
+            distribution_bucket_id: T::DistributionBucketId,
+            worker_id: WorkerId<T>
+        ) {
+            T::ensure_distribution_working_group_leader_origin(origin)?;
+
+            let mut family =
+                Self::ensure_distribution_bucket_family_exists(&distribution_bucket_family_id)?;
+            let mut bucket = Self::ensure_distribution_bucket_exists(
+                &family,
+                &distribution_bucket_id
+            )?;
+
+            ensure!(
+                bucket.pending_invitations.contains(&worker_id),
+                Error::<T>::NoDistributionBucketInvitation
+            );
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            bucket.pending_invitations.remove(&worker_id);
+            family.distribution_buckets.insert(distribution_bucket_id, bucket);
+
+            <DistributionBucketFamilyById<T>>::insert(distribution_bucket_family_id, family);
+
+            Self::deposit_event(
+                RawEvent::DistributionBucketInvitationCancelled(
+                    distribution_bucket_family_id,
+                    distribution_bucket_id,
+                    worker_id
+                )
+            );
+        }
+
         // ===== Distribution Operator actions =====
 
     }

+ 63 - 1
runtime-modules/storage/src/tests/fixtures.rs

@@ -10,7 +10,9 @@ use super::mocks::{
     DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID, STORAGE_WG_LEADER_ACCOUNT_ID,
 };
 
-use crate::tests::mocks::DISTRIBUTION_WG_LEADER_ACCOUNT_ID;
+use crate::tests::mocks::{
+    DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID, DISTRIBUTION_WG_LEADER_ACCOUNT_ID,
+};
 use crate::{
     BagId, ContentId, DataObjectCreationParameters, DataObjectStorage, DistributionBucketFamily,
     DynamicBagId, DynamicBagType, RawEvent, StaticBagId, StorageBucketOperatorStatus,
@@ -1688,3 +1690,63 @@ impl InviteDistributionBucketOperatorFixture {
         }
     }
 }
+
+pub struct CancelDistributionBucketInvitationFixture {
+    origin: RawOrigin<u64>,
+    bucket_id: u64,
+    family_id: u64,
+    operator_worker_id: u64,
+}
+
+impl CancelDistributionBucketInvitationFixture {
+    pub fn default() -> Self {
+        Self {
+            origin: RawOrigin::Signed(DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID),
+            bucket_id: Default::default(),
+            family_id: Default::default(),
+            operator_worker_id: Default::default(),
+        }
+    }
+
+    pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    pub fn with_bucket_id(self, bucket_id: u64) -> Self {
+        Self { bucket_id, ..self }
+    }
+
+    pub fn with_family_id(self, family_id: u64) -> Self {
+        Self { family_id, ..self }
+    }
+
+    pub fn with_operator_worker_id(self, operator_worker_id: u64) -> Self {
+        Self {
+            operator_worker_id,
+            ..self
+        }
+    }
+
+    pub fn call_and_assert(&self, expected_result: DispatchResult) {
+        let actual_result = Storage::cancel_distribution_bucket_operator_invite(
+            self.origin.clone().into(),
+            self.family_id,
+            self.bucket_id,
+            self.operator_worker_id,
+        );
+
+        assert_eq!(actual_result, expected_result);
+
+        if actual_result.is_ok() {
+            let new_family = Storage::distribution_bucket_family_by_id(self.family_id);
+            let new_bucket = new_family
+                .distribution_buckets
+                .get(&self.bucket_id)
+                .unwrap();
+
+            assert!(!new_bucket
+                .pending_invitations
+                .contains(&self.operator_worker_id));
+        }
+    }
+}

+ 111 - 0
runtime-modules/storage/src/tests/mod.rs

@@ -4327,3 +4327,114 @@ fn invite_distribution_bucket_operator_fails_with_invalid_storage_provider_id()
             ));
     });
 }
+
+#[test]
+fn invite_distribution_bucket_operator_fails_with_invalid_distribution_bucket_family() {
+    build_test_externalities().execute_with(|| {
+        CancelDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Err(
+                Error::<Test>::DistributionBucketFamilyDoesntExist.into()
+            ));
+    });
+}
+
+#[test]
+fn cancel_distribution_bucket_operator_invite_succeeded() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let provider_id = DEFAULT_DISTRIBUTION_PROVIDER_ID;
+
+        let family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let bucket_id = CreateDistributionBucketFixture::default()
+            .with_family_id(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_id(bucket_id)
+            .with_family_id(family_id)
+            .with_operator_worker_id(provider_id)
+            .call_and_assert(Ok(()));
+
+        CancelDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_family_id(family_id)
+            .with_bucket_id(bucket_id)
+            .with_operator_worker_id(provider_id)
+            .call_and_assert(Ok(()));
+
+        EventFixture::assert_last_crate_event(RawEvent::DistributionBucketInvitationCancelled(
+            family_id,
+            bucket_id,
+            provider_id,
+        ));
+    });
+}
+
+#[test]
+fn cancel_distribution_bucket_operator_invite_fails_with_non_leader_origin() {
+    build_test_externalities().execute_with(|| {
+        let non_leader_account_id = 11111;
+
+        CancelDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(non_leader_account_id))
+            .call_and_assert(Err(DispatchError::BadOrigin));
+    });
+}
+
+#[test]
+fn cancel_distribution_bucket_operator_invite_fails_with_non_existing_storage_bucket() {
+    build_test_externalities().execute_with(|| {
+        let family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        CancelDistributionBucketInvitationFixture::default()
+            .with_family_id(family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Err(Error::<Test>::DistributionBucketDoesntExist.into()));
+    });
+}
+
+#[test]
+fn cancel_distribution_bucket_operator_invite_fails_with_non_invited_storage_provider() {
+    build_test_externalities().execute_with(|| {
+        let family_id = CreateDistributionBucketFamilyFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        let bucket_id = CreateDistributionBucketFixture::default()
+            .with_family_id(family_id)
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Ok(()))
+            .unwrap();
+
+        CancelDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .with_family_id(family_id)
+            .with_bucket_id(bucket_id)
+            .call_and_assert(Err(Error::<Test>::NoDistributionBucketInvitation.into()));
+    });
+}
+
+#[test]
+fn cancel_distribution_bucket_operator_invite_fails_with_invalid_distribution_bucket_family() {
+    build_test_externalities().execute_with(|| {
+        CancelDistributionBucketInvitationFixture::default()
+            .with_origin(RawOrigin::Signed(DISTRIBUTION_WG_LEADER_ACCOUNT_ID))
+            .call_and_assert(Err(
+                Error::<Test>::DistributionBucketFamilyDoesntExist.into()
+            ));
+    });
+}