Skip to content

Commit 77d22e8

Browse files
feat: index orders in bulks
1 parent bb7e8b9 commit 77d22e8

File tree

5 files changed

+253
-42
lines changed

5 files changed

+253
-42
lines changed

schema.graphql

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ type PolicyUpdate implements WorkerpoolEvent @entity {
232232
# ================================== Orders ===================================
233233
type AppOrder @entity {
234234
id: ID!
235-
app: App!
236-
appprice: BigDecimal!
235+
app: App
236+
appprice: BigDecimal
237237
volume: BigInt
238238
tag: Bytes
239239
datasetrestrict: Bytes
@@ -246,8 +246,8 @@ type AppOrder @entity {
246246

247247
type DatasetOrder @entity {
248248
id: ID!
249-
dataset: Dataset!
250-
datasetprice: BigDecimal!
249+
dataset: Dataset
250+
datasetprice: BigDecimal
251251
volume: BigInt
252252
tag: Bytes
253253
apprestrict: Bytes
@@ -260,8 +260,8 @@ type DatasetOrder @entity {
260260

261261
type WorkerpoolOrder @entity {
262262
id: ID!
263-
workerpool: Workerpool!
264-
workerpoolprice: BigDecimal!
263+
workerpool: Workerpool
264+
workerpoolprice: BigDecimal
265265
volume: BigInt
266266
tag: Bytes
267267
category: Category
@@ -282,7 +282,7 @@ type RequestOrder @entity {
282282
datasetmaxprice: BigDecimal
283283
workerpool: Workerpool # could be null or whitelist
284284
workerpoolmaxprice: BigDecimal
285-
requester: Account!
285+
requester: Account
286286
volume: BigInt
287287
tag: Bytes
288288
category: Category
@@ -355,7 +355,7 @@ type BulkSlice @entity(immutable: true) {
355355
content: String!
356356
bulk: Bulk!
357357
index: BigInt!
358-
datasets: [Dataset!]
358+
datasetOrders: [DatasetOrder!]
359359
}
360360

361361
enum TaskStatus {

src/Modules/Bulk.ts

Lines changed: 119 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
Address,
23
BigInt,
34
Bytes,
45
dataSource,
@@ -8,40 +9,41 @@ import {
89
JSONValueKind,
910
} from '@graphprotocol/graph-ts';
1011
import { Bulk, BulkSlice } from '../../generated/schema';
11-
import { CONTEXT_BULK, CONTEXT_INDEX, CONTEXT_REQUESTHASH, createBulkSliceID } from '../utils';
12-
13-
function isIntegerString(str: string): boolean {
14-
// empty string is not valid
15-
if (str.length == 0) {
16-
return false;
17-
}
18-
// 0 prefixed string is not valid
19-
if (str[0] === '0' && str.length > 1) {
20-
return false;
21-
}
22-
// non numeric character is not valid
23-
for (let i = 0; i < str.length; i++) {
24-
if (!['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(str[i])) {
25-
return false;
26-
}
27-
}
28-
return true;
29-
}
12+
import {
13+
CONTEXT_BULK,
14+
CONTEXT_DOMAIN_SEPARATOR_HASH,
15+
CONTEXT_INDEX,
16+
CONTEXT_REQUESTHASH,
17+
createBulkSliceID,
18+
fetchDatasetorder,
19+
hashDatasetOrder,
20+
isAddressString,
21+
isBytes32String,
22+
isHexString,
23+
isIntegerString,
24+
toRLC,
25+
} from '../utils';
3026

3127
export function handleBulk(content: Bytes): void {
3228
const hash = dataSource.stringParam();
3329
const context = dataSource.context();
3430
const requestorder = context.getString(CONTEXT_REQUESTHASH);
31+
const domainSeparator = context.getBytes(CONTEXT_DOMAIN_SEPARATOR_HASH);
3532

3633
// multiple deals using same requestorder use the same bulk, we use requestorderHash as bulk ID
3734
const bulkid = requestorder;
3835

39-
let bulk = new Bulk(bulkid);
36+
let bulk = Bulk.load(bulkid);
37+
if (bulk != null) {
38+
// immutable bulk already exists nothing to do
39+
return;
40+
}
41+
bulk = new Bulk(bulkid);
4042
bulk.hash = hash;
4143
bulk.content = content.toString();
4244

4345
const jsonContent = json.try_fromBytes(content);
44-
if (jsonContent.isOk) {
46+
if (jsonContent.isOk && jsonContent.value.kind == JSONValueKind.OBJECT) {
4547
const contentObject = jsonContent.value.toObject();
4648

4749
for (let i = 0; i < contentObject.entries.length; i++) {
@@ -50,11 +52,12 @@ export function handleBulk(content: Bytes): void {
5052
if (isIntegerString(entry.key)) {
5153
const index = BigInt.fromString(entry.key);
5254
if (entry.value.kind == JSONValueKind.OBJECT) {
53-
let sliceCid = entry.value.toObject().getEntry('datasets');
55+
let sliceCid = entry.value.toObject().getEntry('orders');
5456
if (sliceCid != null && sliceCid.value.kind == JSONValueKind.STRING) {
5557
let sliceContext = new DataSourceContext();
5658
sliceContext.setString(CONTEXT_BULK, bulkid);
5759
sliceContext.setBigInt(CONTEXT_INDEX, index);
60+
sliceContext.setBytes(CONTEXT_DOMAIN_SEPARATOR_HASH, domainSeparator);
5861
DataSourceTemplate.createWithContext(
5962
'BulkSlice',
6063
[sliceCid.value.toString()],
@@ -74,27 +77,109 @@ export function handleBulkSlice(content: Bytes): void {
7477
const context = dataSource.context();
7578
const bulk = context.getString(CONTEXT_BULK);
7679
const index = context.getBigInt(CONTEXT_INDEX);
80+
const domainSeparator = context.getBytes(CONTEXT_DOMAIN_SEPARATOR_HASH);
81+
82+
const bulkSliceId = createBulkSliceID(bulk, index);
7783

78-
let bulkSlice = new BulkSlice(createBulkSliceID(bulk, index));
84+
let bulkSlice = BulkSlice.load(bulkSliceId);
85+
if (bulkSlice != null) {
86+
// immutable bulk slice already exists nothing to do
87+
return;
88+
}
89+
bulkSlice = new BulkSlice(createBulkSliceID(bulk, index));
7990
bulkSlice.hash = hash;
8091
bulkSlice.bulk = bulk;
8192
bulkSlice.index = index;
8293
bulkSlice.content = content.toString();
8394

8495
const jsonContent = json.try_fromBytes(content);
8596
if (jsonContent.isOk && jsonContent.value.kind == JSONValueKind.ARRAY) {
86-
const datasetArray = jsonContent.value.toArray();
87-
for (let i = 0; i < datasetArray.length; i++) {
88-
const dataset = datasetArray[i];
89-
if (dataset.kind == JSONValueKind.STRING) {
90-
let datasetAddress = dataset.toString().toLowerCase();
91-
let datasets = bulkSlice.datasets;
92-
if (datasets == null) {
93-
datasets = new Array<string>();
97+
const datasetOrderArray = jsonContent.value.toArray();
98+
for (let i = 0; i < datasetOrderArray.length; i++) {
99+
const datasetOrder = datasetOrderArray[i];
100+
if (datasetOrder.kind == JSONValueKind.OBJECT) {
101+
const orderObj = datasetOrder.toObject();
102+
103+
const datasetEntry = orderObj.getEntry('dataset');
104+
const datasetPriceEntry = orderObj.getEntry('datasetprice');
105+
const volumeEntry = orderObj.getEntry('volume');
106+
const tagEntry = orderObj.getEntry('tag');
107+
const apprestrictEntry = orderObj.getEntry('apprestrict');
108+
const workerpoolrestrictEntry = orderObj.getEntry('workerpoolrestrict');
109+
const requesterrestrictEntry = orderObj.getEntry('requesterrestrict');
110+
const saltEntry = orderObj.getEntry('salt');
111+
const signEntry = orderObj.getEntry('sign');
112+
// check that all entries are present and valid
113+
if (
114+
datasetEntry != null &&
115+
datasetEntry.value.kind == JSONValueKind.STRING &&
116+
isAddressString(datasetEntry.value.toString().toLowerCase()) &&
117+
datasetPriceEntry != null &&
118+
datasetPriceEntry.value.kind == JSONValueKind.STRING &&
119+
isIntegerString(datasetPriceEntry.value.toString()) &&
120+
volumeEntry != null &&
121+
volumeEntry.value.kind == JSONValueKind.STRING &&
122+
isIntegerString(volumeEntry.value.toString()) &&
123+
tagEntry != null &&
124+
tagEntry.value.kind == JSONValueKind.STRING &&
125+
isBytes32String(tagEntry.value.toString()) &&
126+
apprestrictEntry != null &&
127+
apprestrictEntry.value.kind == JSONValueKind.STRING &&
128+
isAddressString(apprestrictEntry.value.toString().toLowerCase()) &&
129+
workerpoolrestrictEntry != null &&
130+
workerpoolrestrictEntry.value.kind == JSONValueKind.STRING &&
131+
isAddressString(workerpoolrestrictEntry.value.toString().toLowerCase()) &&
132+
requesterrestrictEntry != null &&
133+
requesterrestrictEntry.value.kind == JSONValueKind.STRING &&
134+
isAddressString(requesterrestrictEntry.value.toString().toLowerCase()) &&
135+
saltEntry != null &&
136+
saltEntry.value.kind == JSONValueKind.STRING &&
137+
isBytes32String(saltEntry.value.toString()) &&
138+
signEntry != null &&
139+
signEntry.value.kind == JSONValueKind.STRING &&
140+
isHexString(signEntry.value.toString())
141+
) {
142+
// compute order hash with domain separator from contract
143+
const orderHash = hashDatasetOrder(
144+
Address.fromString(datasetEntry.value.toString()),
145+
BigInt.fromString(datasetPriceEntry.value.toString()),
146+
BigInt.fromString(volumeEntry.value.toString()),
147+
Bytes.fromHexString(tagEntry.value.toString()),
148+
Address.fromString(apprestrictEntry.value.toString()),
149+
Address.fromString(workerpoolrestrictEntry.value.toString()),
150+
Address.fromString(requesterrestrictEntry.value.toString()),
151+
Bytes.fromHexString(saltEntry.value.toString()),
152+
domainSeparator,
153+
);
154+
155+
// store dataset order
156+
let datasetOrder = fetchDatasetorder(orderHash.toHex());
157+
datasetOrder.dataset = datasetEntry.value.toString().toLowerCase();
158+
datasetOrder.datasetprice = toRLC(
159+
BigInt.fromString(datasetPriceEntry.value.toString()),
160+
);
161+
datasetOrder.volume = BigInt.fromString(volumeEntry.value.toString());
162+
datasetOrder.tag = Bytes.fromHexString(tagEntry.value.toString());
163+
datasetOrder.apprestrict = Address.fromString(
164+
apprestrictEntry.value.toString().toLowerCase(),
165+
);
166+
datasetOrder.workerpoolrestrict = Address.fromString(
167+
workerpoolrestrictEntry.value.toString().toLowerCase(),
168+
);
169+
datasetOrder.requesterrestrict = Address.fromString(
170+
requesterrestrictEntry.value.toString().toLowerCase(),
171+
);
172+
datasetOrder.salt = Bytes.fromHexString(saltEntry.value.toString());
173+
datasetOrder.sign = Bytes.fromHexString(signEntry.value.toString());
174+
datasetOrder.save();
175+
176+
let datasetOrders = bulkSlice.datasetOrders;
177+
if (datasetOrders == null) {
178+
datasetOrders = new Array<string>();
179+
}
180+
datasetOrders.push(orderHash.toHex());
181+
bulkSlice.datasetOrders = datasetOrders;
94182
}
95-
// dataset address may be invalid, this is not an issue, the model will prune it
96-
datasets.push(datasetAddress);
97-
bulkSlice.datasets = datasets;
98183
}
99184
}
100185
}

src/Modules/IexecPoco.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
} from '../../generated/schema';
4343

4444
import {
45+
CONTEXT_DOMAIN_SEPARATOR_HASH,
4546
CONTEXT_REQUESTHASH,
4647
createContributionID,
4748
createEventID,
@@ -115,6 +116,9 @@ export function handleOrdersMatched(event: OrdersMatchedEvent): void {
115116
if (!indexedBulk) {
116117
let context = new DataSourceContext();
117118
context.setString(CONTEXT_REQUESTHASH, bulkId);
119+
// pass the domainSeparator to the template, as it cannot be retrieved from the contract in the template
120+
const domainSeparator = contract.eip712domain_separator();
121+
context.setBytes(CONTEXT_DOMAIN_SEPARATOR_HASH, domainSeparator);
118122
DataSourceTemplate.createWithContext('Bulk', [bulkCid.value.toString()], context);
119123
}
120124
// bulk may not be indexed, this is not an issue, the model will prune it

0 commit comments

Comments
 (0)