@prosopo/provider 0.1.18 → 0.1.19
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/api/admin.d.ts +2 -0
- package/dist/api/admin.d.ts.map +1 -0
- package/dist/api/admin.js +58 -0
- package/dist/api/admin.js.map +1 -0
- package/dist/api/captcha.d.ts +10 -0
- package/dist/api/captcha.d.ts.map +1 -0
- package/dist/api/captcha.js +166 -0
- package/dist/api/captcha.js.map +1 -0
- package/dist/batch/commitments.d.ts +23 -0
- package/dist/batch/commitments.d.ts.map +1 -0
- package/dist/batch/commitments.js +145 -0
- package/dist/batch/commitments.js.map +1 -0
- package/dist/batch/index.d.ts +2 -0
- package/dist/batch/index.d.ts.map +1 -0
- package/dist/batch/index.js +15 -0
- package/dist/batch/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/scheduler.d.ts +5 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +49 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/tasks/calculateSolutions.d.ts +10 -0
- package/dist/tasks/calculateSolutions.d.ts.map +1 -0
- package/dist/tasks/calculateSolutions.js +92 -0
- package/dist/tasks/calculateSolutions.js.map +1 -0
- package/dist/tasks/index.d.ts +3 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +16 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/tasks.d.ts +109 -0
- package/dist/tasks/tasks.d.ts.map +1 -0
- package/dist/tasks/tasks.js +365 -0
- package/dist/tasks/tasks.js.map +1 -0
- package/dist/util.d.ts +28 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +117 -0
- package/dist/util.js.map +1 -0
- package/package.json +9 -9
- package/Dockerfile +0 -12
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Copyright 2021-2023 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { CaptchaStates } from '@prosopo/types';
|
|
15
|
+
import { ProsopoEnvError, getLogger } from '@prosopo/common';
|
|
16
|
+
import { ScheduledTaskNames } from '@prosopo/types';
|
|
17
|
+
import { Tasks } from './tasks.js';
|
|
18
|
+
import { calculateNewSolutions, checkIfTaskIsRunning, updateSolutions } from '../util.js';
|
|
19
|
+
import { captchaSort } from '@prosopo/datasets';
|
|
20
|
+
export class CalculateSolutionsTask extends Tasks {
|
|
21
|
+
constructor(env) {
|
|
22
|
+
super(env);
|
|
23
|
+
this.logger = getLogger(env.config.logLevel, 'CalculateSolutionsTask');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Apply new captcha solutions to captcha dataset and recalculate merkle tree
|
|
27
|
+
*/
|
|
28
|
+
async run() {
|
|
29
|
+
try {
|
|
30
|
+
const taskRunning = await checkIfTaskIsRunning(ScheduledTaskNames.CalculateSolution, this.db);
|
|
31
|
+
if (!taskRunning) {
|
|
32
|
+
// Get the current datasetId from the contract
|
|
33
|
+
const provider = (await this.contract.methods.getProvider(this.contract.pair.address, {})).value
|
|
34
|
+
.unwrap()
|
|
35
|
+
.unwrap();
|
|
36
|
+
// Get any unsolved CAPTCHA challenges from the database for this datasetId
|
|
37
|
+
const unsolvedCaptchas = await this.db.getAllCaptchasByDatasetId(provider.datasetId.toString(), CaptchaStates.Unsolved);
|
|
38
|
+
// edge case when a captcha dataset contains no unsolved CAPTCHA challenges
|
|
39
|
+
if (!unsolvedCaptchas) {
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
// Sort the unsolved CAPTCHA challenges by their captchaId
|
|
43
|
+
const unsolvedSorted = unsolvedCaptchas.sort(captchaSort);
|
|
44
|
+
this.logger.info(`There are ${unsolvedSorted.length} unsolved CAPTCHA challenges`);
|
|
45
|
+
// Get the solution configuration from the config file
|
|
46
|
+
const requiredNumberOfSolutions = this.captchaSolutionConfig.requiredNumberOfSolutions;
|
|
47
|
+
const winningPercentage = this.captchaSolutionConfig.solutionWinningPercentage;
|
|
48
|
+
const winningNumberOfSolutions = Math.round(requiredNumberOfSolutions * (winningPercentage / 100));
|
|
49
|
+
if (unsolvedSorted && unsolvedSorted.length > 0) {
|
|
50
|
+
const captchaIds = unsolvedSorted.map((captcha) => captcha.captchaId);
|
|
51
|
+
const solutions = (await this.db.getAllDappUserSolutions(captchaIds)) || [];
|
|
52
|
+
const solutionsToUpdate = calculateNewSolutions(solutions, winningNumberOfSolutions);
|
|
53
|
+
if (solutionsToUpdate.rows().length > 0) {
|
|
54
|
+
this.logger.info(`There are ${solutionsToUpdate.rows().length} CAPTCHA challenges to update with solutions`);
|
|
55
|
+
try {
|
|
56
|
+
// TODO polars doesn't have the captchaId field in the type
|
|
57
|
+
const captchaIdsToUpdate = [...solutionsToUpdate['captchaId'].values()];
|
|
58
|
+
const commitmentIds = solutions
|
|
59
|
+
.filter((s) => captchaIdsToUpdate.indexOf(s.captchaId) > -1)
|
|
60
|
+
.map((s) => s.commitmentId);
|
|
61
|
+
const dataset = await this.db.getDataset(provider.datasetId.toString());
|
|
62
|
+
dataset.captchas = updateSolutions(solutionsToUpdate, dataset.captchas, this.logger);
|
|
63
|
+
// store new solutions in database
|
|
64
|
+
await this.providerSetDataset(dataset);
|
|
65
|
+
// mark user solutions as used to calculate new solutions
|
|
66
|
+
await this.db.flagProcessedDappUserSolutions(captchaIdsToUpdate);
|
|
67
|
+
// mark user commitments as used to calculate new solutions
|
|
68
|
+
await this.db.flagProcessedDappUserCommitments(commitmentIds);
|
|
69
|
+
// remove old captcha challenges from database
|
|
70
|
+
await this.db.removeCaptchas(captchaIdsToUpdate);
|
|
71
|
+
return solutionsToUpdate.rows().length;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.logger.error(error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.logger.info(`There are no CAPTCHA challenges that require their solutions to be updated`);
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// TODO fix error handling
|
|
88
|
+
throw new ProsopoEnvError(error, 'GENERAL.CALCULATE_CAPTCHA_SOLUTION');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=calculateSolutions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculateSolutions.js","sourceRoot":"","sources":["../../src/tasks/calculateSolutions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAaA,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2021-2023 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
export * from './tasks.js';
|
|
15
|
+
export * from './calculateSolutions.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { ArgumentTypes, Captcha, CaptchaConfig, CaptchaSolution, CaptchaSolutionConfig, CaptchaWithProof, DappUserSolutionResult, DatasetRaw, DatasetWithIds, Hash, PendingCaptchaRequest, ProsopoConfig, Provider, ProviderRegistered } from '@prosopo/types';
|
|
2
|
+
import { Header } from '@polkadot/types/interfaces';
|
|
3
|
+
import { CaptchaMerkleTree } from '@prosopo/datasets';
|
|
4
|
+
import { ContractPromise } from '@polkadot/api-contract';
|
|
5
|
+
import { Database, UserCommitmentRecord } from '@prosopo/types-database';
|
|
6
|
+
import { Logger } from '@prosopo/common';
|
|
7
|
+
import { ProsopoCaptchaContract } from '@prosopo/contract';
|
|
8
|
+
import { ProviderEnvironment } from '@prosopo/types-env';
|
|
9
|
+
import { SubmittableResult } from '@polkadot/api';
|
|
10
|
+
/**
|
|
11
|
+
* @description Tasks that are shared by the API and CLI
|
|
12
|
+
*/
|
|
13
|
+
export declare class Tasks {
|
|
14
|
+
contract: ProsopoCaptchaContract;
|
|
15
|
+
db: Database;
|
|
16
|
+
captchaConfig: CaptchaConfig;
|
|
17
|
+
captchaSolutionConfig: CaptchaSolutionConfig;
|
|
18
|
+
logger: Logger;
|
|
19
|
+
config: ProsopoConfig;
|
|
20
|
+
constructor(env: ProviderEnvironment);
|
|
21
|
+
providerSetDatasetFromFile(file: JSON): Promise<SubmittableResult | undefined>;
|
|
22
|
+
providerSetDataset(datasetRaw: DatasetRaw): Promise<SubmittableResult | undefined>;
|
|
23
|
+
/**
|
|
24
|
+
* @description Get random captchas that are solved or not solved, along with the merkle proof for each
|
|
25
|
+
* @param {string} datasetId the id of the data set
|
|
26
|
+
* @param {boolean} solved `true` when captcha is solved
|
|
27
|
+
* @param {number} size the number of records to be returned
|
|
28
|
+
*/
|
|
29
|
+
getCaptchaWithProof(datasetId: ArgumentTypes.Hash, solved: boolean, size: number): Promise<CaptchaWithProof[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Validate and store the text captcha solution(s) from the Dapp User in a web2 environment
|
|
32
|
+
* @param {string} userAccount
|
|
33
|
+
* @param {string} dappAccount
|
|
34
|
+
* @param {string} requestHash
|
|
35
|
+
* @param {JSON} captchas
|
|
36
|
+
* @param {string} signature
|
|
37
|
+
* @return {Promise<DappUserSolutionResult>} result containing the contract event
|
|
38
|
+
*/
|
|
39
|
+
dappUserSolution(userAccount: string, dappAccount: string, requestHash: string, captchas: CaptchaSolution[], signature: string): Promise<DappUserSolutionResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Validate that the dapp is active in the contract
|
|
42
|
+
*/
|
|
43
|
+
dappIsActive(dappAccount: string): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Gets provider status in contract
|
|
46
|
+
*/
|
|
47
|
+
providerStatus(): Promise<ProviderRegistered>;
|
|
48
|
+
/**
|
|
49
|
+
* Validate length of received captchas array matches length of captchas found in database
|
|
50
|
+
* Validate that the datasetId is the same for all captchas and is equal to the datasetId on the stored captchas
|
|
51
|
+
*/
|
|
52
|
+
validateReceivedCaptchasAgainstStoredCaptchas(captchas: CaptchaSolution[]): Promise<{
|
|
53
|
+
storedCaptchas: Captcha[];
|
|
54
|
+
receivedCaptchas: CaptchaSolution[];
|
|
55
|
+
captchaIds: string[];
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Build merkle tree and get commitment from contract, returning the tree, commitment, and commitmentId
|
|
59
|
+
* @param {CaptchaSolution[]} captchaSolutions
|
|
60
|
+
* @returns {Promise<{ tree: CaptchaMerkleTree, commitment: CaptchaSolutionCommitment, commitmentId: string }>}
|
|
61
|
+
*/
|
|
62
|
+
buildTreeAndGetCommitmentId(captchaSolutions: CaptchaSolution[]): Promise<{
|
|
63
|
+
tree: CaptchaMerkleTree;
|
|
64
|
+
commitmentId: string;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Validate that a Dapp User is responding to their own pending captcha request
|
|
68
|
+
* @param {string} requestHash
|
|
69
|
+
* @param {PendingCaptchaRequest} pendingRecord
|
|
70
|
+
* @param {string} userAccount
|
|
71
|
+
* @param {string[]} captchaIds
|
|
72
|
+
*/
|
|
73
|
+
validateDappUserSolutionRequestIsPending(requestHash: string, pendingRecord: PendingCaptchaRequest, userAccount: string, captchaIds: string[]): Promise<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Get two random captchas from specified dataset, create the response and store a hash of it, marked as pending
|
|
76
|
+
* @param {string} datasetId
|
|
77
|
+
* @param {string} userAccount
|
|
78
|
+
*/
|
|
79
|
+
getRandomCaptchasAndRequestHash(datasetId: string, userAccount: string): Promise<{
|
|
80
|
+
captchas: CaptchaWithProof[];
|
|
81
|
+
requestHash: string;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Block by block search for blockNo
|
|
85
|
+
*/
|
|
86
|
+
isRecentBlock(contract: ContractPromise, header: Header, blockNo: number, depth?: number): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Validate that provided `datasetId` was a result of calling `get_random_provider` method
|
|
89
|
+
* @param {string} userAccount - Same user that called `get_random_provider`
|
|
90
|
+
* @param {string} dappContractAccount - account of dapp that is requesting captcha
|
|
91
|
+
* @param {string} datasetId - `captcha_dataset_id` from the result of `get_random_provider`
|
|
92
|
+
* @param {string} blockNumber - Block on which `get_random_provider` was called
|
|
93
|
+
*/
|
|
94
|
+
validateProviderWasRandomlyChosen(userAccount: string, dappContractAccount: string, datasetId: string | Hash, blockNumber: number): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Get payment info for a transaction
|
|
97
|
+
* @param {string} userAccount
|
|
98
|
+
* @param {string} blockHash
|
|
99
|
+
* @param {string} txHash
|
|
100
|
+
* @returns {Promise<RuntimeDispatchInfo|null>}
|
|
101
|
+
*/
|
|
102
|
+
private getPaymentInfo;
|
|
103
|
+
getDappUserCommitmentById(commitmentId: string): Promise<UserCommitmentRecord>;
|
|
104
|
+
getDappUserCommitmentByAccount(userAccount: string): Promise<UserCommitmentRecord | undefined>;
|
|
105
|
+
getProviderDetails(): Promise<Provider>;
|
|
106
|
+
/** Get the dataset from the databse */
|
|
107
|
+
getProviderDataset(datasetId: string): Promise<DatasetWithIds>;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=tasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/tasks/tasks.ts"],"names":[],"mappings":"AAaA,OAAO,EACH,aAAa,EACb,OAAO,EACP,aAAa,EACb,eAAe,EACf,qBAAqB,EAErB,gBAAgB,EAEhB,sBAAsB,EAEtB,UAAU,EACV,cAAc,EACd,IAAI,EACJ,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACR,kBAAkB,EAErB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAa,MAAM,EAAsC,MAAM,4BAA4B,CAAA;AAClG,OAAO,EACH,iBAAiB,EAOpB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,EAAE,MAAM,EAA8B,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,sBAAsB,EAA6B,MAAM,mBAAmB,CAAA;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAMjD;;GAEG;AACH,qBAAa,KAAK;IACd,QAAQ,EAAE,sBAAsB,CAAA;IAEhC,EAAE,EAAE,QAAQ,CAAA;IAEZ,aAAa,EAAE,aAAa,CAAA;IAE5B,qBAAqB,EAAE,qBAAqB,CAAA;IAE5C,MAAM,EAAE,MAAM,CAAA;IAEd,MAAM,EAAE,aAAa,CAAA;gBAET,GAAG,EAAE,mBAAmB;IAiB9B,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAM9E,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAmCxF;;;;;OAKG;IACG,mBAAmB,CACrB,SAAS,EAAE,aAAa,CAAC,IAAI,EAC7B,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,EAAE,CAAC;IA0B9B;;;;;;;;OAQG;IACG,gBAAgB,CAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,CAAC;IAsElC;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMzD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAYnD;;;OAGG;IACG,6CAA6C,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QACtF,cAAc,EAAE,OAAO,EAAE,CAAA;QACzB,gBAAgB,EAAE,eAAe,EAAE,CAAA;QACnC,UAAU,EAAE,MAAM,EAAE,CAAA;KACvB,CAAC;IAuBF;;;;OAIG;IACG,2BAA2B,CAC7B,gBAAgB,EAAE,eAAe,EAAE,GACpC,OAAO,CAAC;QAAE,IAAI,EAAE,iBAAiB,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAiB7D;;;;;;OAMG;IACG,wCAAwC,CAC1C,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,qBAAqB,EACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,OAAO,CAAC;IAcnB;;;;OAIG;IACG,+BAA+B,CACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAoCjE;;OAEG;IACG,aAAa,CACf,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,SAAiD,GACvD,OAAO,CAAC,OAAO,CAAC;IAenB;;;;;;OAMG;IACG,iCAAiC,CACnC,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,EAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,WAAW,EAAE,MAAM;IA2CvB;;;;;;OAMG;YACW,cAAc;IA4BtB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAc9E,8BAA8B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAa9F,kBAAkB,IAAI,OAAO,CAAC,QAAQ,CAAC;IAI7C,uCAAuC;IAEjC,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAGvE"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// Copyright 2021-2023 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { ArgumentTypes, CaptchaStatus, } from '@prosopo/types';
|
|
15
|
+
import { CaptchaMerkleTree, buildDataset, compareCaptchaSolutions, computeCaptchaSolutionHash, computePendingRequestHash, parseAndSortCaptchaSolutions, parseCaptchaDataset, } from '@prosopo/datasets';
|
|
16
|
+
import { ProsopoEnvError, getLogger } from '@prosopo/common';
|
|
17
|
+
import { getBlockNumber, wrapQuery } from '@prosopo/contract';
|
|
18
|
+
import { at } from '@prosopo/util';
|
|
19
|
+
import { hexToU8a, stringToHex } from '@polkadot/util';
|
|
20
|
+
import { randomAsHex, signatureVerify } from '@polkadot/util-crypto';
|
|
21
|
+
import { shuffleArray } from '../util.js';
|
|
22
|
+
/**
|
|
23
|
+
* @description Tasks that are shared by the API and CLI
|
|
24
|
+
*/
|
|
25
|
+
export class Tasks {
|
|
26
|
+
constructor(env) {
|
|
27
|
+
if (!env.contractInterface) {
|
|
28
|
+
throw new ProsopoEnvError('CONTRACT.CONTRACT_UNDEFINED', this.constructor.name, {}, { contractAddress: env.contractAddress });
|
|
29
|
+
}
|
|
30
|
+
this.config = env.config;
|
|
31
|
+
this.contract = env.contractInterface;
|
|
32
|
+
this.db = env.db;
|
|
33
|
+
this.captchaConfig = env.config.captchas;
|
|
34
|
+
this.captchaSolutionConfig = env.config.captchaSolutions;
|
|
35
|
+
this.logger = getLogger(env.config.logLevel, 'Tasks');
|
|
36
|
+
}
|
|
37
|
+
async providerSetDatasetFromFile(file) {
|
|
38
|
+
const datasetRaw = parseCaptchaDataset(file);
|
|
39
|
+
this.logger.debug('Parsed raw data set');
|
|
40
|
+
return await this.providerSetDataset(datasetRaw);
|
|
41
|
+
}
|
|
42
|
+
async providerSetDataset(datasetRaw) {
|
|
43
|
+
// check that the number of captchas contained within dataset.captchas is greater than or equal to the total
|
|
44
|
+
// number of captchas that must be served
|
|
45
|
+
if (datasetRaw.captchas.length < this.config.captchas.solved.count + this.config.captchas.unsolved.count) {
|
|
46
|
+
throw new ProsopoEnvError('DATASET.CAPTCHAS_COUNT_LESS_THAN_CONFIGURED', this.providerSetDataset.name);
|
|
47
|
+
}
|
|
48
|
+
// check that the number of solutions contained within dataset.captchas is greater than or equal to the number
|
|
49
|
+
// of solved captchas that must be served
|
|
50
|
+
const solutions = datasetRaw.captchas
|
|
51
|
+
.map((captcha) => (captcha.solution ? 1 : 0))
|
|
52
|
+
.reduce((partialSum, b) => partialSum + b, 0);
|
|
53
|
+
if (solutions < this.config.captchas.solved.count) {
|
|
54
|
+
throw new ProsopoEnvError('DATASET.SOLUTIONS_COUNT_LESS_THAN_CONFIGURED', this.providerSetDataset.name);
|
|
55
|
+
}
|
|
56
|
+
const dataset = await buildDataset(datasetRaw);
|
|
57
|
+
if (!dataset.datasetId || !dataset.datasetContentId) {
|
|
58
|
+
throw new ProsopoEnvError('DATASET.DATASET_ID_UNDEFINED', this.providerSetDataset.name);
|
|
59
|
+
}
|
|
60
|
+
await this.db?.storeDataset(dataset);
|
|
61
|
+
// catch any errors before running the tx
|
|
62
|
+
await wrapQuery(this.contract.query.providerSetDataset, this.contract.query)(dataset.datasetId, dataset.datasetContentId);
|
|
63
|
+
const txResult = await this.contract.methods.providerSetDataset(dataset.datasetId, dataset.datasetContentId, {
|
|
64
|
+
value: 0,
|
|
65
|
+
});
|
|
66
|
+
return txResult.result;
|
|
67
|
+
}
|
|
68
|
+
// Other tasks
|
|
69
|
+
/**
|
|
70
|
+
* @description Get random captchas that are solved or not solved, along with the merkle proof for each
|
|
71
|
+
* @param {string} datasetId the id of the data set
|
|
72
|
+
* @param {boolean} solved `true` when captcha is solved
|
|
73
|
+
* @param {number} size the number of records to be returned
|
|
74
|
+
*/
|
|
75
|
+
async getCaptchaWithProof(datasetId, solved, size) {
|
|
76
|
+
const captchaDocs = await this.db.getRandomCaptcha(solved, datasetId, size);
|
|
77
|
+
if (captchaDocs) {
|
|
78
|
+
const captchas = [];
|
|
79
|
+
for (const captcha of captchaDocs) {
|
|
80
|
+
const datasetDetails = await this.db.getDatasetDetails(datasetId);
|
|
81
|
+
const tree = new CaptchaMerkleTree();
|
|
82
|
+
if (datasetDetails.contentTree) {
|
|
83
|
+
tree.layers = datasetDetails.contentTree;
|
|
84
|
+
const proof = tree.proof(captcha.captchaContentId);
|
|
85
|
+
// cannot pass solution to dapp user as they are required to solve the captcha!
|
|
86
|
+
delete captcha.solution;
|
|
87
|
+
captcha.items = shuffleArray(captcha.items);
|
|
88
|
+
captchas.push({ captcha, proof });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return captchas;
|
|
92
|
+
}
|
|
93
|
+
throw new ProsopoEnvError('DATABASE.CAPTCHA_GET_FAILED', this.getCaptchaWithProof.name, {}, { datasetId, solved, size });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validate and store the text captcha solution(s) from the Dapp User in a web2 environment
|
|
97
|
+
* @param {string} userAccount
|
|
98
|
+
* @param {string} dappAccount
|
|
99
|
+
* @param {string} requestHash
|
|
100
|
+
* @param {JSON} captchas
|
|
101
|
+
* @param {string} signature
|
|
102
|
+
* @return {Promise<DappUserSolutionResult>} result containing the contract event
|
|
103
|
+
*/
|
|
104
|
+
async dappUserSolution(userAccount, dappAccount, requestHash, captchas, signature // the signature to indicate ownership of account (web2 only)
|
|
105
|
+
) {
|
|
106
|
+
if (!(await this.dappIsActive(dappAccount))) {
|
|
107
|
+
throw new ProsopoEnvError('CONTRACT.DAPP_NOT_ACTIVE', this.getPaymentInfo.name, {}, { dappAccount });
|
|
108
|
+
}
|
|
109
|
+
// check that the signature is valid (i.e. the web2 user has signed the message with their private key, proving they own their account)
|
|
110
|
+
const verification = signatureVerify(stringToHex(requestHash), signature, userAccount);
|
|
111
|
+
if (!verification.isValid) {
|
|
112
|
+
// the signature is not valid, so the user is not the owner of the account. May have given a false account address with good reputation in an attempt to impersonate
|
|
113
|
+
throw new ProsopoEnvError('GENERAL.INVALID_SIGNATURE', this.dappUserSolution.name, {}, { userAccount });
|
|
114
|
+
}
|
|
115
|
+
let response = {
|
|
116
|
+
captchas: [],
|
|
117
|
+
solutionApproved: false,
|
|
118
|
+
};
|
|
119
|
+
const { storedCaptchas, receivedCaptchas, captchaIds } = await this.validateReceivedCaptchasAgainstStoredCaptchas(captchas);
|
|
120
|
+
const { tree, commitmentId } = await this.buildTreeAndGetCommitmentId(receivedCaptchas);
|
|
121
|
+
const provider = (await this.contract.methods.getProvider(this.contract.pair.address, {})).value
|
|
122
|
+
.unwrap()
|
|
123
|
+
.unwrap();
|
|
124
|
+
const pendingRecord = await this.db.getDappUserPending(requestHash);
|
|
125
|
+
const pendingRequest = await this.validateDappUserSolutionRequestIsPending(requestHash, pendingRecord, userAccount, captchaIds);
|
|
126
|
+
// Only do stuff if the request is in the local DB
|
|
127
|
+
const userSignature = hexToU8a(signature);
|
|
128
|
+
const blockNumber = (await getBlockNumber(this.contract.api)).toNumber();
|
|
129
|
+
if (pendingRequest) {
|
|
130
|
+
const commit = {
|
|
131
|
+
id: commitmentId,
|
|
132
|
+
userAccount: userAccount,
|
|
133
|
+
dappContract: dappAccount,
|
|
134
|
+
providerAccount: this.contract.pair.address,
|
|
135
|
+
datasetId: provider.datasetId.toString(),
|
|
136
|
+
status: CaptchaStatus.pending,
|
|
137
|
+
userSignature: Array.from(userSignature),
|
|
138
|
+
requestedAt: pendingRecord.requestedAtBlock,
|
|
139
|
+
completedAt: blockNumber,
|
|
140
|
+
processed: false,
|
|
141
|
+
batched: false,
|
|
142
|
+
};
|
|
143
|
+
await this.db.storeDappUserSolution(receivedCaptchas, commit);
|
|
144
|
+
if (compareCaptchaSolutions(receivedCaptchas, storedCaptchas)) {
|
|
145
|
+
response = {
|
|
146
|
+
captchas: captchaIds.map((id) => ({
|
|
147
|
+
captchaId: id,
|
|
148
|
+
proof: tree.proof(id),
|
|
149
|
+
})),
|
|
150
|
+
solutionApproved: true,
|
|
151
|
+
};
|
|
152
|
+
await this.db.approveDappUserCommitment(commitmentId);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
response = {
|
|
156
|
+
captchas: captchaIds.map((id) => ({
|
|
157
|
+
captchaId: id,
|
|
158
|
+
proof: [[]],
|
|
159
|
+
})),
|
|
160
|
+
solutionApproved: false,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return response;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Validate that the dapp is active in the contract
|
|
168
|
+
*/
|
|
169
|
+
async dappIsActive(dappAccount) {
|
|
170
|
+
const dapp = await wrapQuery(this.contract.query.getDapp, this.contract.query)(dappAccount);
|
|
171
|
+
//dapp.status.isActive doesn't work: https://substrate.stackexchange.com/questions/6333/how-do-we-work-with-polkadot-js-enums-in-typescript
|
|
172
|
+
return dapp.status.toString() === 'Active';
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Gets provider status in contract
|
|
176
|
+
*/
|
|
177
|
+
async providerStatus() {
|
|
178
|
+
try {
|
|
179
|
+
const provider = await wrapQuery(this.contract.query.getProvider, this.contract.query)(this.contract.pair.address);
|
|
180
|
+
return { status: provider.status ? 'Registered' : 'Unregistered' };
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
return { status: 'Unregistered' };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Validate length of received captchas array matches length of captchas found in database
|
|
188
|
+
* Validate that the datasetId is the same for all captchas and is equal to the datasetId on the stored captchas
|
|
189
|
+
*/
|
|
190
|
+
async validateReceivedCaptchasAgainstStoredCaptchas(captchas) {
|
|
191
|
+
const receivedCaptchas = parseAndSortCaptchaSolutions(captchas);
|
|
192
|
+
const captchaIds = receivedCaptchas.map((captcha) => captcha.captchaId);
|
|
193
|
+
const storedCaptchas = await this.db.getCaptchaById(captchaIds);
|
|
194
|
+
if (!storedCaptchas || receivedCaptchas.length !== storedCaptchas.length) {
|
|
195
|
+
throw new ProsopoEnvError('CAPTCHA.INVALID_CAPTCHA_ID', this.validateReceivedCaptchasAgainstStoredCaptchas.name, {}, captchas);
|
|
196
|
+
}
|
|
197
|
+
if (!storedCaptchas.every((captcha) => captcha.datasetId === at(storedCaptchas, 0).datasetId)) {
|
|
198
|
+
throw new ProsopoEnvError('CAPTCHA.DIFFERENT_DATASET_IDS', this.validateReceivedCaptchasAgainstStoredCaptchas.name, {}, captchas);
|
|
199
|
+
}
|
|
200
|
+
return { storedCaptchas, receivedCaptchas, captchaIds };
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Build merkle tree and get commitment from contract, returning the tree, commitment, and commitmentId
|
|
204
|
+
* @param {CaptchaSolution[]} captchaSolutions
|
|
205
|
+
* @returns {Promise<{ tree: CaptchaMerkleTree, commitment: CaptchaSolutionCommitment, commitmentId: string }>}
|
|
206
|
+
*/
|
|
207
|
+
async buildTreeAndGetCommitmentId(captchaSolutions) {
|
|
208
|
+
const tree = new CaptchaMerkleTree();
|
|
209
|
+
const solutionsHashed = captchaSolutions.map((captcha) => computeCaptchaSolutionHash(captcha));
|
|
210
|
+
tree.build(solutionsHashed);
|
|
211
|
+
const commitmentId = tree.root?.hash;
|
|
212
|
+
if (!commitmentId) {
|
|
213
|
+
throw new ProsopoEnvError('CONTRACT.CAPTCHA_SOLUTION_COMMITMENT_DOES_NOT_EXIST', this.buildTreeAndGetCommitmentId.name, {}, { commitmentId: commitmentId });
|
|
214
|
+
}
|
|
215
|
+
return { tree, commitmentId };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Validate that a Dapp User is responding to their own pending captcha request
|
|
219
|
+
* @param {string} requestHash
|
|
220
|
+
* @param {PendingCaptchaRequest} pendingRecord
|
|
221
|
+
* @param {string} userAccount
|
|
222
|
+
* @param {string[]} captchaIds
|
|
223
|
+
*/
|
|
224
|
+
async validateDappUserSolutionRequestIsPending(requestHash, pendingRecord, userAccount, captchaIds) {
|
|
225
|
+
const currentTime = Date.now();
|
|
226
|
+
if (pendingRecord.deadlineTimestamp < currentTime) {
|
|
227
|
+
// deadline for responding to the captcha has expired
|
|
228
|
+
this.logger.info('Deadline for responding to captcha has expired');
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
if (pendingRecord) {
|
|
232
|
+
const pendingHashComputed = computePendingRequestHash(captchaIds, userAccount, pendingRecord.salt);
|
|
233
|
+
return requestHash === pendingHashComputed;
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get two random captchas from specified dataset, create the response and store a hash of it, marked as pending
|
|
239
|
+
* @param {string} datasetId
|
|
240
|
+
* @param {string} userAccount
|
|
241
|
+
*/
|
|
242
|
+
async getRandomCaptchasAndRequestHash(datasetId, userAccount) {
|
|
243
|
+
const dataset = await this.db.getDatasetDetails(datasetId);
|
|
244
|
+
if (!dataset) {
|
|
245
|
+
throw new ProsopoEnvError('DATABASE.DATASET_GET_FAILED');
|
|
246
|
+
}
|
|
247
|
+
const unsolvedCount = Math.abs(Math.trunc(this.captchaConfig.unsolved.count));
|
|
248
|
+
const solvedCount = Math.abs(Math.trunc(this.captchaConfig.solved.count));
|
|
249
|
+
if (!solvedCount) {
|
|
250
|
+
throw new ProsopoEnvError('CONFIG.INVALID_CAPTCHA_NUMBER');
|
|
251
|
+
}
|
|
252
|
+
const solved = await this.getCaptchaWithProof(datasetId, true, solvedCount);
|
|
253
|
+
let unsolved = [];
|
|
254
|
+
if (unsolvedCount) {
|
|
255
|
+
unsolved = await this.getCaptchaWithProof(datasetId, false, unsolvedCount);
|
|
256
|
+
}
|
|
257
|
+
const captchas = shuffleArray([...solved, ...unsolved]);
|
|
258
|
+
const salt = randomAsHex();
|
|
259
|
+
const requestHash = computePendingRequestHash(captchas.map((c) => c.captcha.captchaId), userAccount, salt);
|
|
260
|
+
const currentTime = Date.now();
|
|
261
|
+
const timeLimit = captchas.map((captcha) => captcha.captcha.timeLimitMs || 30000).reduce((a, b) => a + b, 0);
|
|
262
|
+
const deadlineTs = timeLimit + currentTime;
|
|
263
|
+
const currentBlockNumber = await getBlockNumber(this.contract.api);
|
|
264
|
+
await this.db.storeDappUserPending(userAccount, requestHash, salt, deadlineTs, currentBlockNumber.toNumber());
|
|
265
|
+
return { captchas, requestHash };
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Block by block search for blockNo
|
|
269
|
+
*/
|
|
270
|
+
async isRecentBlock(contract, header, blockNo, depth = this.captchaSolutionConfig.captchaBlockRecency) {
|
|
271
|
+
if (depth == 0) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
const headerBlockNo = header.number.toPrimitive();
|
|
275
|
+
if (headerBlockNo === blockNo) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
const parent = await contract.api.rpc.chain.getBlock(header.parentHash);
|
|
279
|
+
return this.isRecentBlock(contract, parent.block.header, blockNo, depth - 1);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Validate that provided `datasetId` was a result of calling `get_random_provider` method
|
|
283
|
+
* @param {string} userAccount - Same user that called `get_random_provider`
|
|
284
|
+
* @param {string} dappContractAccount - account of dapp that is requesting captcha
|
|
285
|
+
* @param {string} datasetId - `captcha_dataset_id` from the result of `get_random_provider`
|
|
286
|
+
* @param {string} blockNumber - Block on which `get_random_provider` was called
|
|
287
|
+
*/
|
|
288
|
+
async validateProviderWasRandomlyChosen(userAccount, dappContractAccount, datasetId, blockNumber) {
|
|
289
|
+
const contract = await this.contract.contract;
|
|
290
|
+
if (!contract) {
|
|
291
|
+
throw new ProsopoEnvError('CONTRACT.CONTRACT_UNDEFINED', this.validateProviderWasRandomlyChosen.name);
|
|
292
|
+
}
|
|
293
|
+
const header = await contract.api.rpc.chain.getHeader();
|
|
294
|
+
const isBlockNoValid = await this.isRecentBlock(contract, header, blockNumber);
|
|
295
|
+
if (!isBlockNoValid) {
|
|
296
|
+
throw new ProsopoEnvError('CAPTCHA.INVALID_BLOCK_NO', this.validateProviderWasRandomlyChosen.name, {}, {
|
|
297
|
+
userAccount,
|
|
298
|
+
dappContractAccount,
|
|
299
|
+
datasetId,
|
|
300
|
+
header,
|
|
301
|
+
blockNumber,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const block = (await contract.api.rpc.chain.getBlockHash(blockNumber));
|
|
305
|
+
const randomProviderAndBlockNo = await this.contract.queryAtBlock(block, 'getRandomActiveProvider', [userAccount, dappContractAccount]);
|
|
306
|
+
if (datasetId.toString().localeCompare(randomProviderAndBlockNo.provider.datasetId.toString())) {
|
|
307
|
+
throw new ProsopoEnvError('DATASET.INVALID_DATASET_ID', this.validateProviderWasRandomlyChosen.name, {}, randomProviderAndBlockNo);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get payment info for a transaction
|
|
312
|
+
* @param {string} userAccount
|
|
313
|
+
* @param {string} blockHash
|
|
314
|
+
* @param {string} txHash
|
|
315
|
+
* @returns {Promise<RuntimeDispatchInfo|null>}
|
|
316
|
+
*/
|
|
317
|
+
async getPaymentInfo(userAccount, blockHash, txHash) {
|
|
318
|
+
// Validate block and transaction, checking that the signer matches the userAccount
|
|
319
|
+
const signedBlock = (await this.contract.api.rpc.chain.getBlock(blockHash));
|
|
320
|
+
if (!signedBlock) {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const extrinsic = signedBlock.block.extrinsics.find((extrinsic) => extrinsic.hash.toString() === txHash);
|
|
324
|
+
if (!extrinsic || extrinsic.signer.toString() !== userAccount) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
// Retrieve tx fee for extrinsic
|
|
328
|
+
const paymentInfo = (await this.contract.api.rpc.payment.queryInfo(extrinsic.toHex(), blockHash));
|
|
329
|
+
if (!paymentInfo) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
return paymentInfo;
|
|
333
|
+
}
|
|
334
|
+
/*
|
|
335
|
+
* Get dapp user solution from database
|
|
336
|
+
*/
|
|
337
|
+
async getDappUserCommitmentById(commitmentId) {
|
|
338
|
+
const dappUserSolution = await this.db.getDappUserCommitmentById(commitmentId);
|
|
339
|
+
if (!dappUserSolution) {
|
|
340
|
+
throw new ProsopoEnvError('CAPTCHA.DAPP_USER_SOLUTION_NOT_FOUND', this.getDappUserCommitmentById.name, {}, { commitmentId: commitmentId });
|
|
341
|
+
}
|
|
342
|
+
return dappUserSolution;
|
|
343
|
+
}
|
|
344
|
+
/* Check if dapp user has verified solution in cache */
|
|
345
|
+
async getDappUserCommitmentByAccount(userAccount) {
|
|
346
|
+
const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(userAccount);
|
|
347
|
+
if (dappUserSolutions.length > 0) {
|
|
348
|
+
for (const dappUserSolution of dappUserSolutions) {
|
|
349
|
+
if (dappUserSolution.status === ArgumentTypes.CaptchaStatus.approved) {
|
|
350
|
+
return dappUserSolution;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
/* Returns public details of provider */
|
|
357
|
+
async getProviderDetails() {
|
|
358
|
+
return await wrapQuery(this.contract.query.getProvider, this.contract.query)(this.contract.pair.address);
|
|
359
|
+
}
|
|
360
|
+
/** Get the dataset from the databse */
|
|
361
|
+
async getProviderDataset(datasetId) {
|
|
362
|
+
return await this.db.getDataset(datasetId);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/tasks/tasks.ts"],"names":[],"mappings":"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"}
|