From 813050e40dec5c7ae8fc05120b0629a978e8e031 Mon Sep 17 00:00:00 2001 From: Pierre Jeanjacquot <26487010+PierreJeanjacquot@users.noreply.github.com> Date: Wed, 13 May 2026 16:08:27 +0200 Subject: [PATCH 1/3] feat!: set TDX as default tag for all order creation Co-authored-by: paypes <43441600+abbesBenayache@users.noreply.github.com> --- src/cli/utils/templates.js | 15 +- src/common/market/order.js | 103 ++++++++++---- src/common/utils/constant.js | 4 + test/cli/cli-iexec-app.test.js | 9 +- test/cli/cli-iexec-dataset.test.js | 31 +++- test/cli/cli-iexec-deal.test.js | 3 + test/cli/cli-iexec-order.test.js | 20 ++- test/cli/cli-iexec-task.test.js | 3 + test/cli/cli-iexec-workerpool.test.js | 4 +- test/cli/cli-test-utils.js | 3 +- test/docker-compose.yml | 11 ++ test/lib/e2e/IExecOrderModule.test.js | 197 ++++++++++---------------- test/lib/lib-test-utils.js | 4 + 13 files changed, 241 insertions(+), 166 deletions(-) diff --git a/src/cli/utils/templates.js b/src/cli/utils/templates.js index 28f6baed..6e3fd0b1 100644 --- a/src/cli/utils/templates.js +++ b/src/cli/utils/templates.js @@ -1,4 +1,7 @@ -import { IEXEC_REQUEST_PARAMS } from '../../common/utils/constant.js'; +import { + IEXEC_REQUEST_PARAMS, + TDX_DEFAULT_TAG, +} from '../../common/utils/constant.js'; export const main = { description: @@ -25,7 +28,7 @@ export const buyConf = { params: { [IEXEC_REQUEST_PARAMS.IEXEC_ARGS]: '', }, - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, trust: '0', callback: '0x0000000000000000000000000000000000000000', }; @@ -58,7 +61,7 @@ export const order = { app: '0x0000000000000000000000000000000000000000', appprice: '0', volume: '1000000', - tag: [], + tag: ['tee', 'tdx'], datasetrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default workerpoolrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default requesterrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default @@ -67,7 +70,7 @@ export const order = { dataset: '0x0000000000000000000000000000000000000000', datasetprice: '0', volume: '1000000', - tag: [], // todo remove from default + tag: ['tee', 'tdx'], // todo remove from default apprestrict: '0x0000000000000000000000000000000000000000', // todo remove from default workerpoolrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default requesterrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default @@ -78,7 +81,7 @@ export const order = { volume: '1', category: '0', trust: '0', - tag: [], // todo remove from default + tag: ['tee', 'tdx'], // todo remove from default apprestrict: '0x0000000000000000000000000000000000000000', // todo remove from default datasetrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default requesterrestrict: '0x0000000000000000000000000000000000000000', // todo remove from default @@ -93,7 +96,7 @@ export const order = { volume: '1', category: '0', trust: '0', // todo remove from default - tag: [], // todo remove from default + tag: ['tee', 'tdx'], // todo remove from default beneficiary: '0x0000000000000000000000000000000000000000', // todo remove from default callback: '0x0000000000000000000000000000000000000000', // todo remove from default params: { diff --git a/src/common/market/order.js b/src/common/market/order.js index 96f9fd19..b5258e98 100644 --- a/src/common/market/order.js +++ b/src/common/market/order.js @@ -27,8 +27,9 @@ import { import { hashEIP712 } from '../utils/sig-utils.js'; import { NULL_BYTES, - NULL_BYTES32, NULL_ADDRESS, + NULL_BYTES32, + TDX_DEFAULT_TAG, APP_ORDER, DATASET_ORDER, WORKERPOOL_ORDER, @@ -333,7 +334,15 @@ const signOrder = async ( export const signApporder = async ( contracts = throwIfMissing(), apporder = throwIfMissing(), -) => signOrder(contracts, APP_ORDER, await apporderSchema().validate(apporder)); +) => + signOrder( + contracts, + APP_ORDER, + await apporderSchema().validate({ + ...apporder, + tag: sumTags([await tagSchema().validate(apporder.tag), TDX_DEFAULT_TAG]), + }), + ); export const signDatasetorder = async ( contracts = throwIfMissing(), @@ -342,7 +351,16 @@ export const signDatasetorder = async ( signOrder( contracts, DATASET_ORDER, - await datasetorderSchema().validate(datasetorder), + await datasetorderSchema().validate({ + ...datasetorder, + tag: sumTags([ + await tagSchema({ + allowAgnosticTee: true, + ignoreLegacyTeeFramework: true, + }).validate(datasetorder.tag), + TDX_DEFAULT_TAG, + ]), + }), ); export const signWorkerpoolorder = async ( @@ -352,7 +370,13 @@ export const signWorkerpoolorder = async ( signOrder( contracts, WORKERPOOL_ORDER, - await workerpoolorderSchema().validate(workerpoolorder), + await workerpoolorderSchema().validate({ + ...workerpoolorder, + tag: sumTags([ + await tagSchema().validate(workerpoolorder.tag), + TDX_DEFAULT_TAG, + ]), + }), ); export const signRequestorder = async ( @@ -362,7 +386,13 @@ export const signRequestorder = async ( signOrder( contracts, REQUEST_ORDER, - await requestorderSchema().validate(requestorder), + await requestorderSchema().validate({ + ...requestorder, + tag: sumTags([ + await tagSchema().validate(requestorder.tag), + TDX_DEFAULT_TAG, + ]), + }), ); const cancelOrder = async ( @@ -463,6 +493,28 @@ const getMatchableVolume = async ( signedRequestorderSchema().validate(requestOrder), ]); + // check resulting tag + const resultingTag = await tagSchema() + .validate( + sumTags([ + vAppOrder.tag, + stripTeeFrameworkFromTag(vDatasetOrder.tag), + vRequestOrder.tag, + ]), + ) + .catch((e) => { + throw new Error( + `Matching order would produce an invalid deal tag. ${e.message}`, + ); + }); + const isTee = checkActiveBitInTag(resultingTag, TAG_MAP.tee); + const isTdx = checkActiveBitInTag(resultingTag, TAG_MAP.tdx); + if (!isTee || !isTdx) { + throw new Error( + 'Resulting deal tag must have both [tee] and [tdx] tags active. Matching orders have incompatible tags.', + ); + } + // deployment checks const checkAppDeployedAsync = async () => { if (!(await checkDeployedApp(contracts, vAppOrder.app))) { @@ -793,21 +845,6 @@ export const matchOrders = async ({ .validate(requestorder), ]); - // check resulting tag - await tagSchema() - .validate( - sumTags([ - vAppOrder.tag, - stripTeeFrameworkFromTag(vDatasetOrder.tag), - vRequestOrder.tag, - ]), - ) - .catch((e) => { - throw new Error( - `Matching order would produce an invalid deal tag. ${e.message}`, - ); - }); - // check matchability const matchableVolume = await getMatchableVolume( contracts, @@ -892,7 +929,9 @@ export const createApporder = async ({ app: await addressSchema().required().label('app').validate(app), appprice: await nRlcAmountSchema().validate(appprice), volume: await uint256Schema().validate(volume), - tag: await tagSchema().validate(tag), + tag: await tagSchema().validate( + sumTags([await tagSchema().validate(tag), TDX_DEFAULT_TAG]), + ), datasetrestrict: await addressSchema().validate(datasetrestrict), workerpoolrestrict: await addressSchema().validate(workerpoolrestrict), requesterrestrict: await addressSchema().validate(requesterrestrict), @@ -911,9 +950,16 @@ export const createDatasetorder = async ({ datasetprice: await nRlcAmountSchema().validate(datasetprice), volume: await uint256Schema().validate(volume), tag: await tagSchema({ - allowAgnosticTee: true, ignoreLegacyTeeFramework: true, - }).validate(tag), + }).validate( + sumTags([ + await tagSchema({ + allowAgnosticTee: true, + ignoreLegacyTeeFramework: true, + }).validate(tag), + TDX_DEFAULT_TAG, + ]), + ), apprestrict: await addressSchema().validate(apprestrict), workerpoolrestrict: await addressSchema().validate(workerpoolrestrict), requesterrestrict: await addressSchema().validate(requesterrestrict), @@ -935,7 +981,9 @@ export const createWorkerpoolorder = async ({ volume: await uint256Schema().validate(volume), category: await uint256Schema().validate(category), trust: await uint256Schema().validate(trust), - tag: await tagSchema().validate(tag), + tag: await tagSchema().validate( + sumTags([await tagSchema().validate(tag), TDX_DEFAULT_TAG]), + ), apprestrict: await addressSchema().validate(apprestrict), datasetrestrict: await addressSchema().validate(datasetrestrict), requesterrestrict: await addressSchema().validate(requesterrestrict), @@ -961,7 +1009,12 @@ export const createRequestorder = async ( } = {}, ) => { const requesterOrUser = requester || (await getAddress(contracts)); - const vTag = await tagSchema({ allowAgnosticTee: true }).validate(tag); + const vTag = await tagSchema().validate( + sumTags([ + await tagSchema({ allowAgnosticTee: true }).validate(tag), + TDX_DEFAULT_TAG, + ]), + ); return { app: await addressSchema().required().label('app').validate(app), appmaxprice: await nRlcAmountSchema().validate(appmaxprice), diff --git a/src/common/utils/constant.js b/src/common/utils/constant.js index 2c89e2e8..9a4ac469 100644 --- a/src/common/utils/constant.js +++ b/src/common/utils/constant.js @@ -30,6 +30,10 @@ export const TEE_FRAMEWORKS = { TDX: 'tdx', }; +// TDX default tag: bit 0 (tee) + bit 3 (tdx) = 0x9 +export const TDX_DEFAULT_TAG = + '0x0000000000000000000000000000000000000000000000000000000000000009'; + export const STORAGE_PROVIDERS = { DROPBOX: 'dropbox', IPFS: 'ipfs', diff --git a/test/cli/cli-iexec-app.test.js b/test/cli/cli-iexec-app.test.js index 929a4581..28b9bba8 100644 --- a/test/cli/cli-iexec-app.test.js +++ b/test/cli/cli-iexec-app.test.js @@ -20,6 +20,7 @@ import { } from './cli-test-utils.js'; import '../jest-setup.js'; import { encodeTag } from '../../src/lib/utils.js'; +import { TDX_DEFAULT_TAG } from '../../src/common/utils/constant.js'; const testChain = TEST_CHAINS['arbitrum-sepolia-fork']; @@ -202,7 +203,7 @@ describe('iexec app', () => { expect(resDeal.deal.beneficiary).toBe(userWallet.address); expect(resDeal.deal.botFirst).toBe('0'); expect(resDeal.deal.botSize).toBe('1'); - expect(resDeal.deal.tag).toBe(NULL_BYTES32); + expect(resDeal.deal.tag).toBe(TDX_DEFAULT_TAG); expect(resDeal.deal.trust).toBe('1'); expect(Object.keys(resDeal.deal.tasks).length).toBe(1); expect(resDeal.deal.tasks['0']).toBeDefined(); @@ -241,7 +242,7 @@ describe('iexec app', () => { expect(resDeal.deal.beneficiary).toBe(userWallet.address); expect(resDeal.deal.botFirst).toBe('0'); expect(resDeal.deal.botSize).toBe('1'); - expect(resDeal.deal.tag).toBe(NULL_BYTES32); + expect(resDeal.deal.tag).toBe(TDX_DEFAULT_TAG); expect(resDeal.deal.trust).toBe('1'); expect(Object.keys(resDeal.deal.tasks).length).toBe(1); expect(resDeal.deal.tasks['0']).toBeDefined(); @@ -400,7 +401,7 @@ describe('iexec app', () => { app: address, appprice: 0, volume: 1000000, - tag: NULL_BYTES32, + tag: TDX_DEFAULT_TAG, datasetrestrict: NULL_ADDRESS, workerpoolrestrict: NULL_ADDRESS, requesterrestrict: NULL_ADDRESS, @@ -422,7 +423,7 @@ describe('iexec app', () => { app: userFirstDeployedAppAddress, appprice: 100000000, volume: 100, - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, datasetrestrict: NULL_ADDRESS, workerpoolrestrict: NULL_ADDRESS, requesterrestrict: NULL_ADDRESS, diff --git a/test/cli/cli-iexec-dataset.test.js b/test/cli/cli-iexec-dataset.test.js index 66ddabd7..bc3ca915 100644 --- a/test/cli/cli-iexec-dataset.test.js +++ b/test/cli/cli-iexec-dataset.test.js @@ -1,7 +1,6 @@ import { describe, test, expect } from '@jest/globals'; import { NULL_ADDRESS, - NULL_BYTES32, TEST_CHAINS, execAsync, getRandomAddress, @@ -17,12 +16,15 @@ import { checkExists, } from './cli-test-utils.js'; import '../jest-setup.js'; +import { TDX_DEFAULT_TAG } from '../../src/common/utils/constant.js'; +import { sumTags } from '../../src/lib/utils.js'; const testChain = TEST_CHAINS['arbitrum-sepolia-fork']; describe('iexec dataset', () => { let userWallet; let userFirstDeployedDatasetAddress; + let userDatasetMissingSecret; beforeAll(async () => { await globalSetup('cli-iexec-dataset'); @@ -33,7 +35,15 @@ describe('iexec dataset', () => { await execAsync(`${iexecPath} dataset init`); await setDatasetUniqueName(); const deployed = await runIExecCliRaw(`${iexecPath} dataset deploy`); + await execAsync( + `echo "foo" > secret.txt && ${iexecPath} dataset push-secret --secret-path secret.txt`, + ); userFirstDeployedDatasetAddress = deployed.address; + await setDatasetUniqueName(); + const deployedMissingSecret = await runIExecCliRaw( + `${iexecPath} dataset deploy`, + ); + userDatasetMissingSecret = deployedMissingSecret.address; }); afterAll(async () => { @@ -271,6 +281,9 @@ describe('iexec dataset', () => { test('from deployed', async () => { await setDatasetUniqueName(); const { address } = await runIExecCliRaw(`${iexecPath} dataset deploy`); + await execAsync( + `echo "foo" > secret.txt && ${iexecPath} dataset push-secret --secret-path secret.txt`, + ); const res = await runIExecCliRaw(`${iexecPath} dataset publish --force`); expect(res.ok).toBe(true); expect(res.orderHash).toBeDefined(); @@ -283,7 +296,7 @@ describe('iexec dataset', () => { dataset: address, datasetprice: 0, volume: 1000000, - tag: NULL_BYTES32, + tag: TDX_DEFAULT_TAG, apprestrict: NULL_ADDRESS, workerpoolrestrict: NULL_ADDRESS, requesterrestrict: NULL_ADDRESS, @@ -296,13 +309,13 @@ describe('iexec dataset', () => { const appAddress = getRandomAddress(); await expect( execAsync( - `${iexecPath} dataset publish ${userFirstDeployedDatasetAddress} --price 0.1 RLC --volume 100 --tag tee,tdx --app-restrict ${appAddress} --force`, + `${iexecPath} dataset publish ${userDatasetMissingSecret} --price 0.1 RLC --volume 100 --tag 0x1000000000000000000000000000000000000000000000000000000000000000 --app-restrict ${appAddress} --force`, ), ).rejects.toThrow( - `Dataset encryption key is not set for dataset ${userFirstDeployedDatasetAddress} in the SMS. Dataset decryption will fail.`, + `Dataset encryption key is not set for dataset ${userDatasetMissingSecret} in the SMS. Dataset decryption will fail.`, ); const res = await runIExecCliRaw( - `${iexecPath} dataset publish ${userFirstDeployedDatasetAddress} --price 0.1 RLC --volume 100 --app-restrict ${appAddress} --force`, + `${iexecPath} dataset publish ${userFirstDeployedDatasetAddress} --price 0.1 RLC --volume 100 --tag 0x1000000000000000000000000000000000000000000000000000000000000000 --app-restrict ${appAddress} --force`, ); expect(res.ok).toBe(true); expect(res.orderHash).toBeDefined(); @@ -315,7 +328,10 @@ describe('iexec dataset', () => { dataset: userFirstDeployedDatasetAddress, datasetprice: 100000000, volume: 100, - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: sumTags([ + '0x1000000000000000000000000000000000000000000000000000000000000000', + TDX_DEFAULT_TAG, + ]), apprestrict: appAddress, workerpoolrestrict: NULL_ADDRESS, requesterrestrict: NULL_ADDRESS, @@ -329,6 +345,9 @@ describe('iexec dataset', () => { test('latest from deployed', async () => { await setDatasetUniqueName(); await runIExecCliRaw(`${iexecPath} dataset deploy`); + await execAsync( + `echo "foo" > secret.txt && ${iexecPath} dataset push-secret --secret-path secret.txt`, + ); await runIExecCliRaw(`${iexecPath} dataset publish --force`); const { orderHash: lastOrderHash } = await runIExecCliRaw( `${iexecPath} dataset publish --force`, diff --git a/test/cli/cli-iexec-deal.test.js b/test/cli/cli-iexec-deal.test.js index 182ad049..71573cbf 100644 --- a/test/cli/cli-iexec-deal.test.js +++ b/test/cli/cli-iexec-deal.test.js @@ -43,6 +43,9 @@ describe('iexec deal', () => { await execAsync(`${iexecPath} workerpool init`); userApp = await runIExecCliRaw(`${iexecPath} app deploy`); userDataset = await runIExecCliRaw(`${iexecPath} dataset deploy`); + await execAsync( + `echo 'foo' > secret.txt && ${iexecPath} dataset push-secret ${userDataset.address} --secret-path secret.txt`, + ); userWorkerpool = await runIExecCliRaw(`${iexecPath} workerpool deploy`); dealid = await runIExecCliRaw( `${iexecPath} app run ${userApp.address} --workerpool ${userWorkerpool.address} --dataset ${userDataset.address} --category ${noDurationCatid} --force`, diff --git a/test/cli/cli-iexec-order.test.js b/test/cli/cli-iexec-order.test.js index 02452f92..bf8f347b 100644 --- a/test/cli/cli-iexec-order.test.js +++ b/test/cli/cli-iexec-order.test.js @@ -9,6 +9,7 @@ import { globalTeardown, iexecPath, setChain, + setDatasetUniqueName, setRandomWallet, } from './cli-test-utils.js'; import '../jest-setup.js'; @@ -19,6 +20,7 @@ describe('iexec order', () => { let userWallet; let userApp; let userDataset; + let userDatasetMissingSecret; let userWorkerpool; beforeAll(async () => { @@ -33,9 +35,17 @@ describe('iexec order', () => { userApp = await execAsync(`${iexecPath} app deploy --raw`).then( (res) => JSON.parse(res).address, ); + await setDatasetUniqueName(); + userDatasetMissingSecret = await execAsync( + `${iexecPath} dataset deploy --raw`, + ).then((res) => JSON.parse(res).address); + await setDatasetUniqueName(); userDataset = await execAsync(`${iexecPath} dataset deploy --raw`).then( (res) => JSON.parse(res).address, ); + await execAsync( + `echo "foo" > secret.txt && ${iexecPath} dataset push-secret ${userDataset} --secret-path secret.txt`, + ); userWorkerpool = await execAsync( `${iexecPath} workerpool deploy --raw`, ).then((res) => JSON.parse(res).address); @@ -129,22 +139,26 @@ describe('iexec order', () => { expect(res.requestorder.app).toBeDefined(); await editRequestorder({ + dataset: userDatasetMissingSecret, tag: ['tee', 'tdx'], }); await editWorkerpoolorder({ tag: ['tee'], }); await editApporder({ tag: ['tdx'] }); - await editDatasetorder({ tag: ['tee', 'tdx'] }); + await editDatasetorder({ + dataset: userDatasetMissingSecret, + tag: ['tee', 'tdx'], + }); const failRes = await execAsync(`${iexecPath} order sign --raw`).then( JSON.parse, ); expect(failRes.ok).toBe(false); expect(failRes.fail).toStrictEqual([ "apporder: 'tdx' tag must be used with 'tee' tag", - `datasetorder: Dataset requirements check failed: Dataset encryption key is not set for dataset ${userDataset} in the SMS. Dataset decryption will fail. (If you consider this is not an issue, use --skip-preflight-check to skip preflight requirement check)`, + `datasetorder: Dataset requirements check failed: Dataset encryption key is not set for dataset ${userDatasetMissingSecret} in the SMS. Dataset decryption will fail. (If you consider this is not an issue, use --skip-preflight-check to skip preflight requirement check)`, "workerpoolorder: 'tee' tag must be used with a tee framework ('tdx')", - `requestorder: Request requirements check failed: Dataset encryption key is not set for dataset ${userDataset} in the SMS. Dataset decryption will fail. (If you consider this is not an issue, use --skip-preflight-check to skip preflight requirement check)`, + `requestorder: Request requirements check failed: Dataset encryption key is not set for dataset ${userDatasetMissingSecret} in the SMS. Dataset decryption will fail. (If you consider this is not an issue, use --skip-preflight-check to skip preflight requirement check)`, ]); }); diff --git a/test/cli/cli-iexec-task.test.js b/test/cli/cli-iexec-task.test.js index 5ed6f0bf..32719a47 100644 --- a/test/cli/cli-iexec-task.test.js +++ b/test/cli/cli-iexec-task.test.js @@ -42,6 +42,9 @@ describe('iexec task', () => { await execAsync(`${iexecPath} workerpool init`); userApp = await runIExecCliRaw(`${iexecPath} app deploy`); userDataset = await runIExecCliRaw(`${iexecPath} dataset deploy`); + await execAsync( + `echo 'foo' > secret.txt && ${iexecPath} dataset push-secret ${userDataset.address} --secret-path secret.txt`, + ); userWorkerpool = await runIExecCliRaw(`${iexecPath} workerpool deploy`); }); diff --git a/test/cli/cli-iexec-workerpool.test.js b/test/cli/cli-iexec-workerpool.test.js index f7742d85..ad481ea9 100644 --- a/test/cli/cli-iexec-workerpool.test.js +++ b/test/cli/cli-iexec-workerpool.test.js @@ -2,7 +2,6 @@ import { describe, test, expect } from '@jest/globals'; import { TEST_CHAINS, NULL_ADDRESS, - NULL_BYTES32, execAsync, getRandomAddress, } from '../test-utils.js'; @@ -17,6 +16,7 @@ import { } from './cli-test-utils.js'; import '../jest-setup.js'; import { encodeTag } from '../../src/lib/utils.js'; +import { TDX_DEFAULT_TAG } from '../../src/common/utils/constant.js'; const testChain = TEST_CHAINS['arbitrum-sepolia-fork']; @@ -152,7 +152,7 @@ describe('iexec workerpool', () => { workerpool: address, workerpoolprice: 0, volume: 1, - tag: NULL_BYTES32, + tag: TDX_DEFAULT_TAG, trust: 0, category: 0, apprestrict: NULL_ADDRESS, diff --git a/test/cli/cli-test-utils.js b/test/cli/cli-test-utils.js index 4ba17fe7..872116da 100644 --- a/test/cli/cli-test-utils.js +++ b/test/cli/cli-test-utils.js @@ -151,8 +151,9 @@ export const editApporder = async ({ tag }) => tag, }); -export const editDatasetorder = async ({ tag }) => +export const editDatasetorder = async ({ dataset, tag }) => editOrder('datasetorder')({ + dataset, tag, }); diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 72314287..a956525e 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -1,5 +1,6 @@ services: arbitrum-sepolia-fork: + platform: linux/amd64 restart: 'no' image: ghcr.io/foundry-rs/foundry:v1.0.0 entrypoint: anvil @@ -17,6 +18,7 @@ services: start_period: 30s unknown-chain-fork: + platform: linux/amd64 restart: 'no' image: ghcr.io/foundry-rs/foundry:v1.0.0 entrypoint: anvil @@ -34,6 +36,7 @@ services: start_period: 30s service-internal-error: + platform: linux/amd64 image: nginx:alpine volumes: - $PWD/mock/server/http500.nginx.conf:/etc/nginx/conf.d/default.conf:ro @@ -43,6 +46,7 @@ services: - 5500:80 sms-arbitrum-sepolia: + platform: linux/amd64 image: iexechub/iexec-sms:8.7.0 restart: unless-stopped environment: @@ -63,6 +67,7 @@ services: arbitrum-sepolia-fork: condition: service_healthy ipfs: + platform: linux/amd64 restart: unless-stopped image: ipfs/go-ipfs:v0.9.1 expose: @@ -79,6 +84,7 @@ services: start_period: 30s market-mongo: + platform: linux/amd64 image: mongo:6.0.3 restart: unless-stopped expose: @@ -87,6 +93,7 @@ services: - 27017:27017 market-redis: + platform: linux/amd64 image: redis:7.0.7-alpine restart: unless-stopped command: redis-server --appendonly yes @@ -102,6 +109,7 @@ services: start_period: 30s market-watcher-arbitrum-sepolia: + platform: linux/amd64 image: iexechub/iexec-market-watcher:7.0.1 restart: unless-stopped environment: @@ -122,6 +130,7 @@ services: condition: service_started market-api-arbitrum-sepolia: + platform: linux/amd64 image: iexechub/iexec-market-api:7.1.2 restart: unless-stopped ports: @@ -147,6 +156,7 @@ services: condition: service_started compass-arbitrum-sepolia: + platform: linux/amd64 image: iexechub/compass:v0.1.1 restart: unless-stopped environment: @@ -159,6 +169,7 @@ services: test: nc -w 1 0.0.0.0 3000 stack-ready: + platform: linux/amd64 image: bash command: - echo "all services ready" diff --git a/test/lib/e2e/IExecOrderModule.test.js b/test/lib/e2e/IExecOrderModule.test.js index 7890925a..2aeb9120 100644 --- a/test/lib/e2e/IExecOrderModule.test.js +++ b/test/lib/e2e/IExecOrderModule.test.js @@ -25,7 +25,12 @@ import { } from '../../test-utils.js'; import '../../jest-setup.js'; import { errors } from '../../../src/lib/index.js'; -import { DATASET_INFINITE_VOLUME, encodeTag } from '../../../src/lib/utils.js'; +import { + DATASET_INFINITE_VOLUME, + encodeTag, + sumTags, +} from '../../../src/lib/utils.js'; +import { TDX_DEFAULT_TAG } from '../../../src/common/utils/constant.js'; const { MarketCallError } = errors; @@ -50,6 +55,7 @@ describe('order', () => { .map(async () => { const { iexec: iexecDataOwner } = await getTestConfig(testChain)(); const { address } = await deployRandomDataset(iexecDataOwner); + await iexecDataOwner.dataset.pushDatasetSecret(address, 'foo'); const datasetBulkOrder = await iexecDataOwner.order .createDatasetorder({ dataset: address, @@ -89,7 +95,7 @@ describe('order', () => { appprice: '0', datasetrestrict: '0x0000000000000000000000000000000000000000', requesterrestrict: '0x0000000000000000000000000000000000000000', - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, volume: '1', workerpoolrestrict: '0x0000000000000000000000000000000000000000', }); @@ -134,7 +140,7 @@ describe('order', () => { dataset, datasetprice: '0', requesterrestrict: '0x0000000000000000000000000000000000000000', - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, volume: '1', workerpoolrestrict: '0x0000000000000000000000000000000000000000', }); @@ -152,7 +158,7 @@ describe('order', () => { apprestrict, workerpoolrestrict, requesterrestrict, - tag: ['tee'], + tag: '0x1000000000000000000000000000000000000000000000000000000000000000', volume: 100, }); expect(order).toEqual({ @@ -160,7 +166,10 @@ describe('order', () => { datasetprice: '1000000000', apprestrict, requesterrestrict, - tag: '0x0000000000000000000000000000000000000000000000000000000000000001', + tag: sumTags([ + '0x1000000000000000000000000000000000000000000000000000000000000000', + TDX_DEFAULT_TAG, + ]), // tee tdx is added by default volume: '100', workerpoolrestrict, }); @@ -180,7 +189,7 @@ describe('order', () => { category: '5', datasetrestrict: '0x0000000000000000000000000000000000000000', requesterrestrict: '0x0000000000000000000000000000000000000000', - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, trust: '0', volume: '1', workerpool, @@ -201,7 +210,7 @@ describe('order', () => { apprestrict, datasetrestrict, requesterrestrict, - tag: ['tee', 'tdx'], + tag: '0x1000000000000000000000000000000000000000000000000000000000000000', trust: '10', volume: '100', }); @@ -210,7 +219,10 @@ describe('order', () => { category: '5', datasetrestrict, requesterrestrict, - tag: encodeTag(['tee', 'tdx']), + tag: sumTags([ + '0x1000000000000000000000000000000000000000000000000000000000000000', + TDX_DEFAULT_TAG, + ]), // tee tdx is added by default trust: '10', volume: '100', workerpool, @@ -239,7 +251,7 @@ describe('order', () => { iexec_result_storage_provider: 'ipfs', }, requester: wallet.address, - tag: '0x0000000000000000000000000000000000000000000000000000000000000000', + tag: TDX_DEFAULT_TAG, trust: '0', volume: '1', workerpool: '0x0000000000000000000000000000000000000000', @@ -266,7 +278,7 @@ describe('order', () => { iexec_result_storage_provider: 'dropbox', iexec_result_encryption: true, }, - tag: ['tee', 'tdx'], + tag: '0x1000000000000000000000000000000000000000000000000000000000000000', trust: '100', volume: '5', }); @@ -283,7 +295,10 @@ describe('order', () => { iexec_result_encryption: true, }, requester: wallet.address, - tag: encodeTag(['tee', 'tdx']), + tag: sumTags([ + '0x1000000000000000000000000000000000000000000000000000000000000000', + TDX_DEFAULT_TAG, + ]), // tee tdx is added by default trust: '100', volume: '5', workerpool, @@ -531,36 +546,12 @@ describe('order', () => { await getTestConfig(testChain)(); const { iexec: iexecDatasetConsumer } = await getTestConfig(testChain)(); - const { address: dataset } = - await deployRandomDataset(iexecDatasetProvider); - - // non tee pass - await expect( - iexecDatasetConsumer.order - .createRequestorder({ - app: getRandomAddress(), - category: 5, - dataset, - }) - .then(iexecDatasetConsumer.order.signRequestorder), - ).resolves.toBeDefined(); - - // tee fail without secret - await expect( - iexecDatasetConsumer.order - .createRequestorder({ - app: getRandomAddress(), - category: 5, - dataset, - tag: ['tee', 'tdx'], - }) - .then(iexecDatasetConsumer.order.signRequestorder), - ).rejects.toThrow( - new Error( - `Dataset encryption key is not set for dataset ${dataset} in the SMS. Dataset decryption will fail.`, - ), + const { address: dataset } = await deployRandomDataset( + iexecDatasetProvider, + { pushDatasetSecret: false }, ); + // tee fail without secret await expect( iexecDatasetConsumer.order .createRequestorder({ @@ -876,6 +867,7 @@ describe('order', () => { const { iexec } = await getTestConfig(testChain)(); const datasetorder = await deployAndGetDatasetorder(iexec, { tag: ['tee'], + pushDatasetSecret: false, }); const datasetAddress = datasetorder.dataset; await expect( @@ -1694,45 +1686,24 @@ describe('order', () => { const requestorderTagTeeGpu = await iexecRequester.order.signRequestorder( { ...requestorderTemplate, - tag: ['tee', 'tdx', 'gpu'], + tag: ['gpu'], }, { preflightCheck: false }, ); - const workerpoolorderTagGpu = - await iexecPoolManager.order.signWorkerpoolorder({ - ...workerpoolorderTemplate, - tag: ['gpu'], - }); - const workerpoolorderTagTee = + const workerpoolorderTagNonGpu = await iexecPoolManager.order.signWorkerpoolorder({ ...workerpoolorderTemplate, - tag: ['tee', 'tdx'], }); await expect( iexecBroker.order.matchOrders( { apporder: apporderTemplate, datasetorder: datasetorderTemplate, - workerpoolorder: workerpoolorderTagGpu, + workerpoolorder: workerpoolorderTagNonGpu, requestorder: requestorderTagTeeGpu, }, { preflightCheck: false }, ), - ).rejects.toThrow(Error('Missing tags [tee,tdx] in workerpoolorder')); - const apporderTagGpu = await iexecAppProvider.order.signApporder({ - ...apporderTemplate, - tag: ['gpu'], - }); - await expect( - iexecBroker.order.matchOrders( - { - apporder: apporderTagGpu, - datasetorder: datasetorderTemplate, - workerpoolorder: workerpoolorderTagTee, - requestorder: requestorderTemplate, - }, - { preflightCheck: false }, - ), ).rejects.toThrow(Error('Missing tags [gpu] in workerpoolorder')); const datasetorderTagTeeGpu = await iexecDatasetProvider.order.signDatasetorder( @@ -1747,31 +1718,12 @@ describe('order', () => { { apporder: apporderTemplate, datasetorder: datasetorderTagTeeGpu, - workerpoolorder: workerpoolorderTagTee, + workerpoolorder: workerpoolorderTagNonGpu, requestorder: requestorderTemplate, }, { preflightCheck: false }, ), ).rejects.toThrow(Error('Missing tags [gpu] in workerpoolorder')); - // app tag check - const requestorderTagTee = await iexecRequester.order.signRequestorder( - { - ...requestorderTemplate, - tag: ['tee', 'tdx'], - }, - { preflightCheck: false }, - ); - await expect( - iexecBroker.order.matchOrders( - { - apporder: apporderTemplate, - datasetorder: datasetorderTemplate, - workerpoolorder: workerpoolorderTagTee, - requestorder: requestorderTagTee, - }, - { preflightCheck: false }, - ), - ).rejects.toThrow(Error('Missing tag [tee] in apporder')); // price check const apporderTooExpensive = await iexecAppProvider.order.signApporder({ ...apporderTemplate, @@ -2057,26 +2009,12 @@ describe('order', () => { const { iexec: iexecRequester } = await getTestConfig(testChain)(); const { iexec: iexecResourcesProvider } = await getTestConfig(testChain)(); - - const apporder = await deployAndGetApporder(iexecResourcesProvider); - const datasetorder = await deployAndGetDatasetorder( - iexecResourcesProvider, - ); - const workerpoolorder = await deployAndGetWorkerpoolorder( - iexecResourcesProvider, - ); - const requestorder = await getMatchableRequestorder(iexecRequester, { - apporder, - datasetorder, - workerpoolorder, - }); - const teeApporder = await deployAndGetApporder(iexecResourcesProvider, { tag: ['tee', 'tdx'], }); const teeDatasetorder = await deployAndGetDatasetorder( iexecResourcesProvider, - { tag: ['tee'] }, + { tag: ['tee'], pushDatasetSecret: false }, ); const teeWorkerpoolorder = await deployAndGetWorkerpoolorder( iexecResourcesProvider, @@ -2084,17 +2022,6 @@ describe('order', () => { tag: ['tee', 'tdx'], }, ); - const res = await iexecRequester.order.matchOrders({ - apporder, - datasetorder, - workerpoolorder, - requestorder, - }); - expect(res.txHash).toBeTxHash(); - expect(res.volume).toBeInstanceOf(BN); - expect(res.volume.eq(new BN(1))).toBe(true); - expect(res.dealid).toBeTxHash(); - // trigger dataset check await expect( iexecRequester.order.matchOrders({ @@ -2124,10 +2051,6 @@ describe('order', () => { tag: ['tee', 'gramine'], }, ); - await iexecResourcesProvider.dataset.pushDatasetSecret( - datasetorder.dataset, - 'foo', - ); const workerpoolorder = await deployAndGetWorkerpoolorder( iexecResourcesProvider, { @@ -2160,12 +2083,6 @@ describe('order', () => { }); const datasetorder = await deployAndGetDatasetorder( iexecResourcesProvider, - {}, - ); - await iexecResourcesProvider.dataset.pushDatasetSecret( - datasetorder.dataset, - 'foo', - { teeFramework: TEE_FRAMEWORKS.TDX }, ); const workerpoolorder = await deployAndGetWorkerpoolorder( iexecResourcesProvider, @@ -2193,5 +2110,47 @@ describe('order', () => { expect(res.dealid).toBeTxHash(); }); }); + + test('default tag (no tag provided) produces a TDX deal', async () => { + const { iexec: iexecRequester, wallet: requesterWallet } = + await getTestConfig(testChain)(); + const { iexec: iexecResourcesProvider, wallet: poolManagerWallet } = + await getTestConfig(testChain)(); + + await setNRlcBalance(testChain)(requesterWallet.address, 10n * ONE_RLC); + await setNRlcBalance(testChain)(poolManagerWallet.address, 10n * ONE_RLC); + + // no tag passed — all orders default to TDX_DEFAULT_TAG + const apporder = await deployAndGetApporder(iexecResourcesProvider); + const datasetorder = await deployAndGetDatasetorder( + iexecResourcesProvider, + ); + const workerpoolorder = await deployAndGetWorkerpoolorder( + iexecResourcesProvider, + ); + const requestorder = await getMatchableRequestorder(iexecRequester, { + apporder, + datasetorder, + workerpoolorder, + }); + + expect(apporder.tag).toBe(TDX_DEFAULT_TAG); + expect(datasetorder.tag).toBe(TDX_DEFAULT_TAG); + expect(workerpoolorder.tag).toBe(TDX_DEFAULT_TAG); + expect(requestorder.tag).toBe(TDX_DEFAULT_TAG); + + const { dealid } = await iexecRequester.order.matchOrders( + { + apporder, + datasetorder, + workerpoolorder, + requestorder, + }, + { preflightCheck: false }, + ); + + const deal = await iexecRequester.deal.show(dealid); + expect(deal.tag).toEqual(encodeTag(['tee', 'tdx'])); + }); }); }); diff --git a/test/lib/lib-test-utils.js b/test/lib/lib-test-utils.js index 7dc4a382..b22ece15 100644 --- a/test/lib/lib-test-utils.js +++ b/test/lib/lib-test-utils.js @@ -81,9 +81,13 @@ export const deployAndGetDatasetorder = async ( workerpoolrestrict, requesterrestrict, tag, + pushDatasetSecret = true, } = {}, ) => { const datasetDeployRes = await deployRandomDataset(iexec); + if (pushDatasetSecret) { + await iexec.dataset.pushDatasetSecret(datasetDeployRes.address, 'foo'); + } const dataset = datasetDeployRes.address; return iexec.order .createDatasetorder({ From b5f15a35c7795e3b8c353151cbbcdcf46fcf1af6 Mon Sep 17 00:00:00 2001 From: Pierre Jeanjacquot <26487010+PierreJeanjacquot@users.noreply.github.com> Date: Wed, 13 May 2026 17:55:33 +0200 Subject: [PATCH 2/3] refactor: run tests against installed CLI only when USE_LOCAL_CLI=true by default run CLI tests against source code to avoid build and install step on developer side, still run test against installed installed CLI in CI. --- .github/workflows/reusable-test.yml | 1 + test/cli/cli-test-utils.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml index 8decdebf..8af609b1 100644 --- a/.github/workflows/reusable-test.yml +++ b/.github/workflows/reusable-test.yml @@ -53,6 +53,7 @@ jobs: - name: Test run: npm test env: + USE_LOCAL_CLI: true INFURA_PROJECT_ID: ${{ secrets.infura-project-id }} ETHERSCAN_API_KEY: ${{ secrets.etherscan-api-key }} ALCHEMY_API_KEY: ${{ secrets.alchemy-api-key }} diff --git a/test/cli/cli-test-utils.js b/test/cli/cli-test-utils.js index 872116da..1127530b 100644 --- a/test/cli/cli-test-utils.js +++ b/test/cli/cli-test-utils.js @@ -7,7 +7,10 @@ import { execAsync, getId, setBalance } from '../test-utils.js'; const IEXEC_JSON = 'iexec.json'; const CHAIN_JSON = 'chain.json'; -export const iexecPath = 'iexec'; +export const iexecPath = + process.env.USE_LOCAL_CLI === 'true' + ? 'iexec' // use installed iexec cli + : '../../../src/cli/cmd/iexec.js'; export const globalSetup = async (testid = 'shared') => { const testDir = `test/tests-working-dir/${testid}`; From 581e0cd0b931a87c0475182841ce07f025a43d62 Mon Sep 17 00:00:00 2001 From: Pierre Jeanjacquot <26487010+PierreJeanjacquot@users.noreply.github.com> Date: Wed, 13 May 2026 18:10:13 +0200 Subject: [PATCH 3/3] chore: cleanup legacy configuration --- .github/workflows/pr-test.yml | 8 -------- .github/workflows/reusable-test.yml | 11 ---------- CLI.md | 32 +++++++---------------------- README.md | 6 ------ cli_template.md | 32 +++++++---------------------- 5 files changed, 14 insertions(+), 75 deletions(-) diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 69cfb86c..76c98bb1 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -41,10 +41,6 @@ jobs: with: node-version: '20' upload-coverage: true - secrets: - infura-project-id: ${{ secrets.INFURA_PROJECT_ID }} - etherscan-api-key: ${{ secrets.ETHERSCAN_API_KEY }} - alchemy-api-key: ${{ secrets.ALCHEMY_API_KEY }} test-supported-node-versions: uses: ./.github/workflows/reusable-test.yml @@ -55,10 +51,6 @@ jobs: node-version: ['22', '24'] with: node-version: ${{ matrix.node-version }} - secrets: - infura-project-id: ${{ secrets.INFURA_PROJECT_ID }} - etherscan-api-key: ${{ secrets.ETHERSCAN_API_KEY }} - alchemy-api-key: ${{ secrets.ALCHEMY_API_KEY }} # sonar: # runs-on: ubuntu-latest diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml index 8af609b1..4484dab3 100644 --- a/.github/workflows/reusable-test.yml +++ b/.github/workflows/reusable-test.yml @@ -1,5 +1,4 @@ name: test SDK -description: reusable test workflow for this project on: workflow_call: @@ -12,13 +11,6 @@ on: description: 'Upload coverage data for later reuse' type: boolean default: false - secrets: - infura-project-id: - required: true - etherscan-api-key: - required: true - alchemy-api-key: - required: true outputs: coverage-artifact-id: description: 'Coverage artifact id (if `upload-coverage: true`)' @@ -54,9 +46,6 @@ jobs: run: npm test env: USE_LOCAL_CLI: true - INFURA_PROJECT_ID: ${{ secrets.infura-project-id }} - ETHERSCAN_API_KEY: ${{ secrets.etherscan-api-key }} - ALCHEMY_API_KEY: ${{ secrets.alchemy-api-key }} - name: Stop e2e test stack if: always() diff --git a/CLI.md b/CLI.md index 1d3fbdb1..d96933bc 100644 --- a/CLI.md +++ b/CLI.md @@ -68,35 +68,17 @@ iexec wallet show # show your wallet iexec storage init # initialize your remote storage ``` -> _NB:_ iExec SDK CLI access the blockchain through [ethers](https://github.com/ethers-io/ethers.js/) to connect different backends ([Alchemy](https://alchemyapi.io/), [Etherscan](https://etherscan.io/), [INFURA](https://infura.io/)). -> -> Default API keys for backend services are provided for convenience. -> As these keys are shared across all users and are subject to rate limits, **you must use your own API keys** or better **your own node**. +> _NB:_ iExec SDK CLI access the blockchain through RPC nodes +> Default RPCs are provided for convenience. +> As these RPC nodes are shared across all users and are subject to limitations, **you must use your own API keys** or better **your own node**. > > Get API keys for backend services: > -> - [INFURA](https://infura.io/register) ([more details on Infura's blog](https://blog.infura.io/getting-started-with-infura-28e41844cc89/)) +> - [INFURA](https://app.infura.io/register) > - [Etherscan](https://etherscan.io/apis) -> - [Alchemy](https://alchemyapi.io/signup) -> -> Once you created your access, you can add your API keys in the `chains.json` configuration file: -> -> ```json -> { -> "default": ..., -> "chains": { ... }, -> "providers": { -> "infura": { -> "projectId": "INFURA_PROJECT_ID", -> "projectSecret": "INFURA_PROJECT_SECRET" -> }, -> "etherscan": "ETHERSCAN_API_KEY", -> "alchemy": "ALCHEMY_API_KEY" -> } -> } -> ``` +> - [Alchemy](https://www.alchemy.com) > -> If you run your own node, you can add an `host` key in the `chains.json` configuration file to target your node: +> You can add your RPC as `host` in the `chains.json` configuration file: > > ```json > { @@ -104,7 +86,7 @@ iexec storage init # initialize your remote storage > "chains": { > ... > "arbitrum-mainnet": { -> "host": "http://localhost:8545" +> "host": "https://", > } > } > } diff --git a/README.md b/README.md index f7312935..87794847 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,6 @@ Run tests when the stack is up npm run test ``` -> Some tests relies on RPC API providers, to have them running smoothly you can provide the following envs -> -> - ALCHEMY_API_KEY (obtained from ) -> - ETHERSCAN_API_KEY (obtained from ) -> - INFURA_PROJECT_ID (obtained from ) - ## Changelog Find changes in the [CHANGELOG](./CHANGELOG.md) diff --git a/cli_template.md b/cli_template.md index f3e12bf4..a00907c2 100644 --- a/cli_template.md +++ b/cli_template.md @@ -68,35 +68,17 @@ iexec wallet show # show your wallet iexec storage init # initialize your remote storage ``` -> _NB:_ iExec SDK CLI access the blockchain through [ethers](https://github.com/ethers-io/ethers.js/) to connect different backends ([Alchemy](https://alchemyapi.io/), [Etherscan](https://etherscan.io/), [INFURA](https://infura.io/)). -> -> Default API keys for backend services are provided for convenience. -> As these keys are shared across all users and are subject to rate limits, **you must use your own API keys** or better **your own node**. +> _NB:_ iExec SDK CLI access the blockchain through RPC nodes +> Default RPCs are provided for convenience. +> As these RPC nodes are shared across all users and are subject to limitations, **you must use your own API keys** or better **your own node**. > > Get API keys for backend services: > -> - [INFURA](https://infura.io/register) ([more details on Infura's blog](https://blog.infura.io/getting-started-with-infura-28e41844cc89/)) +> - [INFURA](https://app.infura.io/register) > - [Etherscan](https://etherscan.io/apis) -> - [Alchemy](https://alchemyapi.io/signup) -> -> Once you created your access, you can add your API keys in the `chains.json` configuration file: -> -> ```json -> { -> "default": ..., -> "chains": { ... }, -> "providers": { -> "infura": { -> "projectId": "INFURA_PROJECT_ID", -> "projectSecret": "INFURA_PROJECT_SECRET" -> }, -> "etherscan": "ETHERSCAN_API_KEY", -> "alchemy": "ALCHEMY_API_KEY" -> } -> } -> ``` +> - [Alchemy](https://www.alchemy.com) > -> If you run your own node, you can add an `host` key in the `chains.json` configuration file to target your node: +> You can add your RPC as `host` in the `chains.json` configuration file: > > ```json > { @@ -104,7 +86,7 @@ iexec storage init # initialize your remote storage > "chains": { > ... > "arbitrum-mainnet": { -> "host": "http://localhost:8545" +> "host": "https://", > } > } > }