@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.
Files changed (42) hide show
  1. package/dist/api/admin.d.ts +2 -0
  2. package/dist/api/admin.d.ts.map +1 -0
  3. package/dist/api/admin.js +58 -0
  4. package/dist/api/admin.js.map +1 -0
  5. package/dist/api/captcha.d.ts +10 -0
  6. package/dist/api/captcha.d.ts.map +1 -0
  7. package/dist/api/captcha.js +166 -0
  8. package/dist/api/captcha.js.map +1 -0
  9. package/dist/batch/commitments.d.ts +23 -0
  10. package/dist/batch/commitments.d.ts.map +1 -0
  11. package/dist/batch/commitments.js +145 -0
  12. package/dist/batch/commitments.js.map +1 -0
  13. package/dist/batch/index.d.ts +2 -0
  14. package/dist/batch/index.d.ts.map +1 -0
  15. package/dist/batch/index.js +15 -0
  16. package/dist/batch/index.js.map +1 -0
  17. package/dist/index.d.ts +5 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +18 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/scheduler.d.ts +5 -0
  22. package/dist/scheduler.d.ts.map +1 -0
  23. package/dist/scheduler.js +49 -0
  24. package/dist/scheduler.js.map +1 -0
  25. package/dist/tasks/calculateSolutions.d.ts +10 -0
  26. package/dist/tasks/calculateSolutions.d.ts.map +1 -0
  27. package/dist/tasks/calculateSolutions.js +92 -0
  28. package/dist/tasks/calculateSolutions.js.map +1 -0
  29. package/dist/tasks/index.d.ts +3 -0
  30. package/dist/tasks/index.d.ts.map +1 -0
  31. package/dist/tasks/index.js +16 -0
  32. package/dist/tasks/index.js.map +1 -0
  33. package/dist/tasks/tasks.d.ts +109 -0
  34. package/dist/tasks/tasks.d.ts.map +1 -0
  35. package/dist/tasks/tasks.js +365 -0
  36. package/dist/tasks/tasks.js.map +1 -0
  37. package/dist/util.d.ts +28 -0
  38. package/dist/util.d.ts.map +1 -0
  39. package/dist/util.js +117 -0
  40. package/dist/util.js.map +1 -0
  41. package/package.json +9 -9
  42. 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":"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,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC7C,YAAY,GAAwB;QAChC,KAAK,CAAC,GAAG,CAAC,CAAA;QACV,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,wBAAwB,CAAC,CAAA;IAC1E,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG;QACL,IAAI;YACA,MAAM,WAAW,GAAG,MAAM,oBAAoB,CAAC,kBAAkB,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;YAC7F,IAAI,CAAC,WAAW,EAAE;gBACd,8CAA8C;gBAC9C,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK;qBAC3F,MAAM,EAAE;qBACR,MAAM,EAAE,CAAA;gBAEb,2EAA2E;gBAC3E,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAC5D,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,EAC7B,aAAa,CAAC,QAAQ,CACzB,CAAA;gBAED,2EAA2E;gBAC3E,IAAI,CAAC,gBAAgB,EAAE;oBACnB,OAAO,CAAC,CAAA;iBACX;gBAED,0DAA0D;gBAC1D,MAAM,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;gBACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,cAAc,CAAC,MAAM,8BAA8B,CAAC,CAAA;gBAElF,sDAAsD;gBACtD,MAAM,yBAAyB,GAAG,IAAI,CAAC,qBAAqB,CAAC,yBAAyB,CAAA;gBACtF,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAC,yBAAyB,CAAA;gBAC9E,MAAM,wBAAwB,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,iBAAiB,GAAG,GAAG,CAAC,CAAC,CAAA;gBAClG,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;oBAC7C,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;oBACrE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAA;oBAC3E,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAA;oBACpF,IAAI,iBAAiB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE;wBACrC,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,aAAa,iBAAiB,CAAC,IAAI,EAAE,CAAC,MAAM,8CAA8C,CAC7F,CAAA;wBACD,IAAI;4BACA,2DAA2D;4BAC3D,MAAM,kBAAkB,GAAG,CAAC,GAAI,iBAAyB,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAA;4BAChF,MAAM,aAAa,GAAG,SAAS;iCAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;iCAC3D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;4BAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAA;4BACvE,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,iBAAiB,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;4BACpF,kCAAkC;4BAClC,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAA;4BACtC,yDAAyD;4BACzD,MAAM,IAAI,CAAC,EAAE,CAAC,8BAA8B,CAAC,kBAAkB,CAAC,CAAA;4BAChE,2DAA2D;4BAC3D,MAAM,IAAI,CAAC,EAAE,CAAC,gCAAgC,CAAC,aAAa,CAAC,CAAA;4BAC7D,8CAA8C;4BAC9C,MAAM,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAA;4BAChD,OAAO,iBAAiB,CAAC,IAAI,EAAE,CAAC,MAAM,CAAA;yBACzC;wBAAC,OAAO,KAAK,EAAE;4BACZ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;yBAC3B;qBACJ;oBACD,OAAO,CAAC,CAAA;iBACX;qBAAM;oBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAA;oBAC9F,OAAO,CAAC,CAAA;iBACX;aACJ;YACD,OAAO,CAAC,CAAA;SACX;QAAC,OAAO,KAAK,EAAE;YACZ,0BAA0B;YAC1B,MAAM,IAAI,eAAe,CAAC,KAAc,EAAE,oCAAoC,CAAC,CAAA;SAClF;IACL,CAAC;CACJ"}
@@ -0,0 +1,3 @@
1
+ export * from './tasks.js';
2
+ export * from './calculateSolutions.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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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"}