Skip to content

Commit 62b4691

Browse files
feat: add support support for data bulk processing (#243)
* feat: bulk processing support in iapp test * feat: add bulk processing in js template * feat: add bulk processing in iapp init * chore: change protectedData mocks content (foo, bar, baz) * fix: update bulk env names * fix: remove useless prompt in init advanced mode * feat: add bulk processing in iapp run * feat: add bulk processing in python template * chore: update iexec
1 parent 5451d66 commit 62b4691

File tree

15 files changed

+890
-157
lines changed

15 files changed

+890
-157
lines changed

cli/package-lock.json

Lines changed: 636 additions & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"dockerode": "^4.0.5",
4141
"ethers": "^6.13.5",
4242
"figlet": "^1.8.1",
43-
"iexec": "^8.20.0",
43+
"iexec": "^8.22.0",
4444
"jszip": "^3.10.1",
4545
"magic-bytes.js": "^1.10.0",
4646
"msgpackr": "^1.11.2",

cli/src/cmd/init.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export async function init() {
8888

8989
const {
9090
useArgs = true,
91-
useProtectedData = true,
91+
protectedData = 'useProtectedData',
9292
useInputFile = false,
9393
useRequesterSecret = false,
9494
useAppSecret = false,
@@ -119,12 +119,29 @@ export async function init() {
119119
initial: false,
120120
},
121121
{
122-
type: 'confirm',
123-
name: 'useProtectedData',
124-
message: `Would you like to use a protected data inside your iApp? ${color.promptHelper(
122+
type: 'select',
123+
name: 'protectedData',
124+
message: `Would you like to use protected data inside your iApp? ${color.promptHelper(
125125
'(protected data a secret file, the protected data is provided by a third party for users that will run your iApp)'
126126
)}`,
127-
initial: false,
127+
choices: [
128+
{
129+
title: 'no',
130+
value: 'noProtectedData',
131+
},
132+
{
133+
title: 'yes - only one protected data',
134+
value: 'useProtectedData',
135+
selected: true,
136+
description: 'one protected data per iApp run',
137+
},
138+
{
139+
title: 'yes - many protected data (bulk processing)',
140+
value: 'useBulkProcessing',
141+
description:
142+
'multiple protected data loaded in the same context of an iApp run',
143+
},
144+
],
128145
},
129146
{
130147
type: 'confirm',
@@ -135,6 +152,9 @@ export async function init() {
135152
])
136153
: {}; // default
137154

155+
const useProtectedData = protectedData === 'useProtectedData';
156+
const useBulkProcessing = protectedData === 'useBulkProcessing';
157+
138158
await mkdir(projectName);
139159
process.chdir(projectName);
140160

@@ -146,6 +166,7 @@ export async function init() {
146166
template,
147167
useArgs,
148168
useProtectedData,
169+
useBulkProcessing,
149170
useInputFile,
150171
useRequesterSecret,
151172
useAppSecret,
@@ -189,6 +210,12 @@ export async function init() {
189210
${color.comment('# with a protected data')}
190211
${color.command('$ iapp test --protectedData default')}`
191212
: ''
213+
}${
214+
useBulkProcessing
215+
? `
216+
${color.comment('# with a multiple protected data processed in bulk')}
217+
${color.command('$ iapp test --protectedData data1 data2 data3')}`
218+
: ''
192219
}
193220
194221
-2- Deploy your iApp on the iExec protocol:

cli/src/cmd/run.ts

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { v4 as uuidV4 } from 'uuid';
22
import { ethers } from 'ethers';
33
import { utils } from 'iexec';
4+
import { ConsumableDatasetorder } from 'iexec/IExecOrderModule';
45
import { mkdir, rm } from 'node:fs/promises';
56
import { askForWallet } from '../cli-helpers/askForWallet.js';
67
import {
@@ -27,14 +28,14 @@ import { warnBeforeTxFees } from '../cli-helpers/warnBeforeTxFees.js';
2728
export async function run({
2829
iAppAddress,
2930
args,
30-
protectedData,
31+
protectedData = [],
3132
inputFile: inputFiles = [], // rename variable (it's an array)
3233
requesterSecret: requesterSecrets = [], // rename variable (it's an array)
3334
chain,
3435
}: {
3536
iAppAddress: string;
3637
args?: string;
37-
protectedData?: string;
38+
protectedData?: string[];
3839
inputFile?: string[];
3940
requesterSecret?: { key: number; value: string }[];
4041
chain?: string;
@@ -62,24 +63,26 @@ export async function run({
6263
if ((await readOnlyIexec.app.checkDeployedApp(iAppAddress)) === false) {
6364
throw Error('No iApp found at the specified address.');
6465
}
65-
if (protectedData) {
66-
if (
67-
(await readOnlyIexec.dataset.checkDeployedDataset(protectedData)) ===
68-
false
69-
) {
70-
throw Error('No protectedData found at the specified address.');
71-
}
72-
const isSecretSet = await readOnlyIexec.dataset.checkDatasetSecretExists(
73-
protectedData,
74-
{
75-
teeFramework: 'scone',
76-
}
66+
if (protectedData.length > 0) {
67+
await Promise.all(
68+
protectedData.map(async (dataset) => {
69+
if (
70+
(await readOnlyIexec.dataset.checkDeployedDataset(dataset)) ===
71+
false
72+
) {
73+
throw Error(`No protectedData found at ${dataset}.`);
74+
}
75+
const isSecretSet =
76+
await readOnlyIexec.dataset.checkDatasetSecretExists(dataset, {
77+
teeFramework: 'scone',
78+
});
79+
if (!isSecretSet) {
80+
throw Error(
81+
`The protectedData secret key for ${dataset} is not registered in the Secret Management Service (SMS) of iExec protocol.`
82+
);
83+
}
84+
})
7785
);
78-
if (!isSecretSet) {
79-
throw Error(
80-
`The protectedData secret key is not registered in the Secret Management Service (SMS) of iExec protocol.`
81-
);
82-
}
8386
}
8487

8588
// Get wallet from privateKey
@@ -96,23 +99,6 @@ export async function run({
9699
});
97100
}
98101

99-
// Workerpool Order
100-
spinner.start('Fetching workerpool order...');
101-
const workerpoolOrderbook = await iexec.orderbook.fetchWorkerpoolOrderbook({
102-
workerpool: useTdx ? WORKERPOOL_TDX : chainConfig.workerpool,
103-
app: iAppAddress,
104-
dataset: protectedData || ethers.ZeroAddress,
105-
minTag: SCONE_TAG,
106-
maxTag: SCONE_TAG,
107-
});
108-
const workerpoolorder = workerpoolOrderbook.orders[0]?.order;
109-
if (!workerpoolorder) {
110-
throw Error(
111-
'No WorkerpoolOrder found, Wait until some workerpoolOrder come back'
112-
);
113-
}
114-
spinner.succeed('Workerpool order fetched');
115-
116102
// App Order
117103
spinner.start('Creating app order...');
118104
const apporderTemplate = await iexec.order.createApporder({
@@ -124,26 +110,37 @@ export async function run({
124110
spinner.succeed('AppOrder created');
125111

126112
// Dataset Order
127-
let datasetorder;
128-
if (protectedData) {
113+
let bulkCid: string | undefined;
114+
let volume = 1;
115+
let datasetorders: ConsumableDatasetorder[] = [];
116+
if (protectedData.length > 0) {
129117
spinner.start('Fetching protectedData access...');
130-
const datasetOrderbook = await iexec.orderbook.fetchDatasetOrderbook(
131-
protectedData,
132-
{
133-
app: iAppAddress,
134-
workerpool: workerpoolorder.workerpool,
135-
requester: userAddress,
136-
minTag: SCONE_TAG,
137-
maxTag: SCONE_TAG,
138-
}
118+
datasetorders = await Promise.all(
119+
protectedData.map(async (dataset) => {
120+
const datasetOrderbook = await iexec.orderbook.fetchDatasetOrderbook({
121+
dataset,
122+
app: iAppAddress,
123+
requester: userAddress,
124+
minTag: SCONE_TAG,
125+
maxTag: SCONE_TAG,
126+
bulkOnly: protectedData.length > 1, // bulk if multiple datasets
127+
});
128+
const datasetorder = datasetOrderbook.orders[0]?.order;
129+
if (!datasetorder) {
130+
throw Error(
131+
`No matching ProtectedData access found, It seems your iApp is not allowed to access the protectedData ${dataset}, please grantAccess to it`
132+
);
133+
}
134+
return datasetorder;
135+
})
139136
);
140-
datasetorder = datasetOrderbook.orders[0]?.order;
141-
if (!datasetorder) {
142-
throw Error(
143-
'No matching ProtectedData access found, It seems your iApp is not allowed to access the protectedData, please grantAccess to it'
144-
);
145-
}
146137
spinner.succeed('ProtectedData access found');
138+
if (protectedData.length > 1) {
139+
spinner.start('Preparing bulk access...');
140+
const bulk = await iexec.order.prepareDatasetBulk(datasetorders);
141+
bulkCid = bulk.cid;
142+
volume = bulk.volume;
143+
}
147144
}
148145

149146
// Requester secrets
@@ -164,28 +161,52 @@ export async function run({
164161
spinner.succeed('Requester secrets provisioned');
165162
}
166163

164+
// Workerpool Order
165+
spinner.start('Fetching workerpool order...');
166+
const workerpoolOrderbook = await iexec.orderbook.fetchWorkerpoolOrderbook({
167+
workerpool: useTdx ? WORKERPOOL_TDX : chainConfig.workerpool,
168+
app: iAppAddress,
169+
minTag: SCONE_TAG,
170+
maxTag: SCONE_TAG,
171+
minVolume: volume, // TODO handle multiple matches if not enough volume
172+
});
173+
const workerpoolorder = workerpoolOrderbook.orders[0]?.order;
174+
if (!workerpoolorder) {
175+
throw Error(
176+
'No workerpool order found, Wait until some workerpool order come back'
177+
);
178+
}
179+
spinner.succeed('Workerpool order fetched');
180+
167181
spinner.start('Creating request order...');
168182
const requestorderToSign = await iexec.order.createRequestorder({
169183
app: iAppAddress,
170184
category: workerpoolorder.category,
171-
dataset: protectedData || ethers.ZeroAddress,
185+
dataset:
186+
datasetorders.length === 1
187+
? datasetorders[0].dataset
188+
: ethers.ZeroAddress,
172189
appmaxprice: apporder.appprice,
173-
datasetmaxprice: datasetorder?.datasetprice || 0,
190+
datasetmaxprice:
191+
datasetorders.length === 1
192+
? datasetorders[0].datasetprice.toString()
193+
: 0,
174194
workerpoolmaxprice: workerpoolorder.workerpoolprice,
175195
tag: SCONE_TAG,
176-
workerpool: workerpoolorder.workerpool,
196+
volume,
177197
params: {
178198
iexec_args: args,
179199
iexec_input_files: inputFiles.length > 0 ? inputFiles : undefined,
180200
iexec_secrets,
201+
bulk_cid: bulkCid,
181202
},
182203
});
183204
const requestorder = await iexec.order.signRequestorder(requestorderToSign);
184205
spinner.succeed('RequestOrder created');
185206

186207
const matchOrderParams = {
187208
apporder,
188-
datasetorder: protectedData ? datasetorder : undefined,
209+
datasetorder: datasetorders.length === 1 ? datasetorders[0] : undefined,
189210
workerpoolorder,
190211
requestorder,
191212
};

0 commit comments

Comments
 (0)