Преглед изворни кода

Merge branch 'sumer' into sumer-content-dir-impl-channels

Mokhtar Naamani пре 4 година
родитељ
комит
90ec3a521a

+ 2 - 2
cli/src/Api.ts

@@ -527,8 +527,8 @@ export default class Api {
     return exists ? await this._api.query.contentDirectory.entityById<Entity>(id) : null
   }
 
-  async dataObjectByContentId(contentId: ContentId): Promise<DataObject | null> {
-    const dataObject = await this._api.query.dataDirectory.dataObjectByContentId<Option<DataObject>>(contentId)
+  async dataByContentId(contentId: ContentId): Promise<DataObject | null> {
+    const dataObject = await this._api.query.dataDirectory.dataByContentId<Option<DataObject>>(contentId)
     return dataObject.unwrapOr(null)
   }
 

+ 1 - 1
cli/src/commands/media/uploadVideo.ts

@@ -395,7 +395,7 @@ export default class UploadVideoCommand extends MediaCommandBase {
       ipfsCid,
     ])
 
-    const dataObject = await this.getApi().dataObjectByContentId(contentId)
+    const dataObject = await this.getApi().dataByContentId(contentId)
     if (!dataObject) {
       this.error('Data object could not be retrieved from chain', { exit: ExitCodes.ApiError })
     }

+ 5 - 5
node/src/chain_spec/content_config.rs

@@ -1,7 +1,7 @@
 use codec::Decode;
 use node_runtime::{
     common::storage::StorageObjectOwner,
-    data_directory::{DataObject, Quota},
+    data_directory::*,
     ChannelId, ContentId, DAOId, DataDirectoryConfig, MemberId, Runtime,
 };
 use serde::Deserialize;
@@ -125,10 +125,10 @@ pub fn empty_data_directory_config() -> DataDirectoryConfig {
     DataDirectoryConfig {
         data_object_by_content_id: vec![],
         quotas: vec![],
-        quota_size_limit_upper_bound: 20000,
-        quota_objects_limit_upper_bound: 200,
-        global_quota: Quota::new(2000000, 2000),
-        uploading_blocked: false,
+        quota_size_limit_upper_bound: DEFAULT_QUOTA_SIZE_LIMIT_UPPER_BOUND,
+        quota_objects_limit_upper_bound: DEFAULT_QUOTA_OBJECTS_LIMIT_UPPER_BOUND,
+        global_quota: DEFAULT_GLOBAL_QUOTA,
+        uploading_blocked: DEFAULT_UPLOADING_BLOCKED_STATUS,
     }
 }
 

+ 39 - 14
runtime-modules/storage/src/data_directory.rs

@@ -40,6 +40,11 @@ use crate::data_object_type_registry;
 use crate::data_object_type_registry::IsActiveDataObjectType;
 use crate::*;
 
+pub const DEFAULT_QUOTA_SIZE_LIMIT_UPPER_BOUND: u64 = 20000;
+pub const DEFAULT_QUOTA_OBJECTS_LIMIT_UPPER_BOUND: u64 = 200;
+pub const DEFAULT_GLOBAL_QUOTA: Quota = Quota::new(2000000, 2000);
+pub const DEFAULT_UPLOADING_BLOCKED_STATUS: bool = false;
+
 /// The _Data directory_ main _Trait_.
 pub trait Trait:
     pallet_timestamp::Trait
@@ -247,7 +252,7 @@ decl_storage! {
     trait Store for Module<T: Trait> as DataDirectory {
 
         /// Maps data objects by their content id.
-        pub DataObjectByContentId get(fn data_object_by_content_id) config():
+        pub DataByContentId get(fn data_object_by_content_id) config():
             map hasher(blake2_128_concat) T::ContentId => Option<DataObject<T>>;
 
         /// Maps storage owner to it`s quota. Created when the first upload by the new actor occured.
@@ -255,16 +260,16 @@ decl_storage! {
             map hasher(blake2_128_concat) StorageObjectOwner<MemberId<T>, ChannelId<T>, DAOId<T>> => Quota;
 
         /// Upper bound for the Quota size limit.
-        pub QuotaSizeLimitUpperBound get(fn quota_size_limit_upper_bound) config(): u64;
+        pub QuotaSizeLimitUpperBound get(fn quota_size_limit_upper_bound) config(): u64 = DEFAULT_QUOTA_SIZE_LIMIT_UPPER_BOUND;
 
         /// Upper bound for the Quota objects number limit.
-        pub QuotaObjectsLimitUpperBound get(fn quota_objects_limit_upper_bound) config(): u64;
+        pub QuotaObjectsLimitUpperBound get(fn quota_objects_limit_upper_bound) config(): u64 = DEFAULT_QUOTA_OBJECTS_LIMIT_UPPER_BOUND;
 
         /// Global quota.
-        pub GlobalQuota get(fn global_quota) config(): Quota;
+        pub GlobalQuota get(fn global_quota) config(): Quota = DEFAULT_GLOBAL_QUOTA;
 
         /// If all new uploads blocked
-        pub UploadingBlocked get(fn uploading_blocked) config(): bool;
+        pub UploadingBlocked get(fn uploading_blocked) config(): bool = DEFAULT_UPLOADING_BLOCKED_STATUS;
     }
 }
 
@@ -400,7 +405,7 @@ decl_module! {
             new_quota_objects_limit: u64
         ) {
             <StorageWorkingGroup<T>>::ensure_origin_is_active_leader(origin)?;
-            ensure!(new_quota_objects_limit <= Self::quota_objects_limit_upper_bound(), Error::<T>::QuotaSizeLimitUpperBoundExceeded);
+            ensure!(new_quota_objects_limit <= Self::quota_objects_limit_upper_bound(), Error::<T>::QuotaObjectsLimitUpperBoundExceeded);
 
             //
             // == MUTATION SAFE ==
@@ -427,7 +432,7 @@ decl_module! {
             new_quota_size_limit: u64
         ) {
             <StorageWorkingGroup<T>>::ensure_origin_is_active_leader(origin)?;
-            ensure!(new_quota_size_limit <= Self::quota_size_limit_upper_bound(), Error::<T>::QuotaObjectsLimitUpperBoundExceeded);
+            ensure!(new_quota_size_limit <= Self::quota_size_limit_upper_bound(), Error::<T>::QuotaSizeLimitUpperBoundExceeded);
 
             //
             // == MUTATION SAFE ==
@@ -481,7 +486,7 @@ decl_module! {
 
         /// Locks / unlocks content uploading
         #[weight = 10_000_000] // TODO: adjust weight
-        fn update_content_uploading_status(origin, is_blocked: bool) {
+        pub fn update_content_uploading_status(origin, is_blocked: bool) {
             <StorageWorkingGroup<T>>::ensure_origin_is_active_leader(origin)?;
 
             // == MUTATION SAFE ==
@@ -493,6 +498,26 @@ decl_module! {
 }
 
 impl<T: Trait> Module<T> {
+    pub fn initialize_data_directory(
+        quotas: Vec<(
+            StorageObjectOwner<MemberId<T>, ChannelId<T>, DAOId<T>>,
+            Quota,
+        )>,
+        quota_size_limit_upper_bound: u64,
+        quota_objects_limit_upper_bound: u64,
+        global_quota: Quota,
+        uploading_blocked: bool,
+    ) {
+        for (storage_object_owner, quota) in quotas {
+            <Quotas<T>>::insert(storage_object_owner, quota);
+        }
+
+        <QuotaSizeLimitUpperBound>::put(quota_size_limit_upper_bound);
+        <QuotaObjectsLimitUpperBound>::put(quota_objects_limit_upper_bound);
+        <GlobalQuota>::put(global_quota);
+        <UploadingBlocked>::put(uploading_blocked);
+    }
+
     // Ensure given origin can perform operation under specific storage object owner
     fn ensure_storage_object_owner_origin(
         origin: T::Origin,
@@ -620,14 +645,14 @@ impl<T: Trait> Module<T> {
                 ipfs_content_id: content.ipfs_content_id,
             };
 
-            <DataObjectByContentId<T>>::insert(content.content_id, data);
+            <DataByContentId<T>>::insert(content.content_id, data);
         }
 
         // Updade or create owner quota.
         <Quotas<T>>::insert(owner, owner_quota.fill_quota(upload_voucher));
 
         // Update global quota
-        <GlobalQuota>::mutate(|global_quota| global_quota.fill_quota(upload_voucher));
+        <GlobalQuota>::put(Self::global_quota().fill_quota(upload_voucher));
     }
 
     // Complete content removal
@@ -639,7 +664,7 @@ impl<T: Trait> Module<T> {
         let removal_voucher = Self::calculate_content_voucher(content);
 
         for content_id in content_ids {
-            <DataObjectByContentId<T>>::remove(content_id);
+            <DataByContentId<T>>::remove(content_id);
         }
 
         // Updade owner quota.
@@ -648,7 +673,7 @@ impl<T: Trait> Module<T> {
         });
 
         // Update global quota
-        <GlobalQuota>::mutate(|global_quota| global_quota.release_quota(removal_voucher));
+        <GlobalQuota>::put(Self::global_quota().release_quota(removal_voucher));
     }
 
     fn ensure_content_is_valid(
@@ -661,7 +686,7 @@ impl<T: Trait> Module<T> {
             );
 
             ensure!(
-                !<DataObjectByContentId<T>>::contains_key(&content.content_id),
+                !<DataByContentId<T>>::contains_key(&content.content_id),
                 Error::<T>::DataObjectAlreadyAdded
             );
         }
@@ -683,7 +708,7 @@ impl<T: Trait> Module<T> {
         );
 
         data.liaison_judgement = judgement;
-        <DataObjectByContentId<T>>::insert(content_id, data);
+        <DataByContentId<T>>::insert(content_id, data);
 
         Ok(())
     }

+ 341 - 1
runtime-modules/storage/src/tests/data_directory.rs

@@ -1,5 +1,6 @@
 #![cfg(test)]
 
+use crate::data_directory::Error;
 use common::storage::StorageObjectOwner;
 use frame_support::dispatch::DispatchError;
 use system::RawOrigin;
@@ -46,13 +47,352 @@ fn add_content_fails_with_invalid_origin() {
             ipfs_content_id: vec![1, 2, 3, 4],
         };
 
-        // Register a content with 1234 bytes of type 1, which should be recognized.
+        // Make an attempt to register a content with 1234 bytes of type 1, which should be recognized.
         let res =
             TestDataDirectory::add_content(RawOrigin::Root.into(), owner, vec![content_parameters]);
         assert_eq!(res, Err(DispatchError::Other("Bad origin")));
     });
 }
 
+#[test]
+fn add_content_uploading_blocked() {
+    ExtBuilder::default()
+        .uploading_blocked_status(true)
+        .build()
+        .execute_with(|| {
+            let sender = 1u64;
+
+            let owner = StorageObjectOwner::Member(1u64);
+
+            let content_parameters = ContentParameters {
+                content_id: 1,
+                type_id: 1234,
+                size: 0,
+                ipfs_content_id: vec![1, 2, 3, 4],
+            };
+
+            // Make an attempt to register a content, when uploading is blocked.
+            let res = TestDataDirectory::add_content(
+                Origin::signed(sender),
+                owner,
+                vec![content_parameters],
+            );
+            assert_eq!(res, Err(Error::<Test>::ContentUploadingBlocked.into()));
+        });
+}
+
+#[test]
+fn add_content_size_limit_reached() {
+    with_default_mock_builder(|| {
+        let sender = 1u64;
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let content_parameters = ContentParameters {
+            content_id: 1,
+            type_id: 1234,
+            size: DefaultQuota::get().size_limit + 1,
+            ipfs_content_id: vec![1, 2, 3, 4],
+        };
+
+        // Make an attempt to register a content, when uploading is blocked.
+        let res =
+            TestDataDirectory::add_content(Origin::signed(sender), owner, vec![content_parameters]);
+        assert_eq!(res, Err(Error::<Test>::QuotaSizeLimitExceeded.into()));
+    });
+}
+
+#[test]
+fn add_content_objects_limit_reached() {
+    with_default_mock_builder(|| {
+        let sender = 1u64;
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let mut content = vec![];
+
+        for i in 0..=DefaultQuota::get().objects_limit {
+            let content_parameters = ContentParameters {
+                content_id: i + 1,
+                type_id: 1234,
+                size: 0,
+                ipfs_content_id: vec![1, 2, 3, 4],
+            };
+            content.push(content_parameters);
+        }
+
+        // Make an attempt to register a content, when uploading is blocked.
+        let res = TestDataDirectory::add_content(Origin::signed(sender), owner, content);
+        assert_eq!(res, Err(Error::<Test>::QuotaObjectsLimitExceeded.into()));
+    });
+}
+
+#[test]
+fn add_content_global_size_limit_reached() {
+    let global_quota_size_limit = 0;
+    let global_quota_objects_limit = 50;
+
+    ExtBuilder::default()
+        .global_quota(Quota::new(
+            global_quota_size_limit,
+            global_quota_objects_limit,
+        ))
+        .build()
+        .execute_with(|| {
+            let sender = 1u64;
+
+            let owner = StorageObjectOwner::Member(1u64);
+
+            let content_parameters = ContentParameters {
+                content_id: 1,
+                type_id: 1234,
+                size: global_quota_size_limit + 1,
+                ipfs_content_id: vec![1, 2, 3, 4],
+            };
+
+            // Make an attempt to register a content, when uploading is blocked.
+            let res = TestDataDirectory::add_content(
+                Origin::signed(sender),
+                owner,
+                vec![content_parameters],
+            );
+            assert_eq!(res, Err(Error::<Test>::GlobalQuotaSizeLimitExceeded.into()));
+        });
+}
+
+#[test]
+fn add_content_global_objects_limit_reached() {
+    let global_quota_size_limit = 50000;
+    let global_quota_objects_limit = 0;
+
+    ExtBuilder::default()
+        .global_quota(Quota::new(
+            global_quota_size_limit,
+            global_quota_objects_limit,
+        ))
+        .build()
+        .execute_with(|| {
+            let sender = 1u64;
+
+            let owner = StorageObjectOwner::Member(1u64);
+
+            let content_parameters = ContentParameters {
+                content_id: 1,
+                type_id: 1234,
+                size: 0,
+                ipfs_content_id: vec![1, 2, 3, 4],
+            };
+
+            // Make an attempt to register a content, when uploading is blocked.
+            let res = TestDataDirectory::add_content(
+                Origin::signed(sender),
+                owner,
+                vec![content_parameters],
+            );
+            assert_eq!(
+                res,
+                Err(Error::<Test>::GlobalQuotaObjectsLimitExceeded.into())
+            );
+        });
+}
+
+#[test]
+fn delete_content() {
+    with_default_mock_builder(|| {
+        let sender = 1u64;
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let content_id = 1;
+
+        let content_parameters = ContentParameters {
+            content_id,
+            type_id: 1234,
+            size: 1,
+            ipfs_content_id: vec![1, 2, 3, 4],
+        };
+
+        // Register a content with 1234 bytes of type 1, which should be recognized.
+
+        TestDataDirectory::add_content(
+            Origin::signed(sender),
+            owner.clone(),
+            vec![content_parameters],
+        )
+        .unwrap();
+
+        let res =
+            TestDataDirectory::remove_content(Origin::signed(sender), owner, vec![content_id]);
+
+        assert!(res.is_ok());
+    });
+}
+
+#[test]
+fn delete_content_id_not_found() {
+    with_default_mock_builder(|| {
+        let sender = 1u64;
+
+        let content_id = 1;
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        // Make an attempt to remove content under non existent id
+        let res =
+            TestDataDirectory::remove_content(Origin::signed(sender), owner, vec![content_id]);
+
+        assert_eq!(res, Err(Error::<Test>::CidNotFound.into()));
+    });
+}
+
+#[test]
+fn delete_content_owners_are_not_equal() {
+    with_default_mock_builder(|| {
+        let sender = 1u64;
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let second_owner = StorageObjectOwner::Member(10u64);
+
+        let content_id = 1;
+
+        let content_parameters = ContentParameters {
+            content_id,
+            type_id: 1234,
+            size: 1,
+            ipfs_content_id: vec![1, 2, 3, 4],
+        };
+
+        // Register a content with 1234 bytes of type 1, which should be recognized.
+
+        TestDataDirectory::add_content(
+            Origin::signed(sender),
+            owner.clone(),
+            vec![content_parameters],
+        )
+        .unwrap();
+
+        // Make an attempt to remove content, providing a wrong origin
+        let res = TestDataDirectory::remove_content(
+            Origin::signed(sender),
+            second_owner,
+            vec![content_id],
+        );
+
+        assert_eq!(res, Err(Error::<Test>::OwnersAreNotEqual.into()));
+    });
+}
+
+#[test]
+fn update_content_uploading_status() {
+    with_default_mock_builder(|| {
+        SetLeadFixture::set_default_lead();
+
+        let res = TestDataDirectory::update_content_uploading_status(
+            Origin::signed(DEFAULT_LEADER_ACCOUNT_ID),
+            true,
+        );
+
+        assert!(res.is_ok());
+
+        assert_eq!(TestDataDirectory::uploading_blocked(), true);
+    });
+}
+
+#[test]
+fn update_storage_object_owner_quota_objects_limit() {
+    with_default_mock_builder(|| {
+        SetLeadFixture::set_default_lead();
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let new_objects_limit = 20;
+
+        let res = TestDataDirectory::update_storage_object_owner_quota_objects_limit(
+            Origin::signed(DEFAULT_LEADER_ACCOUNT_ID),
+            owner.clone(),
+            new_objects_limit,
+        );
+
+        assert!(res.is_ok());
+
+        assert_eq!(
+            TestDataDirectory::quotas(owner).objects_limit,
+            new_objects_limit
+        );
+    });
+}
+
+#[test]
+fn update_storage_object_owner_quota_objects_limit_upper_bound_exceeded() {
+    with_default_mock_builder(|| {
+        SetLeadFixture::set_default_lead();
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let new_objects_limit = TestDataDirectory::quota_objects_limit_upper_bound() + 1;
+
+        // Make an attempt to update storage object owner quota objects limit, providing value, which exceeds upper bound.
+        let res = TestDataDirectory::update_storage_object_owner_quota_objects_limit(
+            Origin::signed(DEFAULT_LEADER_ACCOUNT_ID),
+            owner.clone(),
+            new_objects_limit,
+        );
+
+        assert_eq!(
+            res,
+            Err(Error::<Test>::QuotaObjectsLimitUpperBoundExceeded.into())
+        );
+    });
+}
+
+#[test]
+fn update_storage_object_owner_quota_size_limit() {
+    with_default_mock_builder(|| {
+        SetLeadFixture::set_default_lead();
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let new_objects_total_size_limit = 1500;
+
+        let res = TestDataDirectory::update_storage_object_owner_quota_size_limit(
+            Origin::signed(DEFAULT_LEADER_ACCOUNT_ID),
+            owner.clone(),
+            new_objects_total_size_limit,
+        );
+
+        assert!(res.is_ok());
+
+        assert_eq!(
+            TestDataDirectory::quotas(owner).size_limit,
+            new_objects_total_size_limit
+        );
+    });
+}
+
+#[test]
+fn update_storage_object_owner_quota_size_limit_upper_bound_exceeded() {
+    with_default_mock_builder(|| {
+        SetLeadFixture::set_default_lead();
+
+        let owner = StorageObjectOwner::Member(1u64);
+
+        let new_objects_total_size_limit = TestDataDirectory::quota_size_limit_upper_bound() + 1;
+
+        // Make an attempt to update storage object owner quota size limit, providing value, which exceeds upper bound.
+        let res = TestDataDirectory::update_storage_object_owner_quota_size_limit(
+            Origin::signed(DEFAULT_LEADER_ACCOUNT_ID),
+            owner.clone(),
+            new_objects_total_size_limit,
+        );
+
+        assert_eq!(
+            res,
+            Err(Error::<Test>::QuotaSizeLimitUpperBoundExceeded.into())
+        );
+    });
+}
+
 #[test]
 fn accept_and_reject_content_fail_with_invalid_storage_provider() {
     with_default_mock_builder(|| {

+ 0 - 28
runtime-modules/storage/src/tests/data_object_type_registry.rs

@@ -1,37 +1,9 @@
 #![cfg(test)]
 
-use frame_support::{StorageMap, StorageValue};
 use system::{EventRecord, Phase, RawOrigin};
 
 use super::mock::*;
 
-const DEFAULT_LEADER_ACCOUNT_ID: u64 = 1;
-const DEFAULT_LEADER_MEMBER_ID: u64 = 1;
-const DEFAULT_LEADER_WORKER_ID: u32 = 1;
-
-struct SetLeadFixture;
-impl SetLeadFixture {
-    fn set_default_lead() {
-        let worker = working_group::Worker {
-            member_id: DEFAULT_LEADER_MEMBER_ID,
-            role_account_id: DEFAULT_LEADER_ACCOUNT_ID,
-            reward_relationship: None,
-            role_stake_profile: None,
-        };
-
-        // Create the worker.
-        <working_group::WorkerById<Test, StorageWorkingGroupInstance>>::insert(
-            DEFAULT_LEADER_WORKER_ID,
-            worker,
-        );
-
-        // Update current lead.
-        <working_group::CurrentLead<Test, StorageWorkingGroupInstance>>::put(
-            DEFAULT_LEADER_WORKER_ID,
-        );
-    }
-}
-
 fn get_last_data_object_type_id() -> u64 {
     let dot_id = match System::events().last().unwrap().event {
         MetaEvent::data_object_type_registry(

+ 45 - 5
runtime-modules/storage/src/tests/mock.rs

@@ -11,13 +11,14 @@ use sp_runtime::{
 };
 
 use crate::data_directory::ContentIdExists;
-use crate::data_directory::Quota;
+pub use crate::data_directory::Quota;
 pub use crate::data_directory::{ContentParameters, StorageObjectOwner};
 use crate::data_object_type_registry::IsActiveDataObjectType;
 use crate::ContentId;
 pub use crate::StorageWorkingGroupInstance;
 pub use crate::{data_directory, data_object_storage_registry, data_object_type_registry};
 use common::currency::GovernanceCurrency;
+use frame_support::StorageValue;
 use membership;
 
 mod working_group_mod {
@@ -45,6 +46,33 @@ impl_outer_event! {
     }
 }
 
+pub const DEFAULT_LEADER_ACCOUNT_ID: u64 = 1;
+pub const DEFAULT_LEADER_MEMBER_ID: u64 = 1;
+pub const DEFAULT_LEADER_WORKER_ID: u32 = 1;
+
+pub struct SetLeadFixture;
+impl SetLeadFixture {
+    pub fn set_default_lead() {
+        let worker = working_group::Worker {
+            member_id: DEFAULT_LEADER_MEMBER_ID,
+            role_account_id: DEFAULT_LEADER_ACCOUNT_ID,
+            reward_relationship: None,
+            role_stake_profile: None,
+        };
+
+        // Create the worker.
+        <working_group::WorkerById<Test, StorageWorkingGroupInstance>>::insert(
+            DEFAULT_LEADER_WORKER_ID,
+            worker,
+        );
+
+        // Update current lead.
+        <working_group::CurrentLead<Test, StorageWorkingGroupInstance>>::put(
+            DEFAULT_LEADER_WORKER_ID,
+        );
+    }
+}
+
 pub const TEST_FIRST_DATA_OBJECT_TYPE_ID: u64 = 1000;
 pub const TEST_FIRST_CONTENT_ID: u64 = 2000;
 pub const TEST_FIRST_RELATIONSHIP_ID: u64 = 3000;
@@ -244,18 +272,20 @@ pub struct ExtBuilder {
     first_content_id: u64,
     first_relationship_id: u64,
     first_metadata_id: u64,
+    uploading_blocked: bool,
 }
 
 impl Default for ExtBuilder {
     fn default() -> Self {
         Self {
-            quota_objects_limit_upper_bound: 200,
-            quota_size_limit_upper_bound: 20000,
-            global_quota: Quota::new(2000000, 2000),
+            quota_objects_limit_upper_bound: DEFAULT_QUOTA_SIZE_LIMIT_UPPER_BOUND,
+            quota_size_limit_upper_bound: DEFAULT_QUOTA_OBJECTS_LIMIT_UPPER_BOUND,
+            global_quota: DEFAULT_GLOBAL_QUOTA,
             first_data_object_type_id: 1,
             first_content_id: 2,
             first_relationship_id: 3,
             first_metadata_id: 4,
+            uploading_blocked: DEFAULT_UPLOADING_BLOCKED_STATUS,
         }
     }
 }
@@ -281,6 +311,16 @@ impl ExtBuilder {
         self
     }
 
+    pub fn uploading_blocked_status(mut self, uploading_blocked: bool) -> Self {
+        self.uploading_blocked = uploading_blocked;
+        self
+    }
+
+    pub fn global_quota(mut self, global_quota: Quota) -> Self {
+        self.global_quota = global_quota;
+        self
+    }
+
     pub fn build(self) -> sp_io::TestExternalities {
         let mut t = system::GenesisConfig::default()
             .build_storage::<Test>()
@@ -292,7 +332,7 @@ impl ExtBuilder {
             global_quota: self.global_quota,
             data_object_by_content_id: vec![],
             quotas: vec![],
-            uploading_blocked: false,
+            uploading_blocked: self.uploading_blocked,
         }
         .assimilate_storage(&mut t)
         .unwrap();

+ 37 - 1
runtime/src/runtime_api.rs

@@ -10,9 +10,12 @@ use sp_runtime::traits::{BlakeTwo256, Block as BlockT, NumberFor};
 use sp_runtime::{generic, ApplyExtrinsicResult};
 use sp_std::vec::Vec;
 
+use crate::{BuilderWorkingGroupInstance, DataDirectory, GatewayWorkingGroupInstance};
+
 use crate::constants::PRIMARY_PROBABILITY;
+
 use crate::{
-    content, AccountId, AuthorityDiscoveryId, Balance, BlockNumber, EpochDuration,
+    content, data_directory, AccountId, AuthorityDiscoveryId, Balance, BlockNumber, EpochDuration,
     GrandpaAuthorityList, GrandpaId, Hash, Index, RuntimeVersion, Signature, VERSION,
 };
 use crate::{
@@ -55,12 +58,45 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<AccountId, Call, Signa
 // pub type Executive =
 //     frame_executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;
 
+// Alias for the builder working group
+pub(crate) type BuilderWorkingGroup<T> =
+    working_group::Module<T, BuilderWorkingGroupInstance>;
+
+// Alias for the gateway working group
+pub(crate) type GatewayWorkingGroup<T> =
+    working_group::Module<T, GatewayWorkingGroupInstance>;
+    
 /// Custom runtime upgrade handler.
 pub struct CustomOnRuntimeUpgrade;
 impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
     fn on_runtime_upgrade() -> Weight {
         content::Module::<Runtime>::on_runtime_upgrade();
 
+        let default_text_constraint = crate::working_group::default_text_constraint();
+        let default_content_working_group_mint_capacity = 0;
+
+        BuilderWorkingGroup::<Runtime>::initialize_working_group(
+            default_text_constraint,
+            default_text_constraint,
+            default_text_constraint,
+            default_content_working_group_mint_capacity,
+        );
+        
+        GatewayWorkingGroup::<Runtime>::initialize_working_group(
+            default_text_constraint,
+            default_text_constraint,
+            default_text_constraint,
+            default_content_working_group_mint_capacity,
+        );
+
+        DataDirectory::initialize_data_directory(
+            Vec::new(),
+            data_directory::DEFAULT_QUOTA_SIZE_LIMIT_UPPER_BOUND,
+            data_directory::DEFAULT_QUOTA_OBJECTS_LIMIT_UPPER_BOUND,
+            data_directory::DEFAULT_GLOBAL_QUOTA,
+            data_directory::DEFAULT_UPLOADING_BLOCKED_STATUS
+        );
+
         // TODO: storage / data_directory migration or clear all data objects
 
         10_000_000 // TODO: adjust weight

+ 1 - 1
storage-node/packages/helios/bin/cli.js

@@ -30,7 +30,7 @@ function makeAssetUrl(contentId, source) {
 }
 
 async function assetRelationshipState(api, contentId, providers) {
-  const dataObject = await api.query.dataDirectory.dataObjectByContentId(contentId)
+  const dataObject = await api.query.dataDirectory.dataByContentId(contentId)
 
   const relationshipIds = await api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId)
 

+ 1 - 1
storage-node/packages/runtime-api/assets.js

@@ -44,7 +44,7 @@ class AssetsApi {
    */
   async getDataObject(contentId) {
     contentId = parseContentId(contentId)
-    return this.base.api.query.dataDirectory.dataObjectByContentId(contentId)
+    return this.base.api.query.dataDirectory.dataByContentId(contentId)
   }
 
   /*

+ 2 - 2
tests/network-tests/src/Api.ts

@@ -1790,8 +1790,8 @@ export class Api {
     return this.sendContentDirectoryTransaction(updateOperations)
   }
 
-  async getDataObjectByContentId(contentId: ContentId): Promise<DataObject | null> {
-    const dataObject = await this.api.query.dataDirectory.dataObjectByContentId<Option<DataObject>>(contentId)
+  async getDataByContentId(contentId: ContentId): Promise<DataObject | null> {
+    const dataObject = await this.api.query.dataDirectory.dataByContentId<Option<DataObject>>(contentId)
     return dataObject.unwrapOr(null)
   }
 

+ 1 - 1
tests/network-tests/src/flows/storageNode/getContentFromStorageNode.ts

@@ -29,7 +29,7 @@ export default async function getContentFromStorageNode({ api, query }: FlowProp
   const contentId = ContentId.decode(registry, dataObjectId)
 
   // Decode data object
-  const dataObject = await api.getDataObjectByContentId(contentId)
+  const dataObject = await api.getDataByContentId(contentId)
 
   assert(dataObject, 'dataObject should not be null')
 

+ 1 - 1
types/augment-codec/augment-api-query.ts

@@ -309,7 +309,7 @@ declare module '@polkadot/api/types/storage' {
       /**
        * Maps data objects by their content id.
        **/
-      dataObjectByContentId: AugmentedQuery<ApiType, (arg: ContentId | string | Uint8Array) => Observable<Option<DataObject>>>;
+      dataByContentId: AugmentedQuery<ApiType, (arg: ContentId | string | Uint8Array) => Observable<Option<DataObject>>>;
       /**
        * Global quota.
        **/

+ 1 - 1
types/augment/augment-api-query.ts

@@ -309,7 +309,7 @@ declare module '@polkadot/api/types/storage' {
       /**
        * Maps data objects by their content id.
        **/
-      dataObjectByContentId: AugmentedQuery<ApiType, (arg: ContentId | string | Uint8Array) => Observable<Option<DataObject>>>;
+      dataByContentId: AugmentedQuery<ApiType, (arg: ContentId | string | Uint8Array) => Observable<Option<DataObject>>>;
       /**
        * Global quota.
        **/

+ 1 - 1
utils/api-scripts/scripts/export-data-directory.js

@@ -15,7 +15,7 @@ const script = async ({ api }) => {
 
   const transformed = await Promise.all(
     ids.map(async (id) => {
-      let obj = await api.query.dataDirectory.dataObjectByContentId(id)
+      let obj = await api.query.dataDirectory.dataByContentId(id)
       if (obj.isNone) {
         return null
       }

+ 1 - 1
utils/api-scripts/scripts/list-data-directory.js

@@ -12,7 +12,7 @@ const script = async ({ api }) => {
 
   await Promise.all(
     ids.map(async (id) => {
-      let obj = await api.query.dataDirectory.dataObjectByContentId(id)
+      let obj = await api.query.dataDirectory.dataByContentId(id)
       if (obj.isNone) {
         return
       }