@prosopo/provider 0.2.5 → 0.2.6
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/dist/cjs/contracts/captcha/dist/contract-info/captcha.cjs +2 -2
- package/dist/tests/accounts.d.ts +11 -0
- package/dist/tests/accounts.d.ts.map +1 -0
- package/dist/tests/accounts.js +47 -0
- package/dist/tests/accounts.js.map +1 -0
- package/dist/tests/batch/commitments.test.d.ts +6 -0
- package/dist/tests/batch/commitments.test.d.ts.map +1 -0
- package/dist/tests/batch/commitments.test.js +217 -0
- package/dist/tests/batch/commitments.test.js.map +1 -0
- package/dist/tests/contract/helpers.test.d.ts +6 -0
- package/dist/tests/contract/helpers.test.d.ts.map +1 -0
- package/dist/tests/contract/helpers.test.js +58 -0
- package/dist/tests/contract/helpers.test.js.map +1 -0
- package/dist/tests/data/captchas.d.ts +37 -0
- package/dist/tests/data/captchas.d.ts.map +1 -0
- package/dist/tests/data/captchas.js +902 -0
- package/dist/tests/data/captchas.js.map +1 -0
- package/dist/tests/data/captchas1.json +53 -0
- package/dist/tests/data/captchas2.json +69 -0
- package/dist/tests/data/captchas3.json +54 -0
- package/dist/tests/data/captchas4.json +53 -0
- package/dist/tests/dataUtils/DatabaseAccounts.d.ts +35 -0
- package/dist/tests/dataUtils/DatabaseAccounts.d.ts.map +1 -0
- package/dist/tests/dataUtils/DatabaseAccounts.js +85 -0
- package/dist/tests/dataUtils/DatabaseAccounts.js.map +1 -0
- package/dist/tests/dataUtils/DatabasePopulator.d.ts +66 -0
- package/dist/tests/dataUtils/DatabasePopulator.d.ts.map +1 -0
- package/dist/tests/dataUtils/DatabasePopulator.js +264 -0
- package/dist/tests/dataUtils/DatabasePopulator.js.map +1 -0
- package/dist/tests/dataUtils/dapp-example-contract/dapp.json +648 -0
- package/dist/tests/dataUtils/dapp-example-contract/loadFiles.d.ts +4 -0
- package/dist/tests/dataUtils/dapp-example-contract/loadFiles.d.ts.map +1 -0
- package/dist/tests/dataUtils/dapp-example-contract/loadFiles.js +41 -0
- package/dist/tests/dataUtils/dapp-example-contract/loadFiles.js.map +1 -0
- package/dist/tests/dataUtils/funds.d.ts +23 -0
- package/dist/tests/dataUtils/funds.d.ts.map +1 -0
- package/dist/tests/dataUtils/funds.js +102 -0
- package/dist/tests/dataUtils/funds.js.map +1 -0
- package/dist/tests/dataUtils/populateDatabase.d.ts +15 -0
- package/dist/tests/dataUtils/populateDatabase.d.ts.map +1 -0
- package/dist/tests/dataUtils/populateDatabase.js +76 -0
- package/dist/tests/dataUtils/populateDatabase.js.map +1 -0
- package/dist/tests/getUser.d.ts +5 -0
- package/dist/tests/getUser.d.ts.map +1 -0
- package/dist/tests/getUser.js +18 -0
- package/dist/tests/getUser.js.map +1 -0
- package/dist/tests/tasks/tasks.test.d.ts +7 -0
- package/dist/tests/tasks/tasks.test.d.ts.map +1 -0
- package/dist/tests/tasks/tasks.test.js +719 -0
- package/dist/tests/tasks/tasks.test.js.map +1 -0
- package/dist/tests/util.test.d.ts +2 -0
- package/dist/tests/util.test.d.ts.map +1 -0
- package/dist/tests/util.test.js +51 -0
- package/dist/tests/util.test.js.map +1 -0
- package/package.json +10 -10
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
// Copyright (C) 2021-2022 Prosopo (UK) Ltd.
|
|
2
|
+
// This file is part of provider <https://github.com/prosopo/provider>.
|
|
3
|
+
//
|
|
4
|
+
// provider is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU General Public License as published by
|
|
6
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
// (at your option) any later version.
|
|
8
|
+
//
|
|
9
|
+
// provider is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU General Public License for more details.
|
|
13
|
+
//
|
|
14
|
+
// You should have received a copy of the GNU General Public License
|
|
15
|
+
import { AccountKey } from '../dataUtils/DatabaseAccounts.js';
|
|
16
|
+
import { BN, stringToHex, stringToU8a, u8aToHex } from '@polkadot/util';
|
|
17
|
+
import { CaptchaMerkleTree, computeCaptchaSolutionHash, computePendingRequestHash } from '@prosopo/datasets';
|
|
18
|
+
import { CaptchaStatus, DappPayee, Payee } from '@prosopo/captcha-contract';
|
|
19
|
+
import { ContractDeployer, ProsopoContractError, getBlockNumber, getDispatchError, wrapQuery } from '@prosopo/contract';
|
|
20
|
+
import { DappAbiJSON, DappWasm } from '../dataUtils/dapp-example-contract/loadFiles.js';
|
|
21
|
+
import { MockEnvironment } from '@prosopo/env';
|
|
22
|
+
import { PROVIDER, accountAddress, accountContract, accountMnemonic, getSignedTasks } from '../accounts.js';
|
|
23
|
+
import { ProsopoEnvError, getPair, hexHash, i18n } from '@prosopo/common';
|
|
24
|
+
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
25
|
+
import { at, get } from '@prosopo/util';
|
|
26
|
+
import { captchaData } from '../data/captchas.js';
|
|
27
|
+
import { createType } from '@polkadot/types';
|
|
28
|
+
import { getSendAmount, getStakeAmount, sendFunds } from '../dataUtils/funds.js';
|
|
29
|
+
import { getUser } from '../getUser.js';
|
|
30
|
+
import { parseBlockNumber } from '../../index.js';
|
|
31
|
+
import { randomAsHex, signatureVerify } from '@polkadot/util-crypto';
|
|
32
|
+
import { testConfig } from '@prosopo/config';
|
|
33
|
+
function delay(ms) {
|
|
34
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
35
|
+
}
|
|
36
|
+
export async function sleep(timeout) {
|
|
37
|
+
await delay(timeout);
|
|
38
|
+
}
|
|
39
|
+
const PROVIDER_PAYEE = Payee.dapp;
|
|
40
|
+
describe.sequential('CONTRACT TASKS', async function () {
|
|
41
|
+
beforeEach(async function (context) {
|
|
42
|
+
context.ss58Format = 42;
|
|
43
|
+
context.pairType = 'sr25519';
|
|
44
|
+
const alicePair = await getPair(context.pairType, context.ss58Format, '//Alice');
|
|
45
|
+
console.log('testConfig', testConfig);
|
|
46
|
+
context.env = new MockEnvironment(alicePair, testConfig);
|
|
47
|
+
try {
|
|
48
|
+
await context.env.isReady();
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
throw new ProsopoEnvError(e);
|
|
52
|
+
}
|
|
53
|
+
const promiseStakeDefault = wrapQuery(context.env.getContractInterface().query.getProviderStakeThreshold, context.env.getContractInterface().query)();
|
|
54
|
+
context.providerStakeThreshold = new BN((await promiseStakeDefault).toNumber());
|
|
55
|
+
});
|
|
56
|
+
afterEach(async (context) => {
|
|
57
|
+
if (context.env && 'db' in context.env)
|
|
58
|
+
await context.env.db?.close();
|
|
59
|
+
});
|
|
60
|
+
/** Gets some static solved captchas and constructions captcha solutions from them
|
|
61
|
+
* Computes the request hash for these captchas and the dappUser and then stores the request hash in the mock db
|
|
62
|
+
* @return {CaptchaSolution[], string} captchaSolutions and requestHash
|
|
63
|
+
*/
|
|
64
|
+
async function createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format) {
|
|
65
|
+
// There must exist a dappUser who can receive a captcha
|
|
66
|
+
const dappUserAccount = await getUser(env, AccountKey.dappUsers);
|
|
67
|
+
// There must exist a provider with a dataset for us to get a random dataset with solutions
|
|
68
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
69
|
+
// There must exist a dapp that is staked who can use the service
|
|
70
|
+
const dappContractAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
71
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
72
|
+
const providerDetails = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
73
|
+
.unwrap()
|
|
74
|
+
.unwrap();
|
|
75
|
+
//await sleep(132000)
|
|
76
|
+
const solvedCaptchas = await env.db.getRandomSolvedCaptchasFromSingleDataset(providerDetails.datasetId.toString(), 2);
|
|
77
|
+
const pair = await getPair(pairType, ss58Format, accountMnemonic(dappUserAccount));
|
|
78
|
+
await env.changeSigner(pair);
|
|
79
|
+
const userSalt = randomAsHex();
|
|
80
|
+
const captchaSolutions = solvedCaptchas.map((captcha) => ({
|
|
81
|
+
captchaId: captcha.captchaId,
|
|
82
|
+
salt: userSalt,
|
|
83
|
+
solution: captcha.solution,
|
|
84
|
+
captchaContentId: captcha.captchaContentId,
|
|
85
|
+
}));
|
|
86
|
+
const pendingRequestSalt = randomAsHex();
|
|
87
|
+
const requestHash = computePendingRequestHash(captchaSolutions.map((c) => c.captchaId), accountAddress(dappUserAccount), pendingRequestSalt);
|
|
88
|
+
const blockNumber = (await getBlockNumber(env.getApi())).toNumber();
|
|
89
|
+
if ('storeDappUserPending' in env.db) {
|
|
90
|
+
await env.db.storeDappUserPending(hexHash(accountAddress(dappUserAccount)), requestHash, pendingRequestSalt, 99999999999999, blockNumber);
|
|
91
|
+
}
|
|
92
|
+
const signer = env.keyring.addFromMnemonic(accountMnemonic(dappUserAccount));
|
|
93
|
+
const userSignature = signer.sign(stringToHex(requestHash));
|
|
94
|
+
signatureVerify(stringToHex(requestHash), userSignature, accountAddress(dappUserAccount));
|
|
95
|
+
return {
|
|
96
|
+
dappUserAccount,
|
|
97
|
+
captchaSolutions,
|
|
98
|
+
requestHash,
|
|
99
|
+
providerAccount,
|
|
100
|
+
dappContractAccount,
|
|
101
|
+
userSalt,
|
|
102
|
+
userSignature,
|
|
103
|
+
blockNumber,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
test('Provider registration', async function ({ env, providerStakeThreshold }) {
|
|
107
|
+
const [providerMnemonic, providerAddress] = env.createAccountAndAddToKeyring() || ['', ''];
|
|
108
|
+
const tasks = await getSignedTasks(env, [providerMnemonic, providerAddress]);
|
|
109
|
+
const stakeAmount = getStakeAmount(env, providerStakeThreshold);
|
|
110
|
+
const sendAmount = getSendAmount(env, stakeAmount);
|
|
111
|
+
await sendFunds(env, providerAddress, 'ProsopoPayee', sendAmount);
|
|
112
|
+
const queryResult = await tasks.contract.query.providerRegister(Array.from(stringToU8a(PROVIDER.url + randomAsHex().slice(0, 8))), PROVIDER.fee, PROVIDER_PAYEE);
|
|
113
|
+
if (queryResult.value.err) {
|
|
114
|
+
throw new Error(queryResult.value.err);
|
|
115
|
+
}
|
|
116
|
+
if (queryResult.value.ok?.err) {
|
|
117
|
+
throw new Error(queryResult.value.ok.err);
|
|
118
|
+
}
|
|
119
|
+
const result = await tasks.contract.tx.providerRegister(Array.from(stringToU8a(PROVIDER.url + randomAsHex().slice(0, 8))), PROVIDER.fee, PROVIDER_PAYEE);
|
|
120
|
+
console.log(JSON.stringify(result.error, null, 4));
|
|
121
|
+
expect(result?.error).to.be.undefined;
|
|
122
|
+
}, 8000);
|
|
123
|
+
test('Provider update', async ({ env }) => {
|
|
124
|
+
const providerAccount = await getUser(env, AccountKey.providers);
|
|
125
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
126
|
+
const value = new BN((await tasks.contract.query.getProviderStakeThreshold()).value.unwrap().toNumber());
|
|
127
|
+
const result = (await tasks.contract.tx.providerUpdate(Array.from(stringToU8a(PROVIDER.url + randomAsHex().slice(0, 8))), PROVIDER.fee, PROVIDER_PAYEE, { value })).result;
|
|
128
|
+
if (result?.isError && result?.dispatchError) {
|
|
129
|
+
const dispatchError = getDispatchError(result?.dispatchError);
|
|
130
|
+
throw new ProsopoContractError(dispatchError);
|
|
131
|
+
}
|
|
132
|
+
expect(result?.isError).to.be.false;
|
|
133
|
+
}, 8000);
|
|
134
|
+
test('Provider add dataset', async ({ env }) => {
|
|
135
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStake);
|
|
136
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
137
|
+
await tasks.providerSetDatasetFromFile(JSON.parse(JSON.stringify(captchaData)));
|
|
138
|
+
}, 8000);
|
|
139
|
+
test('Provider add dataset with too few captchas will fail', async ({ env }) => {
|
|
140
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStake);
|
|
141
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
142
|
+
// copy captchaData and remove all but one captcha
|
|
143
|
+
const dataset = { ...captchaData };
|
|
144
|
+
dataset.captchas = dataset.captchas.slice(0, 1);
|
|
145
|
+
try {
|
|
146
|
+
await tasks.providerSetDatasetFromFile(JSON.parse(JSON.stringify(dataset)));
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
expect(e).to.match(/Number of captchas in dataset is less than configured number of captchas/);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
test('Provider add dataset with too few solutions will fail', async ({ env }) => {
|
|
153
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStake);
|
|
154
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
155
|
+
const dataset = { ...captchaData };
|
|
156
|
+
// remove solution field from each captcha
|
|
157
|
+
dataset.captchas = dataset.captchas.map((captcha) => {
|
|
158
|
+
const { solution, ...rest } = captcha;
|
|
159
|
+
return rest;
|
|
160
|
+
});
|
|
161
|
+
try {
|
|
162
|
+
await tasks.providerSetDatasetFromFile(JSON.parse(JSON.stringify(dataset)));
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
expect(e).to.match(/Number of solutions in dataset is less than configured number of solutions/);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
test('Inactive Provider cannot add dataset', async ({ env }) => {
|
|
169
|
+
const providerAccount = await getUser(env, AccountKey.providers);
|
|
170
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
171
|
+
try {
|
|
172
|
+
await tasks.providerSetDatasetFromFile(JSON.parse(JSON.stringify(captchaData)));
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
expect(e).to.match(/ProviderInactive/);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
test('Provider approve', async ({ env, pairType, ss58Format }) => {
|
|
179
|
+
const { dappUserAccount, captchaSolutions, providerAccount, dappContractAccount, userSignature } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
180
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
181
|
+
const salt = randomAsHex();
|
|
182
|
+
const tree = new CaptchaMerkleTree();
|
|
183
|
+
const captchaSolutionsSalted = captchaSolutions.map((captcha) => ({
|
|
184
|
+
...captcha,
|
|
185
|
+
salt: salt,
|
|
186
|
+
}));
|
|
187
|
+
const captchasHashed = captchaSolutionsSalted.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
188
|
+
tree.build(captchasHashed);
|
|
189
|
+
const commitmentId = tree.root.hash;
|
|
190
|
+
const provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
191
|
+
.unwrap()
|
|
192
|
+
.unwrap();
|
|
193
|
+
const completedAt = (await env.getApi().rpc.chain.getBlock()).block.header.number.toNumber();
|
|
194
|
+
const requestedAt = completedAt - 1;
|
|
195
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
196
|
+
const commit = {
|
|
197
|
+
dappContract: accountContract(dappContractAccount),
|
|
198
|
+
datasetId: provider.datasetId,
|
|
199
|
+
id: commitmentId,
|
|
200
|
+
providerAccount: accountAddress(providerAccount),
|
|
201
|
+
userAccount: accountAddress(dappUserAccount),
|
|
202
|
+
status: CaptchaStatus.approved,
|
|
203
|
+
requestedAt,
|
|
204
|
+
completedAt,
|
|
205
|
+
userSignature: [...userSignature],
|
|
206
|
+
};
|
|
207
|
+
const queryResult = await providerTasks.contract.query.providerCommit(commit);
|
|
208
|
+
if (queryResult.value.err) {
|
|
209
|
+
throw new Error(queryResult.value.err);
|
|
210
|
+
}
|
|
211
|
+
const result = await providerTasks.contract.tx.providerCommit(commit);
|
|
212
|
+
if (result.result?.isError && result.result?.dispatchError) {
|
|
213
|
+
const dispatchError = getDispatchError(result.result?.dispatchError);
|
|
214
|
+
throw new ProsopoContractError(dispatchError);
|
|
215
|
+
}
|
|
216
|
+
expect(result.result?.isError).to.be.false;
|
|
217
|
+
if (result.error) {
|
|
218
|
+
throw new ProsopoContractError(result.error.message);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
test('Provider disapprove', async ({ env, pairType, ss58Format }) => {
|
|
222
|
+
const { dappUserAccount, captchaSolutions, providerAccount, dappContractAccount, userSignature } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
223
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
224
|
+
const salt = randomAsHex();
|
|
225
|
+
const tree = new CaptchaMerkleTree();
|
|
226
|
+
const captchaSolutionsSalted = captchaSolutions.map((captcha) => ({
|
|
227
|
+
...captcha,
|
|
228
|
+
salt: salt,
|
|
229
|
+
}));
|
|
230
|
+
const captchasHashed = captchaSolutionsSalted.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
231
|
+
tree.build(captchasHashed);
|
|
232
|
+
const commitmentId = tree.root.hash;
|
|
233
|
+
const provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
234
|
+
.unwrap()
|
|
235
|
+
.unwrap();
|
|
236
|
+
const completedAt = (await env.getApi().rpc.chain.getBlock()).block.header.number.toNumber();
|
|
237
|
+
const requestedAt = completedAt - 1;
|
|
238
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
239
|
+
await providerTasks.contract.tx.providerCommit({
|
|
240
|
+
dappContract: accountContract(dappContractAccount),
|
|
241
|
+
datasetId: provider.datasetId.toString(),
|
|
242
|
+
id: commitmentId,
|
|
243
|
+
providerAccount: accountAddress(providerAccount),
|
|
244
|
+
userAccount: accountAddress(dappUserAccount),
|
|
245
|
+
status: CaptchaStatus.disapproved,
|
|
246
|
+
requestedAt,
|
|
247
|
+
completedAt,
|
|
248
|
+
userSignature: [...userSignature],
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
test('Timestamps check', async ({ env, pairType, ss58Format }) => {
|
|
252
|
+
const salt = randomAsHex();
|
|
253
|
+
const tree = new CaptchaMerkleTree();
|
|
254
|
+
const { dappUserAccount, captchaSolutions, providerAccount, dappContractAccount, userSignature } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
255
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
256
|
+
const captchaSolutionsSalted = captchaSolutions.map((captcha) => ({
|
|
257
|
+
...captcha,
|
|
258
|
+
salt: salt,
|
|
259
|
+
}));
|
|
260
|
+
const captchasHashed = captchaSolutionsSalted.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
261
|
+
tree.build(captchasHashed);
|
|
262
|
+
const commitmentId = tree.root.hash;
|
|
263
|
+
const provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
264
|
+
.unwrap()
|
|
265
|
+
.unwrap();
|
|
266
|
+
const completedAt = (await env.getApi().rpc.chain.getBlock()).block.header.number.toNumber();
|
|
267
|
+
const requestedAt = completedAt - 1;
|
|
268
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
269
|
+
await providerTasks.contract.tx.providerCommit({
|
|
270
|
+
dappContract: accountContract(dappContractAccount),
|
|
271
|
+
datasetId: provider.datasetId.toString(),
|
|
272
|
+
id: commitmentId,
|
|
273
|
+
providerAccount: accountAddress(providerAccount),
|
|
274
|
+
userAccount: accountAddress(dappUserAccount),
|
|
275
|
+
status: CaptchaStatus.approved,
|
|
276
|
+
completedAt,
|
|
277
|
+
requestedAt,
|
|
278
|
+
userSignature: [...userSignature],
|
|
279
|
+
});
|
|
280
|
+
const commitment = (await providerTasks.contract.query.getCommit(commitmentId)).value.unwrap().unwrap();
|
|
281
|
+
// check the timestamp
|
|
282
|
+
const completedAtCheck = parseInt(commitment.completedAt.toString().replace(',', ''));
|
|
283
|
+
expect(completedAtCheck).to.be.above(0);
|
|
284
|
+
// check how much time passed after successful completion
|
|
285
|
+
const lastCorrectCaptcha = (await providerTasks.contract.query.dappOperatorLastCorrectCaptcha(accountAddress(dappUserAccount))).value
|
|
286
|
+
.unwrap()
|
|
287
|
+
.unwrap();
|
|
288
|
+
expect(Number.parseInt(lastCorrectCaptcha.before.toString())).to.be.above(0);
|
|
289
|
+
});
|
|
290
|
+
test('Provider details', async ({ env }) => {
|
|
291
|
+
try {
|
|
292
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
293
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
294
|
+
const result = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
295
|
+
.unwrap()
|
|
296
|
+
.unwrap();
|
|
297
|
+
expect(result).to.have.a.property('status');
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
throw new ProsopoEnvError(err);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
test('Provider accounts', async ({ env }) => {
|
|
304
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
305
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
306
|
+
const result = (await tasks.contract.query.getAllProviderAccounts()).value.unwrap().unwrap();
|
|
307
|
+
expect(result).to.be.an('array');
|
|
308
|
+
});
|
|
309
|
+
test('Dapp registration', async ({ env, providerStakeThreshold }) => {
|
|
310
|
+
const newAccount = env.createAccountAndAddToKeyring() || ['', ''];
|
|
311
|
+
const tasks = await getSignedTasks(env, newAccount);
|
|
312
|
+
const stakeAmount = getStakeAmount(env, providerStakeThreshold);
|
|
313
|
+
const sendAmount = getSendAmount(env, stakeAmount);
|
|
314
|
+
await sendFunds(env, accountAddress(newAccount), 'Dapp', sendAmount);
|
|
315
|
+
const dappParams = ['1000000000000000000', 1000, env.getContractInterface().address, 65, 1000000];
|
|
316
|
+
const deployer = new ContractDeployer(env.getApi(), await DappAbiJSON(), await DappWasm(), env.pair, dappParams, 0, 0, randomAsHex());
|
|
317
|
+
const deployResult = await deployer.deploy();
|
|
318
|
+
const instantiateEvent = deployResult.events.find((event) => event.event.section === 'contracts');
|
|
319
|
+
const contractAddress = String(get(instantiateEvent?.event.data, 'contract'));
|
|
320
|
+
const result = (await tasks.contract.tx.dappRegister(contractAddress, DappPayee.dapp)).result;
|
|
321
|
+
expect(result?.isError).to.be.false;
|
|
322
|
+
const dapp = (await tasks.contract.query.getDapp(contractAddress)).value.unwrap().unwrap();
|
|
323
|
+
expect(dapp.owner).to.equal(accountAddress(newAccount));
|
|
324
|
+
});
|
|
325
|
+
test('Dapp is active', async ({ env }) => {
|
|
326
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
327
|
+
const tasks = await getSignedTasks(env, dappAccount);
|
|
328
|
+
const result = await tasks.dappIsActive(accountContract(dappAccount));
|
|
329
|
+
expect(result).to.equal(true);
|
|
330
|
+
});
|
|
331
|
+
test('Dapp details', async ({ env }) => {
|
|
332
|
+
const dappAccount = await getUser(env, AccountKey.dapps);
|
|
333
|
+
const tasks = await getSignedTasks(env, dappAccount);
|
|
334
|
+
const result = (await tasks.contract.query.getDapp(accountContract(dappAccount))).value.unwrap().unwrap();
|
|
335
|
+
expect(result).to.have.a.property('status');
|
|
336
|
+
});
|
|
337
|
+
test('Dapp fund', async ({ env }) => {
|
|
338
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
339
|
+
const tasks = await getSignedTasks(env, dappAccount);
|
|
340
|
+
const value = createType(env.getContractInterface().abi.registry, 'u128', '10');
|
|
341
|
+
const dappContractAddress = accountContract(dappAccount);
|
|
342
|
+
const dappBefore = (await tasks.contract.query.getDapp(dappContractAddress)).value.unwrap().unwrap();
|
|
343
|
+
const result = (await tasks.contract.tx.dappFund(dappContractAddress, { value })).result;
|
|
344
|
+
expect(result?.isError).to.be.false;
|
|
345
|
+
const dappAfter = (await tasks.contract.query.getDapp(dappContractAddress)).value.unwrap().unwrap();
|
|
346
|
+
expect(dappBefore.balance.toNumber() + value.toNumber()).to.equal(dappAfter.balance.toNumber());
|
|
347
|
+
});
|
|
348
|
+
//TODO reinstate when https://github.com/polkadot-js/api/issues/5410 is resolved
|
|
349
|
+
// it.only('Dapp accounts', async ({env}): Promise<void> => {
|
|
350
|
+
// const account = await getUser(env, AccountKey.dapps)
|
|
351
|
+
//
|
|
352
|
+
// const tasks = await changeSigner(env, account)
|
|
353
|
+
//
|
|
354
|
+
// const result = await tasks.contractApi.getDappAccounts()
|
|
355
|
+
// console.log(result)
|
|
356
|
+
//
|
|
357
|
+
// expect(result).to.be.an('array')
|
|
358
|
+
// })
|
|
359
|
+
test('Captchas are correctly formatted before being passed to the API layer', async ({ env }) => {
|
|
360
|
+
const dappUserAccount = await getUser(env, AccountKey.dappUsers);
|
|
361
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
362
|
+
const dappUserTasks = await getSignedTasks(env, dappUserAccount);
|
|
363
|
+
const provider = (await dappUserTasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
364
|
+
.unwrap()
|
|
365
|
+
.unwrap();
|
|
366
|
+
const captchas = await dappUserTasks.getCaptchaWithProof(provider.datasetId.toString(), true, 1);
|
|
367
|
+
expect(captchas[0]).to.have.nested.property('captcha.captchaId');
|
|
368
|
+
expect(captchas[0]).to.have.nested.property('captcha.datasetId', provider.datasetId.toString());
|
|
369
|
+
expect(captchas[0]).to.have.property('proof');
|
|
370
|
+
expect(captchas[0]).to.not.have.property('solution');
|
|
371
|
+
expect(captchas[0]).to.not.have.nested.property('captcha.solution');
|
|
372
|
+
});
|
|
373
|
+
test('Captcha proofs are returned if commitment found and solution is correct', async ({ env, pairType, ss58Format, }) => {
|
|
374
|
+
// Construct a pending request hash between dappUserAccount, providerAccount and dappContractAccount
|
|
375
|
+
const { captchaSolutions, requestHash, dappUserAccount, providerAccount, dappContractAccount, userSignature } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
376
|
+
const dappUserTasks = await getSignedTasks(env, dappUserAccount);
|
|
377
|
+
const tree = new CaptchaMerkleTree();
|
|
378
|
+
const captchaSolutionsSalted = captchaSolutions;
|
|
379
|
+
const captchasHashed = captchaSolutionsSalted.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
380
|
+
tree.build(captchasHashed);
|
|
381
|
+
const commitmentId = tree.root.hash;
|
|
382
|
+
const provider = (await dappUserTasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
383
|
+
.unwrap()
|
|
384
|
+
.unwrap();
|
|
385
|
+
const completedAt = (await env.getApi().rpc.chain.getBlock()).block.header.number.toNumber();
|
|
386
|
+
const requestedAt = completedAt - 1;
|
|
387
|
+
// next part contains internal contract calls that must be run by provider
|
|
388
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
389
|
+
await providerTasks.contract.tx.providerCommit({
|
|
390
|
+
dappContract: accountContract(dappContractAccount),
|
|
391
|
+
datasetId: provider.datasetId.toString(),
|
|
392
|
+
id: commitmentId,
|
|
393
|
+
providerAccount: accountAddress(providerAccount),
|
|
394
|
+
userAccount: accountAddress(dappUserAccount),
|
|
395
|
+
status: CaptchaStatus.approved,
|
|
396
|
+
completedAt,
|
|
397
|
+
requestedAt,
|
|
398
|
+
userSignature: [...userSignature],
|
|
399
|
+
});
|
|
400
|
+
const commitment = (await providerTasks.contract.query.getCommit(commitmentId)).value.unwrap().unwrap();
|
|
401
|
+
// next part contains internal contract calls that must be run by provider
|
|
402
|
+
await env.getApi().rpc.chain.getBlockHash(commitment.completedAt);
|
|
403
|
+
const result = await providerTasks.dappUserSolution(accountAddress(dappUserAccount), accountContract(dappContractAccount), requestHash, JSON.parse(JSON.stringify(captchaSolutionsSalted)), u8aToHex(userSignature));
|
|
404
|
+
expect(result.captchas.length).to.be.eq(2);
|
|
405
|
+
const expectedProof = tree.proof(at(captchaSolutionsSalted, 0).captchaId);
|
|
406
|
+
const filteredResult = at(result.captchas.filter((res) => res.captchaId == at(captchaSolutionsSalted, 0).captchaId), 0);
|
|
407
|
+
expect(filteredResult.proof).to.deep.eq(expectedProof);
|
|
408
|
+
expect(filteredResult.captchaId).to.eq(at(captchaSolutionsSalted, 0).captchaId);
|
|
409
|
+
});
|
|
410
|
+
// test('Dapp User sending an invalid captchas causes error', async ({env}): Promise<void> => {
|
|
411
|
+
// const { requestHash } = await createMockCaptchaSolutionsAndRequestHash( env, pairType, ss58Format );
|
|
412
|
+
//
|
|
413
|
+
// await env.getContractInterface()!.changeSigner(env, provider.mnemonic as string);
|
|
414
|
+
// const providerTasks = new Tasks(env);
|
|
415
|
+
// const captchaSolutions = [
|
|
416
|
+
// { captchaId: 'blah', solution: [21], salt: 'blah' }
|
|
417
|
+
// ];
|
|
418
|
+
// const tree = new CaptchaMerkleTree();
|
|
419
|
+
// const captchasHashed = captchaSolutions.map((captcha) =>
|
|
420
|
+
// computeCaptchaSolutionHash(captcha)
|
|
421
|
+
// );
|
|
422
|
+
//
|
|
423
|
+
// tree.build(captchasHashed);
|
|
424
|
+
// const solutionPromise = providerTasks.dappUserSolution(
|
|
425
|
+
// dappUser.address,
|
|
426
|
+
// dapp.contractAccount as string,
|
|
427
|
+
// requestHash,
|
|
428
|
+
// JSON.parse(JSON.stringify(captchaSolutions)) as JSON
|
|
429
|
+
// );
|
|
430
|
+
//
|
|
431
|
+
// solutionPromise.catch((e) =>
|
|
432
|
+
// e.message.should.match(`/${ERRORS.CAPTCHA.INVALID_CAPTCHA_ID.message}/`)
|
|
433
|
+
// );
|
|
434
|
+
// });
|
|
435
|
+
//
|
|
436
|
+
// test('Dapp User sending solutions without committing to blockchain causes error', async ({env}): Promise<void> => {
|
|
437
|
+
// const { captchaSolutions, requestHash } = await createMockCaptchaSolutionsAndRequestHash( env, pairType, ss58Format );
|
|
438
|
+
//
|
|
439
|
+
// await env.getContractInterface()!.changeSigner(env, provider.mnemonic as string);
|
|
440
|
+
// const providerTasks = new Tasks(env);
|
|
441
|
+
// const tree = new CaptchaMerkleTree();
|
|
442
|
+
// const captchasHashed = captchaSolutions.map((captcha) =>
|
|
443
|
+
// computeCaptchaSolutionHash(captcha)
|
|
444
|
+
// );
|
|
445
|
+
//
|
|
446
|
+
// tree.build(captchasHashed);
|
|
447
|
+
// const solutionPromise = providerTasks.dappUserSolution(
|
|
448
|
+
// dappUser.address,
|
|
449
|
+
// dapp.contractAccount as string,
|
|
450
|
+
// requestHash,
|
|
451
|
+
// JSON.parse(JSON.stringify(captchaSolutions)) as JSON
|
|
452
|
+
// );
|
|
453
|
+
//
|
|
454
|
+
// solutionPromise.catch((e) =>
|
|
455
|
+
// e.message.should.match(
|
|
456
|
+
// `/${ERRORS.CONTRACT.CAPTCHA_SOLUTION_COMMITMENT_DOES_NOT_EXIST.message}/`
|
|
457
|
+
// )
|
|
458
|
+
// );
|
|
459
|
+
// });
|
|
460
|
+
//
|
|
461
|
+
// test('No proofs are returned if commitment found and solution is incorrect', async ({env}): Promise<void> => {
|
|
462
|
+
// const { captchaSolutions, requestHash } = await createMockCaptchaSolutionsAndRequestHash( env, pairType, ss58Format );
|
|
463
|
+
// const captchaSolutionsBad = captchaSolutions.map((original) => ({
|
|
464
|
+
// ...original,
|
|
465
|
+
// solution: [3]
|
|
466
|
+
// }));
|
|
467
|
+
// const tree = new CaptchaMerkleTree();
|
|
468
|
+
// const salt = randomAsHex();
|
|
469
|
+
// // Have to salt the solutions with random salt each time otherwise we end up with the same commitment for
|
|
470
|
+
// // multiple users
|
|
471
|
+
// const captchaSolutionsSalted = captchaSolutionsBad.map((captcha) => ({
|
|
472
|
+
// ...captcha,
|
|
473
|
+
// salt: salt
|
|
474
|
+
// }));
|
|
475
|
+
// const solutionsHashed = captchaSolutionsSalted.map((captcha) =>
|
|
476
|
+
// computeCaptchaSolutionHash(captcha)
|
|
477
|
+
// );
|
|
478
|
+
//
|
|
479
|
+
// tree.build(solutionsHashed);
|
|
480
|
+
// const commitmentId = tree.root!.hash;
|
|
481
|
+
//
|
|
482
|
+
// await env.getContractInterface()!.changeSigner(env, dappUser.mnemonic);
|
|
483
|
+
// const dappUserTasks = new Tasks(env);
|
|
484
|
+
//
|
|
485
|
+
// await ,dappUserTasks.contractApi.dappUserCommtest(
|
|
486
|
+
// dapp.contractAccount as string,
|
|
487
|
+
// datasetId as string,
|
|
488
|
+
// commitmentId,
|
|
489
|
+
// provider.address as string
|
|
490
|
+
// );
|
|
491
|
+
// // next part contains internal contract calls that must be run by provider
|
|
492
|
+
// await env.getContractInterface()!.changeSigner(env, provider.mnemonic as string);
|
|
493
|
+
// const providerTasks = new Tasks(env);
|
|
494
|
+
// const result = await providerTasks.dappUserSolution(
|
|
495
|
+
// dappUser.address,
|
|
496
|
+
// dapp.contractAccount as string,
|
|
497
|
+
// requestHash,
|
|
498
|
+
// JSON.parse(JSON.stringify(captchaSolutionsSalted)) as JSON
|
|
499
|
+
// );
|
|
500
|
+
//
|
|
501
|
+
// expect(result!.length).to.be.eq(0);
|
|
502
|
+
// });
|
|
503
|
+
test('Validates the received captchas length', async ({ env, pairType, ss58Format }) => {
|
|
504
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
505
|
+
const { captchaSolutions } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
506
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
507
|
+
// All of the captchaIds present in the solutions should be in the database
|
|
508
|
+
expect(async function () {
|
|
509
|
+
await providerTasks.validateReceivedCaptchasAgainstStoredCaptchas(captchaSolutions);
|
|
510
|
+
}).to.not.throw();
|
|
511
|
+
});
|
|
512
|
+
test('Builds the tree and gets the commitment', async ({ env, pairType, ss58Format }) => {
|
|
513
|
+
try {
|
|
514
|
+
const { captchaSolutions, dappUserAccount, userSignature } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
515
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
516
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
517
|
+
const initialTree = new CaptchaMerkleTree();
|
|
518
|
+
const captchasHashed = captchaSolutions.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
519
|
+
initialTree.build(captchasHashed);
|
|
520
|
+
const initialCommitmentId = initialTree.root.hash;
|
|
521
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
522
|
+
const provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value
|
|
523
|
+
.unwrap()
|
|
524
|
+
.unwrap();
|
|
525
|
+
const providerTasks = await getSignedTasks(env, providerAccount);
|
|
526
|
+
const completedAt = (await env.getApi().rpc.chain.getBlock()).block.header.number.toNumber();
|
|
527
|
+
const requestedAt = completedAt - 1;
|
|
528
|
+
const commit = {
|
|
529
|
+
dappContract: accountContract(dappAccount),
|
|
530
|
+
datasetId: provider.datasetId.toString(),
|
|
531
|
+
id: initialCommitmentId,
|
|
532
|
+
providerAccount: accountAddress(providerAccount),
|
|
533
|
+
userAccount: accountAddress(dappUserAccount),
|
|
534
|
+
status: CaptchaStatus.approved,
|
|
535
|
+
completedAt,
|
|
536
|
+
requestedAt,
|
|
537
|
+
userSignature: [...userSignature],
|
|
538
|
+
};
|
|
539
|
+
const queryResult = await providerTasks.contract.query.providerCommit(commit);
|
|
540
|
+
const error = queryResult.value.err || queryResult.value.ok?.err;
|
|
541
|
+
if (error) {
|
|
542
|
+
throw new Error(error);
|
|
543
|
+
}
|
|
544
|
+
const result = (await providerTasks.contract.tx.providerCommit(commit)).result;
|
|
545
|
+
expect(result?.isError).to.be.false;
|
|
546
|
+
const { commitmentId, tree } = await tasks.buildTreeAndGetCommitmentId(captchaSolutions);
|
|
547
|
+
expect(tree).to.deep.equal(initialTree);
|
|
548
|
+
expect(commitmentId).to.equal(initialCommitmentId);
|
|
549
|
+
const commitment = await wrapQuery(tasks.contract.query.getCommit, tasks.contract.query)(commitmentId);
|
|
550
|
+
expect(commitment).to.not.be.undefined;
|
|
551
|
+
}
|
|
552
|
+
catch (e) {
|
|
553
|
+
console.log(e);
|
|
554
|
+
throw e;
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
test('BuildTreeAndGetCommitment throws if commitment does not exist', async ({ env, pairType, ss58Format, }) => {
|
|
558
|
+
const { captchaSolutions, dappUserAccount } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
559
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
560
|
+
const salt = randomAsHex();
|
|
561
|
+
const captchaSolutionsSalted = captchaSolutions.map((captcha) => ({
|
|
562
|
+
...captcha,
|
|
563
|
+
salt: salt,
|
|
564
|
+
}));
|
|
565
|
+
const commitmentPromise = tasks.buildTreeAndGetCommitmentId(captchaSolutionsSalted);
|
|
566
|
+
commitmentPromise.catch((e) => e.message.should.match(new RegExp(i18n.t('CONTRACT.CAPTCHA_SOLUTION_COMMITMENT_DOES_NOT_EXIST'))));
|
|
567
|
+
});
|
|
568
|
+
test('Validates the Dapp User Solution Request is Pending', async ({ env, pairType, ss58Format, }) => {
|
|
569
|
+
const { dappUserAccount, captchaSolutions, blockNumber } = await createMockCaptchaSolutionsAndRequestHash(env, pairType, ss58Format);
|
|
570
|
+
const tasks = await getSignedTasks(env, dappUserAccount);
|
|
571
|
+
const pendingRequestSalt = randomAsHex();
|
|
572
|
+
const captchaIds = captchaSolutions.map((c) => c.captchaId);
|
|
573
|
+
const requestHash = computePendingRequestHash(captchaIds, accountAddress(dappUserAccount), pendingRequestSalt);
|
|
574
|
+
await env.db.storeDappUserPending(hexHash(accountAddress(dappUserAccount)), requestHash, pendingRequestSalt, 99999999999999, blockNumber);
|
|
575
|
+
const pendingRecord = await env.db.getDappUserPending(requestHash);
|
|
576
|
+
const valid = await tasks.validateDappUserSolutionRequestIsPending(requestHash, pendingRecord, accountAddress(dappUserAccount), captchaIds);
|
|
577
|
+
expect(valid).to.be.true;
|
|
578
|
+
});
|
|
579
|
+
test('Get random captchas and request hash', async ({ env }) => {
|
|
580
|
+
try {
|
|
581
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
582
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
583
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
584
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
585
|
+
// NOTE this test can fail if the contract contains Providers that
|
|
586
|
+
// are not present in the database. It can also fail if the contract
|
|
587
|
+
// contains providers that have loaded a different dataset to the
|
|
588
|
+
// one imported from captchasData (above)
|
|
589
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
590
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
591
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
592
|
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
593
|
+
const dappUserAccount = await getUser(env, AccountKey.dappUsers);
|
|
594
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
595
|
+
// there must be at least one provider in the contract and db
|
|
596
|
+
await getUser(env, AccountKey.providersWithStakeAndDataset);
|
|
597
|
+
const dappUserTasks = await getSignedTasks(env, dappUserAccount);
|
|
598
|
+
const solvedCaptchaCount = env.config.captchas.solved.count;
|
|
599
|
+
const unsolvedCaptchaCount = env.config.captchas.unsolved.count;
|
|
600
|
+
const { provider } = (await dappUserTasks.contract.query.getRandomActiveProvider(accountAddress(dappUserAccount), accountContract(dappAccount))).value
|
|
601
|
+
.unwrap()
|
|
602
|
+
.unwrap();
|
|
603
|
+
const { captchas, requestHash } = await dappUserTasks.getRandomCaptchasAndRequestHash(provider.datasetId.toString(), hexHash(accountAddress(dappUserAccount)));
|
|
604
|
+
expect(captchas.length).to.equal(solvedCaptchaCount + unsolvedCaptchaCount);
|
|
605
|
+
const pendingRequest = env.db?.getDappUserPending(requestHash);
|
|
606
|
+
expect(pendingRequest).to.not.be.null;
|
|
607
|
+
}
|
|
608
|
+
catch (err) {
|
|
609
|
+
throw new ProsopoEnvError(err);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
test('Validate provided captcha dataset', async ({ env }) => {
|
|
613
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
614
|
+
const tasks = await getSignedTasks(env, dappAccount);
|
|
615
|
+
const res = (await tasks.contract.query.getRandomActiveProvider(accountContract(dappAccount), accountContract(dappAccount))).value
|
|
616
|
+
.unwrap()
|
|
617
|
+
.unwrap();
|
|
618
|
+
const blockNumberParsed = parseBlockNumber(res.blockNumber.toString());
|
|
619
|
+
await tasks.validateProviderWasRandomlyChosen(accountContract(dappAccount), accountContract(dappAccount), res.provider.datasetId.toString(), blockNumberParsed);
|
|
620
|
+
const valid = await tasks
|
|
621
|
+
.validateProviderWasRandomlyChosen(accountContract(dappAccount), accountContract(dappAccount), res.provider.datasetId.toString(), blockNumberParsed)
|
|
622
|
+
.then(() => true)
|
|
623
|
+
.catch(() => false);
|
|
624
|
+
expect(valid).to.be.true;
|
|
625
|
+
});
|
|
626
|
+
test('Validate provided captcha dataset - fail', async ({ env, providerStakeThreshold }) => {
|
|
627
|
+
const providerAccount = await getUser(env, AccountKey.providers);
|
|
628
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
629
|
+
let provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value.unwrap().unwrap();
|
|
630
|
+
const resultProviderUpdate1 = (await tasks.contract.tx.providerUpdate(provider.url, provider.fee, PROVIDER_PAYEE, {
|
|
631
|
+
value: 0,
|
|
632
|
+
})).result;
|
|
633
|
+
expect(resultProviderUpdate1?.isError).to.be.false;
|
|
634
|
+
provider = (await tasks.contract.query.getProvider(accountAddress(providerAccount))).value.unwrap().unwrap();
|
|
635
|
+
expect(provider.status).to.equal('Inactive');
|
|
636
|
+
const resultproviderUpdate2 = (await tasks.contract.tx.providerUpdate(provider.url, provider.fee, PROVIDER_PAYEE, {
|
|
637
|
+
value: providerStakeThreshold,
|
|
638
|
+
})).result;
|
|
639
|
+
expect(resultproviderUpdate2?.isError).to.be.false;
|
|
640
|
+
await tasks.providerSetDatasetFromFile(JSON.parse(JSON.stringify(captchaData)));
|
|
641
|
+
const dappAccount = await getUser(env, AccountKey.dappsWithStake);
|
|
642
|
+
const dappUser = await getUser(env, AccountKey.dappUsers);
|
|
643
|
+
const dappUserTasks = await getSignedTasks(env, dappUser);
|
|
644
|
+
const res = (await dappUserTasks.contract.query.getRandomActiveProvider(accountAddress(dappUser), accountContract(dappAccount))).value
|
|
645
|
+
.unwrap()
|
|
646
|
+
.unwrap();
|
|
647
|
+
const blockNumberParsed = parseBlockNumber(res.blockNumber.toString());
|
|
648
|
+
const valid = await dappUserTasks
|
|
649
|
+
.validateProviderWasRandomlyChosen(accountAddress(dappUser), accountContract(dappAccount), '0x1dc833d14a257f21967feddafb3b3876b75b3fc9b0a2d071f29da9bfebc84f5a', blockNumberParsed)
|
|
650
|
+
.then(() => true)
|
|
651
|
+
.catch(() => false);
|
|
652
|
+
expect(valid).to.be.false;
|
|
653
|
+
});
|
|
654
|
+
test('Provider deregister', async ({ env }) => {
|
|
655
|
+
const providerAccount = await getUser(env, AccountKey.providersWithStake);
|
|
656
|
+
const tasks = await getSignedTasks(env, providerAccount);
|
|
657
|
+
const isError = (await tasks.contract.tx.providerDeregister()).result?.isError;
|
|
658
|
+
expect(isError).to.be.false;
|
|
659
|
+
});
|
|
660
|
+
// TODO find out what is making this fail occasionally
|
|
661
|
+
// test('Calculate captcha solution on the basis of Dapp users provided solutions', async ({env}): Promise<void> => {
|
|
662
|
+
// const providerAccount = await getUser(env, AccountKey.providersWithStakeAndDataset)
|
|
663
|
+
// const providerTasks = await getSignedTasks(env, providerAccount)
|
|
664
|
+
// const providerDetails = await providerTasks.contractApi.getProvider(accountAddress(providerAccount))
|
|
665
|
+
// const dappAccount = await getUser(env, AccountKey.dapps)
|
|
666
|
+
//
|
|
667
|
+
// const randomCaptchasResult = await providerTasks.db.getRandomCaptcha(false, providerDetails.datasetId)
|
|
668
|
+
// if (randomCaptchasResult) {
|
|
669
|
+
// const unsolvedCaptcha = randomCaptchasResult[0]
|
|
670
|
+
// const solution = [
|
|
671
|
+
// unsolvedCaptcha.items[0].hash || '',
|
|
672
|
+
// unsolvedCaptcha.items[2].hash || '',
|
|
673
|
+
// unsolvedCaptcha.items[3].hash || '',
|
|
674
|
+
// ]
|
|
675
|
+
// const captchaSolution: CaptchaSolution = { ...unsolvedCaptcha, solution, salt: 'blah' }
|
|
676
|
+
// const commitments: string[] = []
|
|
677
|
+
// for (let count = 0; count < 10; count++) {
|
|
678
|
+
// const commitmentId = hexHash(`test${count}`)
|
|
679
|
+
// commitments.push(commitmentId)
|
|
680
|
+
// await providerTasks.db.storeDappUserSolution(
|
|
681
|
+
// [captchaSolution],
|
|
682
|
+
// commitmentId,
|
|
683
|
+
// randomAsHex(),
|
|
684
|
+
// accountContract(dappAccount),
|
|
685
|
+
// providerDetails.datasetId.toString()
|
|
686
|
+
// )
|
|
687
|
+
// const userSolutions = await providerTasks.db.getDappUserSolutionById(commitmentId)
|
|
688
|
+
// expect(userSolutions).to.be.not.empty
|
|
689
|
+
// }
|
|
690
|
+
//
|
|
691
|
+
// const result = await providerTasks.calculateCaptchaSolutions()
|
|
692
|
+
// expect(result).to.equal(1)
|
|
693
|
+
//
|
|
694
|
+
// for (const commitment of commitments) {
|
|
695
|
+
// const userSolution = await providerTasks.db.getDappUserSolutionById(commitment)
|
|
696
|
+
// expect(userSolution?.processed).to.be.true
|
|
697
|
+
// }
|
|
698
|
+
//
|
|
699
|
+
// const providerDetailsNew = await providerTasks.contractApi.getProvider(
|
|
700
|
+
// accountAddress(providerAccount)
|
|
701
|
+
// )
|
|
702
|
+
//
|
|
703
|
+
// const captchas = await providerTasks.db.getAllCaptchasByDatasetId(providerDetailsNew.datasetId.toString())
|
|
704
|
+
// expect(captchas?.every((captcha) => captcha.datasetId === providerDetailsNew.datasetId.toString())).to.be
|
|
705
|
+
// .true
|
|
706
|
+
//
|
|
707
|
+
// expect(providerDetails.datasetId).to.not.equal(providerDetailsNew.datasetId)
|
|
708
|
+
//
|
|
709
|
+
// expect(Promise.resolve(providerTasks.db.getCaptchaById([unsolvedCaptcha.captchaId]))).to.be.rejected.then(
|
|
710
|
+
// (error) => {
|
|
711
|
+
// expect(error.message).to.equal('Failed to get captcha')
|
|
712
|
+
// }
|
|
713
|
+
// )
|
|
714
|
+
// } else {
|
|
715
|
+
// throw new ProsopoEnvError('DATABASE.CAPTCHA_GET_FAILED')
|
|
716
|
+
// }
|
|
717
|
+
// })
|
|
718
|
+
});
|
|
719
|
+
//# sourceMappingURL=tasks.test.js.map
|