@prosopo/database 1.0.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/captchaDatabase/captchaDatabase.d.ts +4 -0
- package/dist/captchaDatabase/captchaDatabase.d.ts.map +1 -0
- package/dist/captchaDatabase/captchaDatabase.js +31 -0
- package/dist/captchaDatabase/captchaDatabase.js.map +1 -0
- package/dist/captchaDatabase/index.d.ts +1 -1
- package/dist/captchaDatabase/index.d.ts.map +1 -1
- package/dist/captchaDatabase/index.js +1 -1
- package/dist/captchaDatabase/index.js.map +1 -1
- package/dist/cjs/captchaDatabase/captchaDatabase.cjs +37 -0
- package/dist/cjs/captchaDatabase/index.cjs +2 -2
- package/dist/cjs/databases/mongo.cjs +176 -69
- package/dist/cjs/databases/mongoMemory.cjs +1 -1
- package/dist/cjs/index.cjs +2 -2
- package/dist/databases/index.d.ts +2 -2
- package/dist/databases/index.d.ts.map +1 -1
- package/dist/databases/index.js +3 -3
- package/dist/databases/index.js.map +1 -1
- package/dist/databases/mongo.d.ts +8 -7
- package/dist/databases/mongo.d.ts.map +1 -1
- package/dist/databases/mongo.js +191 -119
- package/dist/databases/mongo.js.map +1 -1
- package/dist/databases/mongoMemory.d.ts +2 -2
- package/dist/databases/mongoMemory.d.ts.map +1 -1
- package/dist/databases/mongoMemory.js +2 -2
- package/dist/databases/mongoMemory.js.map +1 -1
- package/dist/eventsDatabase/eventsDatabase.d.ts +1 -1
- package/dist/eventsDatabase/eventsDatabase.d.ts.map +1 -1
- package/dist/eventsDatabase/eventsDatabase.js +8 -6
- package/dist/eventsDatabase/eventsDatabase.js.map +1 -1
- package/dist/eventsDatabase/index.d.ts +1 -1
- package/dist/eventsDatabase/index.d.ts.map +1 -1
- package/dist/eventsDatabase/index.js +1 -1
- package/dist/eventsDatabase/index.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +44 -53
- package/vite.cjs.config.ts +3 -3
- package/dist/captchaDatabase/captchaDatabse.d.ts +0 -3
- package/dist/captchaDatabase/captchaDatabse.d.ts.map +0 -1
- package/dist/captchaDatabase/captchaDatabse.js +0 -12
- package/dist/captchaDatabase/captchaDatabse.js.map +0 -1
- package/dist/cjs/captchaDatabase/captchaDatabse.cjs +0 -14
package/dist/databases/mongo.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { ServerApiVersion } from
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const DEFAULT_ENDPOINT = 'mongodb://127.0.0.1:27017';
|
|
1
|
+
import { isHex } from "@polkadot/util/is";
|
|
2
|
+
import { AsyncFactory, ProsopoDBError, ProsopoEnvError, getLoggerDefault, } from "@prosopo/common";
|
|
3
|
+
import { CaptchaStates, CaptchaStatus, DatasetWithIdsAndTreeSchema, ScheduledTaskNames, ScheduledTaskStatus, } from "@prosopo/types";
|
|
4
|
+
import { CaptchaRecordSchema, DatasetRecordSchema, PendingRecordSchema, PowCaptchaRecordSchema, ScheduledTaskRecordSchema, ScheduledTaskSchema, SolutionRecordSchema, UserCommitmentRecordSchema, UserCommitmentSchema, UserSolutionRecordSchema, UserSolutionSchema, } from "@prosopo/types-database";
|
|
5
|
+
import { ServerApiVersion } from "mongodb";
|
|
6
|
+
import mongoose from "mongoose";
|
|
7
|
+
mongoose.set("strictQuery", false);
|
|
8
|
+
const DEFAULT_ENDPOINT = "mongodb://127.0.0.1:27017";
|
|
10
9
|
export class ProsopoDatabase extends AsyncFactory {
|
|
11
10
|
constructor() {
|
|
12
11
|
super();
|
|
13
|
-
this.url =
|
|
14
|
-
this.dbname =
|
|
12
|
+
this.url = "";
|
|
13
|
+
this.dbname = "";
|
|
15
14
|
this.logger = getLoggerDefault();
|
|
16
15
|
}
|
|
17
16
|
async init(url, dbname, logger, authSource) {
|
|
@@ -19,7 +18,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
19
18
|
const parsedUrl = new URL(baseEndpoint);
|
|
20
19
|
parsedUrl.pathname = dbname;
|
|
21
20
|
if (authSource) {
|
|
22
|
-
parsedUrl.searchParams.set(
|
|
21
|
+
parsedUrl.searchParams.set("authSource", authSource);
|
|
23
22
|
}
|
|
24
23
|
this.url = parsedUrl.toString();
|
|
25
24
|
this.dbname = dbname;
|
|
@@ -28,7 +27,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
28
27
|
}
|
|
29
28
|
getTables() {
|
|
30
29
|
if (!this.tables) {
|
|
31
|
-
throw new ProsopoDBError(
|
|
30
|
+
throw new ProsopoDBError("DATABASE.TABLES_UNDEFINED", {
|
|
32
31
|
context: { failedFuncName: this.getTables.name },
|
|
33
32
|
logger: this.logger,
|
|
34
33
|
});
|
|
@@ -37,7 +36,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
37
36
|
}
|
|
38
37
|
getConnection() {
|
|
39
38
|
if (!this.connection) {
|
|
40
|
-
throw new ProsopoDBError(
|
|
39
|
+
throw new ProsopoDBError("DATABASE.CONNECTION_UNDEFINED", {
|
|
41
40
|
context: { failedFuncName: this.getConnection.name },
|
|
42
41
|
logger: this.logger,
|
|
43
42
|
});
|
|
@@ -45,48 +44,51 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
45
44
|
return this.connection;
|
|
46
45
|
}
|
|
47
46
|
async connect() {
|
|
48
|
-
this.logger.info(`Mongo url: ${this.url.replace(/\w+:\w+/,
|
|
47
|
+
this.logger.info(`Mongo url: ${this.url.replace(/\w+:\w+/, "<Credentials>")}`);
|
|
49
48
|
this.connection = await new Promise((resolve, reject) => {
|
|
50
49
|
const connection = mongoose.createConnection(this.url, {
|
|
51
50
|
dbName: this.dbname,
|
|
52
51
|
serverApi: ServerApiVersion.v1,
|
|
53
52
|
});
|
|
54
|
-
connection.on(
|
|
53
|
+
connection.on("open", () => {
|
|
55
54
|
this.logger.info(`Database connection to ${this.url} opened`);
|
|
56
55
|
resolve(connection);
|
|
57
56
|
});
|
|
58
|
-
connection.on(
|
|
57
|
+
connection.on("error", (err) => {
|
|
59
58
|
this.logger.error(`Database error: ${err}`);
|
|
60
59
|
reject(err);
|
|
61
60
|
});
|
|
62
|
-
connection.on(
|
|
61
|
+
connection.on("connected", () => {
|
|
63
62
|
this.logger.info(`Database connected to ${this.url}`);
|
|
63
|
+
resolve(connection);
|
|
64
64
|
});
|
|
65
|
-
connection.on(
|
|
65
|
+
connection.on("disconnected", () => {
|
|
66
66
|
this.logger.info(`Database disconnected from ${this.url}`);
|
|
67
67
|
});
|
|
68
|
-
connection.on(
|
|
68
|
+
connection.on("reconnected", () => {
|
|
69
69
|
this.logger.info(`Database reconnected to ${this.url}`);
|
|
70
|
+
resolve(connection);
|
|
70
71
|
});
|
|
71
|
-
connection.on(
|
|
72
|
+
connection.on("reconnectFailed", () => {
|
|
72
73
|
this.logger.error(`Database reconnect failed to ${this.url}`);
|
|
73
74
|
});
|
|
74
|
-
connection.on(
|
|
75
|
+
connection.on("close", () => {
|
|
75
76
|
this.logger.info(`Database connection to ${this.url} closed`);
|
|
76
77
|
});
|
|
77
|
-
connection.on(
|
|
78
|
+
connection.on("fullsetup", () => {
|
|
78
79
|
this.logger.info(`Database connection to ${this.url} is fully setup`);
|
|
80
|
+
resolve(connection);
|
|
79
81
|
});
|
|
80
82
|
});
|
|
81
83
|
this.tables = {
|
|
82
|
-
captcha: this.connection.model(
|
|
83
|
-
powCaptcha: this.connection.model(
|
|
84
|
-
dataset: this.connection.model(
|
|
85
|
-
solution: this.connection.model(
|
|
86
|
-
commitment: this.connection.model(
|
|
87
|
-
usersolution: this.connection.model(
|
|
88
|
-
pending: this.connection.model(
|
|
89
|
-
scheduler: this.connection.model(
|
|
84
|
+
captcha: this.connection.model("Captcha", CaptchaRecordSchema),
|
|
85
|
+
powCaptcha: this.connection.model("PowCaptcha", PowCaptchaRecordSchema),
|
|
86
|
+
dataset: this.connection.model("Dataset", DatasetRecordSchema),
|
|
87
|
+
solution: this.connection.model("Solution", SolutionRecordSchema),
|
|
88
|
+
commitment: this.connection.model("UserCommitment", UserCommitmentRecordSchema),
|
|
89
|
+
usersolution: this.connection.model("UserSolution", UserSolutionRecordSchema),
|
|
90
|
+
pending: this.connection.model("Pending", PendingRecordSchema),
|
|
91
|
+
scheduler: this.connection.model("Scheduler", ScheduledTaskRecordSchema),
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
async close() {
|
|
@@ -95,7 +97,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
95
97
|
}
|
|
96
98
|
async storeDataset(dataset) {
|
|
97
99
|
try {
|
|
98
|
-
this.logger.debug(
|
|
100
|
+
this.logger.debug("Storing dataset in database");
|
|
99
101
|
const parsedDataset = DatasetWithIdsAndTreeSchema.parse(dataset);
|
|
100
102
|
const datasetDoc = {
|
|
101
103
|
datasetId: parsedDataset.datasetId,
|
|
@@ -112,7 +114,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
112
114
|
index,
|
|
113
115
|
solved: !!solution?.length,
|
|
114
116
|
}));
|
|
115
|
-
this.logger.debug(
|
|
117
|
+
this.logger.debug("Inserting captcha records");
|
|
116
118
|
if (captchaDocs.length) {
|
|
117
119
|
await this.tables?.captcha.bulkWrite(captchaDocs.map((captchaDoc) => ({
|
|
118
120
|
updateOne: {
|
|
@@ -132,7 +134,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
132
134
|
datasetId: parsedDataset.datasetId,
|
|
133
135
|
datasetContentId: parsedDataset.datasetContentId,
|
|
134
136
|
}));
|
|
135
|
-
this.logger.debug(
|
|
137
|
+
this.logger.debug("Inserting solution records");
|
|
136
138
|
if (captchaSolutionDocs.length) {
|
|
137
139
|
await this.tables?.solution.bulkWrite(captchaSolutionDocs.map((captchaSolutionDoc) => ({
|
|
138
140
|
updateOne: {
|
|
@@ -142,23 +144,23 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
142
144
|
},
|
|
143
145
|
})));
|
|
144
146
|
}
|
|
145
|
-
this.logger.debug(
|
|
147
|
+
this.logger.debug("Dataset stored in database");
|
|
146
148
|
}
|
|
147
149
|
catch (err) {
|
|
148
|
-
throw new ProsopoDBError(
|
|
150
|
+
throw new ProsopoDBError("DATABASE.DATASET_LOAD_FAILED", {
|
|
149
151
|
context: { failedFuncName: this.storeDataset.name, error: err },
|
|
150
152
|
logger: this.logger,
|
|
151
153
|
});
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
async getSolutions(datasetId) {
|
|
155
|
-
const docs = await this.tables?.solution
|
|
157
|
+
const docs = await this.tables?.solution
|
|
158
|
+
.find({ datasetId })
|
|
159
|
+
.lean();
|
|
156
160
|
return docs ? docs : [];
|
|
157
161
|
}
|
|
158
162
|
async getDataset(datasetId) {
|
|
159
|
-
const datasetDoc = await this.tables?.dataset
|
|
160
|
-
.findOne({ datasetId: datasetId })
|
|
161
|
-
.lean();
|
|
163
|
+
const datasetDoc = await this.tables?.dataset.findOne({ datasetId: datasetId }).lean();
|
|
162
164
|
if (datasetDoc) {
|
|
163
165
|
const { datasetContentId, format, contentTree, solutionTree } = datasetDoc;
|
|
164
166
|
const captchas = (await this.tables?.captcha.find({ datasetId }).lean()) || [];
|
|
@@ -188,13 +190,13 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
188
190
|
}),
|
|
189
191
|
};
|
|
190
192
|
}
|
|
191
|
-
throw new ProsopoDBError(
|
|
193
|
+
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
192
194
|
context: { failedFuncName: this.getDataset.name, datasetId },
|
|
193
195
|
});
|
|
194
196
|
}
|
|
195
197
|
async getRandomCaptcha(solved, datasetId, size) {
|
|
196
198
|
if (!isHex(datasetId)) {
|
|
197
|
-
throw new ProsopoDBError(
|
|
199
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
198
200
|
context: { failedFuncName: this.getRandomCaptcha.name, datasetId },
|
|
199
201
|
});
|
|
200
202
|
}
|
|
@@ -214,26 +216,33 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
214
216
|
},
|
|
215
217
|
]);
|
|
216
218
|
const docs = await cursor;
|
|
217
|
-
if (docs
|
|
219
|
+
if (docs?.length) {
|
|
218
220
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
219
221
|
}
|
|
220
|
-
throw new ProsopoDBError(
|
|
221
|
-
context: {
|
|
222
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
223
|
+
context: {
|
|
224
|
+
failedFuncName: this.getRandomCaptcha.name,
|
|
225
|
+
solved,
|
|
226
|
+
datasetId,
|
|
227
|
+
size,
|
|
228
|
+
},
|
|
222
229
|
});
|
|
223
230
|
}
|
|
224
231
|
async getCaptchaById(captchaId) {
|
|
225
|
-
const cursor = this.tables?.captcha
|
|
232
|
+
const cursor = this.tables?.captcha
|
|
233
|
+
.find({ captchaId: { $in: captchaId } })
|
|
234
|
+
.lean();
|
|
226
235
|
const docs = await cursor;
|
|
227
|
-
if (docs
|
|
236
|
+
if (docs?.length) {
|
|
228
237
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
229
238
|
}
|
|
230
|
-
throw new ProsopoDBError(
|
|
239
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
231
240
|
context: { failedFuncName: this.getCaptchaById.name, captchaId },
|
|
232
241
|
});
|
|
233
242
|
}
|
|
234
243
|
async updateCaptcha(captcha, datasetId) {
|
|
235
244
|
if (!isHex(datasetId)) {
|
|
236
|
-
throw new ProsopoDBError(
|
|
245
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
237
246
|
context: { failedFuncName: this.updateCaptcha.name, datasetId },
|
|
238
247
|
});
|
|
239
248
|
}
|
|
@@ -241,7 +250,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
241
250
|
await this.tables?.captcha.updateOne({ datasetId }, { $set: captcha }, { upsert: false });
|
|
242
251
|
}
|
|
243
252
|
catch (err) {
|
|
244
|
-
throw new ProsopoDBError(
|
|
253
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
245
254
|
context: { failedFuncName: this.getDatasetDetails.name, error: err },
|
|
246
255
|
});
|
|
247
256
|
}
|
|
@@ -251,16 +260,21 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
251
260
|
}
|
|
252
261
|
async getDatasetDetails(datasetId) {
|
|
253
262
|
if (!isHex(datasetId)) {
|
|
254
|
-
throw new ProsopoDBError(
|
|
263
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
255
264
|
context: { failedFuncName: this.getDatasetDetails.name, datasetId },
|
|
256
265
|
});
|
|
257
266
|
}
|
|
258
|
-
const doc = await this.tables?.dataset
|
|
267
|
+
const doc = await this.tables?.dataset
|
|
268
|
+
.findOne({ datasetId })
|
|
269
|
+
.lean();
|
|
259
270
|
if (doc) {
|
|
260
271
|
return doc;
|
|
261
272
|
}
|
|
262
|
-
throw new ProsopoDBError(
|
|
263
|
-
context: {
|
|
273
|
+
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
274
|
+
context: {
|
|
275
|
+
failedFuncName: this.getDatasetDetails.name,
|
|
276
|
+
datasetId,
|
|
277
|
+
},
|
|
264
278
|
});
|
|
265
279
|
}
|
|
266
280
|
async storeDappUserSolution(captchas, commit) {
|
|
@@ -288,24 +302,29 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
288
302
|
await this.tables?.usersolution.bulkWrite(ops);
|
|
289
303
|
}
|
|
290
304
|
}
|
|
291
|
-
async storePowCaptchaRecord(challenge, checked) {
|
|
292
|
-
|
|
293
|
-
throw new ProsopoEnvError('DATABASE.DATABASE_UNDEFINED', {
|
|
294
|
-
context: { failedFuncName: this.storePowCaptchaRecord.name },
|
|
295
|
-
logger: this.logger,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
305
|
+
async storePowCaptchaRecord(challenge, components, checked, stored = false) {
|
|
306
|
+
const tables = this.getTables();
|
|
298
307
|
const powCaptchaRecord = {
|
|
299
308
|
challenge,
|
|
309
|
+
...components,
|
|
300
310
|
checked,
|
|
311
|
+
stored
|
|
301
312
|
};
|
|
302
313
|
try {
|
|
303
|
-
await
|
|
304
|
-
this.logger.info(
|
|
314
|
+
await tables.powCaptcha.create(powCaptchaRecord);
|
|
315
|
+
this.logger.info("PowCaptcha record added successfully", {
|
|
316
|
+
challenge,
|
|
317
|
+
checked,
|
|
318
|
+
stored
|
|
319
|
+
});
|
|
305
320
|
}
|
|
306
321
|
catch (error) {
|
|
307
|
-
this.logger.error(
|
|
308
|
-
|
|
322
|
+
this.logger.error("Failed to add PowCaptcha record", {
|
|
323
|
+
error,
|
|
324
|
+
challenge,
|
|
325
|
+
checked,
|
|
326
|
+
});
|
|
327
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
309
328
|
context: { error, challenge, checked },
|
|
310
329
|
logger: this.logger,
|
|
311
330
|
});
|
|
@@ -313,60 +332,70 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
313
332
|
}
|
|
314
333
|
async getPowCaptchaRecordByChallenge(challenge) {
|
|
315
334
|
if (!this.tables) {
|
|
316
|
-
throw new ProsopoEnvError(
|
|
335
|
+
throw new ProsopoEnvError("DATABASE.DATABASE_UNDEFINED", {
|
|
317
336
|
context: { failedFuncName: this.getPowCaptchaRecordByChallenge.name },
|
|
318
337
|
logger: this.logger,
|
|
319
338
|
});
|
|
320
339
|
}
|
|
321
340
|
try {
|
|
322
|
-
const record = await this.tables.powCaptcha
|
|
341
|
+
const record = await this.tables.powCaptcha
|
|
342
|
+
.findOne({ challenge })
|
|
343
|
+
.lean();
|
|
323
344
|
if (record) {
|
|
324
|
-
this.logger.info(
|
|
345
|
+
this.logger.info("PowCaptcha record retrieved successfully", {
|
|
346
|
+
challenge,
|
|
347
|
+
});
|
|
325
348
|
return record;
|
|
326
349
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
350
|
+
this.logger.info("No PowCaptcha record found", { challenge });
|
|
351
|
+
return null;
|
|
331
352
|
}
|
|
332
353
|
catch (error) {
|
|
333
|
-
this.logger.error(
|
|
334
|
-
|
|
354
|
+
this.logger.error("Failed to retrieve PowCaptcha record", {
|
|
355
|
+
error,
|
|
356
|
+
challenge,
|
|
357
|
+
});
|
|
358
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
335
359
|
context: { error, challenge },
|
|
336
360
|
logger: this.logger,
|
|
337
361
|
});
|
|
338
362
|
}
|
|
339
363
|
}
|
|
340
364
|
async updatePowCaptchaRecord(challenge, checked) {
|
|
341
|
-
|
|
342
|
-
throw new ProsopoEnvError('DATABASE.DATABASE_UNDEFINED', {
|
|
343
|
-
context: { failedFuncName: this.updatePowCaptchaRecord.name },
|
|
344
|
-
logger: this.logger,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
365
|
+
const tables = this.getTables();
|
|
347
366
|
try {
|
|
348
|
-
const updateResult = await
|
|
367
|
+
const updateResult = await tables.powCaptcha.updateOne({ challenge }, { $set: { checked } });
|
|
349
368
|
if (updateResult.matchedCount === 0) {
|
|
350
|
-
this.logger.info(
|
|
351
|
-
|
|
369
|
+
this.logger.info("No PowCaptcha record found to update", {
|
|
370
|
+
challenge,
|
|
371
|
+
checked,
|
|
372
|
+
});
|
|
373
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
352
374
|
context: { challenge, checked },
|
|
353
375
|
logger: this.logger,
|
|
354
376
|
});
|
|
355
377
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
378
|
+
this.logger.info("PowCaptcha record updated successfully", {
|
|
379
|
+
challenge,
|
|
380
|
+
checked,
|
|
381
|
+
});
|
|
359
382
|
}
|
|
360
383
|
catch (error) {
|
|
361
|
-
this.logger.error(
|
|
362
|
-
|
|
384
|
+
this.logger.error("Failed to update PowCaptcha record", {
|
|
385
|
+
error,
|
|
386
|
+
challenge,
|
|
387
|
+
checked,
|
|
388
|
+
});
|
|
389
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
363
390
|
context: { error, challenge, checked },
|
|
364
391
|
logger: this.logger,
|
|
365
392
|
});
|
|
366
393
|
}
|
|
367
394
|
}
|
|
368
395
|
async getProcessedDappUserSolutions() {
|
|
369
|
-
const docs = await this.tables?.usersolution
|
|
396
|
+
const docs = await this.tables?.usersolution
|
|
397
|
+
.find({ processed: true })
|
|
398
|
+
.lean();
|
|
370
399
|
return docs ? docs.map((doc) => UserSolutionSchema.parse(doc)) : [];
|
|
371
400
|
}
|
|
372
401
|
async getProcessedDappUserCommitments() {
|
|
@@ -388,20 +417,40 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
388
417
|
async markDappUserCommitmentsStored(commitmentIds) {
|
|
389
418
|
await this.tables?.commitment.updateMany({ id: { $in: commitmentIds } }, { $set: { stored: true } }, { upsert: false });
|
|
390
419
|
}
|
|
420
|
+
async getUnstoredDappUserPoWCommitments() {
|
|
421
|
+
const docs = await this.tables?.powCaptcha
|
|
422
|
+
.find({
|
|
423
|
+
$or: [{ stored: false }, { stored: { $exists: false } }],
|
|
424
|
+
})
|
|
425
|
+
.lean();
|
|
426
|
+
return docs || [];
|
|
427
|
+
}
|
|
428
|
+
async markDappUserPoWCommitmentsStored(challenges) {
|
|
429
|
+
await this.tables?.powCaptcha.updateMany({ challenge: { $in: challenges } }, { $set: { stored: true } }, { upsert: false });
|
|
430
|
+
}
|
|
391
431
|
async getBatchedDappUserCommitments() {
|
|
392
432
|
const docs = await this.tables?.commitment.find({ batched: true }).lean();
|
|
393
433
|
return docs ? docs.map((doc) => UserCommitmentSchema.parse(doc)) : [];
|
|
394
434
|
}
|
|
395
435
|
async removeProcessedDappUserSolutions(commitmentIds) {
|
|
396
|
-
return await this.tables?.usersolution.deleteMany({
|
|
436
|
+
return await this.tables?.usersolution.deleteMany({
|
|
437
|
+
processed: true,
|
|
438
|
+
commitmentId: { $in: commitmentIds },
|
|
439
|
+
});
|
|
397
440
|
}
|
|
398
441
|
async removeProcessedDappUserCommitments(commitmentIds) {
|
|
399
|
-
return await this.tables?.commitment.deleteMany({
|
|
442
|
+
return await this.tables?.commitment.deleteMany({
|
|
443
|
+
processed: true,
|
|
444
|
+
id: { $in: commitmentIds },
|
|
445
|
+
});
|
|
400
446
|
}
|
|
401
447
|
async storeDappUserPending(userAccount, requestHash, salt, deadlineTimestamp, requestedAtBlock) {
|
|
402
448
|
if (!isHex(requestHash)) {
|
|
403
|
-
throw new ProsopoDBError(
|
|
404
|
-
context: {
|
|
449
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
450
|
+
context: {
|
|
451
|
+
failedFuncName: this.storeDappUserPending.name,
|
|
452
|
+
requestHash,
|
|
453
|
+
},
|
|
405
454
|
});
|
|
406
455
|
}
|
|
407
456
|
const pendingRecord = {
|
|
@@ -416,24 +465,25 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
416
465
|
}
|
|
417
466
|
async getDappUserPending(requestHash) {
|
|
418
467
|
if (!isHex(requestHash)) {
|
|
419
|
-
throw new ProsopoEnvError(
|
|
468
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
420
469
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
421
470
|
});
|
|
422
471
|
}
|
|
423
|
-
const doc = await this.tables?.pending
|
|
424
|
-
.findOne({ requestHash: requestHash })
|
|
425
|
-
.lean();
|
|
472
|
+
const doc = await this.tables?.pending.findOne({ requestHash: requestHash }).lean();
|
|
426
473
|
if (doc) {
|
|
427
474
|
return doc;
|
|
428
475
|
}
|
|
429
|
-
throw new ProsopoEnvError(
|
|
476
|
+
throw new ProsopoEnvError("DATABASE.PENDING_RECORD_NOT_FOUND", {
|
|
430
477
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
431
478
|
});
|
|
432
479
|
}
|
|
433
480
|
async updateDappUserPendingStatus(requestHash) {
|
|
434
481
|
if (!isHex(requestHash)) {
|
|
435
|
-
throw new ProsopoEnvError(
|
|
436
|
-
context: {
|
|
482
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
483
|
+
context: {
|
|
484
|
+
failedFuncName: this.updateDappUserPendingStatus.name,
|
|
485
|
+
requestHash,
|
|
486
|
+
},
|
|
437
487
|
});
|
|
438
488
|
}
|
|
439
489
|
await this.tables?.pending.updateOne({ requestHash: requestHash }, {
|
|
@@ -453,15 +503,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
453
503
|
if (docs) {
|
|
454
504
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
455
505
|
}
|
|
456
|
-
throw new ProsopoEnvError(
|
|
506
|
+
throw new ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED");
|
|
457
507
|
}
|
|
458
508
|
async getAllDappUserSolutions(captchaId) {
|
|
459
|
-
const cursor = this.tables?.usersolution
|
|
509
|
+
const cursor = this.tables?.usersolution
|
|
510
|
+
?.find({ captchaId: { $in: captchaId } })
|
|
511
|
+
.lean();
|
|
460
512
|
const docs = await cursor;
|
|
461
513
|
if (docs) {
|
|
462
514
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
463
515
|
}
|
|
464
|
-
throw new ProsopoEnvError(
|
|
516
|
+
throw new ProsopoEnvError("DATABASE.SOLUTION_GET_FAILED");
|
|
465
517
|
}
|
|
466
518
|
async getDatasetIdWithSolvedCaptchasOfSizeN(solvedCaptchaCount) {
|
|
467
519
|
const cursor = this.tables?.solution.aggregate([
|
|
@@ -470,7 +522,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
470
522
|
},
|
|
471
523
|
{
|
|
472
524
|
$group: {
|
|
473
|
-
_id:
|
|
525
|
+
_id: "$datasetId",
|
|
474
526
|
count: { $sum: 1 },
|
|
475
527
|
},
|
|
476
528
|
},
|
|
@@ -484,15 +536,18 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
484
536
|
},
|
|
485
537
|
]);
|
|
486
538
|
const docs = await cursor;
|
|
487
|
-
if (docs
|
|
539
|
+
if (docs?.length) {
|
|
488
540
|
return docs[0]._id;
|
|
489
541
|
}
|
|
490
|
-
throw new ProsopoDBError(
|
|
542
|
+
throw new ProsopoDBError("DATABASE.DATASET_WITH_SOLUTIONS_GET_FAILED");
|
|
491
543
|
}
|
|
492
544
|
async getRandomSolvedCaptchasFromSingleDataset(datasetId, size) {
|
|
493
545
|
if (!isHex(datasetId)) {
|
|
494
|
-
throw new ProsopoDBError(
|
|
495
|
-
context: {
|
|
546
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
547
|
+
context: {
|
|
548
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
549
|
+
datasetId,
|
|
550
|
+
},
|
|
496
551
|
});
|
|
497
552
|
}
|
|
498
553
|
const sampleSize = size ? Math.abs(Math.trunc(size)) : 1;
|
|
@@ -508,11 +563,15 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
508
563
|
},
|
|
509
564
|
]);
|
|
510
565
|
const docs = await cursor;
|
|
511
|
-
if (docs
|
|
566
|
+
if (docs?.length) {
|
|
512
567
|
return docs;
|
|
513
568
|
}
|
|
514
|
-
throw new ProsopoDBError(
|
|
515
|
-
context: {
|
|
569
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
570
|
+
context: {
|
|
571
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
572
|
+
datasetId,
|
|
573
|
+
size,
|
|
574
|
+
},
|
|
516
575
|
});
|
|
517
576
|
}
|
|
518
577
|
async getDappUserSolutionById(commitmentId) {
|
|
@@ -525,12 +584,14 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
525
584
|
if (doc) {
|
|
526
585
|
return doc;
|
|
527
586
|
}
|
|
528
|
-
throw new ProsopoDBError(
|
|
587
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
529
588
|
context: { failedFuncName: this.getCaptchaById.name, commitmentId },
|
|
530
589
|
});
|
|
531
590
|
}
|
|
532
591
|
async getDappUserCommitmentById(commitmentId) {
|
|
533
|
-
const commitmentCursor = this.tables?.commitment
|
|
592
|
+
const commitmentCursor = this.tables?.commitment
|
|
593
|
+
?.findOne({ id: commitmentId })
|
|
594
|
+
.lean();
|
|
534
595
|
const doc = await commitmentCursor;
|
|
535
596
|
return doc ? UserCommitmentSchema.parse(doc) : undefined;
|
|
536
597
|
}
|
|
@@ -547,7 +608,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
547
608
|
.lean();
|
|
548
609
|
}
|
|
549
610
|
catch (err) {
|
|
550
|
-
throw new ProsopoDBError(
|
|
611
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_APPROVE_FAILED", {
|
|
612
|
+
context: { error: err, commitmentId },
|
|
613
|
+
});
|
|
551
614
|
}
|
|
552
615
|
}
|
|
553
616
|
async flagProcessedDappUserSolutions(captchaIds) {
|
|
@@ -557,7 +620,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
557
620
|
.lean();
|
|
558
621
|
}
|
|
559
622
|
catch (err) {
|
|
560
|
-
throw new ProsopoDBError(
|
|
623
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_FLAG_FAILED", {
|
|
624
|
+
context: { error: err, captchaIds },
|
|
625
|
+
});
|
|
561
626
|
}
|
|
562
627
|
}
|
|
563
628
|
async flagProcessedDappUserCommitments(commitmentIds) {
|
|
@@ -568,7 +633,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
568
633
|
.lean();
|
|
569
634
|
}
|
|
570
635
|
catch (err) {
|
|
571
|
-
throw new ProsopoDBError(
|
|
636
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
637
|
+
context: { error: err, commitmentIds },
|
|
638
|
+
});
|
|
572
639
|
}
|
|
573
640
|
}
|
|
574
641
|
async flagBatchedDappUserCommitments(commitmentIds) {
|
|
@@ -579,12 +646,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
579
646
|
.lean();
|
|
580
647
|
}
|
|
581
648
|
catch (err) {
|
|
582
|
-
throw new ProsopoDBError(
|
|
649
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
650
|
+
context: { error: err, commitmentIds },
|
|
651
|
+
});
|
|
583
652
|
}
|
|
584
653
|
}
|
|
585
654
|
async getLastBatchCommitTime() {
|
|
586
655
|
const cursor = this.tables?.scheduler
|
|
587
|
-
?.findOne({
|
|
656
|
+
?.findOne({
|
|
657
|
+
processName: ScheduledTaskNames.BatchCommitment,
|
|
658
|
+
status: ScheduledTaskStatus.Completed,
|
|
659
|
+
})
|
|
588
660
|
.sort({ timestamp: -1 });
|
|
589
661
|
const doc = await cursor?.lean();
|
|
590
662
|
if (doc) {
|
|
@@ -601,7 +673,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
601
673
|
async getLastScheduledTaskStatus(task, status) {
|
|
602
674
|
const lookup = { processName: task };
|
|
603
675
|
if (status) {
|
|
604
|
-
lookup
|
|
676
|
+
lookup.status = status;
|
|
605
677
|
}
|
|
606
678
|
const cursor = await this.tables?.scheduler
|
|
607
679
|
?.findOne(lookup)
|