瀏覽代碼

storage-cli: sudo-create-sp better input validation

Mokhtar Naamani 4 年之前
父節點
當前提交
3df2f9ce6b

+ 1 - 1
storage-node/packages/cli/src/cli.ts

@@ -49,7 +49,7 @@ const usage = `
   Dev Commands:       Commands to run on a development chain.
     dev-init          Setup chain with Alice as lead and storage provider.
     dev-check         Check the chain is setup with Alice as lead and storage provider.
-    vstore-init      Initialize versioned store, Requires SURI of ContentWorking Lead.
+    sudo-create-sp    Initialize the chain with a lead storage provider.
     
   Type 'storage-cli command' for the exact command usage examples.
   `

+ 71 - 45
storage-node/packages/cli/src/commands/dev.ts

@@ -3,6 +3,8 @@
 import dbug from 'debug'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { RuntimeApi } from '@joystream/storage-runtime-api'
+import { GenericJoyStreamRoleSchema as HRTJson } from '@joystream/types/hiring/schemas/role.schema.typings'
+
 const debug = dbug('joystream:storage-cli:dev')
 
 // Derivation path appended to well known development seed used on
@@ -142,24 +144,52 @@ const init = async (api: RuntimeApi): Promise<any> => {
   return check(api)
 }
 
-// Using sudo create initial storage lead and worker with given keys taken from env variables.
+// Using sudo to create initial storage lead and worker with given keys taken from env variables.
 // Used to quickly setup a storage provider on a new chain before a council is ready.
 const makeMemberInitialLeadAndStorageProvider = async (api: RuntimeApi): Promise<any> => {
+  if (!process.env.SUDO_URI) {
+    throw new Error('required SUDO_URI env variable was not set')
+  }
+
+  if (!process.env.MEMBER_ID) {
+    throw new Error('required MEMBER_ID env variable was not set')
+  }
+
+  if (!process.env.MEMBER_CONTROLLER_URI) {
+    throw new Error('required MEMBER_CONTROLLER_URI env variable was not set')
+  }
+
+  if (!process.env.STORAGE_WORKER_ADDRESS) {
+    throw new Error('required STORAGE_WORKER_ADDRESS env variable was not set')
+  }
+
   const sudoKey = getKeyFromAddressOrSuri(api, process.env.SUDO_URI)
   const memberId = parseInt(process.env.MEMBER_ID)
-  const memberController = getKeyFromAddressOrSuri(api, process.env.MEMBER_URI).address
+  const memberController = getKeyFromAddressOrSuri(api, process.env.MEMBER_CONTROLLER_URI).address
   const leadAccount = memberController
-  const workerAccount = process.env.WORKER_ACCOUNT
+  const workerAccount = process.env.STORAGE_WORKER_ADDRESS
 
   const sudo = await api.identities.getSudoAccount()
 
+  // Ensure correct sudo key was provided
   if (!sudo.eq(sudoKey.address)) {
     throw new Error('Provided SUDO_URI is not the chain sudo')
   }
 
+  // Ensure MEMBER_ID and MEMBER_CONTROLLER_URI are valid
+  const memberIds = await api.identities.memberIdsOfController(memberController)
+  if (memberIds.find((id) => id.eq(memberId)) === undefined) {
+    throw new Error(
+      'MEMBER_ID and MEMBER_CONTROLLER_URI do not correspond to a registered member and their controller account'
+    )
+  }
+
+  // Ensure STORAGE_WORKER_ADDRESS is a valid Address
+  api.identities.keyring.decodeAddress(workerAccount)
+
   debug(`Creating Leader with role key: ${leadAccount}`)
   debug('Creating Lead Opening')
-  const leadOpeningId = await api.workers.devAddStorageLeadOpening(getLeadOpeningInfo())
+  const leadOpeningId = await api.workers.devAddStorageLeadOpening(JSON.stringify(getLeadOpeningInfo()))
   debug('Applying')
   const leadApplicationId = await api.workers.devApplyOnOpening(leadOpeningId, memberId, memberController, leadAccount)
   debug('Starting Review')
@@ -175,7 +205,7 @@ const makeMemberInitialLeadAndStorageProvider = async (api: RuntimeApi): Promise
   // Create a storage openinging, apply, start review, and fill opening
   debug(`Making ${workerAccount} account a storage provider.`)
 
-  const openingId = await api.workers.devAddStorageOpening(getWorkerOpeningInfo())
+  const openingId = await api.workers.devAddStorageOpening(JSON.stringify(getWorkerOpeningInfo()))
   debug(`Created new storage opening: ${openingId}`)
 
   const applicationId = await api.workers.devApplyOnOpening(openingId, memberId, memberController, workerAccount)
@@ -189,54 +219,50 @@ const makeMemberInitialLeadAndStorageProvider = async (api: RuntimeApi): Promise
   debug(`Assigned storage provider id: ${providerId}`)
 }
 
-function getLeadOpeningInfo() {
-  return `{
-    "version": 1,
-    "headline": "Initial Storage Lead",
-    "job": {
-      "title": "Bootstrap Lead",
-      "description": "Starting opportunity to bootstrap the network"
+function getLeadOpeningInfo(): HRTJson {
+  return {
+    'version': 1,
+    'headline': 'Initial Storage Lead',
+    'job': {
+      'title': 'Bootstrap Lead',
+      'description': 'Starting opportunity to bootstrap the network',
     },
-    "application": {
-      "sections": []
+    'application': {
+      'sections': [],
     },
-    "reward": "None",
-    "creator": {
-      "membership": {
-        "handle": "mokhtar"
-      }
+    'reward': 'None',
+    'creator': {
+      'membership': {
+        'handle': 'mokhtar',
+      },
     },
-    "process": {
-      "details": [
-        "automated"
-      ]
-    }
-  }`
+    'process': {
+      'details': ['automated'],
+    },
+  }
 }
 
-function getWorkerOpeningInfo() {
-  return `{
-    "version": 1,
-    "headline": "Initial Storage Worker",
-    "job": {
-      "title": "Bootstrap Worker",
-      "description": "Starting opportunity to bootstrap the network"
+function getWorkerOpeningInfo(): HRTJson {
+  return {
+    'version': 1,
+    'headline': 'Initial Storage Worker',
+    'job': {
+      'title': 'Bootstrap Worker',
+      'description': 'Starting opportunity to bootstrap the network',
     },
-    "application": {
-      "sections": []
+    'application': {
+      'sections': [],
     },
-    "reward": "None",
-    "creator": {
-      "membership": {
-        "handle": "mokhtar"
-      }
+    'reward': 'None',
+    'creator': {
+      'membership': {
+        'handle': 'mokhtar',
+      },
     },
-    "process": {
-      "details": [
-        "automated"
-      ]
-    }
-  }`
+    'process': {
+      'details': ['automated'],
+    },
+  }
 }
 
 export { init, check, aliceKeyPair, roleKeyPair, developmentPort, makeMemberInitialLeadAndStorageProvider }

+ 8 - 0
storage-node/packages/runtime-api/identities.js

@@ -135,6 +135,14 @@ class IdentitiesApi {
     return this.base.api.query.members.memberIdsByRootAccountId(decoded)
   }
 
+  /*
+   * Return all the member IDs of an account by the controller account id
+   */
+  async memberIdsOfController(accountId) {
+    const decoded = this.keyring.decodeAddress(accountId)
+    return this.base.api.query.members.memberIdsByControllerAccountId(decoded)
+  }
+
   /*
    * Return the first member ID of an account, or undefined if not a member root account.
    */