Browse Source

storage-node: use local types and update runtime-api to use latest runtime

Mokhtar Naamani 4 years ago
parent
commit
83797c8957

+ 0 - 68
storage-node/packages/discovery/IpfsResolver.js

@@ -1,68 +0,0 @@
-const IpfsClient = require('ipfs-http-client')
-const axios = require('axios')
-const { Resolver } = require('./Resolver')
-
-class IpfsResolver extends Resolver {
-    constructor({
-        host = 'localhost',
-        port,
-        mode = 'rpc', // rpc or gateway
-        protocol = 'http', // http or https
-        ipfs,
-        runtime
-    }) {
-        super({runtime})
-
-        if (ipfs) {
-            // use an existing ipfs client instance
-            this.ipfs = ipfs
-        } else if (mode == 'rpc') {
-            port = port || '5001'
-            this.ipfs = IpfsClient(host, port, { protocol })
-        } else if (mode === 'gateway') {
-            port = port || '8080'
-            this.gateway = this.constructUrl(protocol, host, port)
-        } else {
-            throw new Error('Invalid IPFS Resolver options')
-        }
-    }
-
-    async _resolveOverRpc(identity) {
-        const ipnsPath = `/ipns/${identity}/`
-
-        const ipfsName = await this.ipfs.name.resolve(ipnsPath, {
-            recursive: false, // there should only be one indirection to service info file
-            nocache: false,
-        })
-
-        const data = await this.ipfs.get(ipfsName)
-
-        // there should only be one file published under the resolved path
-        const content = data[0].content
-
-        return JSON.parse(content)
-    }
-
-    async _resolveOverGateway(identity) {
-        const url = `${this.gateway}/ipns/${identity}`
-
-        // expected JSON object response
-        const response = await axios.get(url)
-
-        return response.data
-    }
-
-    resolve(accountId) {
-        const identity = this.resolveIdentity(accountId)
-
-        if (this.ipfs) {
-            return this._resolveOverRpc(identity)
-        } else {
-            return this._resolveOverGateway(identity)
-        }
-    }
-}
-
-module.exports = {
-    IpfsResolver
-}

+ 0 - 28
storage-node/packages/discovery/JdsResolver.js

@@ -1,28 +0,0 @@
-const axios = require('axios')
-const { Resolver } = require('./Resolver')
-
-class JdsResolver extends Resolver {
-    constructor({
-        protocol = 'http', // http or https
-        host = 'localhost',
-        port,
-        runtime
-    }) {
-        super({runtime})
-
-        this.baseUrl = this.constructUrl(protocol, host, port)
-    }
-
-    async resolve(accountId) {
-        const url = `${this.baseUrl}/discover/v0/${accountId}`
-
-        // expected JSON object response
-        const response = await axios.get(url)
-
-        return response.data
-    }
-}
-
-module.exports = {
-    JdsResolver
-}

+ 0 - 48
storage-node/packages/discovery/Resolver.js

@@ -1,48 +0,0 @@
-class Resolver {
-    constructor ({
-        runtime
-    }) {
-        this.runtime = runtime
-    }
-
-    constructUrl (protocol, host, port) {
-        port = port ? `:${port}` : ''
-        return `${protocol}:://${host}${port}`
-    }
-
-    async resolveServiceInformation(accountId) {
-        let isActor = await this.runtime.identities.isActor(accountId)
-
-        if (!isActor) {
-            throw new Error('Cannot discover non actor account service info')
-        }
-
-        const identity = await this.resolveIdentity(accountId)
-
-        if (identity == null) {
-            // dont waste time trying to resolve if no identity was found
-            throw new Error('no identity to resolve');
-        }
-
-        return this.resolve(accountId)
-    }
-
-    // lookup ipns identity from chain corresponding to accountId
-    // return null if no identity found or record is expired
-    async resolveIdentity(accountId) {
-        const info = await this.runtime.discovery.getAccountInfo(accountId)
-        return info ? info.identity.toString() : null
-    }
-}
-
-Resolver.Error = {};
-Resolver.Error.UnrecognizedProtocol = class UnrecognizedProtocol extends Error {
-    constructor(message) {
-        super(message);
-        this.name = 'UnrecognizedProtocol';
-    }
-}
-
-module.exports = {
-    Resolver
-}

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

@@ -37,15 +37,15 @@ class AssetsApi
   /*
    * Create a data object.
    */
-  async createDataObject(accountId, contentId, doTypeId, size)
+  async createDataObject(accountId, memberId, contentId, doTypeId, size, ipfs_cid)
   {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.addContent(contentId, doTypeId, size);
+    const tx = this.base.api.tx.dataDirectory.addContent(memberId, contentId, doTypeId, size, ipfs_cid);
     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 await this.getDataObject(contentId);
+    return this.getDataObject(contentId);
   }
 
   /*
@@ -66,7 +66,7 @@ class AssetsApi
    *
    * Each failure errors out, success returns the data object.
    */
-  async checkLiaisonForDataObject(accountId, contentId)
+  async checkLiaisonForDataObject(storageProviderId, contentId)
   {
     contentId = parseContentId(contentId)
 
@@ -77,7 +77,7 @@ class AssetsApi
     }
 
     const encoded = encodeAddress(obj.raw.liaison);
-    if (encoded != accountId) {
+    if (obj.raw.liaison.neq(storageProviderId)) {
       throw new Error(`This storage node is not liaison for the content ID: ${contentId}`);
     }
 
@@ -91,39 +91,39 @@ class AssetsApi
   /*
    * Changes a data object liaison judgement.
    */
-  async acceptContent(accountId, contentId)
+  async acceptContent(providerAccoundId, storageProviderId, contentId)
   {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.acceptContent(contentId);
-    return await this.base.signAndSend(accountId, tx);
+    const tx = this.base.api.tx.dataDirectory.acceptContent(storageProviderId, contentId);
+    return await this.base.signAndSend(providerAccoundId, tx);
   }
 
   /*
    * Changes a data object liaison judgement.
    */
-  async rejectContent(accountId, contentId)
+  async rejectContent(providerAccountId, storageProviderId, contentId)
   {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataDirectory.rejectContent(contentId);
-    return await this.base.signAndSend(accountId, tx);
+    const tx = this.base.api.tx.dataDirectory.rejectContent(storageProviderId, contentId);
+    return await this.base.signAndSend(providerAccountId, tx);
   }
 
   /*
    * Create storage relationship
    */
-  async createStorageRelationship(accountId, contentId, callback)
+  async createStorageRelationship(providerAccountId, storageProviderId, contentId, callback)
   {
     contentId = parseContentId(contentId)
-    const tx = this.base.api.tx.dataObjectStorageRegistry.addRelationship(contentId);
+    const tx = this.base.api.tx.dataObjectStorageRegistry.addRelationship(storageProviderId, contentId);
 
     const subscribed = [['dataObjectStorageRegistry', 'DataObjectStorageRelationshipAdded']];
-    return await this.base.signAndSend(accountId, tx, 3, subscribed, callback);
+    return await this.base.signAndSend(providerAccountId, tx, 3, subscribed, callback);
   }
 
   /*
    * Get storage relationship for contentId
    */
-  async getStorageRelationshipAndId(accountId, contentId) {
+  async getStorageRelationshipAndId(storageProviderId, contentId) {
     contentId = parseContentId(contentId)
     let rids = await this.base.api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId);
 
@@ -131,7 +131,7 @@ class AssetsApi
       const relationshipId = rids.shift();
       let relationship = await this.base.api.query.dataObjectStorageRegistry.relationships(relationshipId);
       relationship = relationship.unwrap();
-      if (relationship.storage_provider.eq(decodeAddress(accountId))) {
+      if (relationship.storage_provider.eq(storageProviderId)) {
         return ({ relationship, relationshipId });
       }
     }
@@ -139,12 +139,12 @@ class AssetsApi
     return {};
   }
 
-  async createAndReturnStorageRelationship(accountId, contentId)
+  async createAndReturnStorageRelationship(providerAccountId, storageProviderId, contentId)
   {
     contentId = parseContentId(contentId)
     return new Promise(async (resolve, reject) => {
       try {
-        await this.createStorageRelationship(accountId, contentId, (events) => {
+        await this.createStorageRelationship(providerAccountId, storageProviderId, contentId, (events) => {
           events.forEach((event) => {
             resolve(event[1].DataObjectStorageRelationshipId);
           });
@@ -158,12 +158,12 @@ class AssetsApi
   /*
    * Toggle ready state for DOSR.
    */
-  async toggleStorageRelationshipReady(accountId, dosrId, ready)
+  async toggleStorageRelationshipReady(providerAccountId, storageProviderId, dosrId, ready)
   {
     var tx = ready
-      ? this.base.api.tx.dataObjectStorageRegistry.setRelationshipReady(dosrId)
-      : this.base.api.tx.dataObjectStorageRegistry.unsetRelationshipReady(dosrId);
-    return await this.base.signAndSend(accountId, tx);
+      ? this.base.api.tx.dataObjectStorageRegistry.setRelationshipReady(storageProviderId, dosrId)
+      : this.base.api.tx.dataObjectStorageRegistry.unsetRelationshipReady(storageProviderId, dosrId);
+    return await this.base.signAndSend(providerAccountId, tx);
   }
 
   async getKnownContentIds() {

+ 2 - 2
storage-node/packages/runtime-api/discovery.js

@@ -30,9 +30,9 @@ class DiscoveryApi
   /*
    * Get AccountInfo of an accountId
    */
-  async getAccountInfo(accountId) {
+  async getAccountInfo(storageProviderId) {
     const decoded = this.base.identities.keyring.decodeAddress(accountId, true)
-    const info = await this.base.api.query.discovery.accountInfoByAccountId(decoded)
+    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
   }

+ 24 - 24
storage-node/packages/runtime-api/identities.js

@@ -140,12 +140,12 @@ class IdentitiesApi
   /*
    * Return true if the account is an actor/role account
    */
-  async isActor(accountId)
-  {
-    const decoded = this.keyring.decodeAddress(accountId);
-    const actor = await this.base.api.query.actors.actorByAccountId(decoded)
-    return actor.isSome
-  }
+  // async isActor(accountId) // change to is StorageWorkingGroup worker ?
+  // {
+  //   const decoded = this.keyring.decodeAddress(accountId);
+  //   const actor = await this.base.api.query.actors.actorByAccountId(decoded)
+  //   return actor.isSome
+  // }
 
   /*
    * Return the member IDs of an account
@@ -170,30 +170,30 @@ class IdentitiesApi
    * Create a new key for the given role *name*. If no name is given,
    * default to 'storage'.
    */
-  async createRoleKey(accountId, role)
-  {
-    role = role || 'storage';
+  // async createRoleKey(accountId, role)
+  // {
+  //   role = role || 'storage';
 
-    // Generate new key pair
-    const keyPair = util_crypto.naclKeypairFromRandom();
+  //   // Generate new key pair
+  //   const keyPair = util_crypto.naclKeypairFromRandom();
 
-    // Encode to an address.
-    const addr = this.keyring.encodeAddress(keyPair.publicKey);
-    debug('Generated new key pair with address', addr);
+  //   // Encode to an address.
+  //   const addr = this.keyring.encodeAddress(keyPair.publicKey);
+  //   debug('Generated new key pair with address', addr);
 
-    // Add to key wring. We set the meta to identify the account as
-    // a role key.
-    const meta = {
-      name: `${role} role account for ${accountId}`,
-    };
+  //   // Add to key wring. We set the meta to identify the account as
+  //   // a role key.
+  //   const meta = {
+  //     name: `${role} role account for ${accountId}`,
+  //   };
 
-    const createPair = require('@polkadot/keyring/pair').default;
-    const pair = createPair('ed25519', keyPair, meta);
+  //   const createPair = require('@polkadot/keyring/pair').default;
+  //   const pair = createPair('ed25519', keyPair, meta);
 
-    this.keyring.addPair(pair);
+  //   this.keyring.addPair(pair);
 
-    return pair;
-  }
+  //   return pair;
+  // }
 
   /*
    * Export a key pair to JSON. Will ask for a passphrase.

+ 3 - 3
storage-node/packages/runtime-api/index.js

@@ -25,7 +25,7 @@ const { ApiPromise, WsProvider } = require('@polkadot/api');
 
 const { IdentitiesApi } = require('@joystream/runtime-api/identities');
 const { BalancesApi } = require('@joystream/runtime-api/balances');
-const { RolesApi } = require('@joystream/runtime-api/roles');
+const { WrokersApi } = require('@joystream/runtime-api/workers');
 const { AssetsApi } = require('@joystream/runtime-api/assets');
 const { DiscoveryApi } = require('@joystream/runtime-api/discovery');
 const AsyncLock = require('async-lock');
@@ -68,7 +68,7 @@ class RuntimeApi
       canPromptForPassphrase: options.canPromptForPassphrase
     });
     this.balances = await BalancesApi.create(this);
-    this.roles = await RolesApi.create(this);
+    this.workers = await WorkersApi.create(this);
     this.assets = await AssetsApi.create(this);
     this.discovery = await DiscoveryApi.create(this);
   }
@@ -281,7 +281,7 @@ module.exports = {
 }
 
 function newExternallyControlledPromise () {
-  // externally controller promise
+  // externally controlled promise
   let resolve, reject;
   const promise = new Promise((res, rej) => {
     resolve = res;

+ 1 - 1
storage-node/packages/runtime-api/package.json

@@ -44,7 +44,7 @@
     "temp": "^0.9.0"
   },
   "dependencies": {
-    "@joystream/types": "^0.10.0",
+    "@joystream/types": "./types",
     "@polkadot/api": "^0.96.1",
     "async-lock": "^1.2.0",
     "lodash": "^4.17.11",

+ 0 - 186
storage-node/packages/runtime-api/roles.js

@@ -1,186 +0,0 @@
-/*
- * This file is part of the storage node for the Joystream project.
- * Copyright (C) 2019 Joystream Contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (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
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-'use strict';
-
-const debug = require('debug')('joystream:runtime:roles');
-
-const { Null, u64 } = require('@polkadot/types');
-
-const { _ } = require('lodash');
-
-/*
- * Add role related functionality to the substrate API.
- */
-class RolesApi
-{
-  static async create(base)
-  {
-    const ret = new RolesApi();
-    ret.base = base;
-    await ret.init();
-    return ret;
-  }
-
-  async init()
-  {
-    debug('Init');
-
-    // Constants
-    this.ROLE_STORAGE = 'StorageProvider'; // new u64(0x00);
-  }
-
-  /*
-   * Raises errors if the given account ID is not valid for staking as the given
-   * role. The role should be one of the ROLE_* constants above.
-   */
-  async checkAccountForStaking(accountId, role)
-  {
-    role = role || this.ROLE_STORAGE;
-
-    if (!await this.base.identities.isMember(accountId)) {
-      const msg = `Account with id "${accountId}" is not a member!`;
-      debug(msg);
-      throw new Error(msg);
-    }
-
-    if (!await this.hasBalanceForRoleStaking(accountId, role)) {
-      const msg = `Account with id "${accountId}" does not have sufficient free balance for role staking!`;
-      debug(msg);
-      throw new Error(msg);
-    }
-
-    debug(`Account with id "${accountId}" is a member with sufficient free balance, able to proceed.`);
-    return true;
-  }
-
-  /*
-   * Returns the required balance for staking for a role.
-   */
-  async requiredBalanceForRoleStaking(role)
-  {
-    const params = await this.base.api.query.actors.parameters(role);
-    if (params.isNone) {
-      throw new Error(`Role ${role} is not defined!`);
-    }
-    const result = params.raw.min_stake
-      .add(params.raw.entry_request_fee)
-      .add(await this.base.balances.baseTransactionFee());
-    return result;
-  }
-
-  /*
-   * Returns true/false if the given account has the balance required for
-   * staking for the given role.
-   */
-  async hasBalanceForRoleStaking(accountId, role)
-  {
-    const required = await this.requiredBalanceForRoleStaking(role);
-    return await this.base.balances.hasMinimumBalanceOf(accountId, required);
-  }
-
-  /*
-   * Transfer enough funds to allow the recipient to stake for the given role.
-   */
-  async transferForStaking(from, to, role)
-  {
-    const required = await this.requiredBalanceForRoleStaking(role);
-    return await this.base.balances.transfer(from, to, required);
-  }
-
-  /*
-   * Return current accounts holding a role.
-   */
-  async accountIdsByRole(role)
-  {
-    const ids = await this.base.api.query.actors.accountIdsByRole(role);
-    return ids.map(id => id.toString());
-  }
-
-  /*
-   * Returns the number of slots available for a role
-   */
-  async availableSlotsForRole(role)
-  {
-    let params = await this.base.api.query.actors.parameters(role);
-    if (params.isNone) {
-      throw new Error(`Role ${role} is not defined!`);
-    }
-    params = params.unwrap();
-    const slots = params.max_actors;
-    const active = await this.accountIdsByRole(role);
-    return (slots.subn(active.length)).toNumber();
-  }
-
-  /*
-   * Send a role application.
-   * - The role account must not be a member, but have sufficient funds for
-   *   staking.
-   * - The member account must be a member.
-   *
-   * After sending this application, the member account will have role request
-   * in the 'My Requests' tab of the app.
-   */
-  async applyForRole(roleAccountId, role, memberAccountId)
-  {
-    const memberId = await this.base.identities.firstMemberIdOf(memberAccountId);
-    if (memberId == undefined) {
-      throw new Error('Account is not a member!');
-    }
-
-    const tx = this.base.api.tx.actors.roleEntryRequest(role, memberId);
-    return await this.base.signAndSend(roleAccountId, tx);
-  }
-
-  /*
-   * Check whether the given role is occupying the given role.
-   */
-  async checkForRole(roleAccountId, role)
-  {
-    const actor = await this.base.api.query.actors.actorByAccountId(roleAccountId);
-    return !_.isEqual(actor.raw, new Null());
-  }
-
-  /*
-   * Same as checkForRole(), but if the account is not currently occupying the
-   * role, wait for the appropriate `actors.Staked` event to be emitted.
-   */
-  async waitForRole(roleAccountId, role)
-  {
-    if (await this.checkForRole(roleAccountId, role)) {
-      return true;
-    }
-
-    return new Promise((resolve, reject) => {
-      this.base.waitForEvent('actors', 'Staked').then((values) => {
-        const name = values[0][0];
-        const payload = values[0][1];
-
-        if (payload.AccountId == roleAccountId) {
-          resolve(true);
-        } else {
-          // reject() ?
-        }
-      });
-    });
-  }
-}
-
-module.exports = {
-  RolesApi: RolesApi,
-}

+ 66 - 0
storage-node/packages/runtime-api/workers.js

@@ -0,0 +1,66 @@
+/*
+ * This file is part of the storage node for the Joystream project.
+ * Copyright (C) 2019 Joystream Contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+'use strict';
+
+const debug = require('debug')('joystream:runtime:roles');
+
+const { Null, u64 } = require('@polkadot/types');
+
+const { _ } = require('lodash');
+
+/*
+ * Add worker related functionality to the substrate API.
+ */
+class WorkersApi
+{
+  static async create(base)
+  {
+    const ret = new WorkersApi();
+    ret.base = base;
+    await ret.init();
+    return ret;
+  }
+
+  async init()
+  {
+    debug('Init');
+  }
+
+
+  /*
+   * Check whether the given account and id is an active storage provider
+   */
+  async checkForRole(roleAccountId, storageProviderId)
+  {
+    const worker = await this.base.api.query.storageWorkingGroup.workerById(storageProviderId);
+
+    // FIXME: get single linked entry
+
+    if (_.isEqual(worker.raw, new Null())) {
+      return false
+    }
+
+    return worker.raw.role_account == roleAccountId
+  }
+
+}
+
+module.exports = {
+  WorkersApi: WorkersApi
+}

+ 0 - 10
yarn.lock

@@ -1734,16 +1734,6 @@
     "@types/istanbul-reports" "^1.1.1"
     "@types/yargs" "^13.0.0"
 
-"@joystream/types@^0.10.0":
-  version "0.10.0"
-  resolved "https://registry.yarnpkg.com/@joystream/types/-/types-0.10.0.tgz#7e98ef221410b26a7d952cfc3d1c03d28395ad69"
-  integrity sha512-RDZizqGKWGYpLR5PnUWM4aGa7InpWNh2Txlr7Al3ROFYOHoyQf62/omPfEz29F6scwlFxysOdmEfQaLeVRaUxA==
-  dependencies:
-    "@polkadot/types" "^0.96.1"
-    "@types/vfile" "^4.0.0"
-    ajv "^6.11.0"
-    lodash "^4.17.15"
-
 "@ledgerhq/devices@^4.78.0":
   version "4.78.0"
   resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-4.78.0.tgz#149b572f0616096e2bd5eb14ce14d0061c432be6"