@prosopo/database 1.0.2 → 2.0.0
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 +173 -68
- 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 +189 -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,27 @@ 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) {
|
|
306
|
+
const tables = this.getTables();
|
|
298
307
|
const powCaptchaRecord = {
|
|
299
308
|
challenge,
|
|
309
|
+
...components,
|
|
300
310
|
checked,
|
|
301
311
|
};
|
|
302
312
|
try {
|
|
303
|
-
await
|
|
304
|
-
this.logger.info(
|
|
313
|
+
await tables.powCaptcha.create(powCaptchaRecord);
|
|
314
|
+
this.logger.info("PowCaptcha record added successfully", {
|
|
315
|
+
challenge,
|
|
316
|
+
checked,
|
|
317
|
+
});
|
|
305
318
|
}
|
|
306
319
|
catch (error) {
|
|
307
|
-
this.logger.error(
|
|
308
|
-
|
|
320
|
+
this.logger.error("Failed to add PowCaptcha record", {
|
|
321
|
+
error,
|
|
322
|
+
challenge,
|
|
323
|
+
checked,
|
|
324
|
+
});
|
|
325
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
309
326
|
context: { error, challenge, checked },
|
|
310
327
|
logger: this.logger,
|
|
311
328
|
});
|
|
@@ -313,60 +330,70 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
313
330
|
}
|
|
314
331
|
async getPowCaptchaRecordByChallenge(challenge) {
|
|
315
332
|
if (!this.tables) {
|
|
316
|
-
throw new ProsopoEnvError(
|
|
333
|
+
throw new ProsopoEnvError("DATABASE.DATABASE_UNDEFINED", {
|
|
317
334
|
context: { failedFuncName: this.getPowCaptchaRecordByChallenge.name },
|
|
318
335
|
logger: this.logger,
|
|
319
336
|
});
|
|
320
337
|
}
|
|
321
338
|
try {
|
|
322
|
-
const record = await this.tables.powCaptcha
|
|
339
|
+
const record = await this.tables.powCaptcha
|
|
340
|
+
.findOne({ challenge })
|
|
341
|
+
.lean();
|
|
323
342
|
if (record) {
|
|
324
|
-
this.logger.info(
|
|
343
|
+
this.logger.info("PowCaptcha record retrieved successfully", {
|
|
344
|
+
challenge,
|
|
345
|
+
});
|
|
325
346
|
return record;
|
|
326
347
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
348
|
+
this.logger.info("No PowCaptcha record found", { challenge });
|
|
349
|
+
return null;
|
|
331
350
|
}
|
|
332
351
|
catch (error) {
|
|
333
|
-
this.logger.error(
|
|
334
|
-
|
|
352
|
+
this.logger.error("Failed to retrieve PowCaptcha record", {
|
|
353
|
+
error,
|
|
354
|
+
challenge,
|
|
355
|
+
});
|
|
356
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
335
357
|
context: { error, challenge },
|
|
336
358
|
logger: this.logger,
|
|
337
359
|
});
|
|
338
360
|
}
|
|
339
361
|
}
|
|
340
362
|
async updatePowCaptchaRecord(challenge, checked) {
|
|
341
|
-
|
|
342
|
-
throw new ProsopoEnvError('DATABASE.DATABASE_UNDEFINED', {
|
|
343
|
-
context: { failedFuncName: this.updatePowCaptchaRecord.name },
|
|
344
|
-
logger: this.logger,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
363
|
+
const tables = this.getTables();
|
|
347
364
|
try {
|
|
348
|
-
const updateResult = await
|
|
365
|
+
const updateResult = await tables.powCaptcha.updateOne({ challenge }, { $set: { checked } });
|
|
349
366
|
if (updateResult.matchedCount === 0) {
|
|
350
|
-
this.logger.info(
|
|
351
|
-
|
|
367
|
+
this.logger.info("No PowCaptcha record found to update", {
|
|
368
|
+
challenge,
|
|
369
|
+
checked,
|
|
370
|
+
});
|
|
371
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
352
372
|
context: { challenge, checked },
|
|
353
373
|
logger: this.logger,
|
|
354
374
|
});
|
|
355
375
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
376
|
+
this.logger.info("PowCaptcha record updated successfully", {
|
|
377
|
+
challenge,
|
|
378
|
+
checked,
|
|
379
|
+
});
|
|
359
380
|
}
|
|
360
381
|
catch (error) {
|
|
361
|
-
this.logger.error(
|
|
362
|
-
|
|
382
|
+
this.logger.error("Failed to update PowCaptcha record", {
|
|
383
|
+
error,
|
|
384
|
+
challenge,
|
|
385
|
+
checked,
|
|
386
|
+
});
|
|
387
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
363
388
|
context: { error, challenge, checked },
|
|
364
389
|
logger: this.logger,
|
|
365
390
|
});
|
|
366
391
|
}
|
|
367
392
|
}
|
|
368
393
|
async getProcessedDappUserSolutions() {
|
|
369
|
-
const docs = await this.tables?.usersolution
|
|
394
|
+
const docs = await this.tables?.usersolution
|
|
395
|
+
.find({ processed: true })
|
|
396
|
+
.lean();
|
|
370
397
|
return docs ? docs.map((doc) => UserSolutionSchema.parse(doc)) : [];
|
|
371
398
|
}
|
|
372
399
|
async getProcessedDappUserCommitments() {
|
|
@@ -388,20 +415,40 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
388
415
|
async markDappUserCommitmentsStored(commitmentIds) {
|
|
389
416
|
await this.tables?.commitment.updateMany({ id: { $in: commitmentIds } }, { $set: { stored: true } }, { upsert: false });
|
|
390
417
|
}
|
|
418
|
+
async getUnstoredDappUserPoWCommitments() {
|
|
419
|
+
const docs = await this.tables?.powCaptcha
|
|
420
|
+
.find({
|
|
421
|
+
$or: [{ stored: false }, { stored: { $exists: false } }],
|
|
422
|
+
})
|
|
423
|
+
.lean();
|
|
424
|
+
return docs || [];
|
|
425
|
+
}
|
|
426
|
+
async markDappUserPoWCommitmentsStored(challengeIds) {
|
|
427
|
+
await this.tables?.powCaptcha.updateMany({ challenge: { $in: challengeIds } }, { $set: { stored: true } }, { upsert: false });
|
|
428
|
+
}
|
|
391
429
|
async getBatchedDappUserCommitments() {
|
|
392
430
|
const docs = await this.tables?.commitment.find({ batched: true }).lean();
|
|
393
431
|
return docs ? docs.map((doc) => UserCommitmentSchema.parse(doc)) : [];
|
|
394
432
|
}
|
|
395
433
|
async removeProcessedDappUserSolutions(commitmentIds) {
|
|
396
|
-
return await this.tables?.usersolution.deleteMany({
|
|
434
|
+
return await this.tables?.usersolution.deleteMany({
|
|
435
|
+
processed: true,
|
|
436
|
+
commitmentId: { $in: commitmentIds },
|
|
437
|
+
});
|
|
397
438
|
}
|
|
398
439
|
async removeProcessedDappUserCommitments(commitmentIds) {
|
|
399
|
-
return await this.tables?.commitment.deleteMany({
|
|
440
|
+
return await this.tables?.commitment.deleteMany({
|
|
441
|
+
processed: true,
|
|
442
|
+
id: { $in: commitmentIds },
|
|
443
|
+
});
|
|
400
444
|
}
|
|
401
445
|
async storeDappUserPending(userAccount, requestHash, salt, deadlineTimestamp, requestedAtBlock) {
|
|
402
446
|
if (!isHex(requestHash)) {
|
|
403
|
-
throw new ProsopoDBError(
|
|
404
|
-
context: {
|
|
447
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
448
|
+
context: {
|
|
449
|
+
failedFuncName: this.storeDappUserPending.name,
|
|
450
|
+
requestHash,
|
|
451
|
+
},
|
|
405
452
|
});
|
|
406
453
|
}
|
|
407
454
|
const pendingRecord = {
|
|
@@ -416,24 +463,25 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
416
463
|
}
|
|
417
464
|
async getDappUserPending(requestHash) {
|
|
418
465
|
if (!isHex(requestHash)) {
|
|
419
|
-
throw new ProsopoEnvError(
|
|
466
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
420
467
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
421
468
|
});
|
|
422
469
|
}
|
|
423
|
-
const doc = await this.tables?.pending
|
|
424
|
-
.findOne({ requestHash: requestHash })
|
|
425
|
-
.lean();
|
|
470
|
+
const doc = await this.tables?.pending.findOne({ requestHash: requestHash }).lean();
|
|
426
471
|
if (doc) {
|
|
427
472
|
return doc;
|
|
428
473
|
}
|
|
429
|
-
throw new ProsopoEnvError(
|
|
474
|
+
throw new ProsopoEnvError("DATABASE.PENDING_RECORD_NOT_FOUND", {
|
|
430
475
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
431
476
|
});
|
|
432
477
|
}
|
|
433
478
|
async updateDappUserPendingStatus(requestHash) {
|
|
434
479
|
if (!isHex(requestHash)) {
|
|
435
|
-
throw new ProsopoEnvError(
|
|
436
|
-
context: {
|
|
480
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
481
|
+
context: {
|
|
482
|
+
failedFuncName: this.updateDappUserPendingStatus.name,
|
|
483
|
+
requestHash,
|
|
484
|
+
},
|
|
437
485
|
});
|
|
438
486
|
}
|
|
439
487
|
await this.tables?.pending.updateOne({ requestHash: requestHash }, {
|
|
@@ -453,15 +501,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
453
501
|
if (docs) {
|
|
454
502
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
455
503
|
}
|
|
456
|
-
throw new ProsopoEnvError(
|
|
504
|
+
throw new ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED");
|
|
457
505
|
}
|
|
458
506
|
async getAllDappUserSolutions(captchaId) {
|
|
459
|
-
const cursor = this.tables?.usersolution
|
|
507
|
+
const cursor = this.tables?.usersolution
|
|
508
|
+
?.find({ captchaId: { $in: captchaId } })
|
|
509
|
+
.lean();
|
|
460
510
|
const docs = await cursor;
|
|
461
511
|
if (docs) {
|
|
462
512
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
463
513
|
}
|
|
464
|
-
throw new ProsopoEnvError(
|
|
514
|
+
throw new ProsopoEnvError("DATABASE.SOLUTION_GET_FAILED");
|
|
465
515
|
}
|
|
466
516
|
async getDatasetIdWithSolvedCaptchasOfSizeN(solvedCaptchaCount) {
|
|
467
517
|
const cursor = this.tables?.solution.aggregate([
|
|
@@ -470,7 +520,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
470
520
|
},
|
|
471
521
|
{
|
|
472
522
|
$group: {
|
|
473
|
-
_id:
|
|
523
|
+
_id: "$datasetId",
|
|
474
524
|
count: { $sum: 1 },
|
|
475
525
|
},
|
|
476
526
|
},
|
|
@@ -484,15 +534,18 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
484
534
|
},
|
|
485
535
|
]);
|
|
486
536
|
const docs = await cursor;
|
|
487
|
-
if (docs
|
|
537
|
+
if (docs?.length) {
|
|
488
538
|
return docs[0]._id;
|
|
489
539
|
}
|
|
490
|
-
throw new ProsopoDBError(
|
|
540
|
+
throw new ProsopoDBError("DATABASE.DATASET_WITH_SOLUTIONS_GET_FAILED");
|
|
491
541
|
}
|
|
492
542
|
async getRandomSolvedCaptchasFromSingleDataset(datasetId, size) {
|
|
493
543
|
if (!isHex(datasetId)) {
|
|
494
|
-
throw new ProsopoDBError(
|
|
495
|
-
context: {
|
|
544
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
545
|
+
context: {
|
|
546
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
547
|
+
datasetId,
|
|
548
|
+
},
|
|
496
549
|
});
|
|
497
550
|
}
|
|
498
551
|
const sampleSize = size ? Math.abs(Math.trunc(size)) : 1;
|
|
@@ -508,11 +561,15 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
508
561
|
},
|
|
509
562
|
]);
|
|
510
563
|
const docs = await cursor;
|
|
511
|
-
if (docs
|
|
564
|
+
if (docs?.length) {
|
|
512
565
|
return docs;
|
|
513
566
|
}
|
|
514
|
-
throw new ProsopoDBError(
|
|
515
|
-
context: {
|
|
567
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
568
|
+
context: {
|
|
569
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
570
|
+
datasetId,
|
|
571
|
+
size,
|
|
572
|
+
},
|
|
516
573
|
});
|
|
517
574
|
}
|
|
518
575
|
async getDappUserSolutionById(commitmentId) {
|
|
@@ -525,12 +582,14 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
525
582
|
if (doc) {
|
|
526
583
|
return doc;
|
|
527
584
|
}
|
|
528
|
-
throw new ProsopoDBError(
|
|
585
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
529
586
|
context: { failedFuncName: this.getCaptchaById.name, commitmentId },
|
|
530
587
|
});
|
|
531
588
|
}
|
|
532
589
|
async getDappUserCommitmentById(commitmentId) {
|
|
533
|
-
const commitmentCursor = this.tables?.commitment
|
|
590
|
+
const commitmentCursor = this.tables?.commitment
|
|
591
|
+
?.findOne({ id: commitmentId })
|
|
592
|
+
.lean();
|
|
534
593
|
const doc = await commitmentCursor;
|
|
535
594
|
return doc ? UserCommitmentSchema.parse(doc) : undefined;
|
|
536
595
|
}
|
|
@@ -547,7 +606,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
547
606
|
.lean();
|
|
548
607
|
}
|
|
549
608
|
catch (err) {
|
|
550
|
-
throw new ProsopoDBError(
|
|
609
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_APPROVE_FAILED", {
|
|
610
|
+
context: { error: err, commitmentId },
|
|
611
|
+
});
|
|
551
612
|
}
|
|
552
613
|
}
|
|
553
614
|
async flagProcessedDappUserSolutions(captchaIds) {
|
|
@@ -557,7 +618,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
557
618
|
.lean();
|
|
558
619
|
}
|
|
559
620
|
catch (err) {
|
|
560
|
-
throw new ProsopoDBError(
|
|
621
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_FLAG_FAILED", {
|
|
622
|
+
context: { error: err, captchaIds },
|
|
623
|
+
});
|
|
561
624
|
}
|
|
562
625
|
}
|
|
563
626
|
async flagProcessedDappUserCommitments(commitmentIds) {
|
|
@@ -568,7 +631,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
568
631
|
.lean();
|
|
569
632
|
}
|
|
570
633
|
catch (err) {
|
|
571
|
-
throw new ProsopoDBError(
|
|
634
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
635
|
+
context: { error: err, commitmentIds },
|
|
636
|
+
});
|
|
572
637
|
}
|
|
573
638
|
}
|
|
574
639
|
async flagBatchedDappUserCommitments(commitmentIds) {
|
|
@@ -579,12 +644,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
579
644
|
.lean();
|
|
580
645
|
}
|
|
581
646
|
catch (err) {
|
|
582
|
-
throw new ProsopoDBError(
|
|
647
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
648
|
+
context: { error: err, commitmentIds },
|
|
649
|
+
});
|
|
583
650
|
}
|
|
584
651
|
}
|
|
585
652
|
async getLastBatchCommitTime() {
|
|
586
653
|
const cursor = this.tables?.scheduler
|
|
587
|
-
?.findOne({
|
|
654
|
+
?.findOne({
|
|
655
|
+
processName: ScheduledTaskNames.BatchCommitment,
|
|
656
|
+
status: ScheduledTaskStatus.Completed,
|
|
657
|
+
})
|
|
588
658
|
.sort({ timestamp: -1 });
|
|
589
659
|
const doc = await cursor?.lean();
|
|
590
660
|
if (doc) {
|
|
@@ -601,7 +671,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
601
671
|
async getLastScheduledTaskStatus(task, status) {
|
|
602
672
|
const lookup = { processName: task };
|
|
603
673
|
if (status) {
|
|
604
|
-
lookup
|
|
674
|
+
lookup.status = status;
|
|
605
675
|
}
|
|
606
676
|
const cursor = await this.tables?.scheduler
|
|
607
677
|
?.findOne(lookup)
|