Quellcode durchsuchen

storage node: additional updates

Mokhtar Naamani vor 4 Jahren
Ursprung
Commit
070e23dc28

+ 29 - 24
storage-node/packages/cli/bin/dev.js

@@ -1,22 +1,22 @@
-function aliceKeyPair (runtime_api) {
-  return runtime_api.identities.keyring.addFromUri('//Alice', null, 'sr25519')
+function aliceKeyPair (api) {
+  return api.identities.keyring.addFromUri('//Alice', null, 'sr25519')
 }
 
 // Setup Alice account on a developement chain that was
 // just launched as the storage lead, and a storage provider using the same
 // key as the role key
-const init = async (runtime_api) => {
-  const alice = aliceKeyPair(runtime_api).address
+const init = async (api) => {
+  const alice = aliceKeyPair(api).address
   const providerId = 0 // first assignable id
 
   // Check if setup already completed
-  if (await runtime_api.workers.isRoleAccountOfStorageProvider(providerId, alice)) {
+  if (await api.workers.isRoleAccountOfStorageProvider(providerId, alice)) {
     console.log('Alice already setup as a storage provider')
     return
   }
 
   // make sure alice is sudo - indirectly checking this is a dev chain
-  const sudo = await runtime_api.api.query.sudo.key()
+  const sudo = await api.api.query.sudo.key()
 
   if (!sudo.eq(alice)) {
     throw new Error('Setup requires Alice to be sudo. Are you sure you are running a devchain?')
@@ -25,18 +25,18 @@ const init = async (runtime_api) => {
   // register alice as a member if not already registered
   console.log(`Registering Alice as a member`)
   const aliceMemberId = 0 // first assignable id
-  runtime_api.identities.registerMember(alice, {
+  api.identities.registerMember(alice, {
     handle: 'alice'
   })
 
   // Make alice the storage lead
   // prepare set storage lead tx
-  const setLeadTx = runtime_api.api.tx.storageWorkingGroup.setLead(aliceMemberId, alice)
+  const setLeadTx = api.api.tx.storageWorkingGroup.setLead(aliceMemberId, alice)
   // make sudo call
   console.log('Setting Alice as Lead')
-  runtime_api.signAndSend(
+  api.signAndSend(
     alice,
-    runtime_api.api.tx.sudo.sudo(setLeadTx)
+    api.api.tx.sudo.sudo(setLeadTx)
   )
 
   // create an openinging, apply, start review, fill opening
@@ -44,48 +44,53 @@ const init = async (runtime_api) => {
   // so we don't await each tx to finalize to get the ids. this allows us to
   // batch all the transactions into a single block.
   console.log('Making Alice a storage provider')
-  const openTx = runtime_api.api.tx.storageWorkingGroup.addWorkerOpening('CurrentBlock', {
+  const openTx = api.api.tx.storageWorkingGroup.addWorkerOpening('CurrentBlock', {
     application_rationing_policy: {
       'max_active_applicants': 1
     },
     max_review_period_length: 1000
     // default values for everything else..
   }, 'opening0')
-  runtime_api.signAndSend(alice, openTx)
+  api.signAndSend(alice, openTx)
   const openingId = 0 // first id
-  const applyTx = runtime_api.api.tx.storageWorkingGroup.applyOnWorkerOpening(
+  const applyTx = api.api.tx.storageWorkingGroup.applyOnWorkerOpening(
     aliceMemberId, openingId, alice, null, null, 'alice'
   )
-  runtime_api.signAndSend(alice, applyTx)
+  api.signAndSend(alice, applyTx)
   const applicantId = 0 // first applicant id
 
-  const reviewTx = runtime_api.api.tx.storageWorkingGroup.beginWorkerApplicantReview(openingId)
-  runtime_api.signAndSend(alice, reviewTx)
+  const reviewTx = api.api.tx.storageWorkingGroup.beginWorkerApplicantReview(openingId)
+  api.signAndSend(alice, reviewTx)
 
-  const fillTx = runtime_api.api.tx.storageWorkingGroup.fillWorkerOpening(openingId, [applicantId], null)
+  const fillTx = api.api.tx.storageWorkingGroup.fillWorkerOpening(openingId, [applicantId], null)
 
-  await runtime_api.signAndSend(alice, fillTx)
+  await api.signAndSend(alice, fillTx)
 
-  // const worker = await runtime_api.workers.storageWorkerByProviderId(providerId)
-  if (await runtime_api.workers.isRoleAccountOfStorageProvider(providerId, alice)) {
+  // const worker = await api.workers.storageWorkerByProviderId(providerId)
+  if (await api.workers.isRoleAccountOfStorageProvider(providerId, alice)) {
     console.log('Setup Successful')
   } else { throw new Error('Setup Failed') }
+
+  // set localhost colossus as discovery provider on default port
+  const bootstrapTx = api.discovery.setBootstrapEndpoints(['http://localhost:3001/'])
+  await api.signAndSend(alice, bootstrapTx)
 }
 
-const check = async (runtime_api) => {
+const check = async (api) => {
   const providerId = 0
-  const roleAccountId = aliceKeyPair(runtime_api).address
+  const roleAccountId = aliceKeyPair(api).address
 
-  if (await runtime_api.workers.isRoleAccountOfStorageProvider(providerId, roleAccountId)) {
+  if (await api.workers.isRoleAccountOfStorageProvider(providerId, roleAccountId)) {
     console.log('Alice is correctly setup as a storage provider')
   } else { throw new Error('Alice is not setup as a storage provider') }
 
-  const currentLead = await runtime_api.api.query.storageWorkingGroup.currentLead()
+  const currentLead = await api.api.query.storageWorkingGroup.currentLead()
 
   if (currentLead.isSome && currentLead.unwrap().role_account_id.eq(roleAccountId)) {
     console.log('Alice is correctly setup as the storage lead')
   } else { throw new Error('Alice is not the storage lead') }
 }
+
 module.exports = {
   init,
   check,

+ 56 - 73
storage-node/packages/runtime-api/assets.js

@@ -1,14 +1,9 @@
-'use strict';
+'use strict'
 
-const debug = require('debug')('joystream:runtime:assets');
+const debug = require('debug')('joystream:runtime:assets')
+const { decodeAddress } = require('@polkadot/keyring')
 
-const { Null } = require('@polkadot/types/primitive');
-
-const { _ } = require('lodash');
-
-const { decodeAddress, encodeAddress } = require('@polkadot/keyring');
-
-function parseContentId(contentId) {
+function parseContentId (contentId) {
   try {
     return decodeAddress(contentId)
   } catch (err) {
@@ -19,157 +14,145 @@ function parseContentId(contentId) {
 /*
  * Add asset related functionality to the substrate API.
  */
-class AssetsApi
-{
-  static async create(base)
-  {
-    const ret = new AssetsApi();
-    ret.base = base;
-    await ret.init();
-    return ret;
+class AssetsApi {
+  static async create (base) {
+    const ret = new AssetsApi()
+    ret.base = base
+    await ret.init()
+    return ret
   }
 
-  async init(account_file)
-  {
-    debug('Init');
+  async init () {
+    debug('Init')
   }
 
   /*
    * Create a data object.
    */
-  async createDataObject(accountId, memberId, contentId, doTypeId, size, ipfs_cid)
-  {
+  async createDataObject (accountId, memberId, contentId, doTypeId, size, ipfsCid) {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.addContent(memberId, contentId, doTypeId, size, ipfs_cid);
-    await this.base.signAndSend(accountId, tx);
+    const tx = this.base.api.tx.dataDirectory.addContent(memberId, contentId, doTypeId, size, ipfsCid)
+    await this.base.signAndSend(accountId, tx)
 
     // If the data object constructed properly, we should now be able to return
     // the data object from the state.
-    return this.getDataObject(contentId);
+    return this.getDataObject(contentId)
   }
 
   /*
    * Return the Data Object for a CID
    */
-  async getDataObject(contentId)
-  {
+  async getDataObject (contentId) {
     contentId = parseContentId(contentId)
-    const obj = await this.base.api.query.dataDirectory.dataObjectByContentId(contentId);
-    return obj;
+    return this.base.api.query.dataDirectory.dataObjectByContentId(contentId)
   }
 
   /*
    * Verify the liaison state for a DO:
    * - Check the content ID has a DO
-   * - Check the account is the liaison
+   * - Check the storageProviderId is the liaison
    * - Check the liaison state is pending
    *
    * Each failure errors out, success returns the data object.
    */
-  async checkLiaisonForDataObject(storageProviderId, contentId)
-  {
+  async checkLiaisonForDataObject (storageProviderId, contentId) {
     contentId = parseContentId(contentId)
 
-    let obj = await this.getDataObject(contentId);
+    let obj = await this.getDataObject(contentId)
 
     if (obj.isNone) {
-      throw new Error(`No DataObject created for content ID: ${contentId}`);
+      throw new Error(`No DataObject created for content ID: ${contentId}`)
     }
 
     if (obj.liaison.neq(storageProviderId)) {
-      throw new Error(`This storage node is not liaison for the content ID: ${contentId}`);
+      throw new Error(`This storage node is not liaison for the content ID: ${contentId}`)
     }
 
-    if (obj.liaison_judgement.type != 'Pending') {
-      throw new Error(`Expected Pending judgement, but found: ${obj.liaison_judgement.type}`);
+    if (obj.liaison_judgement.type !== 'Pending') {
+      throw new Error(`Expected Pending judgement, but found: ${obj.liaison_judgement.type}`)
     }
 
-    return obj.unwrap();
+    return obj.unwrap()
   }
 
   /*
    * Changes a data object liaison judgement.
    */
-  async acceptContent(providerAccoundId, storageProviderId, contentId)
-  {
+  async acceptContent (providerAccoundId, storageProviderId, contentId) {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.acceptContent(storageProviderId, contentId);
-    return await this.base.signAndSend(providerAccoundId, tx);
+    const tx = this.base.api.tx.dataDirectory.acceptContent(storageProviderId, contentId)
+    return this.base.signAndSend(providerAccoundId, tx)
   }
 
   /*
    * Changes a data object liaison judgement.
    */
-  async rejectContent(providerAccountId, storageProviderId, contentId)
-  {
+  async rejectContent (providerAccountId, storageProviderId, contentId) {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.rejectContent(storageProviderId, contentId);
-    return await this.base.signAndSend(providerAccountId, tx);
+    const tx = this.base.api.tx.dataDirectory.rejectContent(storageProviderId, contentId)
+    return this.base.signAndSend(providerAccountId, tx)
   }
 
   /*
    * Create storage relationship
    */
-  async createStorageRelationship(providerAccountId, storageProviderId, contentId, callback)
-  {
+  async createStorageRelationship (providerAccountId, storageProviderId, contentId, callback) {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataObjectStorageRegistry.addRelationship(storageProviderId, contentId);
+    const tx = this.base.api.tx.dataObjectStorageRegistry.addRelationship(storageProviderId, contentId)
 
-    const subscribed = [['dataObjectStorageRegistry', 'DataObjectStorageRelationshipAdded']];
-    return await this.base.signAndSend(providerAccountId, tx, 3, subscribed, callback);
+    const subscribed = [['dataObjectStorageRegistry', 'DataObjectStorageRelationshipAdded']]
+    return this.base.signAndSend(providerAccountId, tx, 3, subscribed, callback)
   }
 
   /*
    * Get storage relationship for contentId
    */
-  async getStorageRelationshipAndId(storageProviderId, contentId) {
+  async getStorageRelationshipAndId (storageProviderId, contentId) {
     contentId = parseContentId(contentId)
-    let rids = await this.base.api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId);
+    let rids = await this.base.api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId)
 
-    while(rids.length) {
-      const relationshipId = rids.shift();
-      let relationship = await this.base.api.query.dataObjectStorageRegistry.relationships(relationshipId);
-      relationship = relationship.unwrap();
+    while (rids.length) {
+      const relationshipId = rids.shift()
+      let relationship = await this.base.api.query.dataObjectStorageRegistry.relationships(relationshipId)
+      relationship = relationship.unwrap()
       if (relationship.storage_provider.eq(storageProviderId)) {
-        return ({ relationship, relationshipId });
+        return ({ relationship, relationshipId })
       }
     }
 
-    return {};
+    return {}
   }
 
-  async createAndReturnStorageRelationship(providerAccountId, storageProviderId, contentId)
-  {
+  async createAndReturnStorageRelationship (providerAccountId, storageProviderId, contentId) {
     contentId = parseContentId(contentId)
     return new Promise(async (resolve, reject) => {
       try {
         await this.createStorageRelationship(providerAccountId, storageProviderId, contentId, (events) => {
           events.forEach((event) => {
-            resolve(event[1].DataObjectStorageRelationshipId);
-          });
-        });
+            resolve(event[1].DataObjectStorageRelationshipId)
+          })
+        })
       } catch (err) {
-        reject(err);
+        reject(err)
       }
-    });
+    })
   }
 
   /*
    * Toggle ready state for DOSR.
    */
-  async toggleStorageRelationshipReady(providerAccountId, storageProviderId, dosrId, ready)
-  {
+  async toggleStorageRelationshipReady (providerAccountId, storageProviderId, dosrId, ready) {
     var tx = ready
       ? this.base.api.tx.dataObjectStorageRegistry.setRelationshipReady(storageProviderId, dosrId)
-      : this.base.api.tx.dataObjectStorageRegistry.unsetRelationshipReady(storageProviderId, dosrId);
-    return await this.base.signAndSend(providerAccountId, tx);
+      : this.base.api.tx.dataObjectStorageRegistry.unsetRelationshipReady(storageProviderId, dosrId)
+    return this.base.signAndSend(providerAccountId, tx)
   }
 
-  async getKnownContentIds() {
-    return this.base.api.query.dataDirectory.knownContentIds();
+  async getKnownContentIds () {
+    return this.base.api.query.dataDirectory.knownContentIds()
   }
 }
 
 module.exports = {
-  AssetsApi: AssetsApi,
+  AssetsApi
 }

+ 23 - 27
storage-node/packages/runtime-api/discovery.js

@@ -1,37 +1,33 @@
-'use strict';
+'use strict'
 
-const debug = require('debug')('joystream:runtime:discovery');
+const debug = require('debug')('joystream:runtime:discovery')
 
 /*
  * Add discovery related functionality to the substrate API.
  */
-class DiscoveryApi
-{
-  static async create(base)
-  {
-    const ret = new DiscoveryApi();
-    ret.base = base;
-    await ret.init();
-    return ret;
+class DiscoveryApi {
+  static async create (base) {
+    const ret = new DiscoveryApi()
+    ret.base = base
+    await ret.init()
+    return ret
   }
 
-  async init(account_file)
-  {
-    debug('Init');
+  async init () {
+    debug('Init')
   }
 
   /*
    * Get Bootstrap endpoints
    */
-  async getBootstrapEndpoints() {
+  async getBootstrapEndpoints () {
     return this.base.api.query.discovery.bootstrapEndpoints()
   }
 
   /*
-   * Get AccountInfo of an accountId
+   * Get AccountInfo of a storage provider
    */
-  async getAccountInfo(storageProviderId) {
-    const decoded = this.base.identities.keyring.decodeAddress(accountId, true)
+  async getAccountInfo (storageProviderId) {
     const info = await this.base.api.query.discovery.accountInfoByAccountId(storageProviderId)
     // Not an Option so we use default value check to know if info was found
     return info.expires_at.eq(0) ? null : info
@@ -40,25 +36,25 @@ class DiscoveryApi
   /*
    * Set AccountInfo of an accountId
    */
-  async setAccountInfo(accountId, ipnsId, ttl) {
-    const isActor = await this.base.identities.isActor(accountId)
-    if (isActor) {
-      const tx = this.base.api.tx.discovery.setIpnsId(ipnsId, ttl)
-      return this.base.signAndSend(accountId, tx)
+  async setAccountInfo (storageProviderId, ipnsId) {
+    const isProvider = await this.base.workers.isStorageProvider(storageProviderId)
+    if (isProvider) {
+      const tx = this.base.api.tx.discovery.setIpnsId(storageProviderId, ipnsId)
+      return this.base.signAndSend(this.base.identities.key.address, tx)
     } else {
-      throw new Error('Cannot set AccountInfo for non actor account')
+      throw new Error('Cannot set AccountInfo, id is not a storage provider')
     }
   }
 
   /*
    * Clear AccountInfo of an accountId
    */
-  async unsetAccountInfo(accountId) {
-    var tx = this.base.api.tx.discovery.unsetIpnsId()
-    return this.base.signAndSend(accountId, tx)
+  async unsetAccountInfo (storageProviderId) {
+    var tx = this.base.api.tx.discovery.unsetIpnsId(storageProviderId)
+    return this.base.signAndSend(this.base.identities.key.address, tx)
   }
 }
 
 module.exports = {
-  DiscoveryApi: DiscoveryApi,
+  DiscoveryApi
 }

+ 62 - 76
storage-node/packages/runtime-api/identities.js

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * but WITHOUT ANY WARRANTY without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
@@ -16,178 +16,164 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-'use strict';
+'use strict'
 
-const path = require('path');
-const fs = require('fs');
-// const readline = require('readline');
+const path = require('path')
+const fs = require('fs')
+// const readline = require('readline')
 
-const debug = require('debug')('joystream:runtime:identities');
-
-const { Keyring } = require('@polkadot/keyring');
-// const { Null } = require('@polkadot/types/primitive');
-const util_crypto = require('@polkadot/util-crypto');
-
-// const { _ } = require('lodash');
+const debug = require('debug')('joystream:runtime:identities')
+const { Keyring } = require('@polkadot/keyring')
 
 /*
  * Add identity management to the substrate API.
  *
  * This loosely groups: accounts, key management, and membership.
  */
-class IdentitiesApi
-{
-  static async create(base, {account_file, passphrase, canPromptForPassphrase})
-  {
-    const ret = new IdentitiesApi();
-    ret.base = base;
-    await ret.init(account_file, passphrase, canPromptForPassphrase);
-    return ret;
+class IdentitiesApi {
+  static async create (base, {account_file, passphrase, canPromptForPassphrase}) {
+    const ret = new IdentitiesApi()
+    ret.base = base
+    await ret.init(account_file, passphrase, canPromptForPassphrase)
+    return ret
   }
 
-  async init(account_file, passphrase, canPromptForPassphrase)
-  {
-    debug('Init');
+  async init (account_file, passphrase, canPromptForPassphrase) {
+    debug('Init')
 
     // Creatre keyring
-    this.keyring = new Keyring();
+    this.keyring = new Keyring()
 
-    this.canPromptForPassphrase = canPromptForPassphrase || false;
+    this.canPromptForPassphrase = canPromptForPassphrase || false
 
     // Load account file, if possible.
     try {
-      this.key = await this.loadUnlock(account_file, passphrase);
+      this.key = await this.loadUnlock(account_file, passphrase)
     } catch (err) {
-      debug('Error loading account file:', err.message);
+      debug('Error loading account file:', err.message)
     }
   }
 
   /*
    * Load a key file and unlock it if necessary.
    */
-  async loadUnlock(account_file, passphrase)
-  {
-    const fullname = path.resolve(account_file);
-    debug('Initializing key from', fullname);
-    const key = this.keyring.addFromJson(require(fullname));
-    await this.tryUnlock(key, passphrase);
-    debug('Successfully initialized with address', key.address);
-    return key;
+  async loadUnlock (account_file, passphrase) {
+    const fullname = path.resolve(account_file)
+    debug('Initializing key from', fullname)
+    const key = this.keyring.addFromJson(require(fullname))
+    await this.tryUnlock(key, passphrase)
+    debug('Successfully initialized with address', key.address)
+    return key
   }
 
   /*
    * Try to unlock a key if it isn't already unlocked.
    * passphrase should be supplied as argument.
    */
-  async tryUnlock(key, passphrase)
-  {
+  async tryUnlock (key, passphrase) {
     if (!key.isLocked) {
       debug('Key is not locked, not attempting to unlock')
-      return;
+      return
     }
 
     // First try with an empty passphrase - for convenience
     try {
-      key.decodePkcs8('');
+      key.decodePkcs8('')
 
       if (passphrase) {
-        debug('Key was not encrypted, supplied passphrase was ignored');
+        debug('Key was not encrypted, supplied passphrase was ignored')
       }
 
-      return;
+      return
     } catch (err) {
       // pass
     }
 
     // Then with supplied passphrase
     try {
-      debug('Decrypting with supplied passphrase');
-      key.decodePkcs8(passphrase);
-      return;
+      debug('Decrypting with supplied passphrase')
+      key.decodePkcs8(passphrase)
+      return
     } catch (err) {
       // pass
     }
 
     // If that didn't work, ask for a passphrase if appropriate
     if (this.canPromptForPassphrase) {
-      passphrase = await this.askForPassphrase(key.address);
-      key.decodePkcs8(passphrase);
+      passphrase = await this.askForPassphrase(key.address)
+      key.decodePkcs8(passphrase)
       return
     }
 
-    throw new Error('invalid passphrase supplied');
+    throw new Error('invalid passphrase supplied')
   }
 
   /*
    * Ask for a passphrase
    */
-  askForPassphrase(address)
-  {
+  askForPassphrase (address) {
     // Query for passphrase
-    const prompt = require('password-prompt');
-    return prompt(`Enter passphrase for ${address}: `, { required: false });
+    const prompt = require('password-prompt')
+    return prompt(`Enter passphrase for ${address}: `, { required: false })
   }
 
   /*
    * Return true if the account is a member
    */
-  async isMember(accountId)
-  {
-    const memberIds = await this.memberIdsOf(accountId); // return array of member ids
+  async isMember (accountId) {
+    const memberIds = await this.memberIdsOf(accountId) // return array of member ids
     return memberIds.length > 0 // true if at least one member id exists for the acccount
   }
 
   /*
    * Return the member IDs of an account
    */
-  async memberIdsOf(accountId)
-  {
-    const decoded = this.keyring.decodeAddress(accountId);
-    return await this.base.api.query.members.memberIdsByRootAccountId(decoded);
+  async memberIdsOf (accountId) {
+    const decoded = this.keyring.decodeAddress(accountId)
+    return this.base.api.query.members.memberIdsByRootAccountId(decoded)
   }
 
   /*
    * Return the first member ID of an account, or undefined if not a member.
    */
-  async firstMemberIdOf(accountId)
-  {
-    const decoded = this.keyring.decodeAddress(accountId);
-    let ids = await this.base.api.query.members.memberIdsByRootAccountId(decoded);
+  async firstMemberIdOf (accountId) {
+    const decoded = this.keyring.decodeAddress(accountId)
+    let ids = await this.base.api.query.members.memberIdsByRootAccountId(decoded)
     return ids[0]
   }
 
   /*
    * Export a key pair to JSON. Will ask for a passphrase.
    */
-  async exportKeyPair(accountId)
-  {
-    const passphrase = await this.askForPassphrase(accountId);
+  async exportKeyPair (accountId) {
+    const passphrase = await this.askForPassphrase(accountId)
 
     // Produce JSON output
-    return this.keyring.toJson(accountId, passphrase);
+    return this.keyring.toJson(accountId, passphrase)
   }
 
   /*
    * Export a key pair and write it to a JSON file with the account ID as the
    * name.
    */
-  async writeKeyPairExport(accountId, prefix)
-  {
+  async writeKeyPairExport (accountId, prefix) {
     // Generate JSON
-    const data = await this.exportKeyPair(accountId);
+    const data = await this.exportKeyPair(accountId)
 
     // Write JSON
-    var filename = `${data.address}.json`;
+    var filename = `${data.address}.json`
+
     if (prefix) {
-      const path = require('path');
-      filename = path.resolve(prefix, filename);
+      const path = require('path')
+      filename = path.resolve(prefix, filename)
     }
+
     fs.writeFileSync(filename, JSON.stringify(data), {
       encoding: 'utf8',
-      mode: 0o600,
-    });
+      mode: 0o600
+    })
 
-    return filename;
+    return filename
   }
 
   async registerMember (accountId, userInfo) {
@@ -208,5 +194,5 @@ class IdentitiesApi
 }
 
 module.exports = {
-  IdentitiesApi: IdentitiesApi,
+  IdentitiesApi
 }

+ 104 - 112
storage-node/packages/runtime-api/index.js

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * but WITHOUT ANY WARRANTY without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
@@ -16,70 +16,66 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-'use strict';
+'use strict'
 
-const debug = require('debug')('joystream:runtime:base');
+const debug = require('debug')('joystream:runtime:base')
 
-const { registerJoystreamTypes } = require('@joystream/types');
-const { ApiPromise, WsProvider } = require('@polkadot/api');
+const { registerJoystreamTypes } = require('@joystream/types')
+const { ApiPromise, WsProvider } = require('@polkadot/api')
 
-const { IdentitiesApi } = require('@joystream/runtime-api/identities');
-const { BalancesApi } = require('@joystream/runtime-api/balances');
-const { WorkersApi } = require('@joystream/runtime-api/workers');
-const { AssetsApi } = require('@joystream/runtime-api/assets');
-const { DiscoveryApi } = require('@joystream/runtime-api/discovery');
-const AsyncLock = require('async-lock');
+const { IdentitiesApi } = require('@joystream/runtime-api/identities')
+const { BalancesApi } = require('@joystream/runtime-api/balances')
+const { WorkersApi } = require('@joystream/runtime-api/workers')
+const { AssetsApi } = require('@joystream/runtime-api/assets')
+const { DiscoveryApi } = require('@joystream/runtime-api/discovery')
+const AsyncLock = require('async-lock')
 
 /*
  * Initialize runtime (substrate) API and keyring.
  */
-class RuntimeApi
-{
-  static async create(options)
-  {
-    const runtime_api = new RuntimeApi();
-    await runtime_api.init(options || {});
-    return runtime_api;
+class RuntimeApi {
+  static async create (options) {
+    const runtime_api = new RuntimeApi()
+    await runtime_api.init(options || {})
+    return runtime_api
   }
 
-  async init(options)
-  {
-    debug('Init');
+  async init (options) {
+    debug('Init')
 
-    options = options || {};
+    options = options || {}
 
     // Register joystream types
-    registerJoystreamTypes();
+    registerJoystreamTypes()
 
-    const provider = new WsProvider(options.provider_url || 'ws://localhost:9944');
+    const provider = new WsProvider(options.provider_url || 'ws://localhost:9944')
 
     // Create the API instrance
-    this.api = await ApiPromise.create({ provider });
+    this.api = await ApiPromise.create({ provider })
 
-    this.asyncLock = new AsyncLock();
+    this.asyncLock = new AsyncLock()
 
     // Keep track locally of account nonces.
-    this.nonces = {};
+    this.nonces = {}
 
     // Ok, create individual APIs
     this.identities = await IdentitiesApi.create(this, {
       account_file: options.account_file,
       passphrase: options.passphrase,
       canPromptForPassphrase: options.canPromptForPassphrase
-    });
-    this.balances = await BalancesApi.create(this);
-    this.workers = await WorkersApi.create(this);
-    this.assets = await AssetsApi.create(this);
-    this.discovery = await DiscoveryApi.create(this);
+    })
+    this.balances = await BalancesApi.create(this)
+    this.workers = await WorkersApi.create(this)
+    this.assets = await AssetsApi.create(this)
+    this.discovery = await DiscoveryApi.create(this)
   }
 
-  disconnect()
-  {
-    this.api.disconnect();
+  disconnect () {
+    this.api.disconnect()
   }
 
-  executeWithAccountLock(account_id, func) {
-    return this.asyncLock.acquire(`${account_id}`, func);
+  executeWithAccountLock (account_id, func) {
+    return this.asyncLock.acquire(`${account_id}`, func)
   }
 
   /*
@@ -89,47 +85,45 @@ class RuntimeApi
    * The result of the Promise is an array containing first the full event
    * name, and then the event fields as an object.
    */
-  async waitForEvent(module, name)
-  {
-    return this.waitForEvents([[module, name]]);
+  async waitForEvent (module, name) {
+    return this.waitForEvents([[module, name]])
   }
 
-  _matchingEvents(subscribed, events)
-  {
-    debug(`Number of events: ${events.length}; subscribed to ${subscribed}`);
+  _matchingEvents(subscribed, events) {
+    debug(`Number of events: ${events.length} subscribed to ${subscribed}`)
 
     const filtered = events.filter((record) => {
-      const { event, phase } = record;
+      const { event, phase } = record
 
       // Show what we are busy with
-      debug(`\t${event.section}:${event.method}:: (phase=${phase.toString()})`);
-      debug(`\t\t${event.meta.documentation.toString()}`);
+      debug(`\t${event.section}:${event.method}:: (phase=${phase.toString()})`)
+      debug(`\t\t${event.meta.documentation.toString()}`)
 
       // Skip events we're not interested in.
       const matching = subscribed.filter((value) => {
-        return event.section == value[0] && event.method == value[1];
-      });
-      return matching.length > 0;
-    });
-    debug(`Filtered: ${filtered.length}`);
+        return event.section === value[0] && event.method === value[1]
+      })
+      return matching.length > 0
+    })
+    debug(`Filtered: ${filtered.length}`)
 
     const mapped = filtered.map((record) => {
-      const { event } = record;
-      const types = event.typeDef;
+      const { event } = record
+      const types = event.typeDef
 
       // Loop through each of the parameters, displaying the type and data
-      const payload = {};
+      const payload = {}
       event.data.forEach((data, index) => {
-        debug(`\t\t\t${types[index].type}: ${data.toString()}`);
-        payload[types[index].type] = data;
-      });
+        debug(`\t\t\t${types[index].type}: ${data.toString()}`)
+        payload[types[index].type] = data
+      })
 
-      const full_name = `${event.section}.${event.method}`;
-      return [full_name, payload];
-    });
-    debug('Mapped', mapped);
+      const full_name = `${event.section}.${event.method}`
+      return [full_name, payload]
+    })
+    debug('Mapped', mapped)
 
-    return mapped;
+    return mapped
   }
 
   /*
@@ -139,16 +133,15 @@ class RuntimeApi
    *
    * Returns the first matched event *only*.
    */
-  async waitForEvents(subscribed)
-  {
+  async waitForEvents (subscribed) {
     return new Promise((resolve, reject) => {
       this.api.query.system.events((events) => {
-        const matches = this._matchingEvents(subscribed, events);
+        const matches = this._matchingEvents(subscribed, events)
         if (matches && matches.length) {
-          resolve(matches);
+          resolve(matches)
         }
-      });
-    });
+      })
+    })
   }
 
   /*
@@ -159,68 +152,67 @@ class RuntimeApi
    * If the subscribed events are given, and a callback as well, then the
    * callback is invoked with matching events.
    */
-  async signAndSend(accountId, tx, attempts, subscribed, callback)
-  {
+  async signAndSend (accountId, tx, attempts, subscribed, callback) {
     // Prepare key
-    const from_key = this.identities.keyring.getPair(accountId);
+    const from_key = this.identities.keyring.getPair(accountId)
 
     if (from_key.isLocked) {
-      throw new Error('Must unlock key before using it to sign!');
+      throw new Error('Must unlock key before using it to sign!')
     }
 
-    const finalizedPromise = newExternallyControlledPromise();
+    const finalizedPromise = newExternallyControlledPromise()
 
-    let unsubscribe = await this.executeWithAccountLock(accountId,  async () => {
+    let unsubscribe = await this.executeWithAccountLock(accountId, async () => {
       // Try to get the next nonce to use
-      let nonce = this.nonces[accountId];
+      let nonce = this.nonces[accountId]
 
       let incrementNonce = () => {
         // only increment once
-        incrementNonce = () => {}; // turn it into a no-op
-        nonce = nonce.addn(1);
-        this.nonces[accountId] = nonce;
+        incrementNonce = () => {} // turn it into a no-op
+        nonce = nonce.addn(1)
+        this.nonces[accountId] = nonce
       }
 
       // If the nonce isn't available, get it from chain.
       if (!nonce) {
         // current nonce
-        nonce = await this.api.query.system.accountNonce(accountId);
-        debug(`Got nonce for ${accountId} from chain: ${nonce}`);
+        nonce = await this.api.query.system.accountNonce(accountId)
+        debug(`Got nonce for ${accountId} from chain: ${nonce}`)
       }
 
       return new Promise((resolve, reject) => {
-        debug('Signing and sending tx');
+        debug('Signing and sending tx')
         // send(statusUpdates) returns a function for unsubscribing from status updates
         let unsubscribe = tx.sign(from_key, { nonce })
           .send(({events = [], status}) => {
-            debug(`TX status: ${status.type}`);
+            debug(`TX status: ${status.type}`)
 
             // Whatever events we get, process them if there's someone interested.
             // It is critical that this event handling doesn't prevent
             try {
               if (subscribed && callback) {
-                const matched = this._matchingEvents(subscribed, events);
-                debug('Matching events:', matched);
+                const matched = this._matchingEvents(subscribed, events)
+                debug('Matching events:', matched)
                 if (matched.length) {
-                  callback(matched);
+                  callback(matched)
                 }
               }
-            } catch(err) {
+            } catch (err) {
               debug(`Error handling events ${err.stack}`)
             }
 
             // We want to release lock as early as possible, sometimes Ready status
             // doesn't occur, so we do it on Broadcast instead
             if (status.isReady) {
-              debug('TX Ready.');
-              incrementNonce();
-              resolve(unsubscribe); //releases lock
+              debug('TX Ready.')
+              incrementNonce()
+              resolve(unsubscribe) // releases lock
             } else if (status.isBroadcast) {
-              debug('TX Broadcast.');
-              incrementNonce();
-              resolve(unsubscribe); //releases lock
+              debug('TX Broadcast.')
+              incrementNonce()
+              resolve(unsubscribe) // releases lock
             } else if (status.isFinalized) {
-              debug('TX Finalized.');
+              debug('TX Finalized.')
               finalizedPromise.resolve(status)
             } else if (status.isFuture) {
               // comes before ready.
@@ -228,10 +220,10 @@ class RuntimeApi
               // nonce was set in the future. Treating it as an error for now.
               debug('TX Future!')
               // nonce is likely out of sync, delete it so we reload it from chain on next attempt
-              delete this.nonces[accountId];
-              const err = new Error('transaction nonce set in future');
-              finalizedPromise.reject(err);
-              reject(err);
+              delete this.nonces[accountId]
+              const err = new Error('transaction nonce set in future')
+              finalizedPromise.reject(err)
+              reject(err)
             }
 
             /* why don't we see these status updates on local devchain (single node)
@@ -247,45 +239,45 @@ class RuntimeApi
             // Remember this can also happen if in the past we sent a tx with a future nonce, and the current nonce
             // now matches it.
             if (err) {
-              const errstr = err.toString();
+              const errstr = err.toString()
               // not the best way to check error code.
               // https://github.com/polkadot-js/api/blob/master/packages/rpc-provider/src/coder/index.ts#L52
               if (errstr.indexOf('Error: 1014:') < 0 && // low priority
                   errstr.indexOf('Error: 1010:') < 0) // bad transaction
               {
                 // Error but not nonce related. (bad arguments maybe)
-                debug('TX error', err);
+                debug('TX error', err)
               } else {
                 // nonce is likely out of sync, delete it so we reload it from chain on next attempt
-                delete this.nonces[accountId];
+                delete this.nonces[accountId]
               }
             }
 
-            finalizedPromise.reject(err);
+            finalizedPromise.reject(err)
             // releases lock
-            reject(err);
-          });
-      });
+            reject(err)
+          })
+      })
     })
 
     // when does it make sense to manyally unsubscribe?
     // at this point unsubscribe.then and unsubscribe.catch have been deleted
-    // unsubscribe(); // don't unsubscribe if we want to wait for additional status
+    // unsubscribe() // don't unsubscribe if we want to wait for additional status
     // updates to know when the tx has been finalized
-    return finalizedPromise.promise;
+    return finalizedPromise.promise
   }
 }
 
 module.exports = {
-  RuntimeApi: RuntimeApi,
+  RuntimeApi
 }
 
 function newExternallyControlledPromise () {
   // externally controlled promise
-  let resolve, reject;
+  let resolve, reject
   const promise = new Promise((res, rej) => {
-    resolve = res;
-    reject = rej;
-  });
-  return ({resolve, reject, promise});
+    resolve = res
+    reject = rej
+  })
+  return ({resolve, reject, promise})
 }

+ 2 - 1
storage-node/packages/runtime-api/workers.js

@@ -20,6 +20,7 @@
 
 const debug = require('debug')('joystream:runtime:roles')
 const BN = require('bn.js')
+
 /*
  * Add worker related functionality to the substrate API.
  */
@@ -73,5 +74,5 @@ class WorkersApi {
 }
 
 module.exports = {
-  WorkersApi: WorkersApi
+  WorkersApi
 }