initStorage.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { FlowProps } from '../../Flow'
  2. import { extendDebug } from '../../Debugger'
  3. import { WorkingGroups } from '../../WorkingGroups'
  4. import { IStorageBucketOperatorMetadata, StorageBucketOperatorMetadata } from '@joystream/metadata-protobuf'
  5. import { CreateInterface, createType } from '@joystream/types'
  6. import { BagId, DynamicBagId, StaticBagId } from '@joystream/types/storage'
  7. import _ from 'lodash'
  8. import { Utils } from '../../utils'
  9. import BN from 'bn.js'
  10. type StorageBucketConfig = {
  11. metadata: IStorageBucketOperatorMetadata
  12. staticBags?: CreateInterface<StaticBagId>[]
  13. storageLimit: BN
  14. objectsLimit: number
  15. operatorId: number
  16. transactorKey: string
  17. }
  18. type InitStorageConfig = {
  19. buckets: StorageBucketConfig[]
  20. dynamicBagPolicy: {
  21. [K in keyof typeof DynamicBagId.typeDefinitions]?: number
  22. }
  23. }
  24. export const allStaticBags: CreateInterface<StaticBagId>[] = [
  25. 'Council',
  26. { WorkingGroup: 'Content' },
  27. { WorkingGroup: 'Distribution' },
  28. { WorkingGroup: 'Gateway' },
  29. { WorkingGroup: 'OperationsAlpha' },
  30. { WorkingGroup: 'OperationsBeta' },
  31. { WorkingGroup: 'OperationsGamma' },
  32. { WorkingGroup: 'Storage' },
  33. ]
  34. export const singleBucketConfig: InitStorageConfig = {
  35. dynamicBagPolicy: {
  36. 'Channel': 1,
  37. 'Member': 1,
  38. },
  39. buckets: [
  40. {
  41. metadata: { endpoint: process.env.COLOSSUS_1_URL || 'http://localhost:3333' },
  42. staticBags: allStaticBags,
  43. operatorId: parseInt(process.env.COLOSSUS_1_WORKER_ID || '0'),
  44. storageLimit: new BN(1_000_000_000_000),
  45. objectsLimit: 1000000000,
  46. transactorKey: process.env.COLOSSUS_1_TRANSACTOR_KEY || '5DkE5YD8m5Yzno6EH2RTBnH268TDnnibZMEMjxwYemU4XevU', // //Colossus1
  47. },
  48. ],
  49. }
  50. export const doubleBucketConfig: InitStorageConfig = {
  51. dynamicBagPolicy: {
  52. 'Channel': 2,
  53. 'Member': 2,
  54. },
  55. buckets: [
  56. {
  57. metadata: { endpoint: process.env.COLOSSUS_1_URL || 'http://localhost:3333' },
  58. staticBags: allStaticBags,
  59. operatorId: parseInt(process.env.COLOSSUS_1_WORKER_ID || '0'),
  60. storageLimit: new BN(1_000_000_000_000),
  61. objectsLimit: 1000000000,
  62. transactorKey: process.env.COLOSSUS_1_TRANSACTOR_KEY || '5DkE5YD8m5Yzno6EH2RTBnH268TDnnibZMEMjxwYemU4XevU', // //Colossus1
  63. },
  64. {
  65. metadata: { endpoint: process.env.STORAGE_2_URL || 'http://localhost:3335' },
  66. staticBags: allStaticBags,
  67. operatorId: parseInt(process.env.STORAGE_2_WORKER_ID || '1'),
  68. storageLimit: new BN(1_000_000_000_000),
  69. objectsLimit: 1000000000,
  70. transactorKey: process.env.COLOSSUS_2_TRANSACTOR_KEY || '5FbzYmQ3HogiEEDSXPYJe58yCcmSh3vsZLodTdBB6YuLDAj7', // //Colossus2
  71. },
  72. ],
  73. }
  74. export default function createFlow({ buckets, dynamicBagPolicy }: InitStorageConfig) {
  75. return async function initDistribution({ api }: FlowProps): Promise<void> {
  76. const debug = extendDebug('flow:initStorage')
  77. debug('Started')
  78. // Get working group leaders
  79. const storageLeaderId = await api.getLeadWorkerId(WorkingGroups.Storage)
  80. const storageLeader = await api.getGroupLead(WorkingGroups.Storage)
  81. if (!storageLeaderId || !storageLeader) {
  82. throw new Error('Active storage leader is required in this flow!')
  83. }
  84. const storageLeaderKey = storageLeader.role_account_id.toString()
  85. const maxStorageLimit = buckets.sort((a, b) => b.storageLimit.cmp(a.storageLimit))[0].storageLimit
  86. const maxObjectsLimit = Math.max(...buckets.map((b) => b.objectsLimit))
  87. // Hire operators
  88. // const hireWorkersFixture = new HireWorkesFixture(api, totalBucketsNum, WorkingGroups.Distribution)
  89. // await new FixtureRunner(hireWorkersFixture).run()
  90. // const operatorIds = hireWorkersFixture.getHiredWorkers()
  91. const operatorIds = buckets.map((b) => createType('WorkerId', b.operatorId))
  92. const operatorKeys = await api.getWorkerRoleAccounts(operatorIds, WorkingGroups.Storage)
  93. // Set global limits and policies
  94. const updateDynamicBagPolicyTxs = _.entries(dynamicBagPolicy).map(([bagType, numberOfBuckets]) =>
  95. api.tx.storage.updateNumberOfStorageBucketsInDynamicBagCreationPolicy(
  96. bagType as keyof typeof DynamicBagId.typeDefinitions,
  97. numberOfBuckets
  98. )
  99. )
  100. const setMaxVoucherLimitsTx = api.tx.storage.updateStorageBucketsVoucherMaxLimits(maxStorageLimit, maxObjectsLimit)
  101. const setBucketPerBagLimitTx = api.tx.storage.updateStorageBucketsPerBagLimit(Math.max(5, buckets.length))
  102. await api.signAndSendMany(
  103. [...updateDynamicBagPolicyTxs, setMaxVoucherLimitsTx, setBucketPerBagLimitTx],
  104. storageLeaderKey
  105. )
  106. // Create buckets
  107. const createBucketTxs = buckets.map((b, i) =>
  108. api.tx.storage.createStorageBucket(operatorIds[i], true, b.storageLimit, b.objectsLimit)
  109. )
  110. const createBucketResults = await api.signAndSendMany(createBucketTxs, storageLeaderKey)
  111. const bucketById = new Map<number, StorageBucketConfig>()
  112. createBucketResults.forEach((res, i) => {
  113. const bucketId = api.getEvent(res, 'storage', 'StorageBucketCreated').data[0]
  114. bucketById.set(bucketId.toNumber(), buckets[i])
  115. })
  116. // Accept invitations
  117. const acceptInvitationTxs = Array.from(bucketById.entries()).map(([bucketId, bucketConfig], i) =>
  118. api.tx.storage.acceptStorageBucketInvitation(operatorIds[i], bucketId, bucketConfig.transactorKey)
  119. )
  120. await api.signAndSendManyByMany(acceptInvitationTxs, operatorKeys)
  121. // Bucket metadata and static bags
  122. const bucketSetupPromises = _.flatten(
  123. Array.from(bucketById.entries()).map(([bucketId, bucketConfig], i) => {
  124. const operatorId = operatorIds[i]
  125. const operatorKey = operatorKeys[i]
  126. const metadataBytes = Utils.metadataToBytes(StorageBucketOperatorMetadata, bucketConfig.metadata)
  127. const setMetaTx = api.tx.storage.setStorageOperatorMetadata(operatorId, bucketId, metadataBytes)
  128. const setMetaPromise = api.signAndSendMany([setMetaTx], operatorKey)
  129. const updateBagTxs = (bucketConfig.staticBags || []).map((sBagId) => {
  130. return api.tx.storage.updateStorageBucketsForBag(
  131. createType<BagId, 'BagId'>('BagId', { Static: sBagId }),
  132. createType('BTreeSet<StorageBucketId>', [bucketId]),
  133. createType('BTreeSet<StorageBucketId>', [])
  134. )
  135. })
  136. const updateBagsPromise = api.signAndSendMany(updateBagTxs, storageLeaderKey)
  137. return [updateBagsPromise, setMetaPromise]
  138. })
  139. )
  140. await Promise.all(bucketSetupPromises)
  141. debug('Done')
  142. }
  143. }