diff --git a/.travis.yml b/.travis.yml index 8faa400..99a4e31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_script: - ganache-cli --port 18545 > ganache-cli.log & - git clone https://github.com/oceanprotocol/barge - cd barge - - export AQUARIUS_VERSION=unstable + - export AQUARIUS_VERSION=ctd_trusted_algo - export BRIZO_VERSION=v0.9.5 - export KEEPER_VERSION=v0.13.2 - export EVENTS_HANDLER_VERSION=v0.4.7 diff --git a/src/aquarius/Aquarius.ts b/src/aquarius/Aquarius.ts index d69b046..3611a53 100644 --- a/src/aquarius/Aquarius.ts +++ b/src/aquarius/Aquarius.ts @@ -261,6 +261,60 @@ export class Aquarius { return result } +/** + * Update Compute Privacy + * @param {DID | string} did DID of the asset to update. + * @param {number } serviceIndex Service index + * @param {boolean} allowRawAlgorithm Allow Raw Algorithms + * @param {boolean} allowNetworkAccess Allow Raw Algorithms + * @param {String[]} trustedAlgorithms Allow Raw Algorithms + * @param {String} updated Updated field of the DDO + * @param {String} signature Signature using updated field to verify that the consumer has rights + * @return {Promise} Result. + */ + public async updateComputePrivacy( + did: DID | string, + serviceIndex: number, + allowRawAlgorithm: boolean, + allowNetworkAccess: boolean, + trustedAlgorithms: string[], + updated: string, + signature: string + ): Promise { + did = did && DID.parse(did) + const fullUrl = `${this.url}${apiPath}/computePrivacy/update/${did.getDid()}` + const result = await this.fetch + .put( + fullUrl, + JSON.stringify({ + signature: signature, + updated: updated, + serviceIndex: serviceIndex, + allowRawAlgorithm: allowRawAlgorithm, + allowNetworkAccess: allowNetworkAccess, + trustedAlgorithms: trustedAlgorithms + }) + ) + .then((response: any) => { + if (response.ok) { + return response.text + } + this.logger.log( + 'update compute privacy failed:', + response.status, + response.statusText + ) + return null + }) + + .catch(error => { + this.logger.error('Error updating compute privacy: ', error) + return null + }) + + return result + } + /** * Edit Metadata for a DDO. * @param {did} string DID. diff --git a/src/ddo/Service.ts b/src/ddo/Service.ts index 42a7497..64d2fc7 100644 --- a/src/ddo/Service.ts +++ b/src/ddo/Service.ts @@ -25,6 +25,12 @@ export interface ServiceAccessAttributes extends ServiceCommonAttributes { timeout: number } } +export interface ServiceComputePrivacy{ + allowRawAlgorithm: boolean, + allowNetworkAccess: boolean, + trustedAlgorithms: string[] +} + export interface ServiceComputeAttributes extends ServiceCommonAttributes { main: { @@ -34,6 +40,7 @@ export interface ServiceComputeAttributes extends ServiceCommonAttributes { timeout: number provider?: ServiceComputeProvider name: string + privacy?: ServiceComputePrivacy } } diff --git a/src/ocean/OceanAssets.ts b/src/ocean/OceanAssets.ts index 9e0b9d5..5a07039 100644 --- a/src/ocean/OceanAssets.ts +++ b/src/ocean/OceanAssets.ts @@ -2,7 +2,7 @@ import { TransactionReceipt } from 'web3-core' import { SearchQuery } from '../aquarius/Aquarius' import { DDO } from '../ddo/DDO' import { MetaData, EditableMetaData } from '../ddo/MetaData' -import { Service, ServiceAccess } from '../ddo/Service' +import { Service, ServiceAccess, ServiceComputePrivacy } from '../ddo/Service' import Account from './Account' import DID from './DID' import { fillConditionsWithDDO, SubscribablePromise, didZeroX } from '../utils' @@ -414,6 +414,41 @@ export class OceanAssets extends Instantiable { return result } + /** + * Update Compute Privacy + * @param {did} string DID. + * @param {number} serviceIndex Index of the compute service in the DDO + * @param {ServiceComputePrivacy} computePrivacy ComputePrivacy fields & new values. + * @param {Account} account Ethereum account of owner to sign and prove the ownership. + * @return {Promise} + */ + public async updateComputePrivacy( + did: string, + serviceIndex: number, + computePrivacy: ServiceComputePrivacy, + account: Account + ): Promise { + const oldDdo = await this.ocean.aquarius.retrieveDDO(did) + // get a signature + const signature = await this.ocean.utils.signature.signForAquarius( + oldDdo.updated, + account + ) + let result = null + if (signature != null) + result = await this.ocean.aquarius.updateComputePrivacy( + did, + serviceIndex, + computePrivacy.allowRawAlgorithm, + computePrivacy.allowNetworkAccess, + computePrivacy.trustedAlgorithms, + oldDdo.updated, + signature + ) + + return result + } + /** * Retire a DDO (Delete) * @param {did} string DID. diff --git a/src/ocean/OceanCompute.ts b/src/ocean/OceanCompute.ts index 331f16d..48a488e 100644 --- a/src/ocean/OceanCompute.ts +++ b/src/ocean/OceanCompute.ts @@ -5,7 +5,7 @@ import { DDO } from '../ddo/DDO' import { SubscribablePromise } from '../utils' import { OrderProgressStep } from './utils/ServiceUtils' import { DID } from '../squid' -import { ServiceCompute } from '../ddo/Service' +import { ServiceCompute, ServiceComputePrivacy } from '../ddo/Service' export const ComputeJobStatus = Object.freeze({ Started: 10, @@ -266,12 +266,13 @@ export class OceanCompute extends Instantiable { public async createComputeServiceAttributes( consumerAccount: Account, price: string, - datePublished: string + datePublished: string, + computePrivacy?: ServiceComputePrivacy ): Promise { const { templates } = this.ocean.keeper const serviceAgreementTemplate = await templates.escrowComputeExecutionTemplate.getServiceAgreementTemplate() const name = 'dataAssetComputingServiceAgreement' - return { + let service={ type: 'compute', index: 3, serviceEndpoint: this.ocean.brizo.getComputeEndpoint(), @@ -287,5 +288,8 @@ export class OceanCompute extends Instantiable { serviceAgreementTemplate } } + if (computePrivacy) + service['attributes']['main']['privacy'] = computePrivacy + return service as ServiceCompute } } diff --git a/test/integration/ocean/AssetOwners.test.ts b/test/integration/ocean/AssetOwners.test.ts index 3f1af67..a85c000 100644 --- a/test/integration/ocean/AssetOwners.test.ts +++ b/test/integration/ocean/AssetOwners.test.ts @@ -2,6 +2,7 @@ import { assert } from 'chai' import { config } from '../config' import { getMetadata } from '../utils' import { Ocean, Account, EditableMetaData } from '../../../src' // @oceanprotocol/squid +import { ServiceComputePrivacy } from '../../../src/ddo/Service' describe('Asset Owners', () => { let ocean: Ocean @@ -202,4 +203,56 @@ describe('Asset Owners', () => { assert.equal(-1, remList.indexOf(consumer1.getId())) assert.notEqual(-1, remList.indexOf(consumer2.getId())) }) + + it('should be able to update computePrivacy', async () => { + const origComputePrivacy = { + allowRawAlgorithm: true, + allowNetworkAccess: true, + trustedAlgorithms: [] + } + + const newComputePrivacy = { + allowRawAlgorithm: false, + allowNetworkAccess: false, + trustedAlgorithms: ['did:op:123', 'did:op:1234'] + } + const computeService = await ocean.compute.createComputeServiceAttributes( + account1, + '0', + '2020-03-10T10:00:00Z', + origComputePrivacy as ServiceComputePrivacy + ) + const { id } = await ocean.assets.create(metadata as any, account1, [ + computeService + ]) + + const oldDDO = await ocean.assets.resolve(id) + let serviceIndex = null + + for (let index = 0; index < oldDDO.service.length; index++) { + if (oldDDO.service[index].type == 'compute') serviceIndex = index + } + + await ocean.assets.updateComputePrivacy( + id, + serviceIndex, + newComputePrivacy as ServiceComputePrivacy, + account1 + ) + + const newDDO = await ocean.assets.resolve(id) + + assert.equal( + newDDO.service[serviceIndex].attributes.main.privacy.allowRawAlgorithm, + newComputePrivacy.allowRawAlgorithm + ) + assert.equal( + newDDO.service[serviceIndex].attributes.main.privacy.allowNetworkAccess, + newComputePrivacy.allowNetworkAccess + ) + assert.equal( + newDDO.service[serviceIndex].attributes.main.privacy.trustedAlgorithms, + newComputePrivacy.trustedAlgorithms + ) + }) })