Skip to content

Commit 8112253

Browse files
feat: enable TDX on arbitrum-sepolia-testnet
1 parent 3fe382a commit 8112253

6 files changed

Lines changed: 138 additions & 188 deletions

File tree

cli/src/cmd/deploy.ts

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import {
22
dockerBuild,
33
pushDockerImage,
44
checkDockerDaemon,
5+
parseImagePath,
6+
inspectImage,
7+
tagDockerImage,
58
} from '../execDocker/docker.js';
69
import { sconify } from '../utils/sconify.js';
710
import { askForDockerhubUsername } from '../cli-helpers/askForDockerhubUsername.js';
@@ -20,7 +23,6 @@ import { goToProjectRoot } from '../cli-helpers/goToProjectRoot.js';
2023
import * as color from '../cli-helpers/color.js';
2124
import { hintBox } from '../cli-helpers/box.js';
2225
import { addDeploymentData } from '../utils/cacheExecutions.js';
23-
import { deployTdxApp, getIExecTdx } from '../utils/tdx-poc.js';
2426
import { useTdx } from '../utils/featureFlags.js';
2527
import { ensureBalances } from '../cli-helpers/ensureBalances.js';
2628
import { warnBeforeTxFees } from '../cli-helpers/warnBeforeTxFees.js';
@@ -39,11 +41,16 @@ export async function deploy({ chain }: { chain?: string }) {
3941
const userAddress = await signer.getAddress();
4042

4143
// initialize iExec
42-
let iexec;
43-
if (useTdx) {
44-
iexec = getIExecTdx({ ...chainConfig, signer });
45-
} else {
46-
iexec = getIExec({ ...chainConfig, signer });
44+
const iexec = getIExec({ ...chainConfig, signer });
45+
// determine TEE framework based on feature flag
46+
const teeFramework = useTdx ? 'tdx' : 'scone';
47+
// check TEE framework compatibility with selected chain
48+
try {
49+
await iexec.config.resolveSmsURL({ teeFramework });
50+
} catch {
51+
throw new Error(
52+
`TEE framework ${teeFramework.toUpperCase()} is not supported on the selected chain`
53+
);
4754
}
4855

4956
await ensureBalances({ spinner, iexec, warnOnlyRlc: true });
@@ -64,7 +71,7 @@ export async function deploy({ chain }: { chain?: string }) {
6471
throw Error('Invalid version');
6572
}
6673

67-
const imageTag = `${dockerhubUsername}/${projectNameToImageName(projectName)}:${iAppVersion}`;
74+
const nonTeeImage = `${dockerhubUsername}/${projectNameToImageName(projectName)}:${iAppVersion}`;
6875

6976
const appSecret = await askForAppSecret({ spinner });
7077

@@ -75,37 +82,60 @@ export async function deploy({ chain }: { chain?: string }) {
7582
spinner.start('Building docker image...\n');
7683
const buildLogs = [];
7784
const imageId = await dockerBuild({
78-
tag: imageTag,
85+
tag: nonTeeImage,
7986
progressCallback: (msg) => {
8087
buildLogs.push(msg); // do we want to show build logs after build is successful?
8188
spinner.text = spinner.text + color.comment(msg);
8289
},
8390
});
84-
spinner.succeed(`Docker image built (${imageId}) and tagged ${imageTag}`);
85-
86-
spinner.start('Pushing docker image...\n');
87-
await pushDockerImage({
88-
tag: imageTag,
89-
dockerhubAccessToken,
90-
dockerhubUsername,
91-
progressCallback: (msg) => {
92-
spinner.text = spinner.text + color.comment(msg);
93-
},
94-
});
95-
spinner.succeed(`Pushed image ${imageTag} on dockerhub`);
91+
spinner.succeed(`Docker image built (${imageId})`);
9692

9793
let appDockerImage: string;
9894
let appContractAddress: string;
9995

100-
if (useTdx && iexec) {
96+
if (useTdx) {
97+
spinner.start('Pushing docker image...\n');
98+
const {
99+
dockerUserName,
100+
imageName,
101+
imageTag: originalImageTag,
102+
} = parseImagePath(nonTeeImage);
103+
const repo = `${dockerUserName}/${imageName}`;
104+
const inspectResult = await inspectImage(nonTeeImage);
105+
const tdxImageShortId = inspectResult.Id.substring(7, 7 + 12); // extract 12 first chars after the leading "sha256:"
106+
const tdxImageTag = `${originalImageTag}-tdx-${tdxImageShortId}`; // add digest in tag to avoid replacing previous build
107+
const tdxImage = await tagDockerImage({
108+
image: nonTeeImage,
109+
repo,
110+
tag: tdxImageTag,
111+
});
112+
await pushDockerImage({
113+
tag: tdxImage,
114+
dockerhubUsername,
115+
dockerhubAccessToken,
116+
});
117+
spinner.succeed(`Pushed image ${tdxImage} on dockerhub`);
118+
appDockerImage = tdxImage;
101119
spinner.start('Deploying your TDX TEE app on iExec...');
102-
({ tdxImage: appDockerImage, appContractAddress } = await deployTdxApp({
103-
iexec,
104-
image: imageTag,
120+
const { address } = await iexec.app.deployApp({
121+
owner: await iexec.wallet.getAddress(),
122+
name: `${imageName}-${originalImageTag}`,
123+
type: 'DOCKER',
124+
multiaddr: tdxImage,
125+
checksum: `0x${inspectResult.RepoDigests[0].split('@sha256:')[1]}`,
126+
});
127+
appContractAddress = address;
128+
} else {
129+
spinner.start('Pushing docker image...\n');
130+
await pushDockerImage({
131+
tag: nonTeeImage,
105132
dockerhubAccessToken,
106133
dockerhubUsername,
107-
}));
108-
} else {
134+
progressCallback: (msg) => {
135+
spinner.text = spinner.text + color.comment(msg);
136+
},
137+
});
138+
spinner.succeed(`Pushed image ${nonTeeImage} on dockerhub`);
109139
spinner.start(
110140
'Transforming your image into a TEE image, this may take a few minutes...'
111141
);
@@ -116,17 +146,16 @@ export async function deploy({ chain }: { chain?: string }) {
116146
fingerprint,
117147
entrypoint,
118148
} = await sconify({
119-
iAppNameToSconify: imageTag,
149+
iAppNameToSconify: nonTeeImage,
120150
template,
121151
walletAddress: userAddress,
122152
dockerhubAccessToken,
123153
dockerhubUsername,
124154
});
125155
appDockerImage = dockerImage;
126156
spinner.succeed(`Pushed TEE image ${appDockerImage} on dockerhub`);
127-
128157
spinner.start('Deploying your TEE app on iExec...');
129-
({ address: appContractAddress } = await iexec.app.deployApp({
158+
const { address } = await iexec.app.deployApp({
130159
owner: userAddress,
131160
name: `${projectNameToImageName(projectName)}-${iAppVersion}`,
132161
type: 'DOCKER',
@@ -140,16 +169,19 @@ export async function deploy({ chain }: { chain?: string }) {
140169
heapSize: 1073741824,
141170
fingerprint,
142171
},
143-
}));
172+
});
173+
appContractAddress = address;
144174
}
145-
146175
// Add deployment data to deployments.json
147176
await addDeploymentData({
148177
image: appDockerImage,
149178
app: appContractAddress,
150179
owner: userAddress,
151180
chainName,
152181
});
182+
spinner.succeed(
183+
`TEE app deployed with image ${appDockerImage} on iExec with address ${appContractAddress}`
184+
);
153185

154186
spinner.succeed('TEE app deployed');
155187
if (appSecret !== null && iexec) {

cli/src/cmd/run.ts

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import { utils } from 'iexec';
44
import { ConsumableDatasetorder } from 'iexec/IExecOrderModule';
55
import { mkdir, rm } from 'node:fs/promises';
66
import { askForWallet } from '../cli-helpers/askForWallet.js';
7-
import {
8-
SCONE_TAG,
9-
RUN_OUTPUT_DIR,
10-
TASK_OBSERVATION_TIMEOUT,
11-
} from '../config/config.js';
7+
import { RUN_OUTPUT_DIR, TASK_OBSERVATION_TIMEOUT } from '../config/config.js';
128
import { addRunData } from '../utils/cacheExecutions.js';
139
import { getSpinner, type Spinner } from '../cli-helpers/spinner.js';
1410
import { handleCliError } from '../cli-helpers/handleCliError.js';
@@ -19,8 +15,6 @@ import { goToProjectRoot } from '../cli-helpers/goToProjectRoot.js';
1915
import * as color from '../cli-helpers/color.js';
2016
import { IExec } from 'iexec';
2117
import { getChainConfig, readIAppConfig } from '../utils/iAppConfigFile.js';
22-
import { getIExecTdx, WORKERPOOL_TDX } from '../utils/tdx-poc.js';
23-
import { useTdx } from '../utils/featureFlags.js';
2418
import { ensureBalances } from '../cli-helpers/ensureBalances.js';
2519
import { askForAcknowledgment } from '../cli-helpers/askForAcknowledgment.js';
2620
import { warnBeforeTxFees } from '../cli-helpers/warnBeforeTxFees.js';
@@ -52,17 +46,27 @@ export async function run({
5246
await warnBeforeTxFees({ spinner, chain: chainConfig.name });
5347

5448
spinner.start('checking inputs...');
55-
let readOnlyIexec: IExec;
56-
if (useTdx) {
57-
readOnlyIexec = getIExecTdx(chainConfig);
58-
} else {
59-
readOnlyIexec = getIExec(chainConfig);
60-
}
49+
// initialize iExec
50+
const readOnlyIexec = getIExec(chainConfig);
6151

6252
// input checks
6353
if ((await readOnlyIexec.app.checkDeployedApp(iAppAddress)) === false) {
6454
throw Error('No iApp found at the specified address.');
6555
}
56+
57+
const { app } = await readOnlyIexec.app.showApp(iAppAddress);
58+
// determine TEE framework based on app properties (SCONE apps define `appMREnclave`, TDX apps do NOT define `appMREnclave`)
59+
const isTdxApp = !app.appMREnclave;
60+
const teeFramework = isTdxApp ? 'tdx' : 'scone';
61+
// check TEE framework compatibility with selected chain
62+
try {
63+
await readOnlyIexec.config.resolveSmsURL({ teeFramework });
64+
} catch {
65+
throw new Error(
66+
`TEE framework ${teeFramework.toUpperCase()} is not supported on the selected chain`
67+
);
68+
}
69+
6670
if (protectedData.length > 0) {
6771
await Promise.all(
6872
protectedData.map(async (dataset) => {
@@ -74,7 +78,7 @@ export async function run({
7478
}
7579
const isSecretSet =
7680
await readOnlyIexec.dataset.checkDatasetSecretExists(dataset, {
77-
teeFramework: 'scone',
81+
teeFramework,
7882
});
7983
if (!isSecretSet) {
8084
throw Error(
@@ -89,22 +93,17 @@ export async function run({
8993
const signer = await askForWallet({ spinner });
9094
const userAddress = await signer.getAddress();
9195

92-
let iexec: IExec;
93-
if (useTdx) {
94-
iexec = getIExecTdx({ ...chainConfig, signer });
95-
} else {
96-
iexec = getIExec({
97-
...chainConfig,
98-
signer,
99-
});
100-
}
96+
const iexec = getIExec({
97+
...chainConfig,
98+
signer,
99+
});
101100

102101
// App Order
103102
spinner.start('Creating app order...');
104103
const apporderTemplate = await iexec.order.createApporder({
105104
app: iAppAddress,
106105
requesterrestrict: userAddress,
107-
tag: SCONE_TAG,
106+
tag: ['tee', teeFramework],
108107
});
109108
const apporder = await iexec.order.signApporder(apporderTemplate);
110109
spinner.succeed('AppOrder created');
@@ -121,8 +120,7 @@ export async function run({
121120
dataset,
122121
app: iAppAddress,
123122
requester: userAddress,
124-
minTag: SCONE_TAG,
125-
maxTag: SCONE_TAG,
123+
minTag: ['tee'], // TEE framework tag is ignored for dataset order matching, as dataset can be shared between SCONE and TDX apps
126124
bulkOnly: protectedData.length > 1, // bulk if multiple datasets
127125
});
128126
const datasetorder = datasetOrderbook.orders[0]?.order;
@@ -153,6 +151,7 @@ export async function run({
153151
const name = await pushRequesterSecret({
154152
iexec,
155153
value,
154+
teeFramework,
156155
});
157156
return [key, name];
158157
})
@@ -164,10 +163,11 @@ export async function run({
164163
// Workerpool Order
165164
spinner.start('Fetching workerpool order...');
166165
const workerpoolOrderbook = await iexec.orderbook.fetchWorkerpoolOrderbook({
167-
workerpool: useTdx ? WORKERPOOL_TDX : chainConfig.workerpool,
166+
workerpool: isTdxApp
167+
? chainConfig.tdxWorkerpool
168+
: chainConfig.sconeWorkerpool,
168169
app: iAppAddress,
169-
minTag: SCONE_TAG,
170-
maxTag: SCONE_TAG,
170+
minTag: apporder.tag,
171171
minVolume: volume, // TODO handle multiple matches if not enough volume
172172
});
173173
const workerpoolorder = workerpoolOrderbook.orders[0]?.order;
@@ -192,7 +192,7 @@ export async function run({
192192
? datasetorders[0].datasetprice.toString()
193193
: 0,
194194
workerpoolmaxprice: workerpoolorder.workerpoolprice,
195-
tag: SCONE_TAG,
195+
tag: ['tee', teeFramework],
196196
volume,
197197
params: {
198198
iexec_args: args,
@@ -310,12 +310,14 @@ ${color.link(`${chainConfig.ipfsGatewayUrl}${location}`)}`);
310310
async function pushRequesterSecret({
311311
iexec,
312312
value,
313+
teeFramework,
313314
}: {
314315
iexec: IExec;
315316
value: string;
317+
teeFramework: 'scone' | 'tdx';
316318
}) {
317319
const secretName = uuidV4();
318-
await iexec.secrets.pushRequesterSecret(secretName, value);
320+
await iexec.secrets.pushRequesterSecret(secretName, value, { teeFramework });
319321
return secretName;
320322
}
321323

cli/src/cmd/test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ import {
99
} from '../execDocker/docker.js';
1010
import { checkDeterministicOutputExists } from '../utils/deterministicOutput.js';
1111
import {
12-
IEXEC_WORKER_HEAP_SIZE,
12+
IEXEC_SCONE_WORKER_HEAP_SIZE,
1313
IEXEC_RESULT_UPLOAD_MAX_SIZE,
1414
PROTECTED_DATA_MOCK_DIR,
1515
TASK_OBSERVATION_TIMEOUT,
1616
TEST_INPUT_DIR,
1717
TEST_OUTPUT_DIR,
18+
IEXEC_TDX_WORKER_HEAP_SIZE,
1819
} from '../config/config.js';
1920
import { getSpinner, type Spinner } from '../cli-helpers/spinner.js';
2021
import { handleCliError } from '../cli-helpers/handleCliError.js';
@@ -26,7 +27,6 @@ import { goToProjectRoot } from '../cli-helpers/goToProjectRoot.js';
2627
import * as color from '../cli-helpers/color.js';
2728
import { hintBox } from '../cli-helpers/box.js';
2829
import { useTdx } from '../utils/featureFlags.js';
29-
import { IEXEC_TDX_WORKER_HEAP_SIZE } from '../utils/tdx-poc.js';
3030

3131
export async function test({
3232
args,
@@ -182,7 +182,7 @@ export async function testApp({
182182
}, TASK_OBSERVATION_TIMEOUT);
183183
const memoryLimit = useTdx
184184
? IEXEC_TDX_WORKER_HEAP_SIZE
185-
: IEXEC_WORKER_HEAP_SIZE;
185+
: IEXEC_SCONE_WORKER_HEAP_SIZE;
186186
const appLogs: string[] = [];
187187
const { exitCode, outOfMemory } = await runDockerContainer({
188188
image: imageId,

0 commit comments

Comments
 (0)