1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00

Merge branch 'master' into feature/transferOwnership

This commit is contained in:
Alex Coseru 2020-03-25 11:24:41 +02:00 committed by GitHub
commit 204c5645b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 2990 additions and 1880 deletions

View File

@ -24,9 +24,9 @@ before_script:
- git clone https://github.com/oceanprotocol/barge - git clone https://github.com/oceanprotocol/barge
- cd barge - cd barge
- export AQUARIUS_VERSION=unstable - export AQUARIUS_VERSION=unstable
- export BRIZO_VERSION=v0.8.1 - export BRIZO_VERSION=v0.9.3
- export KEEPER_VERSION=v0.13.2 - export KEEPER_VERSION=v0.13.2
- export EVENTS_HANDLER_VERSION=v0.4.4 - export EVENTS_HANDLER_VERSION=v0.4.5
- export KEEPER_OWNER_ROLE_ADDRESS="0xe2DD09d719Da89e5a3D0F2549c7E24566e947260" - export KEEPER_OWNER_ROLE_ADDRESS="0xe2DD09d719Da89e5a3D0F2549c7E24566e947260"
- rm -rf "${HOME}/.ocean/keeper-contracts/artifacts" - rm -rf "${HOME}/.ocean/keeper-contracts/artifacts"
- bash -x start_ocean.sh --no-commons --no-dashboard 2>&1 > start_ocean.log & - bash -x start_ocean.sh --no-commons --no-dashboard 2>&1 > start_ocean.log &

View File

@ -4,24 +4,70 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v1.3.0](https://github.com/oceanprotocol/squid-js/compare/v1.2.0...v1.3.0) #### [v2.0.0-beta.5](https://github.com/oceanprotocol/squid-js/compare/2.0.0-beta.4...v2.0.0-beta.5)
> 10 March 2020
- Update the compute condition name in ddo jason definition. [`#380`](https://github.com/oceanprotocol/squid-js/pull/380)
#### [2.0.0-beta.4](https://github.com/oceanprotocol/squid-js/compare/v2.0.0-beta.3...2.0.0-beta.4)
> 6 March 2020
- v2: Compute to Data [`#350`](https://github.com/oceanprotocol/squid-js/pull/350)
- Fix style issues and failing unit tests. [`c26ae88`](https://github.com/oceanprotocol/squid-js/commit/c26ae88fa3d63a65b7cba38224cbdcb23cbe6685)
- Fix publishing compute service (fill in parameters value in agreement conditions). Update agreement template events and conditions in the sample json. [`75a0ef0`](https://github.com/oceanprotocol/squid-js/commit/75a0ef05d9789a9358180707b28bad95a84d6499)
- Return proper value from the compute endpoints. [`e2ed974`](https://github.com/oceanprotocol/squid-js/commit/e2ed974af27c7b828980919cb2846fc514fda142)
#### [v2.0.0-beta.3](https://github.com/oceanprotocol/squid-js/compare/v2.0.0-beta.2...v2.0.0-beta.3)
> 20 February 2020
- Adding output section [`#372`](https://github.com/oceanprotocol/squid-js/pull/372)
- add Output Object passed to brizo [`a60e415`](https://github.com/oceanprotocol/squid-js/commit/a60e4159255aadeba00bec2e72cf0fbb4b71489c)
- lint fix [`6e2289b`](https://github.com/oceanprotocol/squid-js/commit/6e2289b27ddc8643076385ee3fe8cfb743d4ecfb)
- add Output interface [`9cf716e`](https://github.com/oceanprotocol/squid-js/commit/9cf716ebe472ec24603c1bcf052848ad4464d9dd)
#### [v2.0.0-beta.2](https://github.com/oceanprotocol/squid-js/compare/v1.3.0...v2.0.0-beta.2)
> 31 January 2020
- Release 2.0.0-beta.2 [`4e45a77`](https://github.com/oceanprotocol/squid-js/commit/4e45a773d67b0f4199ffd5eae00b06213ba5622f)
#### [v2.0.0-beta.1](https://github.com/oceanprotocol/squid-js/compare/v2.0.0-beta.0...v2.0.0-beta.1)
> 28 January 2020
- remove `index` parameter from ocean.assets.consume() [`138a6bf`](https://github.com/oceanprotocol/squid-js/commit/138a6bf75abc402396606fab3bc3701875d7a393)
- Release 2.0.0-beta.1 [`1d7105c`](https://github.com/oceanprotocol/squid-js/commit/1d7105cfb1e80cb45711517ae6840d9ac22e80a6)
#### [v2.0.0-beta.0](https://github.com/oceanprotocol/squid-js/compare/v1.2.0...v2.0.0-beta.0)
> 28 January 2020
- Update cross-env to the latest version 🚀 [`#363`](https://github.com/oceanprotocol/squid-js/pull/363)
- Update mocha to the latest version 🚀 [`#364`](https://github.com/oceanprotocol/squid-js/pull/364)
- new ocean.utils.services [`40754ca`](https://github.com/oceanprotocol/squid-js/commit/40754ca46a10578cfdf0f460a7c33ba37bb2ffde)
- DDO & compute test tweaks [`e7acadb`](https://github.com/oceanprotocol/squid-js/commit/e7acadb2fe91739eee1bff3589801f12c7ab0b1b)
- test data consolidation [`ac39369`](https://github.com/oceanprotocol/squid-js/commit/ac39369543779370b9be6f00b0f2063a7e50c763)
#### [v1.3.0](https://github.com/oceanprotocol/squid-js/compare/v2.0.0-beta.1...v1.3.0)
> 31 January 2020 > 31 January 2020
- switch to @ethereum-navigator for network lookup [`#366`](https://github.com/oceanprotocol/squid-js/pull/366) - switch to @ethereum-navigator for network lookup [`#366`](https://github.com/oceanprotocol/squid-js/pull/366)
- consolidate test files [`#371`](https://github.com/oceanprotocol/squid-js/pull/371) - consolidate test files [`#371`](https://github.com/oceanprotocol/squid-js/pull/371)
- package updates [`#368`](https://github.com/oceanprotocol/squid-js/pull/368) - package updates [`#368`](https://github.com/oceanprotocol/squid-js/pull/368)
- Update cross-env to the latest version 🚀 [`#363`](https://github.com/oceanprotocol/squid-js/pull/363) - service interface refactor and cleanup [`768c69b`](https://github.com/oceanprotocol/squid-js/commit/768c69bdbdc0591e2e747d87082e859bc52cd7d2)
- Update mocha to the latest version 🚀 [`#364`](https://github.com/oceanprotocol/squid-js/pull/364) - fix compute unit tests [`e37420d`](https://github.com/oceanprotocol/squid-js/commit/e37420dabfd23d5f307be695992cac7324d47dd0)
- chore(package): update lockfile package-lock.json [`46c4def`](https://github.com/oceanprotocol/squid-js/commit/46c4defee5beb43fbea41006c5957d086721aff9) - job status cleanup [`f11eaca`](https://github.com/oceanprotocol/squid-js/commit/f11eacaabdc15285ba78a8096e492fd8863c933a)
- switch to @ethereum-navigator/navigator for network lookup [`92dbaae`](https://github.com/oceanprotocol/squid-js/commit/92dbaaeb25b26e28df644be356c347058ca1256a)
- chore(package): update lockfile package-lock.json [`eb141a6`](https://github.com/oceanprotocol/squid-js/commit/eb141a6d3d3131a65e4385f781568d015dac8429)
#### [v1.2.0](https://github.com/oceanprotocol/squid-js/compare/v1.1.0...v1.2.0) #### [v1.2.0](https://github.com/oceanprotocol/squid-js/compare/v1.1.0...v1.2.0)
> 23 January 2020 > 23 January 2020
- Decouple aquarius from ocean [`#354`](https://github.com/oceanprotocol/squid-js/pull/354) - Decouple aquarius from ocean [`#354`](https://github.com/oceanprotocol/squid-js/pull/354)
- merge fixes [`c8ea5f7`](https://github.com/oceanprotocol/squid-js/commit/c8ea5f77c2ec541fdbfb6f77cdabcd5691e4bffa)
- Release 1.2.0 [`56f7d11`](https://github.com/oceanprotocol/squid-js/commit/56f7d1113a6aa1f3318040fb32cfdcc22f5dc13b) - Release 1.2.0 [`56f7d11`](https://github.com/oceanprotocol/squid-js/commit/56f7d1113a6aa1f3318040fb32cfdcc22f5dc13b)
#### [v1.1.0](https://github.com/oceanprotocol/squid-js/compare/v1.1.0-beta.0...v1.1.0) #### [v1.1.0](https://github.com/oceanprotocol/squid-js/compare/v1.1.0-beta.0...v1.1.0)

View File

@ -1,6 +1,34 @@
# Migration Guide # Migration Guide
Instructions on how to migrate between breaking versions. Instructions on how to migrate between versions with breaking changes.
## v1.2.0 → v2.0.0
### Ocean Protocol Components Requirements
squid-js v2.0.0 only works against:
- Aquarius v1.0.7+
- Brizo v0.9.3+
- Events Handler v0.4.5+
- Keeper Contracts v0.13.2+
### Service index parameter removal from `ocean.assets` methods
Removes the need to get the respective service from the DDO, the `ocean.assets` methods will now do this on their own automatically.
```js
// old
const service = ddo.findServiceByType('access')
const did = ddo.id
const agreementId = await ocean.assets.order(did, service.index, account)
const path = await ocean.assets.consume(agreementId, did, service.index, account, folder)
// NEW
const did = ddo.id
const agreementId = await ocean.assets.order(did, account)
const path = await ocean.assets.consume(agreementId, did, account, folder)
```
## v0.8.3 → v1.0.0 ## v0.8.3 → v1.0.0

View File

@ -11,15 +11,15 @@
}, },
{ {
"name": "brizo", "name": "brizo",
"version": "~0.8.1" "version": "~0.9.0"
}, },
{ {
"name": "aquarius", "name": "aquarius",
"version": "~1.0.5" "version": "~1.0.7"
}, },
{ {
"name": "events-handler", "name": "events-handler",
"version": "~0.4.1" "version": "~0.4.4"
} }
] ]
} }

2641
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@oceanprotocol/squid", "name": "@oceanprotocol/squid",
"version": "1.3.0", "version": "2.0.0-beta.5",
"description": "JavaScript client library for Ocean Protocol", "description": "JavaScript client library for Ocean Protocol",
"main": "./dist/node/squid.js", "main": "./dist/node/squid.js",
"typings": "./dist/node/squid.d.ts", "typings": "./dist/node/squid.d.ts",
@ -58,41 +58,43 @@
"deprecated-decorator": "^0.1.6", "deprecated-decorator": "^0.1.6",
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"save-file": "^2.3.1", "save-file": "^2.3.1",
"uuid": "^3.4.0", "uuid": "^7.0.2",
"web3": "^1.2.5", "web3": "^1.2.6",
"whatwg-url": "^8.0.0" "whatwg-url": "^8.0.0"
}, },
"devDependencies": { "devDependencies": {
"@release-it/bumper": "^1.0.5", "@release-it/bumper": "^1.1.0",
"@truffle/hdwallet-provider": "^1.0.29", "@truffle/hdwallet-provider": "^1.0.33",
"@types/chai": "^4.2.8", "@types/chai": "^4.2.11",
"@types/chai-spies": "^1.0.1", "@types/chai-spies": "^1.0.1",
"@types/mocha": "^7.0.1", "@types/mocha": "^7.0.2",
"@types/node": "^13.5.1", "@types/node": "^13.9.1",
"@types/node-fetch": "^2.5.4", "@types/node-fetch": "^2.5.5",
"@typescript-eslint/eslint-plugin": "^2.18.0", "@types/sinon": "^7.5.2",
"@typescript-eslint/parser": "^2.18.0", "@typescript-eslint/eslint-plugin": "^2.23.0",
"@typescript-eslint/parser": "^2.23.0",
"auto-changelog": "^1.16.2", "auto-changelog": "^1.16.2",
"chai": "^4.2.0", "chai": "^4.2.0",
"chai-spies": "^1.0.0", "chai-spies": "^1.0.0",
"cross-env": "^7.0.0", "cross-env": "^7.0.2",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-config-oceanprotocol": "^1.5.0", "eslint-config-oceanprotocol": "^1.5.0",
"eslint-config-prettier": "^6.10.0", "eslint-config-prettier": "^6.10.0",
"eslint-plugin-prettier": "^3.1.2", "eslint-plugin-prettier": "^3.1.2",
"lcov-result-merger": "^3.1.0", "lcov-result-merger": "^3.1.0",
"mocha": "^7.0.1", "mocha": "^7.1.0",
"mock-local-storage": "^1.1.11", "mock-local-storage": "^1.1.11",
"nyc": "^15.0.0", "nyc": "^15.0.0",
"ora": "^4.0.2", "ora": "^4.0.2",
"prettier": "^1.19.1", "prettier": "^1.19.1",
"sinon": "^9.0.1",
"source-map-support": "^0.5.16", "source-map-support": "^0.5.16",
"ts-node": "^8.6.2", "ts-node": "^8.6.2",
"typedoc": "^0.16.9", "typedoc": "^0.17.1",
"typescript": "^3.7.5", "typescript": "^3.8.3",
"uglifyjs-webpack-plugin": "^2.2.0", "uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.5", "webpack": "^4.42.0",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.11",
"webpack-merge": "^4.2.2" "webpack-merge": "^4.2.2"
}, },
"nyc": { "nyc": {

View File

@ -1,7 +1,10 @@
import { File } from '../ddo/MetaData' import { File, MetaDataAlgorithm } from '../ddo/MetaData'
import Account from '../ocean/Account' import Account from '../ocean/Account'
import { noZeroX } from '../utils' import { noZeroX } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract' import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { DDO } from '../ddo/DDO'
import { ServiceType } from '../ddo/Service'
import { ComputeJob, Output } from '../ocean/OceanCompute'
const apiPath = '/api/v1/brizo/services' const apiPath = '/api/v1/brizo/services'
@ -35,15 +38,22 @@ export class Brizo extends Instantiable {
return `${this.url}${apiPath}/publish` return `${this.url}${apiPath}/publish`
} }
public getComputeEndpoint( public getComputeEndpoint() {
pubKey: string,
serviceIndex: number,
_notUsed: string,
container: string
) {
return `${this.url}${apiPath}/compute` return `${this.url}${apiPath}/compute`
} }
public async getEndpointFromAgreement(
type: ServiceType,
agreementId: string
): Promise<string> {
const { assets, keeper } = this.ocean
const { did } = await keeper.agreementStoreManager.getAgreement(agreementId)
const ddo: DDO = await assets.resolve(did)
const { serviceEndpoint } = ddo.findServiceByType(type)
return serviceEndpoint
}
public async initializeServiceAgreement( public async initializeServiceAgreement(
did: string, did: string,
serviceAgreementId: string, serviceAgreementId: string,
@ -78,12 +88,7 @@ export class Brizo extends Instantiable {
destination: string, destination: string,
index: number = -1 index: number = -1
): Promise<string> { ): Promise<string> {
const signature = const signature = await this.createSignature(account, agreementId)
(await account.getToken()) ||
(await this.ocean.utils.signature.signText(
noZeroX(agreementId),
account.getId()
))
const filesPromises = files const filesPromises = files
.filter((_, i) => index === -1 || i === index) .filter((_, i) => index === -1 || i === index)
.map(async ({ index: i }) => { .map(async ({ index: i }) => {
@ -105,6 +110,93 @@ export class Brizo extends Instantiable {
return destination return destination
} }
public async compute(
method: string,
serviceAgreementId: string,
consumerAccount: Account,
algorithmDid?: string,
algorithmMeta?: MetaDataAlgorithm,
jobId?: string,
output?: Output
): Promise<ComputeJob | ComputeJob[]> {
const signature = await this.createSignature(consumerAccount, serviceAgreementId)
const address = consumerAccount.getId()
const serviceEndpoint = await this.getEndpointFromAgreement(
'compute',
serviceAgreementId
)
if (!serviceEndpoint) {
throw new Error(
'Computing on asset failed, service definition is missing the `serviceEndpoint`.'
)
}
// construct Brizo URL
let url = serviceEndpoint
url += `?signature=${signature}`
url += `&consumerAddress=${address}`
url += `&serviceAgreementId=${noZeroX(serviceAgreementId)}`
url += (algorithmDid && `&algorithmDid=${algorithmDid}`) || ''
url +=
(algorithmMeta &&
`&algorithmMeta=${encodeURIComponent(JSON.stringify(algorithmMeta))}`) ||
''
url += (output && `&output=${JSON.stringify(output)}`) || ''
url += (jobId && `&jobId=${jobId}`) || ''
// switch fetch method
let fetch
switch (method) {
case 'post':
fetch = this.ocean.utils.fetch.post(url, '')
break
case 'put':
fetch = this.ocean.utils.fetch.put(url, '')
break
case 'delete':
fetch = this.ocean.utils.fetch.delete(url)
break
default:
fetch = this.ocean.utils.fetch.get(url)
break
}
const result = await fetch
.then((response: any) => {
if (response.ok) {
return response.json()
}
this.logger.error(
'Compute job failed:',
response.status,
response.statusText
)
return null
})
.catch((error: Error) => {
this.logger.error('Error with compute job')
this.logger.error(error.message)
throw error
})
return result
}
public async createSignature(account: Account, agreementId: string): Promise<string> {
const signature =
(await account.getToken()) ||
(await this.ocean.utils.signature.signText(
noZeroX(agreementId),
account.getId()
))
return signature
}
public async encrypt( public async encrypt(
did: string, did: string,
signature: string, signature: string,

View File

@ -1,25 +0,0 @@
export interface Provider {
type: string
description: string
environment: {
cluster: {
type: string
url: string
}
supportedContainers: {
image: string
tag: string
checksum: string
}[]
supportedServers: {
serverId: string
serverType: string
price: string
cpu: string
gpu: string
memory: string
disk: string
maxExecutionTime: number
}[]
}
}

View File

@ -1,72 +1,3 @@
export interface StageRequirements {
container: {
image: string
tag: string
checksum: string
}
}
export interface StageInput {
index: number
id: string
}
export interface StageTransformation {
id: string
}
export interface StageOutput {
metadataUrl: string
secretStoreUrl: string
accessProxyUrl: string
metadata: MetaDataMain
}
export interface Stage {
index: number
stageType?: string
requirements: StageRequirements
input: StageInput
transformation: StageTransformation
output: StageOutput
}
export interface Workflow {
stages: Stage[]
}
export interface Algorithm {
language: string
format?: string
version?: string
entrypoint: string
requirements: {
requirement: string
version: string
}
}
export interface ServiceDefinition {
auth: {
type: string
user?: string
password?: string
token?: string
}
endpoints: {
index: number
url: string
method: string
contentTypes: string[]
}
}
export interface Service {
spec?: string
specChecksum?: string
definition: ServiceDefinition
}
export interface File { export interface File {
/** /**
* File name. * File name.
@ -132,6 +63,19 @@ export interface File {
compression?: string compression?: string
} }
export interface MetaDataAlgorithm {
url?: string
rawcode?: string
language?: string
format?: string
version?: string
container: {
entrypoint: string
image: string
tag: string
}
}
/** /**
* Main attributes of assets metadata. * Main attributes of assets metadata.
* @see https://github.com/oceanprotocol/OEPs/tree/master/8 * @see https://github.com/oceanprotocol/OEPs/tree/master/8
@ -145,12 +89,11 @@ export interface MetaDataMain {
name: string name: string
/** /**
* Type of the Asset. Helps to filter by the type of asset, * Type of the Asset. Helps to filter by the type of asset ("dataset" or "algorithm").
* initially ("dataset", "algorithm", "container", "workflow", "other").
* @type {string} * @type {string}
* @example "dataset" * @example "dataset"
*/ */
type: 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other' type: 'dataset' | 'algorithm'
/** /**
* The date on which the asset was created by the originator in * The date on which the asset was created by the originator in
@ -185,7 +128,7 @@ export interface MetaDataMain {
license: string license: string
/** /**
* Price of the asset. * Price of the asset in vodka (attoOCEAN). It must be an integer encoded as a string.
* @type {string} * @type {string}
* @example "1000000000000000000" * @example "1000000000000000000"
*/ */
@ -197,13 +140,11 @@ export interface MetaDataMain {
*/ */
files: File[] files: File[]
encryptedService?: any /**
* Metadata used only for assets with type `algorithm`.
workflow?: Workflow * @type {MetaDataAlgorithm}
*/
algorithm?: Algorithm algorithm?: MetaDataAlgorithm
service?: Service
} }
/** /**

View File

@ -1,21 +1,65 @@
import { MetaData } from './MetaData' import { MetaData } from './MetaData'
import { ServiceAgreementTemplate } from './ServiceAgreementTemplate' import { ServiceAgreementTemplate } from './ServiceAgreementTemplate'
import { Provider } from './ComputingProvider'
export type ServiceType = export type ServiceType = 'authorization' | 'metadata' | 'access' | 'compute'
| 'authorization'
| 'metadata'
| 'access'
| 'compute'
| 'computing'
| 'fitchainCompute'
export interface ServiceCommon { export interface ServiceCommon {
type: ServiceType type: ServiceType
index: number index: number
serviceEndpoint?: string serviceEndpoint?: string
attributes: any & { attributes: ServiceCommonAttributes
main: { [key: string]: any } }
export interface ServiceCommonAttributes {
main: { [key: string]: any }
additionalInformation?: { [key: string]: any }
serviceAgreementTemplate?: ServiceAgreementTemplate
}
export interface ServiceAccessAttributes extends ServiceCommonAttributes {
main: {
creator: string
name: string
datePublished: string
price: string
timeout: number
}
}
export interface ServiceComputeAttributes extends ServiceCommonAttributes {
main: {
creator: string
datePublished: string
price: string
timeout: number
provider?: ServiceComputeProvider
name: string
}
}
export interface ServiceComputeProvider {
type: string
description: string
environment: {
cluster: {
type: string
url: string
}
supportedContainers: {
image: string
tag: string
checksum: string
}[]
supportedServers: {
serverId: string
serverType: string
price: string
cpu: string
gpu: string
memory: string
disk: string
maxExecutionTime: number
}[]
} }
} }
@ -32,30 +76,13 @@ export interface ServiceMetadata extends ServiceCommon {
export interface ServiceAccess extends ServiceCommon { export interface ServiceAccess extends ServiceCommon {
type: 'access' type: 'access'
templateId?: string templateId?: string
attributes: { attributes: ServiceAccessAttributes
main: {
creator: string
name: string
datePublished: string
price: string
timeout: number
}
serviceAgreementTemplate?: ServiceAgreementTemplate
additionalInformation: {
description: string
}
}
}
export interface ServiceComputing extends ServiceCommon {
type: 'computing'
templateId?: string
provider?: Provider
serviceAgreementTemplate?: ServiceAgreementTemplate
} }
export interface ServiceCompute extends ServiceCommon { export interface ServiceCompute extends ServiceCommon {
type: 'compute'
templateId?: string templateId?: string
attributes: ServiceComputeAttributes
} }
export type Service< export type Service<
@ -64,8 +91,6 @@ export type Service<
? ServiceAuthorization ? ServiceAuthorization
: T extends 'metadata' : T extends 'metadata'
? ServiceMetadata ? ServiceMetadata
: T extends 'computing'
? ServiceComputing
: T extends 'access' : T extends 'access'
? ServiceAccess ? ServiceAccess
: T extends 'compute' : T extends 'compute'

View File

@ -95,24 +95,19 @@ export class Keeper extends Instantiable {
computeExecutionCondition: keeper.instances.computeExecutionCondition computeExecutionCondition: keeper.instances.computeExecutionCondition
} }
// Templates // Templates
keeper.instances.escrowAccessSecretStoreTemplate = new EscrowAccessSecretStoreTemplate( keeper.templates = Object()
keeper.templates.escrowAccessSecretStoreTemplate = new EscrowAccessSecretStoreTemplate(
keeper.templateStoreManager, keeper.templateStoreManager,
keeper.agreementStoreManager, keeper.agreementStoreManager,
keeper.didRegistry, keeper.didRegistry,
keeper.conditions keeper.conditions
) )
keeper.instances.escrowComputeExecutionTemplate = new EscrowComputeExecutionTemplate( keeper.templates.escrowComputeExecutionTemplate = new EscrowComputeExecutionTemplate(
keeper.templateStoreManager, keeper.templateStoreManager,
keeper.agreementStoreManager, keeper.agreementStoreManager,
keeper.didRegistry, keeper.didRegistry,
keeper.conditions keeper.conditions
) )
keeper.templates = {
escrowAccessSecretStoreTemplate:
keeper.instances.escrowAccessSecretStoreTemplate,
escrowComputeExecutionTemplate:
keeper.instances.escrowComputeExecutionTemplate
}
// Utils // Utils
keeper.utils = { keeper.utils = {
eventHandler: new EventHandler(config) eventHandler: new EventHandler(config)

View File

@ -4,10 +4,10 @@ export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
contractName: 'EscrowAccessSecretStoreTemplate', contractName: 'EscrowAccessSecretStoreTemplate',
events: [ events: [
{ {
name: 'AgreementCreated', name: 'AgreementActorAdded',
actorType: 'consumer', actorType: 'provider',
handler: { handler: {
moduleName: 'escrowAccessSecretStoreTemplate', moduleName: '',
functionName: 'fulfillLockRewardCondition', functionName: 'fulfillLockRewardCondition',
version: '0.1' version: '0.1'
} }
@ -45,7 +45,7 @@ export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'lockRewardCondition', moduleName: 'lockRewardCondition',
functionName: 'fulfillAccessSecretStoreCondition', functionName: 'fulfillAccessSecretStoreCondition',
@ -75,7 +75,7 @@ export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'accessSecretStore', moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition', functionName: 'fulfillEscrowRewardCondition',
@ -87,7 +87,7 @@ export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
actorType: 'consumer', actorType: 'consumer',
handler: { handler: {
moduleName: 'accessSecretStore', moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition', functionName: 'refundReward',
version: '0.1' version: '0.1'
} }
} }
@ -129,7 +129,7 @@ export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'escrowRewardCondition', moduleName: 'escrowRewardCondition',
functionName: 'verifyRewardTokens', functionName: 'verifyRewardTokens',

View File

@ -4,10 +4,10 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
contractName: 'EscrowComputeExecutionTemplate', contractName: 'EscrowComputeExecutionTemplate',
events: [ events: [
{ {
name: 'AgreementCreated', name: 'AgreementActorAdded',
actorType: 'consumer', actorType: 'provider',
handler: { handler: {
moduleName: 'serviceExecutionTemplate', moduleName: '',
functionName: 'fulfillLockRewardCondition', functionName: 'fulfillLockRewardCondition',
version: '0.1' version: '0.1'
} }
@ -15,13 +15,13 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
], ],
fulfillmentOrder: [ fulfillmentOrder: [
'lockReward.fulfill', 'lockReward.fulfill',
'serviceExecution.fulfill', 'computeExecution.fulfill',
'escrowReward.fulfill' 'escrowReward.fulfill'
], ],
conditionDependency: { conditionDependency: {
lockReward: [], lockReward: [],
serviceExecution: [], computeExecution: [],
escrowReward: ['lockReward', 'serviceExecution'] escrowReward: ['lockReward', 'computeExecution']
}, },
conditions: [ conditions: [
{ {
@ -45,17 +45,17 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'lockRewardCondition', moduleName: 'lockRewardExecutionCondition',
functionName: 'fulfillServiceExecutionCondition', functionName: 'fulfillComputeExecutionCondition',
version: '0.1' version: '0.1'
} }
} }
] ]
}, },
{ {
name: 'serviceExecution', name: 'computeExecution',
timelock: 0, timelock: 0,
timeout: 0, timeout: 0,
contractName: 'ComputeExecutionCondition', contractName: 'ComputeExecutionCondition',
@ -75,10 +75,10 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'serviceExecution', moduleName: 'accessSecretStore',
functionName: 'fulfillServiceExecutionCondition', functionName: 'fulfillEscrowRewardCondition',
version: '0.1' version: '0.1'
} }
}, },
@ -86,8 +86,8 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
name: 'TimedOut', name: 'TimedOut',
actorType: 'consumer', actorType: 'consumer',
handler: { handler: {
moduleName: 'serviceExec', moduleName: 'accessSecretStore',
functionName: 'fulfillServiceExecutionCondition', functionName: 'refundReward',
version: '0.1' version: '0.1'
} }
} }
@ -129,7 +129,7 @@ export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
events: [ events: [
{ {
name: 'Fulfilled', name: 'Fulfilled',
actorType: 'publisher', actorType: 'provider',
handler: { handler: {
moduleName: 'escrowRewardCondition', moduleName: 'escrowRewardCondition',
functionName: 'verifyRewardTokens', functionName: 'verifyRewardTokens',

View File

@ -2,6 +2,7 @@ import { OceanAccounts } from './OceanAccounts'
import { OceanAgreements } from './OceanAgreements' import { OceanAgreements } from './OceanAgreements'
import { OceanAssets } from './OceanAssets' import { OceanAssets } from './OceanAssets'
import { OceanAuth } from './OceanAuth' import { OceanAuth } from './OceanAuth'
import { OceanCompute } from './OceanCompute'
import { OceanSecretStore } from './OceanSecretStore' import { OceanSecretStore } from './OceanSecretStore'
import { OceanTokens } from './OceanTokens' import { OceanTokens } from './OceanTokens'
import { OceanVersions } from './OceanVersions' import { OceanVersions } from './OceanVersions'
@ -49,6 +50,7 @@ export class Ocean extends Instantiable {
instance.accounts = await OceanAccounts.getInstance(instanceConfig) instance.accounts = await OceanAccounts.getInstance(instanceConfig)
instance.auth = await OceanAuth.getInstance(instanceConfig) instance.auth = await OceanAuth.getInstance(instanceConfig)
instance.assets = await OceanAssets.getInstance(instanceConfig) instance.assets = await OceanAssets.getInstance(instanceConfig)
instance.compute = await OceanCompute.getInstance(instanceConfig)
instance.agreements = await OceanAgreements.getInstance(instanceConfig) instance.agreements = await OceanAgreements.getInstance(instanceConfig)
instance.secretStore = await OceanSecretStore.getInstance(instanceConfig) instance.secretStore = await OceanSecretStore.getInstance(instanceConfig)
instance.tokens = await OceanTokens.getInstance(instanceConfig) instance.tokens = await OceanTokens.getInstance(instanceConfig)
@ -99,6 +101,12 @@ export class Ocean extends Instantiable {
*/ */
public agreements: OceanAgreements public agreements: OceanAgreements
/**
* Ocean compute submodule
* @type {OceanCompute}
*/
public compute: OceanCompute
/** /**
* Ocean secretStore submodule * Ocean secretStore submodule
* @type {OceanSecretStore} * @type {OceanSecretStore}

View File

@ -7,6 +7,7 @@ import { AgreementConditionsStatus } from '../keeper/contracts/templates/Agreeme
import { ConditionState } from '../keeper/contracts/conditions/Condition.abstract' import { ConditionState } from '../keeper/contracts/conditions/Condition.abstract'
import { OceanAgreementsConditions } from './OceanAgreementsConditions' import { OceanAgreementsConditions } from './OceanAgreementsConditions'
import { Service } from '../ddo/Service'
export interface AgreementPrepareResult { export interface AgreementPrepareResult {
agreementId: string agreementId: string
@ -121,7 +122,7 @@ export class OceanAgreements extends Instantiable {
) { ) {
const d: DID = DID.parse(did) const d: DID = DID.parse(did)
const ddo = await this.ocean.aquarius.retrieveDDO(d) const ddo = await this.ocean.aquarius.retrieveDDO(d)
const service = ddo.findServiceById(index) const service: Service = ddo.findServiceById(index)
const templateName = service.attributes.serviceAgreementTemplate.contractName const templateName = service.attributes.serviceAgreementTemplate.contractName
return this.ocean.keeper return this.ocean.keeper
.getTemplateByName(templateName) .getTemplateByName(templateName)

View File

@ -81,13 +81,13 @@ export class OceanAgreementsConditions extends Instantiable {
} }
/** /**
* Authorize the consumer defined in the agreement to execute a remote service associated with this asset. * Authorize the consumer defined in the agreement to compute on this asset.
* @param {string} agreementId Agreement ID. * @param {string} agreementId Agreement ID.
* @param {string} did Asset ID. * @param {string} did Asset ID.
* @param {string} grantee Consumer address. * @param {string} grantee Consumer address.
* @param {Account} from Account of sender. * @param {Account} from Account of sender.
*/ */
public async grantServiceExecution( public async grantCompute(
agreementId: string, agreementId: string,
did: string, did: string,
grantee: string, grantee: string,

View File

@ -2,11 +2,12 @@ import { TransactionReceipt } from 'web3-core'
import { SearchQuery } from '../aquarius/Aquarius' import { SearchQuery } from '../aquarius/Aquarius'
import { DDO } from '../ddo/DDO' import { DDO } from '../ddo/DDO'
import { MetaData } from '../ddo/MetaData' import { MetaData } from '../ddo/MetaData'
import { Service } from '../ddo/Service' import { Service, ServiceAccess } from '../ddo/Service'
import Account from './Account' import Account from './Account'
import DID from './DID' import DID from './DID'
import { fillConditionsWithDDO, SubscribablePromise, generateId, zeroX } from '../utils' import { fillConditionsWithDDO, SubscribablePromise } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract' import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { OrderProgressStep } from './utils/ServiceUtils'
export enum CreateProgressStep { export enum CreateProgressStep {
EncryptingFiles, EncryptingFiles,
@ -19,13 +20,6 @@ export enum CreateProgressStep {
DdoStored DdoStored
} }
export enum OrderProgressStep {
CreatingAgreement,
AgreementInitialized,
LockingPayment,
LockedPayment
}
/** /**
* Assets submodule of Ocean Protocol. * Assets submodule of Ocean Protocol.
*/ */
@ -82,6 +76,16 @@ export class OceanAssets extends Instantiable {
this.logger.log('Files encrypted') this.logger.log('Files encrypted')
observer.next(CreateProgressStep.FilesEncrypted) observer.next(CreateProgressStep.FilesEncrypted)
// make sure that access service is defined if services is empty
if (services.length === 0) {
const accessService = await this.createAccessServiceAttributes(
publisher,
metadata.main.price,
metadata.main.datePublished
)
services.push(accessService)
}
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate() const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
const serviceEndpoint = this.ocean.aquarius.getServiceEndpoint(did) const serviceEndpoint = this.ocean.aquarius.getServiceEndpoint(did)
@ -104,21 +108,6 @@ export class OceanAssets extends Instantiable {
} }
], ],
service: [ service: [
{
type: 'access',
serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(),
templateId: templates.escrowAccessSecretStoreTemplate.getId(),
attributes: {
main: {
creator: publisher.getId(),
datePublished: metadata.main.datePublished,
name: 'dataAssetAccessServiceAgreement',
price: metadata.main.price,
timeout: 3600
},
serviceAgreementTemplate
}
},
{ {
type: 'authorization', type: 'authorization',
service: 'SecretStore', service: 'SecretStore',
@ -165,9 +154,18 @@ export class OceanAssets extends Instantiable {
}) })
// Overwrite initial service agreement conditions // Overwrite initial service agreement conditions
const rawConditions = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplateConditions() serviceAgreementTemplate.conditions = fillConditionsWithDDO(
const conditions = fillConditionsWithDDO(rawConditions, ddo) await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplateConditions(),
serviceAgreementTemplate.conditions = conditions ddo
)
for (const service of services) {
if (service.type === 'compute') {
service.attributes.serviceAgreementTemplate.conditions = fillConditionsWithDDO(
await templates.escrowComputeExecutionTemplate.getServiceAgreementTemplateConditions(),
ddo
)
}
}
this.logger.log('Generating proof') this.logger.log('Generating proof')
observer.next(CreateProgressStep.GeneratingProof) observer.next(CreateProgressStep.GeneratingProof)
@ -200,17 +198,16 @@ export class OceanAssets extends Instantiable {
public async consume( public async consume(
agreementId: string, agreementId: string,
did: string, did: string,
serviceIndex: number,
consumerAccount: Account, consumerAccount: Account,
resultPath: string, resultPath: string,
index?: number, index?: number,
useSecretStore?: boolean useSecretStore?: boolean
): Promise<string> ): Promise<string>
/* eslint-disable no-dupe-class-members */
public async consume( public async consume(
agreementId: string, agreementId: string,
did: string, did: string,
serviceIndex: number,
consumerAccount: Account, consumerAccount: Account,
resultPath?: undefined | null, resultPath?: undefined | null,
index?: number, index?: number,
@ -220,7 +217,6 @@ export class OceanAssets extends Instantiable {
public async consume( public async consume(
agreementId: string, agreementId: string,
did: string, did: string,
serviceIndex: number,
consumerAccount: Account, consumerAccount: Account,
resultPath?: string, resultPath?: string,
index: number = -1, index: number = -1,
@ -228,8 +224,7 @@ export class OceanAssets extends Instantiable {
): Promise<string | true> { ): Promise<string | true> {
const ddo = await this.resolve(did) const ddo = await this.resolve(did)
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')
const accessService = ddo.findServiceByType('access')
const accessService = ddo.findServiceById(serviceIndex)
const { files } = attributes.main const { files } = attributes.main
@ -244,7 +239,7 @@ export class OceanAssets extends Instantiable {
this.logger.log('Consuming files') this.logger.log('Consuming files')
resultPath = resultPath resultPath = resultPath
? `${resultPath}/datafile.${ddo.shortId()}.${serviceIndex}/` ? `${resultPath}/datafile.${ddo.shortId()}.${accessService.index}/`
: undefined : undefined
if (!useSecretStore) { if (!useSecretStore) {
@ -277,109 +272,43 @@ export class OceanAssets extends Instantiable {
} }
return true return true
} }
/* eslint-enable no-dupe-class-members */
/** /**
* Start the purchase/order of an asset's service. Starts by signing the service agreement * Start the purchase/order of an asset's service. Starts by signing the service agreement
* then sends the request to the publisher via the service endpoint (Brizo http service). * then sends the request to the publisher via the service endpoint (Brizo http service).
* @param {string} did Decentralized ID. * @param {string} did Decentralized ID.
* @param {number} index Service index. * @param {Account} consumerAccount Consumer account.
* @param {Account} consumer Consumer account.
* @param {string} provider ethereum address of service provider (optional) * @param {string} provider ethereum address of service provider (optional)
* @return {Promise<string>} Returns Agreement ID * @return {Promise<string>} Returns Agreement ID
*/ */
public order( public order(
did: string, did: string,
index: number, consumerAccount: Account,
consumer: Account,
provider?: string provider?: string
): SubscribablePromise<OrderProgressStep, string> { ): SubscribablePromise<OrderProgressStep, string> {
return new SubscribablePromise(async observer => { return new SubscribablePromise(async observer => {
const oceanAgreements = this.ocean.agreements const { keeper, utils } = this.ocean
const ddo: DDO = await this.resolve(did)
const condition = keeper.conditions.accessSecretStoreCondition
const agreementId = zeroX(generateId()) const agreementId = await utils.services.order(
const ddo = await this.resolve(did) 'access',
condition,
const { keeper } = this.ocean observer,
const templateName = ddo.findServiceByType('access').attributes consumerAccount,
.serviceAgreementTemplate.contractName ddo,
const template = keeper.getTemplateByName(templateName) provider
const accessCondition = keeper.conditions.accessSecretStoreCondition
// eslint-disable-next-line no-async-promise-executor
const paymentFlow = new Promise(async (resolve, reject) => {
await template.getAgreementCreatedEvent(agreementId).once()
this.logger.log('Agreement initialized')
observer.next(OrderProgressStep.AgreementInitialized)
const { attributes } = ddo.findServiceByType('metadata')
this.logger.log('Locking payment')
const accessGranted = accessCondition
.getConditionFulfilledEvent(agreementId)
.once()
observer.next(OrderProgressStep.LockingPayment)
const paid = await oceanAgreements.conditions.lockReward(
agreementId,
attributes.main.price,
consumer
)
observer.next(OrderProgressStep.LockedPayment)
if (paid) {
this.logger.log('Payment was OK')
} else {
this.logger.error('Payment was KO')
this.logger.error('Agreement ID: ', agreementId)
this.logger.error('DID: ', ddo.id)
reject(new Error('Error on payment'))
}
await accessGranted
this.logger.log('Access granted')
resolve()
})
observer.next(OrderProgressStep.CreatingAgreement)
this.logger.log('Creating agreement')
// Get provider from didRegistry if not given in arguments
let _provider = provider
if (!provider) {
const providers = await keeper.didRegistry.getDIDProviders(ddo.shortId())
if (providers) {
_provider = providers[0]
}
}
await oceanAgreements.create(
did,
agreementId,
index,
undefined,
consumer,
_provider,
consumer
) )
this.logger.log('Agreement created')
try {
await paymentFlow
} catch (e) {
throw new Error('Error paying the asset.')
}
return agreementId return agreementId
}) })
} }
/** /**
* Returns the owner of a asset. * Returns the owner of an asset.
* @param {string} did Decentralized ID. * @param {string} did Decentralized ID.
* @return {Promise<string>} Returns eth address * @return {Promise<string>} Returns Account ID
*/ */
public async owner(did: string): Promise<string> { public async owner(did: string): Promise<string> {
const ddo = await this.resolve(did) const ddo = await this.resolve(did)
@ -495,4 +424,29 @@ export class OceanAssets extends Instantiable {
} }
} as SearchQuery) } as SearchQuery)
} }
public async createAccessServiceAttributes(
consumerAccount: Account,
price: string,
datePublished: string
): Promise<ServiceAccess> {
const { templates } = this.ocean.keeper
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
return {
type: 'access',
index: 2,
serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(),
templateId: templates.escrowAccessSecretStoreTemplate.getId(),
attributes: {
main: {
creator: consumerAccount.getId(),
datePublished,
price,
timeout: 3600,
name: 'dataAssetAccessServiceAgreement'
},
serviceAgreementTemplate
}
}
}
} }

291
src/ocean/OceanCompute.ts Normal file
View File

@ -0,0 +1,291 @@
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { MetaData, MetaDataAlgorithm } from '../ddo/MetaData'
import Account from './Account'
import { DDO } from '../ddo/DDO'
import { SubscribablePromise } from '../utils'
import { OrderProgressStep } from './utils/ServiceUtils'
import { DID } from '../squid'
import { ServiceCompute } from '../ddo/Service'
export const ComputeJobStatus = Object.freeze({
Started: 10,
ConfiguringVolumes: 20,
ProvisioningSuccess: 30,
DataProvisioningFailed: 31,
AlgorithmProvisioningFailed: 32,
RunningAlgorithm: 40,
FilteringResults: 50,
PublishingResult: 60,
Completed: 70,
Stopped: 80,
Deleted: 90
})
export interface Output {
publishAlgorithmLog?: boolean
publishOutput?: boolean
brizoAddress?: string
brizoUri?: string
metadata?: MetaData
metadataUri?: string
nodeUri?: string
owner?: string
secretStoreUri?: string
whitelist?: string[]
}
export interface ComputeJob {
owner: string
agreementId: string
jobId: string
dateCreated: string
dateFinished: string
status: number
statusText: string
algorithmLogUrl: string
resultsUrls: string[]
resultsDid?: DID
}
/**
* Compute submodule of Ocean Protocol.
*/
export class OceanCompute extends Instantiable {
/**
* Returns the instance of OceanCompute.
* @return {Promise<OceanCompute>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanCompute> {
const instance = new OceanCompute()
instance.setInstanceConfig(config)
return instance
}
/**
* 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.
* @return {Promise<string>} Returns the Service Agreement ID, representation of `bytes32` ID.
*/
public order(
consumerAccount: Account,
datasetDid: string,
provider?: string
): SubscribablePromise<OrderProgressStep, string> {
return new SubscribablePromise(async observer => {
const { assets, keeper, utils } = this.ocean
const ddo: DDO = await assets.resolve(datasetDid)
const condition = keeper.conditions.computeExecutionCondition
const agreementId = await utils.services.order(
'compute',
condition,
observer,
consumerAccount,
ddo,
provider
)
return agreementId
})
}
/**
* Check the output object and add default properties if needed
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {Output} output Output section used for publishing the result.
* @return {Promise<Output>} Returns output object
*/
public checkOutput(consumerAccount: Account, output?: Output): Output {
const isDefault =
!output || (!output.publishAlgorithmLog && !output.publishOutput)
if (isDefault) {
return {
publishAlgorithmLog: false,
publishOutput: false
}
}
return {
publishAlgorithmLog: output.publishAlgorithmLog,
publishOutput: output.publishOutput,
brizoAddress: output.brizoAddress || this.config.brizoAddress,
brizoUri: output.brizoUri || this.config.brizoUri,
metadataUri: output.metadataUri || this.config.aquariusUri,
nodeUri: output.nodeUri || this.config.nodeUri,
owner: output.owner || consumerAccount.getId(),
secretStoreUri: output.secretStoreUri || this.config.secretStoreUri
}
}
/**
* Start the execution of a compute job.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @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.
* @param {Output} output Define algorithm output publishing. Publishing the result of a compute job is turned off by default.
* @return {Promise<ComputeJob>} Returns compute job ID under status.jobId
*/
public async start(
consumerAccount: Account,
agreementId: string,
algorithmDid?: string,
algorithmMeta?: MetaDataAlgorithm,
output?: Output
): Promise<ComputeJob> {
output = this.checkOutput(consumerAccount, output)
const computeJobsList = await this.ocean.brizo.compute(
'post',
agreementId,
consumerAccount,
algorithmDid,
algorithmMeta,
undefined,
output
)
return computeJobsList[0] as ComputeJob
}
/**
* Ends a running compute job.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @param {string} jobId The ID of the compute job to be stopped
* @return {Promise<ComputeJob>} Returns the new status of a job
*/
public async stop(
consumerAccount: Account,
agreementId: string,
jobId: string
): Promise<ComputeJob> {
const computeJobsList = await this.ocean.brizo.compute(
'put',
agreementId,
consumerAccount,
undefined,
undefined,
jobId
)
return computeJobsList[0] as ComputeJob
}
/**
* Deletes a compute job and all resources associated with the job. If job is running it will be stopped first.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @param {string} jobId The ID of the compute job to be stopped
* @return {Promise<ComputeJob>} Returns the new status of a job
*/
public async delete(
consumerAccount: Account,
agreementId: string,
jobId: string
): Promise<ComputeJob> {
const computeJobsList = await this.ocean.brizo.compute(
'delete',
agreementId,
consumerAccount,
undefined,
undefined,
jobId
)
return computeJobsList[0] as ComputeJob
}
/**
* Ends a running compute job and starts it again.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @param {string} jobId The ID of the compute job to be stopped
* @return {Promise<ComputeJob>} Returns the new status of a job
*/
public async restart(
consumerAccount: Account,
agreementId: string,
jobId: string
): Promise<ComputeJob> {
await this.stop(consumerAccount, agreementId, jobId)
const result = await this.start(consumerAccount, agreementId, jobId)
return result
}
/**
* Returns information about the status of all compute jobs, or a single compute job.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @param {string} jobId The ID of the compute job to be stopped
* @return {Promise<ComputeJob[]>} Returns the status
*/
public async status(
consumerAccount: Account,
agreementId?: string,
jobId?: string
): Promise<ComputeJob[]> {
const computeJobsList = await this.ocean.brizo.compute(
'get',
agreementId,
consumerAccount,
undefined,
undefined,
jobId
)
return computeJobsList as ComputeJob[]
}
/**
* Returns the final result of a specific compute job published as an asset.
* @param {Account} consumerAccount The account of the consumer ordering the service.
* @param {string} agreementId The service agreement ID.
* @param {string} jobId The ID of the compute job to be stopped.
* @return {Promise<ComputeJob>} Returns the DDO of the result asset.
*/
public async result(
consumerAccount: Account,
agreementId: string,
jobId: string
): Promise<ComputeJob> {
const computeJobsList = await this.ocean.brizo.compute(
'get',
agreementId,
consumerAccount,
undefined,
undefined,
jobId
)
return computeJobsList[0] as ComputeJob
}
public async createComputeServiceAttributes(
consumerAccount: Account,
price: string,
datePublished: string
): Promise<ServiceCompute> {
const { templates } = this.ocean.keeper
const serviceAgreementTemplate = await templates.escrowComputeExecutionTemplate.getServiceAgreementTemplate()
const name = 'dataAssetComputingServiceAgreement'
return {
type: 'compute',
index: 3,
serviceEndpoint: this.ocean.brizo.getComputeEndpoint(),
templateId: templates.escrowComputeExecutionTemplate.getId(),
attributes: {
main: {
creator: consumerAccount.getId(),
datePublished,
price,
timeout: 3600,
name
},
serviceAgreementTemplate
}
}
}
}

View File

@ -1,5 +1,6 @@
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract' import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
import { ServiceUtils } from './ServiceUtils'
import { ServiceAgreement } from './ServiceAgreement' import { ServiceAgreement } from './ServiceAgreement'
import { SignatureUtils } from './SignatureUtils' import { SignatureUtils } from './SignatureUtils'
import { WebServiceConnector } from './WebServiceConnector' import { WebServiceConnector } from './WebServiceConnector'
@ -21,6 +22,7 @@ export class OceanUtils extends Instantiable {
config.logger, config.logger,
config.web3 config.web3
) )
instance.services = new ServiceUtils(config.ocean, config.logger)
instance.signature = new SignatureUtils(config.web3, config.logger) instance.signature = new SignatureUtils(config.web3, config.logger)
instance.fetch = new WebServiceConnector(config.logger) instance.fetch = new WebServiceConnector(config.logger)
@ -33,6 +35,12 @@ export class OceanUtils extends Instantiable {
*/ */
public agreements: ServiceAgreement public agreements: ServiceAgreement
/**
* Service utils.
* @type {ServiceUtils}
*/
public services: ServiceUtils
/** /**
* Signature utils. * Signature utils.
* @type {SignatureUtils} * @type {SignatureUtils}

View File

@ -0,0 +1,115 @@
import { DDO } from '../../ddo/DDO'
import Account from '../Account'
import { zeroX, Logger, generateId } from '../../utils'
import { Ocean } from '../../squid'
import { Condition } from '../../keeper/contracts/conditions'
import { ServiceType, Service } from '../../ddo/Service'
export enum OrderProgressStep {
CreatingAgreement,
AgreementInitialized,
LockingPayment,
LockedPayment
}
export class ServiceUtils {
private ocean: Ocean
private logger: Logger
constructor(ocean: Ocean, logger: Logger) {
this.ocean = ocean
this.logger = logger
}
public async order(
type: ServiceType,
condition: Condition,
observer: any,
consumerAccount: Account,
ddo: DDO,
provider?: string
): Promise<string> {
const { keeper, agreements } = this.ocean
const agreementId = zeroX(generateId())
const service: Service = ddo.findServiceByType(type)
const metadata = ddo.findServiceByType('metadata')
const templateName = service.attributes.serviceAgreementTemplate.contractName
const template = keeper.getTemplateByName(templateName)
// use price from compute service,
// otherwise always take the price from metadata
const price =
type === 'compute'
? service.attributes.main.price
: metadata.attributes.main.price
// eslint-disable-next-line no-async-promise-executor
const paymentFlow = new Promise(async (resolve, reject) => {
await template.getAgreementCreatedEvent(agreementId).once()
this.logger.log('Agreement initialized')
observer.next(OrderProgressStep.AgreementInitialized)
this.logger.log('Locking payment')
const serviceGranted = condition
.getConditionFulfilledEvent(agreementId)
.once()
observer.next(OrderProgressStep.LockingPayment)
const paid = await agreements.conditions.lockReward(
agreementId,
price,
consumerAccount
)
observer.next(OrderProgressStep.LockedPayment)
if (paid) {
this.logger.log('Payment was OK')
} else {
this.logger.error('Payment was KO')
this.logger.error('Agreement ID: ', agreementId)
this.logger.error('DID: ', ddo.id)
reject(new Error('Error on payment'))
}
await serviceGranted
this.logger.log(`Service ${type} granted`)
resolve()
})
observer.next(OrderProgressStep.CreatingAgreement)
this.logger.log('Creating agreement')
// Get provider from didRegistry if not given in arguments
let _provider = provider
if (!provider) {
const providers = await keeper.didRegistry.getDIDProviders(ddo.shortId())
if (providers) {
_provider = providers[0]
}
}
await agreements.create(
ddo.id,
agreementId,
service.index,
undefined,
consumerAccount,
_provider,
consumerAccount
)
this.logger.log('Agreement created')
try {
await paymentFlow
} catch (e) {
throw new Error(`Error paying the ${type} service.`)
}
return agreementId
}
}

View File

@ -43,6 +43,15 @@ export class WebServiceConnector {
}) })
} }
public delete(url: string): Promise<Response> {
return this.fetch(url, {
method: 'DELETE',
headers: {
'Content-type': 'application/json'
}
})
}
public async downloadFile( public async downloadFile(
url: string, url: string,
destination?: string, destination?: string,

View File

@ -14,7 +14,9 @@ import * as utils from './utils'
export * from './ddo/DDO' export * from './ddo/DDO'
export * from './ddo/MetaData' export * from './ddo/MetaData'
export { OrderProgressStep, CreateProgressStep } from './ocean/OceanAssets' export { CreateProgressStep } from './ocean/OceanAssets'
export { ComputeJob, ComputeJobStatus } from './ocean/OceanCompute'
export { OrderProgressStep } from './ocean/utils/ServiceUtils'
export { export {
OceanPlatformTechStatus, OceanPlatformTechStatus,
OceanPlatformTech, OceanPlatformTech,

View File

@ -85,12 +85,15 @@ describe('Asset Owners', () => {
// Granting access // Granting access
try { try {
await account2.requestTokens( await account2.requestTokens(
+metadata.main.price * 10 ** -(await ocean.keeper.token.decimals()) parseInt(
(
+metadata.main.price *
10 ** -(await ocean.keeper.token.decimals())
).toString()
)
) )
} catch {} } catch {}
const { index } = ddo.findServiceByType('access') await ocean.assets.order(ddo.id, account2)
await ocean.assets.order(ddo.id, index, account2)
// Access granted // Access granted
const { length: finalLength2 } = await ocean.assets.consumerAssets( const { length: finalLength2 } = await ocean.assets.consumerAssets(
account2.getId() account2.getId()

View File

@ -0,0 +1,121 @@
import { assert } from 'chai'
import { config } from '../config'
import {
Ocean,
Account,
DDO,
MetaData,
ComputeJobStatus,
Config,
MetaDataAlgorithm
} from '../../../src'
import { getMetadata } from '../utils'
import { ServiceCompute } from '../../../src/ddo/Service'
const metadataAsset = getMetadata()
const metadataAlgorithm = getMetadata(0, 'algorithm')
const customConfig: Config = {
...config,
// nodeUri: 'https://nile.dev-ocean.com',
// aquariusUri: 'https://aquarius.nile.dev-ocean.com',
// brizoUri: 'http://89.46.156.10:8030',
// secretStoreUri: 'https://secret-store.nile.dev-ocean.com',
// brizoAddress: '0x413c9ba0a05b8a600899b41b0c62dd661e689354',
verbose: true
}
describe('Compute', () => {
let ocean: Ocean
let account: Account
let agreementId: string
let dataset: DDO
let algorithm: DDO
let computeService: ServiceCompute
before(async () => {
ocean = await Ocean.getInstance(customConfig)
;[account] = await ocean.accounts.list()
})
it('should authenticate the consumer account', async () => {
await account.authenticate()
})
it('should publish a dataset with a compute service object', async () => {
const stepsAsset = []
computeService = await ocean.compute.createComputeServiceAttributes(
account,
'1000',
metadataAsset.main.datePublished
)
dataset = await ocean.assets
.create(metadataAsset as MetaData, account, [computeService])
.next(step => stepsAsset.push(step))
assert.instanceOf(dataset, 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
.create(metadataAlgorithm as MetaData, account)
.next(step => stepsAlgorithm.push(step))
assert.instanceOf(algorithm, DDO)
assert.deepEqual(stepsAlgorithm, [0, 1, 2, 3, 4, 5, 6, 7])
})
it('should order the compute service of the dataset', async () => {
const steps = []
try {
await account.requestTokens(
parseInt(
(
+computeService.attributes.main.price *
10 ** -(await ocean.keeper.token.decimals())
).toString()
)
)
agreementId = await ocean.compute
.order(account, dataset.id)
.next(step => steps.push(step))
console.log(agreementId)
assert.isDefined(agreementId)
assert.deepEqual(steps, [0, 1, 2, 3])
} catch {}
})
it('should start a compute job with a published algo', async () => {
const response = await ocean.compute.start(account, agreementId, algorithm.id)
assert.equal(response.status, ComputeJobStatus.Started)
})
it('should start a compute job with a rawcode algo', async () => {
const algoMeta: MetaDataAlgorithm = {
rawcode: `console.log('Hello world!')`,
container: {
entrypoint: 'node $ALGO',
image: 'node',
tag: '10'
}
}
const response = await ocean.compute.start(
account,
agreementId,
undefined,
algoMeta
)
assert.equal(response.status, ComputeJobStatus.Started)
})
})

View File

@ -45,8 +45,12 @@ describe('Consume Asset', () => {
it('should be able to request tokens for consumer', async () => { it('should be able to request tokens for consumer', async () => {
const initialBalance = (await consumer.getBalance()).ocn const initialBalance = (await consumer.getBalance()).ocn
const claimedTokens = const claimedTokens = parseInt(
+metadata.main.price * 10 ** -(await ocean.keeper.token.decimals()) (
+metadata.main.price *
10 ** -(await ocean.keeper.token.decimals())
).toString()
)
try { try {
await consumer.requestTokens(claimedTokens) await consumer.requestTokens(claimedTokens)
@ -156,13 +160,10 @@ describe('Consume Asset', () => {
}) })
it('should consume and store the assets', async () => { it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('access')
const folder = '/tmp/ocean/squid-js-1' const folder = '/tmp/ocean/squid-js-1'
const path = await ocean.assets.consume( const path = await ocean.assets.consume(
serviceAgreementSignatureResult.agreementId, serviceAgreementSignatureResult.agreementId,
ddo.id, ddo.id,
accessService.index,
consumer, consumer,
folder folder
) )
@ -183,13 +184,10 @@ describe('Consume Asset', () => {
}) })
it('should consume and store one asset', async () => { it('should consume and store one asset', async () => {
const accessService = ddo.findServiceByType('access')
const folder = '/tmp/ocean/squid-js-2' const folder = '/tmp/ocean/squid-js-2'
const path = await ocean.assets.consume( const path = await ocean.assets.consume(
serviceAgreementSignatureResult.agreementId, serviceAgreementSignatureResult.agreementId,
ddo.id, ddo.id,
accessService.index,
consumer, consumer,
folder, folder,
1 1

View File

@ -50,34 +50,30 @@ describe('Consume Asset (Brizo)', () => {
}) })
it('should order the asset', async () => { it('should order the asset', async () => {
const accessService = ddo.findServiceByType('access') const steps = []
try { try {
await consumer.requestTokens( await consumer.requestTokens(
+metadata.main.price * 10 ** -(await ocean.keeper.token.decimals()) parseInt(
(
+metadata.main.price *
10 ** -(await ocean.keeper.token.decimals())
).toString()
)
) )
} catch {}
const steps = [] agreementId = await ocean.assets
agreementId = await ocean.assets .order(ddo.id, consumer)
.order(ddo.id, accessService.index, consumer) .next(step => steps.push(step))
.next(step => steps.push(step)) } catch {}
assert.isDefined(agreementId) assert.isDefined(agreementId)
assert.deepEqual(steps, [0, 1, 2, 3]) assert.deepEqual(steps, [0, 1, 2, 3])
}) })
it('should consume and store the assets', async () => { it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('access')
const folder = '/tmp/ocean/squid-js' const folder = '/tmp/ocean/squid-js'
const path = await ocean.assets.consume( const path = await ocean.assets.consume(agreementId, ddo.id, consumer, folder)
agreementId,
ddo.id,
accessService.index,
consumer,
folder
)
assert.include(path, folder, 'The storage path is not correct.') assert.include(path, folder, 'The storage path is not correct.')

View File

@ -50,30 +50,25 @@ xdescribe('Consume Asset (Large size)', () => {
}) })
it('should order the asset', async () => { it('should order the asset', async () => {
const accessService = ddo.findServiceByType('access')
try { try {
await consumer.requestTokens( await consumer.requestTokens(
+metadata.main.price * 10 ** -(await ocean.keeper.token.decimals()) parseInt(
(
+metadata.main.price *
10 ** -(await ocean.keeper.token.decimals())
).toString()
)
) )
} catch {} } catch {}
agreementId = await ocean.assets.order(ddo.id, accessService.index, consumer) agreementId = await ocean.assets.order(ddo.id, consumer)
assert.isDefined(agreementId) assert.isDefined(agreementId)
}) })
it('should consume and store the assets', async () => { it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('access')
const folder = '/tmp/ocean/squid-js' const folder = '/tmp/ocean/squid-js'
const path = await ocean.assets.consume( const path = await ocean.assets.consume(agreementId, ddo.id, consumer, folder)
agreementId,
ddo.id,
accessService.index,
consumer,
folder
)
assert.include(path, folder, 'The storage path is not correct.') assert.include(path, folder, 'The storage path is not correct.')

View File

@ -26,7 +26,7 @@ describe('Register Escrow Compute Execution Template', () => {
before(async () => { before(async () => {
ocean = await Ocean.getInstance(config) ocean = await Ocean.getInstance(config)
keeper = ocean.keeper ;({ keeper } = ocean)
template = keeper.templates.escrowComputeExecutionTemplate template = keeper.templates.escrowComputeExecutionTemplate
@ -36,9 +36,11 @@ describe('Register Escrow Compute Execution Template', () => {
consumer = (await ocean.accounts.list())[2] consumer = (await ocean.accounts.list())[2]
// Conditions // Conditions
computeExecutionCondition = keeper.conditions.computeExecutionCondition ;({
lockRewardCondition = keeper.conditions.lockRewardCondition computeExecutionCondition,
escrowReward = keeper.conditions.escrowReward lockRewardCondition,
escrowReward
} = keeper.conditions)
if (!ocean.keeper.dispenser) { if (!ocean.keeper.dispenser) {
escrowAmount = 0 escrowAmount = 0
@ -274,7 +276,7 @@ describe('Register Escrow Compute Execution Template', () => {
}) })
it('should fulfill the conditions from computing side', async () => { it('should fulfill the conditions from computing side', async () => {
await ocean.agreements.conditions.grantServiceExecution( await ocean.agreements.conditions.grantCompute(
agreementId, agreementId,
did, did,
consumer.getId(), consumer.getId(),

View File

@ -11,18 +11,17 @@ describe('Versions', () => {
ocean = await Ocean.getInstance(config) ocean = await Ocean.getInstance(config)
}) })
// TODO: enable again after new versions of Brizo it('should return the versions', async () => {
xit('should return the versions', async () => {
const versions = await ocean.versions.get() const versions = await ocean.versions.get()
assert.equal(versions.aquarius.status, OceanPlatformTechStatus.Working) assert.equal(versions.aquarius.status, OceanPlatformTechStatus.Working)
assert.equal(versions.brizo.status, OceanPlatformTechStatus.Working) assert.equal(versions.brizo.status, OceanPlatformTechStatus.Working)
assert.equal(versions.squid.status, OceanPlatformTechStatus.Working) assert.equal(versions.squid.status, OceanPlatformTechStatus.Working)
assert.deepEqual(versions.status, { // assert.deepEqual(versions.status, {
ok: true, // ok: true,
contracts: true, // contracts: true,
network: true // network: true
}) // })
}) })
}) })

View File

@ -1,9 +1,10 @@
import { MetaData } from '../../../src' // @oceanprotocol/squid import { MetaData, MetaDataAlgorithm, Ocean, Account } from '../../../src' // @oceanprotocol/squid
import { ServiceCompute } from '../../../src/ddo/Service'
const metadata: Partial<MetaData> = { const metadata: Partial<MetaData> = {
main: { main: {
name: undefined, name: undefined,
type: 'dataset', type: undefined,
dateCreated: '2012-10-10T17:00:00Z', dateCreated: '2012-10-10T17:00:00Z',
datePublished: '2012-10-10T17:00:00Z', datePublished: '2012-10-10T17:00:00Z',
author: 'Met Office', author: 'Met Office',
@ -46,16 +47,33 @@ const metadata: Partial<MetaData> = {
} }
} }
export const generateMetadata = (name: string, price?: number): Partial<MetaData> => ({ const algorithmMeta: MetaDataAlgorithm = {
...metadata, language: 'scala',
format: 'docker-image',
version: '0.1',
container: {
entrypoint: 'ocean-entrypoint.sh',
image: 'node',
tag: '10'
}
}
export const generateMetadata = (
name: string,
type?: 'dataset' | 'algorithm',
price?: number
): Partial<MetaData> => ({
main: { main: {
...metadata.main, ...metadata.main,
name, name,
price: (price || 21) + '0'.repeat(18) type: type || 'dataset',
price: (price || 21) + '0'.repeat(18),
algorithm: type === 'algorithm' ? algorithmMeta : undefined
}, },
additionalInformation: { additionalInformation: {
...metadata.additionalInformation ...metadata.additionalInformation
} }
}) })
export const getMetadata = (price?: number) => generateMetadata('TestAsset', price) export const getMetadata = (price?: number, type?: 'dataset' | 'algorithm') =>
generateMetadata('TestAsset', type, price)

View File

@ -0,0 +1,459 @@
{
"@context": "https://w3id.org/future-method/v1",
"id": "did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d",
"publicKey": [
{
"id": "did:op:123456789abcdefghi#keys-1",
"type": "RsaVerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
},
{
"id": "did:op:123456789abcdefghi#keys-2",
"type": "Ed25519VerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
},
{
"id": "did:op:123456789abcdefghi#keys-3",
"type": "RsaPublicKeyExchangeKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
}
],
"authentication": [
{
"type": "RsaSignatureAuthentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-1"
},
{
"type": "ieee2410Authentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-2"
}
],
"proof": {
"type": "UUIDSignature",
"created": "2016-02-08T16:02:20Z",
"creator": "did:example:8uQhQMGzWxR8vw5P3UWH1ja",
"signatureValue": "QNB13Y7Q9...1tzjn4w=="
},
"service": [
{
"type": "access",
"index": 0,
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000000",
"attributes": {
"main": {
"name": "dataAssetAccessServiceAgreement",
"creator": "0x36A7f3383A63279cDaF4DfC0F3ABc07d90252C6b",
"datePublished": "2019-11-15T14:11:23Z",
"price": "",
"timeout": 36000
},
"serviceAgreementTemplate": {
"contractName": "EscrowAccessSecretStoreTemplate",
"events": [
{
"name": "AgreementCreated",
"actorType": "consumer",
"handler": {
"moduleName": "escrowAccessSecretStoreTemplate",
"functionName": "fulfillLockRewardCondition",
"version": "0.1"
}
}
],
"fulfillmentOrder": [
"lockReward.fulfill",
"accessSecretStore.fulfill",
"escrowReward.fulfill"
],
"conditionDependency": {
"lockReward": [],
"accessSecretStore": [],
"escrowReward": ["lockReward", "accessSecretStore"]
},
"conditions": [
{
"name": "lockReward",
"timelock": 0,
"timeout": 0,
"contractName": "LockRewardCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_rewardAddress",
"type": "address",
"value": "0x36A7f3383A63279cDaF4DfC0F3ABc07d90252C6b"
},
{
"name": "_amount",
"type": "uint256",
"value": "0"
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "lockRewardCondition",
"functionName": "fulfillAccessSecretStoreCondition",
"version": "0.1"
}
}
]
},
{
"name": "accessSecretStore",
"timelock": 0,
"timeout": 0,
"contractName": "AccessSecretStoreCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_documentId",
"type": "bytes32",
"value": "c678e7e5963d4fdc99afea49ac221d4d4177790f30204417823319d4d35f851f"
},
{
"name": "_grantee",
"type": "address",
"value": ""
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "fulfillEscrowRewardCondition",
"version": "0.1"
}
},
{
"name": "TimedOut",
"actorType": "consumer",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "refundReward",
"version": "0.1"
}
}
]
},
{
"name": "escrowReward",
"timelock": 0,
"timeout": 0,
"contractName": "EscrowReward",
"functionName": "fulfill",
"parameters": [
{
"name": "_amount",
"type": "uint256",
"value": "0"
},
{
"name": "_receiver",
"type": "address",
"value": ""
},
{
"name": "_sender",
"type": "address",
"value": ""
},
{
"name": "_lockCondition",
"type": "bytes32",
"value": ""
},
{
"name": "_releaseCondition",
"type": "bytes32",
"value": ""
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "escrowRewardCondition",
"functionName": "verifyRewardTokens",
"version": "0.1"
}
}
]
}
]
}
}
},
{
"type": "compute",
"index": 1,
"serviceEndpoint": "http://localhost:8030/api/v1/brizo/services/compute",
"templateId": "",
"attributes": {
"main": {
"name": "dataAssetComputingServiceAgreement",
"creator": "0x36A7f3383A63279cDaF4DfC0F3ABc07d90252C6b",
"datePublished": "2019-04-09T19:02:11Z",
"price": "10",
"timeout": 86400,
"provider": {
"type": "Azure",
"description": "",
"environment": {
"cluster": {
"type": "Kubernetes",
"url": "http://10.0.0.17/xxx"
},
"supportedContainers": [
{
"image": "tensorflow/tensorflow",
"tag": "latest",
"checksum": "sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc"
},
{
"image": "tensorflow/tensorflow",
"tag": "latest",
"checksum": "sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc"
}
],
"supportedServers": [
{
"serverId": "1",
"serverType": "xlsize",
"price": "50",
"cpu": "16",
"gpu": "0",
"memory": "128gb",
"disk": "160gb",
"maxExecutionTime": 86400
},
{
"serverId": "2",
"serverType": "medium",
"price": "10",
"cpu": "2",
"gpu": "0",
"memory": "8gb",
"disk": "80gb",
"maxExecutionTime": 86400
}
]
}
}
},
"additionalInformation": {},
"serviceAgreementTemplate": {
"contractName": "EscrowComputeExecutionTemplate",
"events": [
{
"name": "AgreementActorAdded",
"actorType": "provider",
"handler": {
"moduleName": "",
"functionName": "fulfillLockRewardCondition",
"version": "0.1"
}
}
],
"fulfillmentOrder": [
"lockReward.fulfill",
"computeExecution.fulfill",
"escrowReward.fulfill"
],
"conditionDependency": {
"lockReward": [],
"computeExecution": [],
"releaseReward": ["lockReward", "computeExecution"]
},
"conditions": [
{
"name": "lockReward",
"timelock": 0,
"timeout": 0,
"contractName": "LockRewardCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_rewardAddress",
"type": "address",
"value": ""
},
{
"name": "_amount",
"type": "uint256",
"value": ""
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "provider",
"handler": {
"moduleName": "lockRewardExecutionCondition",
"functionName": "fulfillComputeExecutionCondition",
"version": "0.1"
}
}
]
},
{
"name": "computeExecution",
"timelock": 0,
"timeout": 0,
"contractName": "ComputeExecutionCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_documentId",
"type": "bytes32",
"value": ""
},
{
"name": "_grantee",
"type": "address",
"value": ""
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "provider",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "fulfillEscrowRewardCondition",
"version": "0.1"
}
},
{
"name": "TimedOut",
"actorType": "consumer",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "refundReward",
"version": "0.1"
}
}
]
},
{
"name": "escrowReward",
"timelock": 0,
"timeout": 0,
"contractName": "EscrowReward",
"functionName": "fulfill",
"parameters": [
{
"name": "_amount",
"type": "uint256",
"value": ""
},
{
"name": "_receiver",
"type": "address",
"value": ""
},
{
"name": "_sender",
"type": "address",
"value": ""
},
{
"name": "_lockCondition",
"type": "bytes32",
"value": ""
},
{
"name": "_releaseCondition",
"type": "bytes32",
"value": ""
}
],
"events": [
{
"name": "Fulfilled",
"actorType": "provider",
"handler": {
"moduleName": "escrowRewardCondition",
"functionName": "verifyRewardTokens",
"version": "0.1"
}
}
]
}
]
}
}
},
{
"type": "metadata",
"index": 2,
"serviceEndpoint": "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
"attributes": {
"main": {
"name": "UK Weather information 2011",
"type": "dataset",
"dateCreated": "2012-10-10T17:00:000Z",
"author": "Met Office",
"license": "CC-BY",
"price": "1000000000000000000",
"files": [
{
"index": 0,
"url": "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"checksum": "085340abffh21495345af97c6b0e761",
"contentLength": "12324"
},
{
"url": "https://testocnfiles.blob.core.windows.net/testfiles/testzkp2.zip"
}
]
},
"curation": {
"rating": 0.93,
"numVotes": 123,
"schema": "Binary Voting"
},
"additionalInformation": {
"description": "Weather information of UK including temperature and humidity",
"copyrightHolder": "Met Office",
"workExample": "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
"links": [
{
"name": "Sample of Asset Data",
"type": "sample",
"url": "https://foo.com/sample.csv"
},
{
"name": "Data Format Definition",
"type": "format",
"AssetID": "4d517500da0acb0d65a716f61330969334630363ce4a6a9d39691026ac7908ea"
}
],
"inLanguage": "en",
"categories": ["Economy", "Data Science"],
"tags": ["weather", "uk", "2011", "temperature", "humidity"],
"updateFrequency": "yearly",
"structuredMarkup": [
{
"uri": "http://skos.um.es/unescothes/C01194/jsonld",
"mediaType": "application/ld+json"
},
{
"uri": "http://skos.um.es/unescothes/C01194/turtle",
"mediaType": "text/turtle"
}
]
}
}
}
]
}

View File

@ -1,4 +1,4 @@
import WebServiceConnector from '../../src/utils/WebServiceConnector' import { WebServiceConnector } from '../../src/ocean/utils/WebServiceConnector'
// @ts-ignore // @ts-ignore
export default class WebServiceConnectorMock extends WebServiceConnector { export default class WebServiceConnectorMock extends WebServiceConnector {

View File

@ -7,7 +7,7 @@ import { Ocean } from '../../../src/ocean/Ocean'
import config from '../config' import config from '../config'
import TestContractHandler from '../keeper/TestContractHandler' import TestContractHandler from '../keeper/TestContractHandler'
import * as jsonDDO from '../testdata/ddo.json' import * as jsonDDO from '../__fixtures__/ddo.json'
use(spies) use(spies)

View File

@ -2,7 +2,7 @@ import { assert } from 'chai'
import Account from '../../../src/ocean/Account' import Account from '../../../src/ocean/Account'
import { Ocean } from '../../../src/ocean/Ocean' import { Ocean } from '../../../src/ocean/Ocean'
import config from '../config' import config from '../config'
import ContractBaseMock from '../mocks/ContractBase.Mock' import ContractBaseMock from '../__mocks__/ContractBase.Mock'
import TestContractHandler from './TestContractHandler' import TestContractHandler from './TestContractHandler'
const wrappedContract = new ContractBaseMock('OceanToken') const wrappedContract = new ContractBaseMock('OceanToken')

View File

@ -7,6 +7,13 @@ import config from '../config'
interface ContractTest extends Contract { interface ContractTest extends Contract {
testContract?: boolean testContract?: boolean
$initialized?: boolean $initialized?: boolean
options?: {
address: string
}
methods?: {
addMinter(address: string): any
initialize(...args: any[]): any
}
} }
export default class TestContractHandler extends ContractHandler { export default class TestContractHandler extends ContractHandler {

View File

@ -1,13 +0,0 @@
import { Brizo } from '../../../src/brizo/Brizo'
export default class BrizoMock extends Brizo {
public async initializeServiceAgreement(
did: string,
serviceAgreementId: string,
index: number,
signature: string,
consumerPublicKey: string
): Promise<any> {
return true
}
}

View File

@ -0,0 +1,131 @@
import { assert } from 'chai'
import sinon from 'sinon'
import { Ocean } from '../../../src/ocean/Ocean'
import config from '../config'
import { Account } from '../../../src/squid'
import { OceanCompute, ComputeJobStatus } from '../../../src/ocean/OceanCompute'
import TestIdGenerator from '../TestIdGenerator'
describe('OceanCompute', () => {
let ocean: Ocean
let account: Account
let compute: OceanCompute
let agreementId: string
before(async () => {
ocean = await Ocean.getInstance(config)
;[account] = await ocean.accounts.list()
compute = ocean.compute // eslint-disable-line prefer-destructuring
agreementId = TestIdGenerator.generatePrefixedId()
})
afterEach(() => {
sinon.reset()
sinon.restore()
})
describe('#start()', () => {
it('should start a new job', async () => {
sinon.stub(ocean.brizo, 'compute').returns([{ jobId: 'my-job-id' }] as any)
const response = await compute.start(account, agreementId, 'did:op:0xxx')
assert(response.jobId === 'my-job-id')
})
})
describe('#stop()', () => {
it('should stop a job', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([{ status: ComputeJobStatus.Completed }] as any)
const response = await compute.stop(account, agreementId, 'xxx')
assert(response.status === ComputeJobStatus.Completed)
})
})
describe('#restart()', () => {
it('should restart a job', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([
{ status: ComputeJobStatus.Started, jobId: 'my-job-id' }
] as any)
const response = await compute.restart(account, agreementId, 'xxx')
assert(response.jobId === 'my-job-id')
})
})
describe('#delete()', () => {
it('should delete a job', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([{ status: ComputeJobStatus.Deleted }] as any)
const response = await compute.delete(account, agreementId, 'xxx')
assert(response.status === ComputeJobStatus.Deleted)
})
})
describe('#status()', () => {
it('should get the status of one job', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([{ status: ComputeJobStatus.Started }] as any)
const response = await compute.status(account, agreementId, 'xxx')
assert(response.length === 1)
assert(response[0].status === ComputeJobStatus.Started)
})
it('should get the status of multiple jobs', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([
{ status: ComputeJobStatus.Started },
{ status: ComputeJobStatus.Started }
] as any)
const response = await compute.status(account, agreementId)
assert(response.length === 2)
assert(response[0].status === ComputeJobStatus.Started)
})
it('should get all jobs for one owner', async () => {
sinon
.stub(ocean.brizo, 'compute')
.returns([
{ status: ComputeJobStatus.Started },
{ status: ComputeJobStatus.Started }
] as any)
const response = await compute.status(account)
assert(response.length === 2)
assert(response[0].status === ComputeJobStatus.Started)
})
})
describe('#checkOutput()', () => {
it('should return default values', async () => {
const defaultOutput = { publishAlgorithmLog: false, publishOutput: false }
const output = compute.checkOutput(account, undefined)
assert.deepEqual(output, defaultOutput)
})
it('should return output values', async () => {
const newOutput = {
publishAlgorithmLog: true,
publishOutput: true,
brizoAddress: 'hello',
brizoUri: 'hello',
metadataUri: 'hello',
nodeUri: 'hello',
owner: '0xhello',
secretStoreUri: 'hello'
}
const output = compute.checkOutput(account, newOutput)
assert.deepEqual(output, newOutput)
})
})
})

View File

@ -1,215 +0,0 @@
{
"@context": "https://w3id.org/future-method/v1",
"id": "did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d",
"publicKey": [
{
"id": "did:op:123456789abcdefghi#keys-1",
"type": "RsaVerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
},
{
"id": "did:op:123456789abcdefghi#keys-2",
"type": "Ed25519VerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
},
{
"id": "did:op:123456789abcdefghi#keys-3",
"type": "RsaPublicKeyExchangeKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
}
],
"authentication": [
{
"type": "RsaSignatureAuthentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-1"
},
{
"type": "ieee2410Authentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-2"
}
],
"proof": {
"type": "UUIDSignature",
"created": "2016-02-08T16:02:20Z",
"creator": "did:example:8uQhQMGzWxR8vw5P3UWH1ja",
"signatureValue": "QNB13Y7Q9...1tzjn4w=="
},
"service": [
{
"type": "access",
"index": 0,
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"purchaseEndpoint": "http://mybrizo.org/api/v1/brizo/services/access/purchase?",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000000",
"conditions": [
{
"name": "lockPayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0x..."
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentLocked": {
"actorType": ["publisher"],
"handlers": [
{
"moduleName": "accessControl",
"functionName": "grantAccess",
"version": "0.1"
}
]
}
}
},
{
"name": "releasePayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentReleased": {
"actorType": ["publisher"],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
},
{
"name": "grantAccess",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"documentKeyId": "bytes32"
},
"events": {
"AccessGranted": {
"actorType": ["consumer"],
"handlers": [
{
"moduleName": "asset",
"functionName": "consumeService",
"version": "0.1"
}
]
}
}
},
{
"name": "refundPayment",
"timeout": 1,
"condition_key": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "int"
},
"events": {
"PaymentRefund": {
"actorType": ["consumer"],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
}
]
},
{
"type": "compute",
"index": 1,
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000002"
},
{
"type": "metadata",
"index": 2,
"serviceEndpoint": "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
"attributes": {
"main": {
"name": "UK Weather information 2011",
"type": "dataset",
"dateCreated": "2012-10-10T17:00:000Z",
"author": "Met Office",
"license": "CC-BY",
"price": 10,
"files": [
{
"index": 0,
"url": "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"checksum": "085340abffh21495345af97c6b0e761",
"contentLength": "12324"
},
{
"url": "https://testocnfiles.blob.core.windows.net/testfiles/testzkp2.zip"
}
]
},
"curation": {
"rating": 0.93,
"numVotes": 123,
"schema": "Binary Voting"
},
"additionalInformation": {
"description": "Weather information of UK including temperature and humidity",
"copyrightHolder": "Met Office",
"workExample": "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
"links": [
{
"name": "Sample of Asset Data",
"type": "sample",
"url": "https://foo.com/sample.csv"
},
{
"name": "Data Format Definition",
"type": "format",
"AssetID": "4d517500da0acb0d65a716f61330969334630363ce4a6a9d39691026ac7908ea"
}
],
"inLanguage": "en",
"categories": ["Economy", "Data Science"],
"tags": ["weather", "uk", "2011", "temperature", "humidity"],
"updateFrequency": "yearly",
"structuredMarkup": [
{
"uri": "http://skos.um.es/unescothes/C01194/jsonld",
"mediaType": "application/ld+json"
},
{
"uri": "http://skos.um.es/unescothes/C01194/turtle",
"mediaType": "text/turtle"
}
]
}
}
}
]
}