diff --git a/src/@utils/compute.ts b/src/@utils/compute.ts index 4c7c2b6c4..965186644 100644 --- a/src/@utils/compute.ts +++ b/src/@utils/compute.ts @@ -9,11 +9,20 @@ // Account // } from '@oceanprotocol/lib' // import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute' -import { Asset } from '@oceanprotocol/lib' +import { + Asset, + DDO, + ComputeAlgorithm, + Service, + LoggerInstance, + ProviderInstance +} from '@oceanprotocol/lib' import { CancelToken } from 'axios' import { gql } from 'urql' import { queryMetadata, getFilterTerm, generateBaseQuery } from './aquarius' import { fetchDataForMultipleChains } from './subgraph' +import { getServiceById } from './ddo' +import { getOceanConfig } from './ocean' const getComputeOrders = gql` query ComputeOrders($user: String!) { @@ -76,6 +85,38 @@ async function getAssetMetadata( return result.results } +export async function isOrderable( + asset: Asset | DDO, + serviceId: string, + algorithm: ComputeAlgorithm, + algorithmDDO: Asset | DDO +): Promise { + const datasetService: Service = getServiceById(asset, serviceId) + if (!datasetService) return false + if (datasetService.type === 'compute') { + if (algorithm.meta) { + // check if raw algo is allowed + if (datasetService.compute.allowRawAlgorithm) return true + LoggerInstance.error('ERROR: This service does not allow raw algorithm') + return false + } + if (algorithm.documentId) { + const algoService: Service = getServiceById( + algorithmDDO, + algorithm.serviceId + ) + if (algoService && algoService.type === 'compute') { + if (algoService.serviceEndpoint !== datasetService.serviceEndpoint) { + this.logger.error( + 'ERROR: Both assets with compute service are not served by the same provider' + ) + return false + } + } + } + } +} + function getServiceEndpoints(data: TokenOrder[], assets: Asset[]): string[] { // const serviceEndpoints: string[] = [] diff --git a/src/@utils/ddo.ts b/src/@utils/ddo.ts index c77df1097..2b6319573 100644 --- a/src/@utils/ddo.ts +++ b/src/@utils/ddo.ts @@ -15,6 +15,13 @@ export function getServiceByName( return service } +export function getServiceById(ddo: Asset | DDO, serviceId: string): Service { + if (!ddo) return + + const service = ddo.services.find((s) => s.id === serviceId) + return service +} + export function mapTimeoutStringToSeconds(timeout: string): number { switch (timeout) { case 'Forever': diff --git a/src/components/Asset/AssetActions/Compute/index.tsx b/src/components/Asset/AssetActions/Compute/index.tsx index 47d31f199..93cfdf613 100644 --- a/src/components/Asset/AssetActions/Compute/index.tsx +++ b/src/components/Asset/AssetActions/Compute/index.tsx @@ -29,6 +29,7 @@ import FormStartComputeDataset from './FormComputeDataset' import styles from './index.module.css' import SuccessConfetti from '@shared/SuccessConfetti' import { getServiceByName, secondsToString } from '@utils/ddo' +import { isOrderable } from '@utils/compute' import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection' import AlgorithmDatasetsListForCompute from './AlgorithmDatasetsListForCompute' import { getPreviousOrders, getPrice } from '@utils/subgraph' @@ -243,153 +244,156 @@ export default function Compute({ toast.error(newError) }, [error, pricingError]) - // async function startJob(algorithmId: string) { - // try { - // if (!ocean) return + async function startJob(algorithmId: string) { + try { + setIsJobStarting(true) + setIsPublished(false) // would be nice to rename this + setError(undefined) - // setIsJobStarting(true) - // setIsPublished(false) - // setError(undefined) + const computeService = getServiceByName(ddo, 'compute') + const serviceAlgo = getServiceByName(selectedAlgorithmAsset, 'access') + ? getServiceByName(selectedAlgorithmAsset, 'access') + : getServiceByName(selectedAlgorithmAsset, 'compute') - // const computeService = getServiceByName(ddo, 'compute') - // const serviceAlgo = getServiceByName(selectedAlgorithmAsset, 'access') - // ? getServiceByName(selectedAlgorithmAsset, 'access') - // : getServiceByName(selectedAlgorithmAsset, 'compute') + const computeAlgorithm: ComputeAlgorithm = { + documentId: selectedAlgorithmAsset.id, + serviceId: serviceAlgo.id + // dataToken: selectedAlgorithmAsset.services[0].datatokenAddress + } - // const computeAlgorithm: ComputeAlgorithm = { - // did: selectedAlgorithmAsset.id, - // serviceIndex: serviceAlgo.index, - // dataToken: selectedAlgorithmAsset.services[0].datatokenAddress - // } - // const allowed = await ocean.compute.isOrderable( - // ddo.id, - // computeService.index, - // computeAlgorithm - // ) - // LoggerInstance.log('[compute] Is data set orderable?', allowed) + const allowed = await isOrderable( + ddo, + computeService.id, + computeAlgorithm, + selectedAlgorithmAsset + ) + LoggerInstance.log('[compute] Is data set orderable?', allowed) - // if (!allowed) { - // setError( - // 'Data set is not orderable in combination with selected algorithm.' - // ) - // LoggerInstance.error( - // '[compute] Error starting compute job. Dataset is not orderable in combination with selected algorithm.' - // ) - // return - // } + if (!allowed) { + setError( + 'Data set is not orderable in combination with selected algorithm.' + ) + LoggerInstance.error( + '[compute] Error starting compute job. Dataset is not orderable in combination with selected algorithm.' + ) + return + } - // if (!hasPreviousDatasetOrder && !hasDatatoken) { - // const tx = await buyDT('1', price, ddo) - // if (!tx) { - // setError('Error buying datatoken.') - // LoggerInstance.error('[compute] Error buying datatoken for data set ', ddo.id) - // return - // } - // } + if (!hasPreviousDatasetOrder && !hasDatatoken) { + const tx = await buyDT('1', price, ddo) + if (!tx) { + setError('Error buying datatoken.') + LoggerInstance.error( + '[compute] Error buying datatoken for data set ', + ddo.id + ) + return + } + } - // if (!hasPreviousAlgorithmOrder && !hasAlgoAssetDatatoken) { - // const tx = await buyDT('1', algorithmPrice, selectedAlgorithmAsset) - // if (!tx) { - // setError('Error buying datatoken.') - // LoggerInstance.error( - // '[compute] Error buying datatoken for algorithm ', - // selectedAlgorithmAsset.id - // ) - // return - // } - // } + if (!hasPreviousAlgorithmOrder && !hasAlgoAssetDatatoken) { + const tx = await buyDT('1', algorithmPrice, selectedAlgorithmAsset) + if (!tx) { + setError('Error buying datatoken.') + LoggerInstance.error( + '[compute] Error buying datatoken for algorithm ', + selectedAlgorithmAsset.id + ) + return + } + } - // // TODO: pricingError is always undefined even upon errors during buyDT for whatever reason. - // // So manually drop out above, but ideally could be replaced with this alone. - // if (pricingError) { - // setError(pricingError) - // return - // } + // // TODO: pricingError is always undefined even upon errors during buyDT for whatever reason. + // // So manually drop out above, but ideally could be replaced with this alone. + // if (pricingError) { + // setError(pricingError) + // return + // } - // const assetOrderId = hasPreviousDatasetOrder - // ? previousDatasetOrderId - // : await ocean.compute.orderAsset( - // accountId, - // ddo.id, - // computeService.index, - // computeAlgorithm, - // appConfig.marketFeeAddress, - // undefined, - // null, - // false - // ) + // const assetOrderId = hasPreviousDatasetOrder + // ? previousDatasetOrderId + // : await ocean.compute.orderAsset( + // accountId, + // ddo.id, + // computeService.index, + // computeAlgorithm, + // appConfig.marketFeeAddress, + // undefined, + // null, + // false + // ) - // assetOrderId && - // LoggerInstance.log( - // `[compute] Got ${ - // hasPreviousDatasetOrder ? 'existing' : 'new' - // } order ID for dataset: `, - // assetOrderId - // ) + // assetOrderId && + // LoggerInstance.log( + // `[compute] Got ${ + // hasPreviousDatasetOrder ? 'existing' : 'new' + // } order ID for dataset: `, + // assetOrderId + // ) - // const algorithmAssetOrderId = hasPreviousAlgorithmOrder - // ? previousAlgorithmOrderId - // : await ocean.compute.orderAlgorithm( - // algorithmId, - // serviceAlgo.type, - // accountId, - // serviceAlgo.index, - // appConfig.marketFeeAddress, - // undefined, - // null, - // false - // ) + // const algorithmAssetOrderId = hasPreviousAlgorithmOrder + // ? previousAlgorithmOrderId + // : await ocean.compute.orderAlgorithm( + // algorithmId, + // serviceAlgo.type, + // accountId, + // serviceAlgo.index, + // appConfig.marketFeeAddress, + // undefined, + // null, + // false + // ) - // algorithmAssetOrderId && - // LoggerInstance.log( - // `[compute] Got ${ - // hasPreviousAlgorithmOrder ? 'existing' : 'new' - // } order ID for algorithm: `, - // algorithmAssetOrderId - // ) + // algorithmAssetOrderId && + // LoggerInstance.log( + // `[compute] Got ${ + // hasPreviousAlgorithmOrder ? 'existing' : 'new' + // } order ID for algorithm: `, + // algorithmAssetOrderId + // ) - // if (!assetOrderId || !algorithmAssetOrderId) { - // setError('Error ordering assets.') - // return - // } + // if (!assetOrderId || !algorithmAssetOrderId) { + // setError('Error ordering assets.') + // return + // } - // computeAlgorithm.transferTxId = algorithmAssetOrderId - // LoggerInstance.log('[compute] Starting compute job.') + // computeAlgorithm.transferTxId = algorithmAssetOrderId + // LoggerInstance.log('[compute] Starting compute job.') - // const output: ComputeOutput = { - // publishAlgorithmLog: true, - // publishOutput: true - // } - // const response = await ocean.compute.start( - // ddo.id, - // assetOrderId, - // ddo.services[0].datatokenAddress, - // account, - // computeAlgorithm, - // output, - // `${computeService.index}`, - // computeService.type - // ) + // const output: ComputeOutput = { + // publishAlgorithmLog: true, + // publishOutput: true + // } + // const response = await ocean.compute.start( + // ddo.id, + // assetOrderId, + // ddo.services[0].datatokenAddress, + // account, + // computeAlgorithm, + // output, + // `${computeService.index}`, + // computeService.type + // ) - // if (!response) { - // setError('Error starting compute job.') - // return - // } + // if (!response) { + // setError('Error starting compute job.') + // return + // } - // LoggerInstance.log('[compute] Starting compute job response: ', response) + // LoggerInstance.log('[compute] Starting compute job response: ', response) - // await checkPreviousOrders(selectedAlgorithmAsset) - // await checkPreviousOrders(ddo) - // setIsPublished(true) - // } catch (error) { - // await checkPreviousOrders(selectedAlgorithmAsset) - // await checkPreviousOrders(ddo) - // setError('Failed to start job!') - // LoggerInstance.error('[compute] Failed to start job: ', error.message) - // } finally { - // setIsJobStarting(false) - // } - // } + // await checkPreviousOrders(selectedAlgorithmAsset) + // await checkPreviousOrders(ddo) + // setIsPublished(true) + } catch (error) { + await checkPreviousOrders(selectedAlgorithmAsset) + await checkPreviousOrders(ddo) + setError('Failed to start job!') + LoggerInstance.error('[compute] Failed to start job: ', error.message) + } finally { + setIsJobStarting(false) + } + } return ( <>