Skip to content

Commit f50b898

Browse files
authored
refactor: Refactor dataset order tag ignoring code (#332)
1 parent 81778ee commit f50b898

File tree

3 files changed

+118
-123
lines changed

3 files changed

+118
-123
lines changed

contracts/facets/IexecPoco1Facet.sol

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,17 @@ contract IexecPoco1Facet is
125125
if (!_isAccountAuthorizedByRestriction(datasetOrder.requesterrestrict, deal.requester)) {
126126
revert IncompatibleDatasetOrder("Requester restriction not satisfied");
127127
}
128-
// The deal's tag should include all tag bits of the dataset order.
129-
// For dataset orders: ignore Scone, Gramine, and TDX framework bits to allow
130-
// dataset orders from SGX workerpools to be consumed on TDX workerpools and vice versa.
131-
// Examples after masking:
132-
// Deal: 0b0101, Dataset: 0b0101 => Masked Dataset: 0b0001 => ok
133-
// Deal: 0b0101, Dataset: 0b0001 => Masked Dataset: 0b0001 => ok
134-
// Deal: 0b1001 (TDX), Dataset: 0b0011 (Scone) => Masked Dataset: 0b0001 => ok (cross-framework compatibility)
135-
bytes32 maskedDatasetTag = datasetOrder.tag &
136-
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1;
137-
if ((deal.tag & maskedDatasetTag) != maskedDatasetTag) {
128+
// The deal's tag should include all activated tag bits of the dataset order.
129+
// For the dataset tag, bits of TEE frameworks (Scone, Gramine, and TDX) must be ignored
130+
// to allow existing dataset orders with SGX tags to be consumed on TDX workerpools.
131+
// Examples:
132+
// Deal: 0b0101, Dataset: 0b0101 (final: 0b0001) => ok
133+
// Deal: 0b0101, Dataset: 0b0001 (final: 0b0001) => ok
134+
// Deal: 0b0000, Dataset: 0b0001 (final: 0b0001) => !ok
135+
// Cross-framework examples:
136+
// Deal: 0b1001 (TDX), Dataset: 0b0011 (Scone) (final: 0b0001) => ok
137+
bytes32 finalDatasetTag = _ignoreTeeFramework(datasetOrder.tag);
138+
if ((deal.tag & finalDatasetTag) != finalDatasetTag) {
138139
revert IncompatibleDatasetOrder("Tag compatibility not satisfied");
139140
}
140141
}
@@ -229,8 +230,7 @@ contract IexecPoco1Facet is
229230
/**
230231
* Check orders compatibility
231232
*/
232-
233-
// computation environment & allowed enough funds
233+
// Check computation environment & prices.
234234
require(_requestorder.category == _workerpoolorder.category, "iExecV5-matchOrders-0x00");
235235
require(_requestorder.category < $.m_categories.length, "iExecV5-matchOrders-0x01");
236236
require(_requestorder.trust <= _workerpoolorder.trust, "iExecV5-matchOrders-0x02");
@@ -243,14 +243,11 @@ contract IexecPoco1Facet is
243243
_requestorder.workerpoolmaxprice >= _workerpoolorder.workerpoolprice,
244244
"iExecV5-matchOrders-0x05"
245245
);
246-
// The workerpool tag should include all tag bits of dataset, app, and requester orders.
247-
// For dataset orders: ignore Scone, Gramine, and TDX framework bits to allow
248-
// dataset orders from SGX workerpools to be consumed on TDX workerpools and vice versa.
249-
// Bit positions: bit 0 = TEE, bit 1 = Scone, bit 2 = Gramine, bit 3 = TDX
250-
// Mask: ~(BIT_SCONE | BIT_GRAMINE | BIT_TDX) = ~0xE = 0xFFF...FF1
251-
bytes32 maskedDatasetTag = _datasetorder.tag &
252-
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1;
253-
bytes32 tag = _apporder.tag | maskedDatasetTag | _requestorder.tag;
246+
// Check tags compatibility:
247+
// - The workerpool tag should include all activated tag bits of dataset, app, and requester orders.
248+
// - For the dataset tag, bits of TEE frameworks (Scone, Gramine, and TDX) must be ignored
249+
// to allow existing dataset orders with SGX tags to be consumed on TDX workerpools.
250+
bytes32 tag = _apporder.tag | _ignoreTeeFramework(_datasetorder.tag) | _requestorder.tag;
254251
require(tag & ~_workerpoolorder.tag == 0x0, "iExecV5-matchOrders-0x06");
255252
require((tag ^ _apporder.tag)[31] & 0x01 == 0x0, "iExecV5-matchOrders-0x07");
256253

@@ -474,4 +471,25 @@ contract IexecPoco1Facet is
474471

475472
return dealid;
476473
}
474+
475+
/**
476+
* Ignore TEE framework bits (Scone, Gramine, TDX) in the provided tag to allow
477+
* cross-framework compatibility.
478+
*
479+
* Ignored bit positions in the tag:
480+
* 0b(31 bytes...)1111
481+
* ||||
482+
* |||└─ bit 0: TEE
483+
* ||└── bit 1: Scone (ignored)
484+
* |└─── bit 2: Gramine (ignored)
485+
* └──── bit 3: TDX (ignored)
486+
*
487+
* @param tag original tag
488+
* @return tag with TEE framework bits ignored
489+
*/
490+
function _ignoreTeeFramework(bytes32 tag) private pure returns (bytes32) {
491+
// (BIT_SCONE | BIT_GRAMINE | BIT_TDX) → 0b 0000 1110 = 0x0E
492+
// Mask = ~0x0E = 0xF1 → 0xFFF...FF1
493+
return tag & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1;
494+
}
477495
}

test/byContract/IexecPoco/IexecPoco1.test.ts

Lines changed: 62 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ import {
1717
OwnableMock__factory,
1818
} from '../../../typechain';
1919
import {
20-
TAG_ALL_TEE_FRAMEWORKS,
20+
ALL_TEE_TAGS,
2121
TAG_BIT_2,
2222
TAG_BIT_4,
2323
TAG_BIT_4_AND_TEE,
24+
TAG_NAMES,
2425
TAG_STANDARD,
2526
TAG_TEE,
2627
TAG_TEE_GRAMINE,
2728
TAG_TEE_SCONE,
28-
TAG_TEE_TDX,
2929
} from '../../../utils/constants';
3030
import {
3131
IexecOrders,
@@ -637,41 +637,26 @@ describe('IexecPoco1', () => {
637637
);
638638
});
639639

640-
[
641-
{
642-
datasetTag: TAG_TEE_SCONE,
643-
workerpoolTag: TAG_TEE_TDX,
644-
description: 'Scone tag (0x3) and workerpool has TDX tag (0x9)',
645-
},
646-
{
647-
datasetTag: TAG_TEE_GRAMINE,
648-
workerpoolTag: TAG_TEE_TDX,
649-
description: 'Gramine tag (0x5) and workerpool has TDX tag (0x9)',
650-
},
651-
{
652-
datasetTag: TAG_TEE_TDX,
653-
workerpoolTag: TAG_TEE_SCONE,
654-
description: 'TDX tag (0x9) and workerpool has Scone tag (0x3)',
655-
},
656-
{
657-
datasetTag: TAG_ALL_TEE_FRAMEWORKS,
658-
workerpoolTag: TAG_TEE,
659-
description: 'all TEE framework bits (0xF) and workerpool has TEE only (0x1)',
660-
},
661-
].forEach(({ datasetTag, workerpoolTag, description }) => {
662-
it(`Should match orders when dataset has ${description}`, async () => {
663-
orders.dataset.tag = datasetTag;
664-
orders.workerpool.tag = workerpoolTag;
665-
orders.app.tag = TAG_TEE;
666-
orders.requester.tag = TAG_TEE;
667-
668-
await depositForRequesterAndSchedulerWithDefaultPrices(volume);
669-
await signOrders(iexecWrapper.getDomain(), orders, ordersActors);
670-
671-
await expect(iexecPocoAsRequester.matchOrders(...orders.toArray())).to.emit(
672-
iexecPoco,
673-
'OrdersMatched',
674-
);
640+
/**
641+
* Successful match orders with all combinations of TEE tags in dataset and workerpool orders.
642+
* Validates ignored dataset tag bits.
643+
*/
644+
ALL_TEE_TAGS.forEach((datasetTag) => {
645+
ALL_TEE_TAGS.forEach((workerpoolTag) => {
646+
it(`Should match orders with compatible TEE tags [dataset:${TAG_NAMES[datasetTag]}, workerpool:${TAG_NAMES[workerpoolTag]}]`, async () => {
647+
orders.dataset.tag = datasetTag;
648+
orders.workerpool.tag = workerpoolTag;
649+
orders.app.tag = TAG_TEE;
650+
orders.requester.tag = TAG_TEE;
651+
652+
await depositForRequesterAndSchedulerWithDefaultPrices(volume);
653+
await signOrders(iexecWrapper.getDomain(), orders, ordersActors);
654+
655+
await expect(iexecPocoAsRequester.matchOrders(...orders.toArray())).to.emit(
656+
iexecPoco,
657+
'OrdersMatched',
658+
);
659+
});
675660
});
676661
});
677662

@@ -1163,6 +1148,46 @@ describe('IexecPoco1', () => {
11631148
).to.not.be.reverted;
11641149
});
11651150

1151+
/**
1152+
* Successful compatibility check with all combinations of TEE tags in deal and dataset order.
1153+
* Validates ignored dataset tag bits.
1154+
*/
1155+
ALL_TEE_TAGS.forEach((datasetTag) => {
1156+
ALL_TEE_TAGS.forEach((dealTag) => {
1157+
it(`Should not revert with compatible TEE tags [dataset:${TAG_NAMES[datasetTag]}, deal:${TAG_NAMES[dealTag]}]`, async () => {
1158+
// Create a new deal with the specified tag, don't reuse the one from beforeEach.
1159+
const newDealOrders = buildOrders({
1160+
assets: { ...ordersAssets, dataset: ZeroAddress },
1161+
prices: ordersPrices,
1162+
requester: requester.address,
1163+
tag: dealTag,
1164+
volume: volume,
1165+
});
1166+
// Override salts to avoid order consumption conflicts.
1167+
newDealOrders.app.salt = ethers.id('app-salt');
1168+
newDealOrders.workerpool.salt = ethers.id('workerpool-salt');
1169+
newDealOrders.requester.salt = ethers.id('requester-salt');
1170+
await depositForRequesterAndSchedulerWithDefaultPrices(volume);
1171+
await signOrders(iexecWrapper.getDomain(), newDealOrders, ordersActors);
1172+
const dealId = getDealId(iexecWrapper.getDomain(), newDealOrders.requester);
1173+
await iexecPocoAsRequester
1174+
.matchOrders(...newDealOrders.toArray())
1175+
.then((tx) => tx.wait());
1176+
// Create dataset order with the specified tag
1177+
const datasetOrder = {
1178+
...compatibleDatasetOrder,
1179+
tag: datasetTag,
1180+
salt: ethers.id('dataset-salt'),
1181+
};
1182+
await signOrder(iexecWrapper.getDomain(), datasetOrder, datasetProvider);
1183+
1184+
// Should not revert because bits in positions 1 to 3 of the dataset order tag are ignored.
1185+
await expect(iexecPoco.assertDatasetDealCompatibility(datasetOrder, dealId)).to
1186+
.not.be.reverted;
1187+
});
1188+
});
1189+
});
1190+
11661191
it('Should revert when the dataset order is revoked or fully consumed', async () => {
11671192
await signOrder(iexecWrapper.getDomain(), compatibleDatasetOrder, datasetProvider);
11681193
// Revoke order on-chain.
@@ -1318,64 +1343,6 @@ describe('IexecPoco1', () => {
13181343
.withArgs('Tag compatibility not satisfied');
13191344
});
13201345

1321-
// TODO: Add more test cases for tag compatibility
1322-
[
1323-
{
1324-
datasetTag: TAG_TEE_SCONE,
1325-
dealTag: TAG_TEE_TDX,
1326-
description: 'Scone tag (0x3) and deal has TDX tag (0x9)',
1327-
saltPrefix: 'scone-tdx',
1328-
},
1329-
{
1330-
datasetTag: TAG_TEE_GRAMINE,
1331-
dealTag: TAG_TEE_TDX,
1332-
description: 'Gramine tag (0x5) and deal has TDX tag (0x9)',
1333-
saltPrefix: 'gramine-tdx',
1334-
},
1335-
{
1336-
datasetTag: TAG_TEE_TDX,
1337-
dealTag: TAG_TEE_SCONE,
1338-
description: 'TDX tag (0x9) and deal has Scone tag (0x3)',
1339-
saltPrefix: 'tdx-scone',
1340-
},
1341-
{
1342-
datasetTag: TAG_ALL_TEE_FRAMEWORKS,
1343-
dealTag: TAG_TEE,
1344-
description: 'all TEE framework bits (0xF) and deal has TEE only (0x1)',
1345-
saltPrefix: 'all-frameworks-tee',
1346-
},
1347-
].forEach(({ datasetTag, dealTag, description, saltPrefix }) => {
1348-
it(`Should not revert when dataset has ${description}`, async () => {
1349-
// Create a deal with the specified tag
1350-
const dealOrders = buildOrders({
1351-
assets: { ...ordersAssets, dataset: ZeroAddress },
1352-
prices: ordersPrices,
1353-
requester: requester.address,
1354-
tag: dealTag,
1355-
volume: volume,
1356-
});
1357-
dealOrders.app.salt = ethers.id(`${saltPrefix}-app-salt`);
1358-
dealOrders.workerpool.salt = ethers.id(`${saltPrefix}-workerpool-salt`);
1359-
dealOrders.requester.salt = ethers.id(`${saltPrefix}-requester-salt`);
1360-
await depositForRequesterAndSchedulerWithDefaultPrices(volume);
1361-
await signOrders(iexecWrapper.getDomain(), dealOrders, ordersActors);
1362-
const dealId = getDealId(iexecWrapper.getDomain(), dealOrders.requester);
1363-
await iexecPocoAsRequester.matchOrders(...dealOrders.toArray());
1364-
1365-
// Create dataset order with the specified tag
1366-
const datasetOrder = {
1367-
...compatibleDatasetOrder,
1368-
tag: datasetTag,
1369-
salt: ethers.id(`${saltPrefix}-dataset-salt`),
1370-
};
1371-
await signOrder(iexecWrapper.getDomain(), datasetOrder, datasetProvider);
1372-
1373-
// Should not revert because bits 1-3 of dataset tag are ignored
1374-
await expect(iexecPoco.assertDatasetDealCompatibility(datasetOrder, dealId)).to.not
1375-
.be.reverted;
1376-
});
1377-
});
1378-
13791346
it('Should revert when dataset has bit 4 set (not masked) and deal does not', async () => {
13801347
// Create a deal with TEE only (0b0001 = 0x1)
13811348
const teeOnlyOrders = buildOrders({

utils/constants.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
// SPDX-FileCopyrightText: 2020-2025 IEXEC BLOCKCHAIN TECH <[email protected]>
22
// SPDX-License-Identifier: Apache-2.0
33

4-
/**
5-
* Tag constants:
6-
* - Bit 0: TEE
7-
* - Bit 1: Scone
8-
* - Bit 2: Gramine
9-
* - Bit 3: TDX
10-
* - Bit 4: GPU (0x10)
11-
*/
4+
// Tag constants.
5+
// For TEE bits positions, see IexecPoco1Facet.sol#_ignoreTeeFramework
126
export const TAG_STANDARD = '0x0000000000000000000000000000000000000000000000000000000000000000';
137
export const TAG_TEE = '0x0000000000000000000000000000000000000000000000000000000000000001';
148
export const TAG_TEE_SCONE = '0x0000000000000000000000000000000000000000000000000000000000000003'; // 0b0011 = TEE + Scone
@@ -20,6 +14,22 @@ export const TAG_BIT_2 = '0x0000000000000000000000000000000000000000000000000000
2014
export const TAG_BIT_4 = '0x0000000000000000000000000000000000000000000000000000000000000010'; // 0b10000 (bit 4 in 0-indexed)
2115
export const TAG_BIT_4_AND_TEE =
2216
'0x0000000000000000000000000000000000000000000000000000000000000011'; // 0b10001
17+
// Tag helpers:
18+
export const ALL_TEE_TAGS = [
19+
TAG_TEE,
20+
TAG_TEE_SCONE,
21+
TAG_TEE_GRAMINE,
22+
TAG_TEE_TDX,
23+
TAG_ALL_TEE_FRAMEWORKS,
24+
];
25+
export const TAG_NAMES: { [key: string]: string } = {
26+
[TAG_STANDARD]: 'STANDARD',
27+
[TAG_TEE]: 'TEE',
28+
[TAG_TEE_SCONE]: 'TEE_SCONE',
29+
[TAG_TEE_GRAMINE]: 'TEE_GRAMINE',
30+
[TAG_TEE_TDX]: 'TEE_TDX',
31+
[TAG_ALL_TEE_FRAMEWORKS]: 'TEE_ALL',
32+
};
2333

2434
export const NULL = {
2535
BYTES32: '0x0000000000000000000000000000000000000000000000000000000000000000',

0 commit comments

Comments
 (0)