@human-protocol/sdk 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/example/simple-existing-job.ts +86 -0
- package/example/simple-new-job-public.ts +74 -0
- package/example/simple-new-job.ts +72 -0
- package/package.json +8 -3
- package/src/job.ts +58 -34
- package/src/storage.ts +1 -1
- package/test/job.test.ts +753 -0
- package/test/utils/constants.ts +27 -0
- package/test/utils/manifest.ts +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Job } from '../src';
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_GAS_PAYER_PRIVKEY,
|
|
5
|
+
DEFAULT_HMTOKEN_ADDR,
|
|
6
|
+
REPUTATION_ORACLE_PRIVKEY,
|
|
7
|
+
WORKER1_ADDR,
|
|
8
|
+
WORKER2_ADDR,
|
|
9
|
+
} from '../test/utils/constants';
|
|
10
|
+
import { manifest } from '../test/utils/manifest';
|
|
11
|
+
import * as dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
dotenv.config();
|
|
14
|
+
|
|
15
|
+
const main = async () => {
|
|
16
|
+
// Create job object
|
|
17
|
+
const newJob = new Job({
|
|
18
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
19
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
20
|
+
manifest: manifest,
|
|
21
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
22
|
+
logLevel: 'debug',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Initialize new job object
|
|
26
|
+
await newJob.initialize();
|
|
27
|
+
|
|
28
|
+
// Launch the job
|
|
29
|
+
await newJob.launch();
|
|
30
|
+
|
|
31
|
+
// Access the existing job
|
|
32
|
+
const job = new Job({
|
|
33
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
34
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
35
|
+
manifest: manifest,
|
|
36
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
37
|
+
factoryAddr: newJob.contractData?.factoryAddr,
|
|
38
|
+
escrowAddr: newJob.contractData?.escrowAddr,
|
|
39
|
+
storageAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
40
|
+
storageSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
41
|
+
storageEndpoint: process.env.AWS_ENDPOINT,
|
|
42
|
+
storageBucket: process.env.AWS_BUCKET,
|
|
43
|
+
storagePublicBucket: process.env.AWS_PUBLIC_BUCKET,
|
|
44
|
+
logLevel: 'debug',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Initialize the job object
|
|
48
|
+
await job.initialize();
|
|
49
|
+
|
|
50
|
+
// Setup the job
|
|
51
|
+
await job.setup();
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
55
|
+
await job.balance()
|
|
56
|
+
)?.toString()}`
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Bulk payout workers
|
|
60
|
+
await job.bulkPayout(
|
|
61
|
+
[
|
|
62
|
+
{
|
|
63
|
+
address: WORKER1_ADDR,
|
|
64
|
+
amount: 70,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
address: WORKER2_ADDR,
|
|
68
|
+
amount: 30,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
{
|
|
72
|
+
result: 'result',
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Complete the job
|
|
77
|
+
await job.complete();
|
|
78
|
+
|
|
79
|
+
console.log(
|
|
80
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
81
|
+
await job.balance()
|
|
82
|
+
)?.toString()}`
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
main();
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Job } from '../src';
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_GAS_PAYER_PRIVKEY,
|
|
5
|
+
DEFAULT_HMTOKEN_ADDR,
|
|
6
|
+
REPUTATION_ORACLE_PRIVKEY,
|
|
7
|
+
WORKER1_ADDR,
|
|
8
|
+
WORKER2_ADDR,
|
|
9
|
+
} from '../test/utils/constants';
|
|
10
|
+
import { manifest } from '../test/utils/manifest';
|
|
11
|
+
import * as dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
dotenv.config();
|
|
14
|
+
|
|
15
|
+
const main = async () => {
|
|
16
|
+
// Create job object
|
|
17
|
+
const job = new Job({
|
|
18
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
19
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
20
|
+
manifest: manifest,
|
|
21
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
22
|
+
storageAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
23
|
+
storageSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
24
|
+
storageEndpoint: process.env.AWS_ENDPOINT,
|
|
25
|
+
storageBucket: process.env.AWS_BUCKET,
|
|
26
|
+
storagePublicBucket: process.env.AWS_PUBLIC_BUCKET,
|
|
27
|
+
logLevel: 'debug',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Initialize new job
|
|
31
|
+
await job.initialize();
|
|
32
|
+
|
|
33
|
+
// Launch the job
|
|
34
|
+
await job.launch();
|
|
35
|
+
|
|
36
|
+
// Setup the job
|
|
37
|
+
await job.setup();
|
|
38
|
+
|
|
39
|
+
console.log(
|
|
40
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
41
|
+
await job.balance()
|
|
42
|
+
)?.toString()}`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Bulk payout workers
|
|
46
|
+
await job.bulkPayout(
|
|
47
|
+
[
|
|
48
|
+
{
|
|
49
|
+
address: WORKER1_ADDR,
|
|
50
|
+
amount: 70,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
address: WORKER2_ADDR,
|
|
54
|
+
amount: 30,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
{
|
|
58
|
+
result: 'result',
|
|
59
|
+
},
|
|
60
|
+
false,
|
|
61
|
+
true
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Complete the job
|
|
65
|
+
await job.complete();
|
|
66
|
+
|
|
67
|
+
console.log(
|
|
68
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
69
|
+
await job.balance()
|
|
70
|
+
)?.toString()}`
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
main();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Job } from '../src';
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_GAS_PAYER_PRIVKEY,
|
|
5
|
+
DEFAULT_HMTOKEN_ADDR,
|
|
6
|
+
REPUTATION_ORACLE_PRIVKEY,
|
|
7
|
+
WORKER1_ADDR,
|
|
8
|
+
WORKER2_ADDR,
|
|
9
|
+
} from '../test/utils/constants';
|
|
10
|
+
import { manifest } from '../test/utils/manifest';
|
|
11
|
+
import * as dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
dotenv.config();
|
|
14
|
+
|
|
15
|
+
const main = async () => {
|
|
16
|
+
// Create job object
|
|
17
|
+
const job = new Job({
|
|
18
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
19
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
20
|
+
manifest: manifest,
|
|
21
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
22
|
+
storageAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
23
|
+
storageSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
24
|
+
storageEndpoint: process.env.AWS_ENDPOINT,
|
|
25
|
+
storageBucket: process.env.AWS_BUCKET,
|
|
26
|
+
storagePublicBucket: process.env.AWS_PUBLIC_BUCKET,
|
|
27
|
+
logLevel: 'debug',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Initialize new job
|
|
31
|
+
await job.initialize();
|
|
32
|
+
|
|
33
|
+
// Launch the job
|
|
34
|
+
await job.launch();
|
|
35
|
+
|
|
36
|
+
// Setup the job
|
|
37
|
+
await job.setup();
|
|
38
|
+
|
|
39
|
+
console.log(
|
|
40
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
41
|
+
await job.balance()
|
|
42
|
+
)?.toString()}`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Bulk payout workers
|
|
46
|
+
await job.bulkPayout(
|
|
47
|
+
[
|
|
48
|
+
{
|
|
49
|
+
address: WORKER1_ADDR,
|
|
50
|
+
amount: 70,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
address: WORKER2_ADDR,
|
|
54
|
+
amount: 30,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
{
|
|
58
|
+
result: 'result',
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Complete the job
|
|
63
|
+
await job.complete();
|
|
64
|
+
|
|
65
|
+
console.log(
|
|
66
|
+
`Status: ${await job.status()}, Balance: ${(
|
|
67
|
+
await job.balance()
|
|
68
|
+
)?.toString()}`
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@human-protocol/sdk",
|
|
3
3
|
"description": "Human Protocol SDK",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
7
|
-
"dist"
|
|
7
|
+
"dist",
|
|
8
|
+
"example",
|
|
9
|
+
"test"
|
|
8
10
|
],
|
|
9
11
|
"main": "dist/index.js",
|
|
10
12
|
"types": "dist/index.d.ts",
|
|
@@ -36,12 +38,15 @@
|
|
|
36
38
|
]
|
|
37
39
|
},
|
|
38
40
|
"dependencies": {
|
|
39
|
-
"@human-protocol/core": "
|
|
41
|
+
"@human-protocol/core": "^1.0.9",
|
|
40
42
|
"aws-sdk": "^2.1255.0",
|
|
41
43
|
"crypto": "^1.0.1",
|
|
42
44
|
"dotenv": "^16.0.3",
|
|
43
45
|
"ethers": "^5.7.2",
|
|
44
46
|
"secp256k1": "^4.0.3",
|
|
45
47
|
"winston": "^3.8.2"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@human-protocol/core": "^1.0.9"
|
|
46
51
|
}
|
|
47
52
|
}
|
package/src/job.ts
CHANGED
|
@@ -142,8 +142,8 @@ export class Job {
|
|
|
142
142
|
accessKeyId: storageAccessKeyId || '',
|
|
143
143
|
secretAccessKey: storageSecretAccessKey || '',
|
|
144
144
|
endpoint: storageEndpoint,
|
|
145
|
-
publicBucket: storagePublicBucket ||
|
|
146
|
-
bucket: storageBucket ||
|
|
145
|
+
publicBucket: storagePublicBucket || DEFAULT_PUBLIC_BUCKET,
|
|
146
|
+
bucket: storageBucket || DEFAULT_BUCKET,
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
this._logger = createLogger(logLevel);
|
|
@@ -204,6 +204,8 @@ export class Job {
|
|
|
204
204
|
|
|
205
205
|
if (!hasEscrow) {
|
|
206
206
|
this._logError(new Error('Factory does not contain the escrow'));
|
|
207
|
+
this.contractData.factory = undefined;
|
|
208
|
+
|
|
207
209
|
return false;
|
|
208
210
|
}
|
|
209
211
|
|
|
@@ -214,17 +216,34 @@ export class Job {
|
|
|
214
216
|
);
|
|
215
217
|
this._logger.info('Accessed the escrow successfully.');
|
|
216
218
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
const manifestUrl = await this.contractData?.escrow.manifestUrl();
|
|
220
|
+
const manifestHash = await this.contractData?.escrow.manifestHash();
|
|
221
|
+
|
|
222
|
+
if (
|
|
223
|
+
(!manifestUrl.length || !manifestHash.length) &&
|
|
224
|
+
!this.manifestData?.manifest
|
|
225
|
+
) {
|
|
226
|
+
this._logError(ErrorManifestMissing);
|
|
227
|
+
|
|
228
|
+
this.contractData.factory = undefined;
|
|
229
|
+
this.contractData.escrow = undefined;
|
|
230
|
+
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
224
233
|
|
|
225
|
-
|
|
226
|
-
this.manifestData
|
|
227
|
-
|
|
234
|
+
if (manifestUrl.length && manifestHash.length) {
|
|
235
|
+
this.manifestData = {
|
|
236
|
+
...this.manifestData,
|
|
237
|
+
manifestlink: {
|
|
238
|
+
url: manifestUrl,
|
|
239
|
+
hash: manifestHash,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
this.manifestData.manifest = (await this._download(
|
|
244
|
+
manifestUrl
|
|
245
|
+
)) as Manifest;
|
|
246
|
+
}
|
|
228
247
|
}
|
|
229
248
|
|
|
230
249
|
return true;
|
|
@@ -238,18 +257,13 @@ export class Job {
|
|
|
238
257
|
* @returns {Promise<boolean>} - True if the escrow is launched successfully.
|
|
239
258
|
*/
|
|
240
259
|
async launch(): Promise<boolean> {
|
|
241
|
-
if (!this.contractData || this.contractData.escrow) {
|
|
242
|
-
this._logError(ErrorJobAlreadyLaunched);
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
260
|
if (!this.contractData || !this.contractData.factory) {
|
|
247
261
|
this._logError(ErrorJobNotInitialized);
|
|
248
262
|
return false;
|
|
249
263
|
}
|
|
250
264
|
|
|
251
|
-
if (!this.
|
|
252
|
-
this._logError(
|
|
265
|
+
if (!this.contractData || this.contractData.escrow) {
|
|
266
|
+
this._logError(ErrorJobAlreadyLaunched);
|
|
253
267
|
return false;
|
|
254
268
|
}
|
|
255
269
|
|
|
@@ -281,21 +295,6 @@ export class Job {
|
|
|
281
295
|
this.providerData?.gasPayer
|
|
282
296
|
);
|
|
283
297
|
|
|
284
|
-
this._logger.info('Uploading manifest...');
|
|
285
|
-
const uploadResult = await this._upload(this.manifestData.manifest);
|
|
286
|
-
if (!uploadResult) {
|
|
287
|
-
this._logError(new Error('Error uploading manifest'));
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
this.manifestData.manifestlink = {
|
|
292
|
-
url: uploadResult.key,
|
|
293
|
-
hash: uploadResult.hash,
|
|
294
|
-
};
|
|
295
|
-
this._logger.info(
|
|
296
|
-
`Uploaded manifest.\n\tKey: ${uploadResult.key}\n\tHash: ${uploadResult.hash}`
|
|
297
|
-
);
|
|
298
|
-
|
|
299
298
|
return (
|
|
300
299
|
(await this.status()) == EscrowStatus.Launched &&
|
|
301
300
|
(await this.balance())?.toNumber() === 0
|
|
@@ -316,6 +315,16 @@ export class Job {
|
|
|
316
315
|
return false;
|
|
317
316
|
}
|
|
318
317
|
|
|
318
|
+
if (!this.manifestData || !this.manifestData.manifest) {
|
|
319
|
+
this._logError(ErrorManifestMissing);
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (this.manifestData.manifestlink) {
|
|
324
|
+
this._logError(new Error('Job is already setup'));
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
|
|
319
328
|
if (!this.contractData.hmToken) {
|
|
320
329
|
this._logError(ErrorHMTokenMissing);
|
|
321
330
|
return false;
|
|
@@ -358,6 +367,21 @@ export class Job {
|
|
|
358
367
|
}
|
|
359
368
|
this._logger.info('HMT transferred.');
|
|
360
369
|
|
|
370
|
+
this._logger.info('Uploading manifest...');
|
|
371
|
+
const uploadResult = await this._upload(this.manifestData.manifest);
|
|
372
|
+
if (!uploadResult) {
|
|
373
|
+
this._logError(new Error('Error uploading manifest'));
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.manifestData.manifestlink = {
|
|
378
|
+
url: uploadResult.key,
|
|
379
|
+
hash: uploadResult.hash,
|
|
380
|
+
};
|
|
381
|
+
this._logger.info(
|
|
382
|
+
`Uploaded manifest.\n\tKey: ${uploadResult.key}\n\tHash: ${uploadResult.hash}`
|
|
383
|
+
);
|
|
384
|
+
|
|
361
385
|
this._logger.info('Setting up the escrow...');
|
|
362
386
|
const contractSetup = await this._raffleExecute(
|
|
363
387
|
this.contractData.escrow,
|
package/src/storage.ts
CHANGED
package/test/job.test.ts
ADDED
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
import { getPublicURL } from './../src/storage';
|
|
2
|
+
import { EscrowStatus, Job } from '../src';
|
|
3
|
+
import { upload } from '../src/storage';
|
|
4
|
+
import { toFullDigit } from '../src/utils';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_GAS_PAYER_ADDR,
|
|
7
|
+
DEFAULT_GAS_PAYER_PRIVKEY,
|
|
8
|
+
DEFAULT_HMTOKEN_ADDR,
|
|
9
|
+
NOT_TRUSTED_OPERATOR_PRIVKEY,
|
|
10
|
+
REPUTATION_ORACLE_PRIVKEY,
|
|
11
|
+
TRUSTED_OPERATOR1_ADDR,
|
|
12
|
+
TRUSTED_OPERATOR1_PRIVKEY,
|
|
13
|
+
TRUSTED_OPERATOR2_ADDR,
|
|
14
|
+
WORKER1_ADDR,
|
|
15
|
+
WORKER2_ADDR,
|
|
16
|
+
WORKER3_ADDR,
|
|
17
|
+
} from './utils/constants';
|
|
18
|
+
import { manifest } from './utils/manifest';
|
|
19
|
+
|
|
20
|
+
jest.mock('../src/storage', () => ({
|
|
21
|
+
...jest.requireActual('../src/storage'),
|
|
22
|
+
upload: jest.fn().mockResolvedValue({
|
|
23
|
+
key: 'uploaded-key',
|
|
24
|
+
hash: 'uploaded-hash',
|
|
25
|
+
}),
|
|
26
|
+
download: jest.fn().mockResolvedValue({
|
|
27
|
+
results: 0,
|
|
28
|
+
}),
|
|
29
|
+
getPublicURL: jest.fn().mockResolvedValue('public-url'),
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
describe('Test Job', () => {
|
|
33
|
+
describe('New job', () => {
|
|
34
|
+
let job: Job;
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
job = new Job({
|
|
38
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
39
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
40
|
+
manifest: manifest,
|
|
41
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
42
|
+
logLevel: 'debug',
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
jest.clearAllMocks();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('Should be able to initializes the job by deploying escrow factory', async () => {
|
|
51
|
+
const initialized = await job.initialize();
|
|
52
|
+
expect(initialized).toBe(true);
|
|
53
|
+
|
|
54
|
+
expect(await job.contractData?.factory?.address).not.toBeNull();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('Should be able to launch the job', async () => {
|
|
58
|
+
// Fail to launch the job before initialization
|
|
59
|
+
expect(await job.launch()).toBe(false);
|
|
60
|
+
|
|
61
|
+
await job.initialize();
|
|
62
|
+
|
|
63
|
+
expect(await job.launch()).toBe(true);
|
|
64
|
+
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('Should be able to setup the job', async () => {
|
|
68
|
+
// Fail to setup the job before launch
|
|
69
|
+
expect(await job.setup()).toBe(false);
|
|
70
|
+
|
|
71
|
+
await job.initialize();
|
|
72
|
+
await job.launch();
|
|
73
|
+
|
|
74
|
+
expect(await job.setup()).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('Should be able to add trusted handlers', async () => {
|
|
78
|
+
await job.initialize();
|
|
79
|
+
await job.launch();
|
|
80
|
+
|
|
81
|
+
expect(await job.isTrustedHandler(DEFAULT_GAS_PAYER_ADDR)).toBe(true);
|
|
82
|
+
|
|
83
|
+
expect(
|
|
84
|
+
await job.addTrustedHandlers([
|
|
85
|
+
TRUSTED_OPERATOR1_ADDR,
|
|
86
|
+
TRUSTED_OPERATOR2_ADDR,
|
|
87
|
+
])
|
|
88
|
+
).toBe(true);
|
|
89
|
+
|
|
90
|
+
expect(await job.isTrustedHandler(TRUSTED_OPERATOR1_ADDR)).toBe(true);
|
|
91
|
+
expect(await job.isTrustedHandler(TRUSTED_OPERATOR2_ADDR)).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('Should be able to bulk payout workers', async () => {
|
|
95
|
+
await job.initialize();
|
|
96
|
+
await job.launch();
|
|
97
|
+
await job.setup();
|
|
98
|
+
|
|
99
|
+
expect(
|
|
100
|
+
await job.bulkPayout(
|
|
101
|
+
[
|
|
102
|
+
{
|
|
103
|
+
address: WORKER1_ADDR,
|
|
104
|
+
amount: 20,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
address: WORKER2_ADDR,
|
|
108
|
+
amount: 50,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
{}
|
|
112
|
+
)
|
|
113
|
+
).toBe(true);
|
|
114
|
+
|
|
115
|
+
// The escrow contract is still in Partial state as there's still balance left.
|
|
116
|
+
expect((await job.balance())?.toString()).toBe(
|
|
117
|
+
toFullDigit(30).toString()
|
|
118
|
+
);
|
|
119
|
+
expect(await job.status()).toBe(EscrowStatus.Partial);
|
|
120
|
+
|
|
121
|
+
// Trying to pay more than the contract balance results in failure.
|
|
122
|
+
expect(
|
|
123
|
+
await job.bulkPayout(
|
|
124
|
+
[
|
|
125
|
+
{
|
|
126
|
+
address: WORKER3_ADDR,
|
|
127
|
+
amount: 50,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
{}
|
|
131
|
+
)
|
|
132
|
+
).toBe(false);
|
|
133
|
+
|
|
134
|
+
// Paying the remaining amount empties the escrow and updates the status correctly.
|
|
135
|
+
expect(
|
|
136
|
+
await job.bulkPayout(
|
|
137
|
+
[
|
|
138
|
+
{
|
|
139
|
+
address: WORKER3_ADDR,
|
|
140
|
+
amount: 30,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
{}
|
|
144
|
+
)
|
|
145
|
+
).toBe(true);
|
|
146
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
147
|
+
expect(await job.status()).toBe(EscrowStatus.Paid);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('Should encrypt result, when bulk paying out workers', async () => {
|
|
151
|
+
await job.initialize();
|
|
152
|
+
await job.launch();
|
|
153
|
+
await job.setup();
|
|
154
|
+
|
|
155
|
+
jest.clearAllMocks();
|
|
156
|
+
const finalResults = { results: 0 };
|
|
157
|
+
await job.bulkPayout(
|
|
158
|
+
[
|
|
159
|
+
{
|
|
160
|
+
address: WORKER1_ADDR,
|
|
161
|
+
amount: 100,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
finalResults,
|
|
165
|
+
true
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
expect(upload).toHaveBeenCalledWith(
|
|
169
|
+
job.storageAccessData,
|
|
170
|
+
finalResults,
|
|
171
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
172
|
+
true,
|
|
173
|
+
false
|
|
174
|
+
);
|
|
175
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('Should not encrypt result, when bulk paying out workers', async () => {
|
|
179
|
+
await job.initialize();
|
|
180
|
+
await job.launch();
|
|
181
|
+
await job.setup();
|
|
182
|
+
|
|
183
|
+
jest.clearAllMocks();
|
|
184
|
+
const finalResults = { results: 0 };
|
|
185
|
+
await job.bulkPayout(
|
|
186
|
+
[
|
|
187
|
+
{
|
|
188
|
+
address: WORKER1_ADDR,
|
|
189
|
+
amount: 100,
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
finalResults,
|
|
193
|
+
false
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
expect(upload).toHaveBeenCalledWith(
|
|
197
|
+
job.storageAccessData,
|
|
198
|
+
finalResults,
|
|
199
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
200
|
+
false,
|
|
201
|
+
false
|
|
202
|
+
);
|
|
203
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('Should store result in private storage, when bulk paying out workers', async () => {
|
|
207
|
+
await job.initialize();
|
|
208
|
+
await job.launch();
|
|
209
|
+
await job.setup();
|
|
210
|
+
|
|
211
|
+
jest.clearAllMocks();
|
|
212
|
+
const finalResults = { results: 0 };
|
|
213
|
+
await job.bulkPayout(
|
|
214
|
+
[
|
|
215
|
+
{
|
|
216
|
+
address: WORKER1_ADDR,
|
|
217
|
+
amount: 100,
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
finalResults,
|
|
221
|
+
false,
|
|
222
|
+
false
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(upload).toHaveBeenCalledWith(
|
|
226
|
+
job.storageAccessData,
|
|
227
|
+
finalResults,
|
|
228
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
229
|
+
false,
|
|
230
|
+
false
|
|
231
|
+
);
|
|
232
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('Should store result in public storage, when bulk paying out workers', async () => {
|
|
236
|
+
await job.initialize();
|
|
237
|
+
await job.launch();
|
|
238
|
+
await job.setup();
|
|
239
|
+
|
|
240
|
+
jest.clearAllMocks();
|
|
241
|
+
const finalResults = { results: 0 };
|
|
242
|
+
await job.bulkPayout(
|
|
243
|
+
[
|
|
244
|
+
{
|
|
245
|
+
address: WORKER1_ADDR,
|
|
246
|
+
amount: 50,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
finalResults,
|
|
250
|
+
false,
|
|
251
|
+
true
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
expect(upload).toHaveBeenCalledWith(
|
|
255
|
+
job.storageAccessData,
|
|
256
|
+
finalResults,
|
|
257
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
258
|
+
false,
|
|
259
|
+
true
|
|
260
|
+
);
|
|
261
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
262
|
+
expect(getPublicURL).toHaveBeenCalledTimes(1);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('Should return final result', async () => {
|
|
266
|
+
await job.initialize();
|
|
267
|
+
await job.launch();
|
|
268
|
+
await job.setup();
|
|
269
|
+
|
|
270
|
+
const finalResults = { results: 0 };
|
|
271
|
+
await job.bulkPayout(
|
|
272
|
+
[
|
|
273
|
+
{
|
|
274
|
+
address: WORKER1_ADDR,
|
|
275
|
+
amount: 100,
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
finalResults,
|
|
279
|
+
true
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(JSON.stringify(await job.finalResults())).toBe(
|
|
283
|
+
JSON.stringify(finalResults)
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('Should be able to abort the job', async () => {
|
|
288
|
+
await job.initialize();
|
|
289
|
+
await job.launch();
|
|
290
|
+
await job.setup();
|
|
291
|
+
|
|
292
|
+
expect(await job.abort()).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('Should be able to abort partially paid job', async () => {
|
|
296
|
+
await job.initialize();
|
|
297
|
+
await job.launch();
|
|
298
|
+
await job.setup();
|
|
299
|
+
|
|
300
|
+
const finalResults = { results: 0 };
|
|
301
|
+
await job.bulkPayout(
|
|
302
|
+
[
|
|
303
|
+
{
|
|
304
|
+
address: WORKER1_ADDR,
|
|
305
|
+
amount: 50,
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
finalResults,
|
|
309
|
+
true
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(await job.abort()).toBe(true);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('Should not be able to abort fully paid job', async () => {
|
|
316
|
+
await job.initialize();
|
|
317
|
+
await job.launch();
|
|
318
|
+
await job.setup();
|
|
319
|
+
|
|
320
|
+
const finalResults = { results: 0 };
|
|
321
|
+
await job.bulkPayout(
|
|
322
|
+
[
|
|
323
|
+
{
|
|
324
|
+
address: WORKER1_ADDR,
|
|
325
|
+
amount: 100,
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
finalResults,
|
|
329
|
+
true
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
expect(await job.abort()).toBe(false);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('Should be able to cancel the job', async () => {
|
|
336
|
+
await job.initialize();
|
|
337
|
+
await job.launch();
|
|
338
|
+
await job.setup();
|
|
339
|
+
|
|
340
|
+
expect(await job.cancel()).toBe(true);
|
|
341
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('Should be able to cancel partially paid job', async () => {
|
|
345
|
+
await job.initialize();
|
|
346
|
+
await job.launch();
|
|
347
|
+
await job.setup();
|
|
348
|
+
|
|
349
|
+
const finalResults = { results: 0 };
|
|
350
|
+
await job.bulkPayout(
|
|
351
|
+
[
|
|
352
|
+
{
|
|
353
|
+
address: WORKER1_ADDR,
|
|
354
|
+
amount: 50,
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
finalResults,
|
|
358
|
+
true
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
expect(await job.cancel()).toBe(true);
|
|
362
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('Should not be able to cancel paid job', async () => {
|
|
366
|
+
await job.initialize();
|
|
367
|
+
await job.launch();
|
|
368
|
+
await job.setup();
|
|
369
|
+
|
|
370
|
+
const finalResults = { results: 0 };
|
|
371
|
+
await job.bulkPayout(
|
|
372
|
+
[
|
|
373
|
+
{
|
|
374
|
+
address: WORKER1_ADDR,
|
|
375
|
+
amount: 100,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
finalResults,
|
|
379
|
+
true
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
expect(await job.cancel()).toBe(false);
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe('Access existing job from trusted handler', () => {
|
|
387
|
+
let job: Job;
|
|
388
|
+
|
|
389
|
+
beforeEach(async () => {
|
|
390
|
+
const originalJob = new Job({
|
|
391
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
392
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
393
|
+
manifest: manifest,
|
|
394
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
395
|
+
trustedHandlers: [TRUSTED_OPERATOR1_PRIVKEY],
|
|
396
|
+
logLevel: 'error',
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
await originalJob.initialize();
|
|
400
|
+
await originalJob.launch();
|
|
401
|
+
await originalJob.setup();
|
|
402
|
+
|
|
403
|
+
job = new Job({
|
|
404
|
+
gasPayer: NOT_TRUSTED_OPERATOR_PRIVKEY,
|
|
405
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
406
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
407
|
+
escrowAddr: originalJob.contractData?.escrowAddr,
|
|
408
|
+
factoryAddr: originalJob.contractData?.factoryAddr,
|
|
409
|
+
trustedHandlers: [TRUSTED_OPERATOR1_PRIVKEY],
|
|
410
|
+
logLevel: 'debug',
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
afterEach(() => {
|
|
415
|
+
jest.clearAllMocks();
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('Should be able to initializes the job by accessing existing escrow', async () => {
|
|
419
|
+
const initialized = await job.initialize();
|
|
420
|
+
expect(initialized).toBe(true);
|
|
421
|
+
|
|
422
|
+
expect(await job.manifestData?.manifestlink?.url).toBe('uploaded-key');
|
|
423
|
+
expect(await job.manifestData?.manifestlink?.hash).toBe('uploaded-hash');
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('Should not be able to launch the job again', async () => {
|
|
427
|
+
await job.initialize();
|
|
428
|
+
|
|
429
|
+
expect(await job.launch()).toBe(false);
|
|
430
|
+
expect(await job.status()).toBe(EscrowStatus.Pending);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('Should be able to setup the job again', async () => {
|
|
434
|
+
await job.initialize();
|
|
435
|
+
|
|
436
|
+
expect(await job.setup()).toBe(false);
|
|
437
|
+
|
|
438
|
+
expect((await job.balance())?.toString()).toBe(
|
|
439
|
+
toFullDigit(100).toString()
|
|
440
|
+
);
|
|
441
|
+
expect(await job.manifestData?.manifestlink?.url).toBe('uploaded-key');
|
|
442
|
+
expect(await job.manifestData?.manifestlink?.hash).toBe('uploaded-hash');
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('Should be able to add trusted handlers', async () => {
|
|
446
|
+
await job.initialize();
|
|
447
|
+
await job.launch();
|
|
448
|
+
|
|
449
|
+
expect(await job.isTrustedHandler(DEFAULT_GAS_PAYER_ADDR)).toBe(true);
|
|
450
|
+
|
|
451
|
+
expect(
|
|
452
|
+
await job.addTrustedHandlers([
|
|
453
|
+
TRUSTED_OPERATOR1_ADDR,
|
|
454
|
+
TRUSTED_OPERATOR2_ADDR,
|
|
455
|
+
])
|
|
456
|
+
).toBe(true);
|
|
457
|
+
|
|
458
|
+
expect(await job.isTrustedHandler(TRUSTED_OPERATOR1_ADDR)).toBe(true);
|
|
459
|
+
expect(await job.isTrustedHandler(TRUSTED_OPERATOR2_ADDR)).toBe(true);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it('Should be able to bulk payout workers', async () => {
|
|
463
|
+
await job.initialize();
|
|
464
|
+
await job.launch();
|
|
465
|
+
await job.setup();
|
|
466
|
+
|
|
467
|
+
expect(
|
|
468
|
+
await job.bulkPayout(
|
|
469
|
+
[
|
|
470
|
+
{
|
|
471
|
+
address: WORKER1_ADDR,
|
|
472
|
+
amount: 20,
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
address: WORKER2_ADDR,
|
|
476
|
+
amount: 50,
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
{}
|
|
480
|
+
)
|
|
481
|
+
).toBe(true);
|
|
482
|
+
|
|
483
|
+
// The escrow contract is still in Partial state as there's still balance left.
|
|
484
|
+
expect((await job.balance())?.toString()).toBe(
|
|
485
|
+
toFullDigit(30).toString()
|
|
486
|
+
);
|
|
487
|
+
expect(await job.status()).toBe(EscrowStatus.Partial);
|
|
488
|
+
|
|
489
|
+
// Trying to pay more than the contract balance results in failure.
|
|
490
|
+
expect(
|
|
491
|
+
await job.bulkPayout(
|
|
492
|
+
[
|
|
493
|
+
{
|
|
494
|
+
address: WORKER3_ADDR,
|
|
495
|
+
amount: 50,
|
|
496
|
+
},
|
|
497
|
+
],
|
|
498
|
+
{}
|
|
499
|
+
)
|
|
500
|
+
).toBe(false);
|
|
501
|
+
|
|
502
|
+
// Paying the remaining amount empties the escrow and updates the status correctly.
|
|
503
|
+
expect(
|
|
504
|
+
await job.bulkPayout(
|
|
505
|
+
[
|
|
506
|
+
{
|
|
507
|
+
address: WORKER3_ADDR,
|
|
508
|
+
amount: 30,
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
{}
|
|
512
|
+
)
|
|
513
|
+
).toBe(true);
|
|
514
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
515
|
+
expect(await job.status()).toBe(EscrowStatus.Paid);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
it('Should encrypt result, when bulk paying out workers', async () => {
|
|
519
|
+
await job.initialize();
|
|
520
|
+
await job.launch();
|
|
521
|
+
await job.setup();
|
|
522
|
+
|
|
523
|
+
jest.clearAllMocks();
|
|
524
|
+
const finalResults = { results: 0 };
|
|
525
|
+
await job.bulkPayout(
|
|
526
|
+
[
|
|
527
|
+
{
|
|
528
|
+
address: WORKER1_ADDR,
|
|
529
|
+
amount: 100,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
finalResults,
|
|
533
|
+
true
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
expect(upload).toHaveBeenCalledWith(
|
|
537
|
+
job.storageAccessData,
|
|
538
|
+
finalResults,
|
|
539
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
540
|
+
true,
|
|
541
|
+
false
|
|
542
|
+
);
|
|
543
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
it('Should not encrypt result, when bulk paying out workers', async () => {
|
|
547
|
+
await job.initialize();
|
|
548
|
+
await job.launch();
|
|
549
|
+
await job.setup();
|
|
550
|
+
|
|
551
|
+
jest.clearAllMocks();
|
|
552
|
+
const finalResults = { results: 0 };
|
|
553
|
+
await job.bulkPayout(
|
|
554
|
+
[
|
|
555
|
+
{
|
|
556
|
+
address: WORKER1_ADDR,
|
|
557
|
+
amount: 100,
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
finalResults,
|
|
561
|
+
false
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
expect(upload).toHaveBeenCalledWith(
|
|
565
|
+
job.storageAccessData,
|
|
566
|
+
finalResults,
|
|
567
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
568
|
+
false,
|
|
569
|
+
false
|
|
570
|
+
);
|
|
571
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('Should store result in private storage, when bulk paying out workers', async () => {
|
|
575
|
+
await job.initialize();
|
|
576
|
+
await job.launch();
|
|
577
|
+
await job.setup();
|
|
578
|
+
|
|
579
|
+
jest.clearAllMocks();
|
|
580
|
+
const finalResults = { results: 0 };
|
|
581
|
+
await job.bulkPayout(
|
|
582
|
+
[
|
|
583
|
+
{
|
|
584
|
+
address: WORKER1_ADDR,
|
|
585
|
+
amount: 100,
|
|
586
|
+
},
|
|
587
|
+
],
|
|
588
|
+
finalResults,
|
|
589
|
+
false,
|
|
590
|
+
false
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
expect(upload).toHaveBeenCalledWith(
|
|
594
|
+
job.storageAccessData,
|
|
595
|
+
finalResults,
|
|
596
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
597
|
+
false,
|
|
598
|
+
false
|
|
599
|
+
);
|
|
600
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
it('Should store result in public storage, when bulk paying out workers', async () => {
|
|
604
|
+
await job.initialize();
|
|
605
|
+
await job.launch();
|
|
606
|
+
await job.setup();
|
|
607
|
+
|
|
608
|
+
jest.clearAllMocks();
|
|
609
|
+
const finalResults = { results: 0 };
|
|
610
|
+
await job.bulkPayout(
|
|
611
|
+
[
|
|
612
|
+
{
|
|
613
|
+
address: WORKER1_ADDR,
|
|
614
|
+
amount: 50,
|
|
615
|
+
},
|
|
616
|
+
],
|
|
617
|
+
finalResults,
|
|
618
|
+
false,
|
|
619
|
+
true
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
expect(upload).toHaveBeenCalledWith(
|
|
623
|
+
job.storageAccessData,
|
|
624
|
+
finalResults,
|
|
625
|
+
job.providerData?.reputationOracle?.publicKey,
|
|
626
|
+
false,
|
|
627
|
+
true
|
|
628
|
+
);
|
|
629
|
+
expect(upload).toHaveBeenCalledTimes(1);
|
|
630
|
+
expect(getPublicURL).toHaveBeenCalledTimes(1);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it('Should return final result', async () => {
|
|
634
|
+
await job.initialize();
|
|
635
|
+
await job.launch();
|
|
636
|
+
await job.setup();
|
|
637
|
+
|
|
638
|
+
const finalResults = { results: 0 };
|
|
639
|
+
await job.bulkPayout(
|
|
640
|
+
[
|
|
641
|
+
{
|
|
642
|
+
address: WORKER1_ADDR,
|
|
643
|
+
amount: 100,
|
|
644
|
+
},
|
|
645
|
+
],
|
|
646
|
+
finalResults,
|
|
647
|
+
true
|
|
648
|
+
);
|
|
649
|
+
|
|
650
|
+
expect(JSON.stringify(await job.finalResults())).toBe(
|
|
651
|
+
JSON.stringify(finalResults)
|
|
652
|
+
);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it('Should be able to abort the job', async () => {
|
|
656
|
+
await job.initialize();
|
|
657
|
+
await job.launch();
|
|
658
|
+
await job.setup();
|
|
659
|
+
|
|
660
|
+
expect(await job.abort()).toBe(true);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
it('Should be able to abort partially paid job', async () => {
|
|
664
|
+
await job.initialize();
|
|
665
|
+
await job.launch();
|
|
666
|
+
await job.setup();
|
|
667
|
+
|
|
668
|
+
const finalResults = { results: 0 };
|
|
669
|
+
await job.bulkPayout(
|
|
670
|
+
[
|
|
671
|
+
{
|
|
672
|
+
address: WORKER1_ADDR,
|
|
673
|
+
amount: 50,
|
|
674
|
+
},
|
|
675
|
+
],
|
|
676
|
+
finalResults,
|
|
677
|
+
true
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
expect(await job.abort()).toBe(true);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
it('Should not be able to abort fully paid job', async () => {
|
|
684
|
+
await job.initialize();
|
|
685
|
+
await job.launch();
|
|
686
|
+
await job.setup();
|
|
687
|
+
|
|
688
|
+
const finalResults = { results: 0 };
|
|
689
|
+
await job.bulkPayout(
|
|
690
|
+
[
|
|
691
|
+
{
|
|
692
|
+
address: WORKER1_ADDR,
|
|
693
|
+
amount: 100,
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
finalResults,
|
|
697
|
+
true
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
expect(await job.abort()).toBe(false);
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
it('Should be able to cancel the job', async () => {
|
|
704
|
+
await job.initialize();
|
|
705
|
+
await job.launch();
|
|
706
|
+
await job.setup();
|
|
707
|
+
|
|
708
|
+
expect(await job.cancel()).toBe(true);
|
|
709
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
it('Should be able to cancel partially paid job', async () => {
|
|
713
|
+
await job.initialize();
|
|
714
|
+
await job.launch();
|
|
715
|
+
await job.setup();
|
|
716
|
+
|
|
717
|
+
const finalResults = { results: 0 };
|
|
718
|
+
await job.bulkPayout(
|
|
719
|
+
[
|
|
720
|
+
{
|
|
721
|
+
address: WORKER1_ADDR,
|
|
722
|
+
amount: 50,
|
|
723
|
+
},
|
|
724
|
+
],
|
|
725
|
+
finalResults,
|
|
726
|
+
true
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
expect(await job.cancel()).toBe(true);
|
|
730
|
+
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
it('Should not be able to cancel paid job', async () => {
|
|
734
|
+
await job.initialize();
|
|
735
|
+
await job.launch();
|
|
736
|
+
await job.setup();
|
|
737
|
+
|
|
738
|
+
const finalResults = { results: 0 };
|
|
739
|
+
await job.bulkPayout(
|
|
740
|
+
[
|
|
741
|
+
{
|
|
742
|
+
address: WORKER1_ADDR,
|
|
743
|
+
amount: 100,
|
|
744
|
+
},
|
|
745
|
+
],
|
|
746
|
+
finalResults,
|
|
747
|
+
true
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
expect(await job.cancel()).toBe(false);
|
|
751
|
+
});
|
|
752
|
+
});
|
|
753
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const DEFAULT_HMTOKEN_ADDR =
|
|
2
|
+
'0x5FbDB2315678afecb367f032d93F642f64180aa3';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_GAS_PAYER_ADDR =
|
|
5
|
+
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
6
|
+
export const DEFAULT_GAS_PAYER_PRIVKEY =
|
|
7
|
+
'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
8
|
+
|
|
9
|
+
export const REPUTATION_ORACLE_ADDR =
|
|
10
|
+
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8';
|
|
11
|
+
export const REPUTATION_ORACLE_PRIVKEY =
|
|
12
|
+
'59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d';
|
|
13
|
+
|
|
14
|
+
export const TRUSTED_OPERATOR1_ADDR =
|
|
15
|
+
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC';
|
|
16
|
+
export const TRUSTED_OPERATOR1_PRIVKEY =
|
|
17
|
+
'5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a';
|
|
18
|
+
|
|
19
|
+
export const TRUSTED_OPERATOR2_ADDR =
|
|
20
|
+
'0x90F79bf6EB2c4f870365E785982E1f101E93b906';
|
|
21
|
+
|
|
22
|
+
export const WORKER1_ADDR = '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65';
|
|
23
|
+
export const WORKER2_ADDR = '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc';
|
|
24
|
+
export const WORKER3_ADDR = '0x976EA74026E726554dB657fA54763abd0C3a0aa9';
|
|
25
|
+
|
|
26
|
+
export const NOT_TRUSTED_OPERATOR_PRIVKEY =
|
|
27
|
+
'5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365b';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Manifest } from '../../src';
|
|
2
|
+
|
|
3
|
+
const CALLBACK_URL = 'http://google.com/webback';
|
|
4
|
+
const GAS_PAYER = '0x1413862c2b7054cdbfdc181b83962cb0fc11fd92';
|
|
5
|
+
const FAKE_URL = 'http://google.com/fake';
|
|
6
|
+
const IMAGE_LABEL_BINARY = 'image_label_binary';
|
|
7
|
+
|
|
8
|
+
export const manifest: Manifest = {
|
|
9
|
+
requester_restricted_answer_set: {
|
|
10
|
+
'0': { en: 'English Answer 1' },
|
|
11
|
+
'1': {
|
|
12
|
+
en: 'English Answer 2',
|
|
13
|
+
answer_example_uri: 'https://hcaptcha.com/example_answer2.jpg',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
job_mode: 'batch',
|
|
17
|
+
request_type: IMAGE_LABEL_BINARY,
|
|
18
|
+
unsafe_content: false,
|
|
19
|
+
task_bid_price: 1,
|
|
20
|
+
oracle_stake: 0.05,
|
|
21
|
+
expiration_date: 0,
|
|
22
|
+
minimum_trust_server: 0.1,
|
|
23
|
+
minimum_trust_client: 0.1,
|
|
24
|
+
requester_accuracy_target: 0.1,
|
|
25
|
+
recording_oracle_addr: GAS_PAYER,
|
|
26
|
+
reputation_oracle_addr: GAS_PAYER,
|
|
27
|
+
reputation_agent_addr: GAS_PAYER,
|
|
28
|
+
instant_result_delivery_webhook: CALLBACK_URL,
|
|
29
|
+
requester_question: { en: 'How much money are we to make' },
|
|
30
|
+
requester_question_example: FAKE_URL,
|
|
31
|
+
job_total_tasks: 100,
|
|
32
|
+
taskdata_uri: FAKE_URL,
|
|
33
|
+
};
|