Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 4.0 - Includes breaking changes for C2D V2 (also free compute) #1891

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions ComputeExamples.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ Let's have 5 minute of compute access
computeEnv.id,
computeValidUntil,
providerUrl,
await consumerAccount.getAddress()
consumerAccount
)
```
<!--
Expand Down Expand Up @@ -655,7 +655,7 @@ Let's have 5 minute of compute access
providerUrl,
consumerAccount,
computeEnv.id,
assets[0],
assets,
algo
)

Expand Down
2 changes: 1 addition & 1 deletion docs/classes/Provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ Initializes the provider for a compute request.
| `computeEnv` | `string` | The compute environment. |
| `validUntil` | `number` | The job expiration date. |
| `providerUri` | `string` | The provider URI. |
| `accountId` | `string` | caller address |
| `signer` | `Signer` | caller account |
| `signal?` | `AbortSignal` | abort signal |

#### Returns
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@oceanprotocol/lib",
"source": "./src/index.ts",
"version": "3.4.4",
"version": "4.0.0-next.1",
"description": "JavaScript client library for Ocean Protocol",
"main": "./dist/lib.js",
"umd:main": "dist/lib.umd.js",
Expand Down
37 changes: 37 additions & 0 deletions src/@types/Compute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
storageExpiry: number
maxJobDuration: number
lastSeen: number
free: boolean
}

export interface ComputeResult {
Expand Down Expand Up @@ -59,14 +60,50 @@
whitelist?: string[]
}

export enum FileObjectType {
URL = 'url',

Check warning on line 64 in src/@types/Compute.ts

View workflow job for this annotation

GitHub Actions / lint

'URL' is defined but never used
IPFS = 'ipfs',

Check warning on line 65 in src/@types/Compute.ts

View workflow job for this annotation

GitHub Actions / lint

'IPFS' is defined but never used
ARWEAVE = 'arweave'

Check warning on line 66 in src/@types/Compute.ts

View workflow job for this annotation

GitHub Actions / lint

'ARWEAVE' is defined but never used
}

export enum EncryptMethod {
AES = 'AES',

Check warning on line 70 in src/@types/Compute.ts

View workflow job for this annotation

GitHub Actions / lint

'AES' is defined but never used
ECIES = 'ECIES'

Check warning on line 71 in src/@types/Compute.ts

View workflow job for this annotation

GitHub Actions / lint

'ECIES' is defined but never used
}

export interface HeadersObject {
[key: string]: string
}

export interface BaseFileObject {
type: string
encryptedBy?: string
encryptMethod?: EncryptMethod
}

export interface UrlFileObject extends BaseFileObject {
url: string
method: string
headers?: [HeadersObject]
}

export interface IpfsFileObject extends BaseFileObject {
hash: string
}

export interface ArweaveFileObject extends BaseFileObject {
transactionId: string
}
export interface ComputeAsset {
fileObject?: BaseFileObject // C2D v2
documentId: string
serviceId: string
transferTxId?: string
userdata?: { [key: string]: any }
}

export interface ComputeAlgorithm {
fileObject?: BaseFileObject // C2D v2
documentId?: string
serviceId?: string
meta?: MetadataAlgorithm
Expand Down
187 changes: 184 additions & 3 deletions src/services/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ export class Provider {
* @param {AbortSignal} signal abort signal
* @return {Promise<ProviderComputeInitialize>} ProviderComputeInitialize data
*/
public async initializeCompute(
public async initializeComputeV1(
assets: ComputeAsset[],
algorithm: ComputeAlgorithm,
computeEnv: string,
Expand Down Expand Up @@ -470,6 +470,90 @@ export class Provider {
throw new Error(JSON.stringify(resolvedResponse))
}

/** Initializes the provider for a compute request.
* @param {ComputeAsset[]} assets The datasets array to initialize compute request.
* @param {ComputeAlgorithmber} algorithm The algorithm to use.
* @param {string} computeEnv The compute environment.
* @param {number} validUntil The job expiration date.
* @param {string} providerUri The provider URI.
* @param {Signer} signer caller address
* @param {AbortSignal} signal abort signal
* @return {Promise<ProviderComputeInitialize>} ProviderComputeInitialize data
*/
public async initializeCompute(
assets: ComputeAsset[],
algorithm: ComputeAlgorithm,
computeEnv: string,
validUntil: number,
providerUri: string,
signer: Signer,
signal?: AbortSignal
): Promise<ProviderComputeInitializeResults> {
const providerEndpoints = await this.getEndpoints(providerUri)
const serviceEndpoints = await this.getServiceEndpoints(
providerUri,
providerEndpoints
)

// Diff from V1. We might need a signature to get the files object, specially if dealing with confidential evm and template 4
// otherwise it can be ignored
const consumerAddress = await signer.getAddress()
const nonce = (
(await this.getNonce(
providerUri,
consumerAddress,
signal,
providerEndpoints,
serviceEndpoints
)) + 1
).toString()

// same signed message as for start compute (consumer address + did[0] + nonce)
let signatureMessage = consumerAddress
signatureMessage += assets[0].documentId
signatureMessage += nonce
const signature = await this.signProviderRequest(signer, signatureMessage)

const providerData = {
datasets: assets,
algorithm,
compute: { env: computeEnv, validUntil },
consumerAddress,
signature
}
const initializeUrl = this.getEndpointURL(serviceEndpoints, 'initializeCompute')
? this.getEndpointURL(serviceEndpoints, 'initializeCompute').urlPath
: null
if (!initializeUrl) return null

let response
try {
response = await fetch(initializeUrl, {
method: 'POST',
body: JSON.stringify(providerData),
headers: { 'Content-Type': 'application/json' },
signal
})
} catch (e) {
LoggerInstance.error('Initialize compute failed: ')
LoggerInstance.error(e)
throw new Error('ComputeJob cannot be initialized')
}
if (response?.ok) {
const params = await response.json()
return params
}
const resolvedResponse = await response.json()
LoggerInstance.error(
'Initialize compute failed: ',
response.status,
response.statusText,
resolvedResponse
)
LoggerInstance.error('Payload was:', providerData)
throw new Error(JSON.stringify(resolvedResponse))
}

/**
* Gets the download URL.
* @param {string} did - The DID.
Expand Down Expand Up @@ -524,7 +608,7 @@ export class Provider {
return consumeUrl
}

/** Instruct the provider to start a compute job
/** Instruct the provider to start a compute job (Old C2D V1) Kept for now, for backwards compatibility
* @param {string} providerUri The provider URI.
* @param {Signer} signer The consumer signer object.
* @param {string} computeEnv The compute environment.
Expand All @@ -535,7 +619,7 @@ export class Provider {
* @param {ComputeOutput} output The compute job output settings.
* @return {Promise<ComputeJob | ComputeJob[]>} The compute job or jobs.
*/
public async computeStart(
public async computeStartV1(
providerUri: string,
consumer: Signer,
computeEnv: string,
Expand Down Expand Up @@ -607,6 +691,103 @@ export class Provider {
return null
}

/** Instruct the provider to start a compute job (new C2D V2)
* @param {string} providerUri The provider URI.
* @param {Signer} signer The consumer signer object.
* @param {string} computeEnv The compute environment.
* @param {ComputeAsset} datasets The dataset to start compute on + additionalDatasets (the additional datasets if that is the case)
* @param {ComputeAlgorithm} algorithm The algorithm to start compute with.
* @param {AbortSignal} signal abort signal
* @param {ComputeOutput} output The compute job output settings.
* @param {boolean} freeEnvironment is it a free environment? uses different route
* @return {Promise<ComputeJob | ComputeJob[]>} The compute job or jobs.
*/
public async computeStart(
providerUri: string,
consumer: Signer,
computeEnv: string,
datasets: ComputeAsset[],
algorithm: ComputeAlgorithm,
signal?: AbortSignal,
output?: ComputeOutput,
freeEnvironment?: boolean
): Promise<ComputeJob | ComputeJob[]> {
console.log('called new compute start method...')
console.log('datasets: ', datasets)
console.log('algorithm: ', algorithm)
const providerEndpoints = await this.getEndpoints(providerUri)
const serviceEndpoints = await this.getServiceEndpoints(
providerUri,
providerEndpoints
)
let computeStartUrl = null

if (freeEnvironment) {
computeStartUrl = this.getEndpointURL(serviceEndpoints, 'freeCompute')
? this.getEndpointURL(serviceEndpoints, 'freeCompute').urlPath
: null
} else {
computeStartUrl = this.getEndpointURL(serviceEndpoints, 'computeStart')
? this.getEndpointURL(serviceEndpoints, 'computeStart').urlPath
: null
}

const consumerAddress = await consumer.getAddress()
const nonce = (
(await this.getNonce(
providerUri,
consumerAddress,
signal,
providerEndpoints,
serviceEndpoints
)) + 1
).toString()

let signatureMessage = consumerAddress
signatureMessage += datasets[0].documentId
signatureMessage += nonce
const signature = await this.signProviderRequest(consumer, signatureMessage)
const payload = Object()
payload.consumerAddress = consumerAddress
payload.signature = signature
payload.nonce = nonce
payload.environment = computeEnv
// kept for backwards compatibility (tests running against existing provider)
payload.dataset = datasets[0]
// new field for C2D v2
payload.datasets = datasets
payload.algorithm = algorithm
// if (additionalDatasets) payload.additionalDatasets = additionalDatasets
if (output) payload.output = output
if (!computeStartUrl) return null
let response
try {
response = await fetch(computeStartUrl, {
method: 'POST',
body: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' },
signal
})
} catch (e) {
LoggerInstance.error('Compute start failed:')
LoggerInstance.error(e)
LoggerInstance.error('Payload was:', payload)
throw new Error('HTTP request failed calling Provider')
}
if (response?.ok) {
const params = await response.json()
return params
}
LoggerInstance.error(
'Compute start failed: ',
response.status,
response.statusText,
await response.json()
)
LoggerInstance.error('Payload was:', payload)
return null
}

/** Instruct the provider to Stop the execution of a to stop a compute job.
* @param {string} did the asset did
* @param {string} consumerAddress The consumer address.
Expand Down
10 changes: 10 additions & 0 deletions src/utils/Assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ProviderInstance } from '../services/Provider'
import AccessListFactory from '@oceanprotocol/contracts/artifacts/contracts/accesslists/AccessListFactory.sol/AccessListFactory.json'
import ERC20Template4 from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template4.sol/ERC20Template4.json'
import { calculateActiveTemplateIndex } from './Adresses'
import { FileObjectType } from '../@types'

// import * as hre from 'hardhat'

Expand Down Expand Up @@ -113,6 +114,15 @@ export async function createAsset(
mpFeeAddress: ZERO_ADDRESS
}

if (
!assetUrl.type ||
![FileObjectType.ARWEAVE, FileObjectType.IPFS, FileObjectType.URL].includes(
assetUrl.type.toLowerCase()
)
) {
console.log('Missing or invalid files object type, defaulting to "url"')
assetUrl.type = FileObjectType.URL
}
// include fileObject in the DT constructor
if (config.sdk === 'oasis') {
datatokenParams.filesObject = assetUrl
Expand Down
4 changes: 2 additions & 2 deletions test/integration/ComputeExamples.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ describe('Compute-to-data example tests', async () => {
computeEnv.id,
computeValidUntil,
providerUrl,
await consumerAccount.getAddress()
consumerAccount
)
/// ```
/// <!--
Expand Down Expand Up @@ -655,7 +655,7 @@ describe('Compute-to-data example tests', async () => {
providerUrl,
consumerAccount,
computeEnv.id,
assets[0],
assets,
algo
)

Expand Down
Loading
Loading