diff --git a/src/ocean/OceanCompute.ts b/src/ocean/OceanCompute.ts index 6e75735..fc4140a 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, ServiceComputePrivacy } from '../ddo/Service' +import { Service, ServiceCompute, ServiceComputePrivacy } from '../ddo/Service' export const ComputeJobStatus = Object.freeze({ Started: 10, @@ -66,16 +66,43 @@ export class OceanCompute extends Instantiable { * Starts an order of a compute service that is defined in an asset's services. * @param {Account} consumerAccount The account of the consumer ordering the service. * @param {string} datasetDid The DID of the dataset asset (of type `dataset`) to run the algorithm on. + * @param {string} algorithmDid The DID of the algorithm asset (of type `algorithm`) to run on the asset. + * @param {MetaData} algorithmMeta Metadata about the algorithm being run if `algorithm` is being used. This is ignored when `algorithmDid` is specified. * @return {Promise} Returns the Service Agreement ID, representation of `bytes32` ID. + * + * Note: algorithmDid and algorithmMeta are optional, but if they are not passed, + * you can end up in the situation that you are ordering and paying for your agreement, + * but brizo will not allow the compute, due to privacy settings of the ddo */ public order( consumerAccount: Account, datasetDid: string, + algorithmDid?: string, + algorithmMeta?: MetaDataAlgorithm, provider?: string ): SubscribablePromise { return new SubscribablePromise(async observer => { const { assets, keeper, utils } = this.ocean const ddo: DDO = await assets.resolve(datasetDid) + const service: Service = ddo.findServiceByType('compute') + if (!service) return null + if (algorithmMeta) { + // check if raw algo is allowed + if (service.attributes.main.privacy) + if (!service.attributes.main.privacy.allowRawAlgorithm) return null + } + if (algorithmDid) { + // check if did is in trusted list + if (service.attributes.main.privacy) + if (service.attributes.main.privacy.trustedAlgorithms) + if (service.attributes.main.privacy.trustedAlgorithms.length > 0) + if ( + !service.attributes.main.privacy.trustedAlgorithms.includes( + algorithmDid + ) + ) + return null + } const condition = keeper.conditions.computeExecutionCondition const agreementId = await utils.services.order( @@ -137,17 +164,18 @@ export class OceanCompute extends Instantiable { output?: Output ): Promise { output = this.checkOutput(consumerAccount, output) - const computeJobsList = await this.ocean.brizo.compute( - 'post', - agreementId, - consumerAccount, - algorithmDid, - algorithmMeta, - undefined, - output - ) - - return computeJobsList[0] as ComputeJob + if (agreementId) { + const computeJobsList = await this.ocean.brizo.compute( + 'post', + agreementId, + consumerAccount, + algorithmDid, + algorithmMeta, + undefined, + output + ) + return computeJobsList[0] as ComputeJob + } else return null } /** diff --git a/test/integration/ocean/Compute.test.ts b/test/integration/ocean/Compute.test.ts index bf1e60d..9723748 100644 --- a/test/integration/ocean/Compute.test.ts +++ b/test/integration/ocean/Compute.test.ts @@ -11,7 +11,7 @@ import { MetaDataAlgorithm } from '../../../src' import { getMetadata } from '../utils' -import { ServiceCompute } from '../../../src/ddo/Service' +import { ServiceCompute, ServiceComputePrivacy } from '../../../src/ddo/Service' const metadataAsset = getMetadata() const metadataAlgorithm = getMetadata(0, 'algorithm') @@ -26,11 +26,24 @@ const customConfig: Config = { verbose: true } +export const rawAlgoMeta = { + rawcode: `console.log('Hello world'!)`, + format: 'docker-image', + version: '0.1', + container: { + entrypoint: 'node $ALGO', + image: 'node', + tag: '10' + } +} + describe('Compute', () => { let ocean: Ocean let account: Account let agreementId: string let dataset: DDO + let datasetNoRawAlgo: DDO + let datasetWithTrustedAlgo: DDO let algorithm: DDO let computeService: ServiceCompute let jobId: string @@ -63,6 +76,58 @@ describe('Compute', () => { assert.deepEqual(stepsAsset, [0, 1, 2, 3, 4, 5, 6, 7]) }) + it('should publish a dataset with a compute service object that does not allow rawAlgo', async () => { + const stepsAsset = [] + const origComputePrivacy = { + allowRawAlgorithm: false, + allowNetworkAccess: false, + trustedAlgorithms: [] + } + + computeService = await ocean.compute.createComputeServiceAttributes( + account, + '1000', + metadataAsset.main.datePublished, + origComputePrivacy as ServiceComputePrivacy + ) + datasetNoRawAlgo = await ocean.assets + .create(metadataAsset as MetaData, account, [computeService]) + .next(step => stepsAsset.push(step)) + + assert.instanceOf(datasetNoRawAlgo, DDO) + assert.isDefined( + dataset.findServiceByType('compute'), + `DDO compute service doesn't exist` + ) + assert.deepEqual(stepsAsset, [0, 1, 2, 3, 4, 5, 6, 7]) + }) + + it('should publish a dataset with a compute service object that allows only algo with did:op:1234', async () => { + const stepsAsset = [] + const origComputePrivacy = { + allowRawAlgorithm: false, + allowNetworkAccess: false, + trustedAlgorithms: ['did:op:1234'] + } + + computeService = await ocean.compute.createComputeServiceAttributes( + account, + '1000', + metadataAsset.main.datePublished, + origComputePrivacy as ServiceComputePrivacy + ) + datasetWithTrustedAlgo = await ocean.assets + .create(metadataAsset as MetaData, account, [computeService]) + .next(step => stepsAsset.push(step)) + + assert.instanceOf(datasetWithTrustedAlgo, DDO) + assert.isDefined( + dataset.findServiceByType('compute'), + `DDO compute service doesn't exist` + ) + assert.deepEqual(stepsAsset, [0, 1, 2, 3, 4, 5, 6, 7]) + }) + it('should publish an algorithm', async () => { const stepsAlgorithm = [] algorithm = await ocean.assets @@ -73,6 +138,26 @@ describe('Compute', () => { assert.deepEqual(stepsAlgorithm, [0, 1, 2, 3, 4, 5, 6, 7]) }) + it('should not allow order the compute service with raw algo for dataset that does not allow raw algo', async () => { + const steps = [] + + agreementId = await ocean.compute + .order(account, datasetNoRawAlgo.id, null, rawAlgoMeta) + .next(step => steps.push(step)) + + assert.equal(agreementId, null) + }) + + it('should not allow order the compute service with did != did:op:1234 for dataset that allows only did:op:1234 as algo', async () => { + const steps = [] + + agreementId = await ocean.compute + .order(account, datasetWithTrustedAlgo.id, 'did:op:233454', null) + .next(step => steps.push(step)) + + assert.equal(agreementId, null) + }) + it('should order the compute service of the dataset', async () => { const steps = [] try {