lib.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. // Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
  4. // #![warn(missing_docs)]
  5. // TODO: remove all: #[allow(dead_code)]
  6. // TODO: add module comment
  7. // TODO: add types comments
  8. // TODO: add benchmarks
  9. // TODO: add constants:
  10. // Max size of blacklist.
  11. // Max number of distribution bucket families
  12. // Max number of distribution buckets per family.
  13. // Max number of pending invitations per distribution bucket.
  14. // Max number of data objects per bag.
  15. #[cfg(test)]
  16. mod tests;
  17. #[cfg(feature = "runtime-benchmarks")]
  18. mod benchmarking;
  19. use codec::{Codec, Decode, Encode};
  20. use frame_support::dispatch::DispatchResult;
  21. use frame_support::traits::Get;
  22. use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure, Parameter};
  23. use frame_system::ensure_signed;
  24. #[cfg(feature = "std")]
  25. use serde::{Deserialize, Serialize};
  26. use sp_arithmetic::traits::BaseArithmetic;
  27. use sp_arithmetic::traits::One;
  28. use sp_runtime::traits::{MaybeSerialize, Member};
  29. use sp_std::collections::btree_map::BTreeMap;
  30. use sp_std::collections::btree_set::BTreeSet;
  31. use sp_std::vec::Vec;
  32. /// Storage trait.
  33. pub trait Trait: frame_system::Trait + balances::Trait + membership::Trait {
  34. /// Storage event type.
  35. type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
  36. /// Data object ID type.
  37. type DataObjectId: Parameter
  38. + Member
  39. + BaseArithmetic
  40. + Codec
  41. + Default
  42. + Copy
  43. + MaybeSerialize
  44. + PartialEq;
  45. /// Storage bucket ID type.
  46. type StorageBucketId: Parameter
  47. + Member
  48. + BaseArithmetic
  49. + Codec
  50. + Default
  51. + Copy
  52. + MaybeSerialize
  53. + PartialEq;
  54. /// Defines max allowed storage bucket number.
  55. type MaxStorageBucketNumber: Get<u64>;
  56. }
  57. // /// Member identifier in membership::member module
  58. // pub type MemberId<T> = <T as membership::Trait>::MemberId;
  59. /// Type identifier for worker role, which must be same as membership actor identifier
  60. pub type WorkerId<T> = <T as membership::Trait>::ActorId;
  61. /// Balance alias for `balances` module.
  62. pub type BalanceOf<T> = <T as balances::Trait>::Balance;
  63. //type DistributionBucketId = u64; // TODO: Move to the Trait
  64. // type ChannelId = u64; // Move to the Trait
  65. // type DaoId = u64; // Move to the Trait
  66. // type WorkerId = u64; // Move to the Trait
  67. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  68. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  69. pub struct PendingDataObjectStatus<StorageBucketId> {
  70. pub liaison: StorageBucketId,
  71. }
  72. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  73. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  74. pub enum DataObjectStatus<StorageBucketId> {
  75. Pending(PendingDataObjectStatus<StorageBucketId>),
  76. AcceptedByLiaison,
  77. }
  78. impl<StorageBucketId: Default> Default for DataObjectStatus<StorageBucketId> {
  79. fn default() -> Self {
  80. Self::Pending(Default::default())
  81. }
  82. }
  83. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  84. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  85. pub struct DataObject<StorageBucketId, Balance> {
  86. pub status: DataObjectStatus<StorageBucketId>,
  87. pub deletion_prize: Balance,
  88. }
  89. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  90. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  91. pub struct StaticBag<DataObjectId: Ord, StorageBucketId: Ord, Balance> {
  92. pub objects: BTreeMap<DataObjectId, DataObject<StorageBucketId, Balance>>,
  93. pub stored_by: BTreeSet<StorageBucketId>,
  94. //TODO: implement - pub distributed_by: BTreeSet<DistributionBucketId>,
  95. }
  96. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  97. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  98. pub struct DataObjectCreationParameters {
  99. pub size: u64,
  100. pub ipfs_content_id: Vec<u8>,
  101. }
  102. /// Identifier for a bag.
  103. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  104. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
  105. pub enum BagId {
  106. //TODO: implement - DynamicBag(DynamicBagId),
  107. StaticBag(StaticBagId),
  108. }
  109. impl Default for BagId {
  110. fn default() -> Self {
  111. Self::StaticBag(Default::default())
  112. }
  113. }
  114. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  115. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
  116. pub enum StaticBagId {
  117. Council,
  118. //TODO: implement - WorkingGroup(WorkingGroup),
  119. }
  120. impl Default for StaticBagId {
  121. fn default() -> Self {
  122. Self::Council
  123. }
  124. }
  125. //TODO: implement:
  126. // #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  127. // #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  128. // pub enum DynamicBagId {
  129. // Member(MemberId),
  130. // Channel(ChannelId),
  131. // Dao(DaoId),
  132. // }
  133. //
  134. // impl Default for DynamicBagId {
  135. // fn default() -> Self {
  136. // Self::Member(Default::default())
  137. // }
  138. // }
  139. pub type UploadParameters<T> = UploadParametersObject<<T as frame_system::Trait>::AccountId>;
  140. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  141. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  142. pub struct UploadParametersObject<AccountId> {
  143. /// Public key used authentication in upload to liaison.
  144. pub authentication_key: Vec<u8>,
  145. pub bag: BagId,
  146. pub object_creation: Vec<DataObjectCreationParameters>,
  147. pub deletion_prize_source_account: AccountId,
  148. }
  149. /// Defines storage bucket parameters.
  150. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  151. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  152. pub struct Voucher {
  153. /// Total size limit.
  154. pub size_limit: u64,
  155. /// Object number limit.
  156. pub objects_limit: u64,
  157. /// Current size.
  158. pub size_used: u64,
  159. /// Current object number.
  160. pub objects_used: u64,
  161. }
  162. /// Defines the storage bucket connection to the storage operator (storage WG worker).
  163. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  164. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  165. pub enum StorageBucketOperatorStatus<WorkerId> {
  166. /// No connection.
  167. Missing,
  168. /// Storage operator was invited.
  169. InvitedStorageWorker(WorkerId),
  170. /// Storage operator accepted the invitation.
  171. StorageWorker(WorkerId),
  172. }
  173. impl<WorkerId> Default for StorageBucketOperatorStatus<WorkerId> {
  174. fn default() -> Self {
  175. Self::Missing
  176. }
  177. }
  178. /// A commitment to hold some set of bags for long term storage. A bucket may have a bucket
  179. /// operator, which is a single worker in the storage working group.
  180. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  181. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  182. pub struct StorageBucket<WorkerId> {
  183. /// Current storage operator status.
  184. pub operator_status: StorageBucketOperatorStatus<WorkerId>,
  185. /// Defines whether the bucket accepts new bags.
  186. pub accepting_new_bags: bool,
  187. /// Number of pending (not accepted) data objects.
  188. pub number_of_pending_data_objects: u32,
  189. /// Defines limits for a bucket.
  190. pub voucher: Voucher,
  191. }
  192. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  193. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
  194. pub struct BaggedDataObject<DataObjectId> {
  195. pub bag_id: BagId,
  196. pub data_object_id: DataObjectId,
  197. }
  198. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  199. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  200. pub struct UpdateStorageBucketForStaticBagsParams<StorageBucketId: Ord> {
  201. pub bags: BTreeMap<BagId, BTreeSet<StorageBucketId>>, //TODO: change to StaticBagId
  202. }
  203. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  204. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  205. pub struct AcceptPendingDataObjectsParams<DataObjectId: Ord> {
  206. pub bagged_data_objects: BTreeSet<BaggedDataObject<DataObjectId>>,
  207. }
  208. decl_storage! {
  209. trait Store for Module<T: Trait> as Storage {
  210. // === Static bags
  211. /// Council bag.
  212. pub CouncilBag get(fn council_bag): StaticBag<T::DataObjectId, T::StorageBucketId, BalanceOf<T>>;
  213. /// Storage bucket id counter. Starts at zero.
  214. pub NextStorageBucketId get(fn next_storage_bucket_id): T::StorageBucketId;
  215. /// Total number of the storage buckets in the system.
  216. pub StorageBucketsNumber get(fn storage_buckets_number): u64;
  217. // TODO: rework back to "Storage bucket (flat) map" - BTreemap
  218. /// Storage buckets.
  219. pub StorageBucketById get (fn storage_bucket_by_id): map hasher(blake2_128_concat)
  220. T::StorageBucketId => StorageBucket<WorkerId<T>>;
  221. }
  222. }
  223. decl_event! {
  224. /// Storage events
  225. pub enum Event<T>
  226. where
  227. <T as Trait>::StorageBucketId,
  228. WorkerId = WorkerId<T>,
  229. {
  230. /// Emits on creating the storage bucket.
  231. /// Params
  232. /// - storage bucket ID
  233. /// - invited worker
  234. /// - flag "accepting_new_data_objects"
  235. /// - voucher struct
  236. StorageBucketCreated(StorageBucketId, Option<WorkerId>, bool, Voucher),
  237. }
  238. }
  239. decl_error! {
  240. /// Storage module predefined errors
  241. pub enum Error for Module<T: Trait>{
  242. /// Max storage number limit exceeded.
  243. MaxStorageNumberLimitExceeded,
  244. /// Empty "data object creation" collection.
  245. NoObjectsOnUpload,
  246. }
  247. }
  248. decl_module! {
  249. /// _Storage_ substrate module.
  250. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  251. /// Default deposit_event() handler
  252. fn deposit_event() = default;
  253. /// Predefined errors.
  254. type Error = Error<T>;
  255. /// Exports const - max allowed storage bucket number.
  256. const MaxStorageBucketNumber: u64 = T::MaxStorageBucketNumber::get();
  257. /// Upload new objects, and does so atomically if there is more than one provided.
  258. /// TODO:
  259. /// - Must return rich information about bags & data objects created.
  260. /// - a `can_upload` extrinsic is likely going to be needed
  261. #[weight = 10_000_000] // TODO: adjust weight
  262. pub fn upload(_origin, params: UploadParameters<T>) {
  263. //TODO implement
  264. Self::validate_upload_parameter(&params)?;
  265. }
  266. //TODO: add comment
  267. #[weight = 10_000_000] // TODO: adjust weight
  268. pub fn update_storage_buckets_for_static_bags(
  269. _origin,
  270. _update: UpdateStorageBucketForStaticBagsParams<T::StorageBucketId>
  271. // _update: Vec<(BagId, Vec<T::StorageBucketId>)>
  272. ) {
  273. //TODO implement
  274. }
  275. // ===== Storage Lead actions =====
  276. /// Create storage bucket.
  277. #[weight = 10_000_000] // TODO: adjust weight
  278. pub fn create_storage_bucket(
  279. origin,
  280. invite_worker: Option<WorkerId<T>>,
  281. accepting_new_data_objects: bool,
  282. voucher: Voucher
  283. ) {
  284. ensure_signed(origin)?; // TODO: change to the WG lead verification
  285. let buckets_number = Self::storage_buckets_number();
  286. ensure!(
  287. buckets_number < T::MaxStorageBucketNumber::get(),
  288. Error::<T>::MaxStorageNumberLimitExceeded
  289. );
  290. let operator_status = invite_worker
  291. .map(StorageBucketOperatorStatus::InvitedStorageWorker)
  292. .unwrap_or(StorageBucketOperatorStatus::Missing);
  293. //TODO: validate voucher?
  294. let storage_bucket = StorageBucket {
  295. operator_status,
  296. accepting_new_bags: accepting_new_data_objects, //TODO: correct?
  297. number_of_pending_data_objects: 0,
  298. voucher: voucher.clone(),
  299. };
  300. let storage_bucket_id = Self::next_storage_bucket_id();
  301. //
  302. // == MUTATION SAFE ==
  303. //
  304. StorageBucketsNumber::put(buckets_number + 1);
  305. <NextStorageBucketId<T>>::put(storage_bucket_id + One::one());
  306. <StorageBucketById<T>>::insert(storage_bucket_id, storage_bucket);
  307. Self::deposit_event(
  308. RawEvent::StorageBucketCreated(
  309. storage_bucket_id,
  310. invite_worker,
  311. accepting_new_data_objects,
  312. voucher,
  313. )
  314. );
  315. }
  316. // ===== Storage Operator actions =====
  317. //TODO: add comment
  318. #[weight = 10_000_000] // TODO: adjust weight
  319. pub fn set_storage_operator_metadata(
  320. _origin,
  321. _storage_bucket_id: T::StorageBucketId,
  322. _metadata: Vec<u8>
  323. ) {
  324. //TODO implement
  325. }
  326. //TODO: add comment
  327. #[weight = 10_000_000] // TODO: adjust weight
  328. pub fn accept_pending_data_objects(
  329. _origin,
  330. _worker_id: WorkerId<T>,
  331. _objects: AcceptPendingDataObjectsParams<T::DataObjectId>
  332. ) {
  333. //TODO implement
  334. }
  335. //TODO: add comment
  336. #[weight = 10_000_000] // TODO: adjust weight
  337. pub fn accept_storage_bucket_invitation(_origin, _storage_bucket_id: T::StorageBucketId) {
  338. //TODO implement
  339. }
  340. }
  341. }
  342. impl<T: Trait> Module<T> {
  343. // TODO: add comment
  344. fn validate_upload_parameter(params: &UploadParameters<T>) -> DispatchResult {
  345. //TODO implement
  346. ensure!(
  347. !params.object_creation.is_empty(),
  348. Error::<T>::NoObjectsOnUpload
  349. );
  350. Ok(())
  351. }
  352. }