@certik/skynet 0.10.7 → 0.10.10
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/.editorconfig +5 -5
- package/.eslintrc.js +13 -13
- package/.prettierrc.js +3 -3
- package/CHANGELOG.md +389 -372
- package/README.md +23 -23
- package/abi.js +353 -353
- package/ably.js +29 -29
- package/address.js +18 -18
- package/api.js +128 -105
- package/app.js +718 -709
- package/availability.js +58 -58
- package/block.js +83 -83
- package/cli.js +53 -53
- package/const.js +92 -92
- package/deploy.js +676 -676
- package/dynamodb.js +444 -444
- package/env.js +90 -90
- package/examples/api +70 -73
- package/examples/consumer +47 -47
- package/examples/indexer +65 -65
- package/examples/mode-indexer +82 -82
- package/examples/producer +80 -80
- package/indexer.js +596 -595
- package/inquiry.js +14 -14
- package/kafka.js +444 -443
- package/labelling.js +90 -90
- package/log.js +46 -29
- package/metric.js +65 -65
- package/monitor.js +196 -191
- package/opsgenie.js +55 -55
- package/package.json +37 -37
- package/price.js +48 -48
- package/primitive.js +77 -77
- package/proxy.js +157 -157
- package/rateLimit.js +21 -21
- package/s3.js +122 -122
- package/scan.js +74 -74
- package/selector.js +53 -53
- package/slack.js +87 -87
- package/snowflake.js +36 -36
- package/sqs.js +12 -12
- package/token.js +46 -46
- package/transaction.js +41 -41
- package/util.js +67 -67
- package/web3.js +117 -117
package/indexer.js
CHANGED
|
@@ -1,595 +1,596 @@
|
|
|
1
|
-
const meow = require("meow");
|
|
2
|
-
const { createRecord, getRecordByKey } = require("./dynamodb");
|
|
3
|
-
const { getEnvironment } = require("./env");
|
|
4
|
-
const { exponentialRetry } = require("./availability");
|
|
5
|
-
const { range, fillRange } = require("./util");
|
|
6
|
-
const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
|
|
7
|
-
const { getBinaryName } = require("./cli");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
await
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
//
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
--
|
|
465
|
-
--
|
|
466
|
-
--
|
|
467
|
-
--
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
1
|
+
const meow = require("meow");
|
|
2
|
+
const { createRecord, getRecordByKey } = require("./dynamodb");
|
|
3
|
+
const { getEnvironment } = require("./env");
|
|
4
|
+
const { exponentialRetry } = require("./availability");
|
|
5
|
+
const { range, fillRange } = require("./util");
|
|
6
|
+
const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
|
|
7
|
+
const { getBinaryName } = require("./cli");
|
|
8
|
+
const { inline } = require("./log");
|
|
9
|
+
|
|
10
|
+
const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
|
|
11
|
+
|
|
12
|
+
async function getIndexerState(name, selectorFlags) {
|
|
13
|
+
const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
14
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (!stateItem) {
|
|
18
|
+
return "N/A";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return stateItem.value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function getIndexerLatestId(name, selectorFlags) {
|
|
25
|
+
const record = await getRecordByKey(STATE_TABLE_NAME, {
|
|
26
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (record) {
|
|
30
|
+
return record.value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function getIndexerValidatedId(name, selectorFlags) {
|
|
37
|
+
const record = await getRecordByKey(STATE_TABLE_NAME, {
|
|
38
|
+
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (record) {
|
|
42
|
+
return record.value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// for those indexers that can have progress tracked by a numeric state.type
|
|
49
|
+
// such as block height, or timestamp
|
|
50
|
+
// managing state would be helpful to reduce the build time
|
|
51
|
+
// and avoid unnecessary computation & storage
|
|
52
|
+
function createModeIndexerApp({
|
|
53
|
+
binaryName,
|
|
54
|
+
name,
|
|
55
|
+
selector = {},
|
|
56
|
+
build,
|
|
57
|
+
// number of items run in a batch, determines the { from, to } to the build function
|
|
58
|
+
buildBatchSize = 1,
|
|
59
|
+
// number of build functions calling at a time
|
|
60
|
+
buildConcurrency = 1,
|
|
61
|
+
// commit updates every rolling window = buildBatchSize * buildConcurrency
|
|
62
|
+
validate,
|
|
63
|
+
// number of items run in a batch, determines the { from, to } to the validate function
|
|
64
|
+
validateBatchSize = 1,
|
|
65
|
+
// number of validate functions calling at a time
|
|
66
|
+
validateConcurrency = 1,
|
|
67
|
+
// commit updates every rolling window = validateBatchSize * validateConcurrency
|
|
68
|
+
maxRetry = 2,
|
|
69
|
+
state,
|
|
70
|
+
}) {
|
|
71
|
+
const finalState = {
|
|
72
|
+
type: "block",
|
|
73
|
+
getMinId: async () => 1,
|
|
74
|
+
getMaxId: async () => {
|
|
75
|
+
throw new Error("must implement getMaxId");
|
|
76
|
+
},
|
|
77
|
+
...state,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
async function runMode({ mode, from, to, status, verbose, ...selectorFlags }) {
|
|
81
|
+
if (status) {
|
|
82
|
+
const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
83
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const fromItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
87
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const validateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
91
|
+
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
inline.log(`RebuildState=${stateItem?.value} Since=${fromItem?.value} Validated=${validateItem?.value}`);
|
|
95
|
+
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (from === 0) {
|
|
100
|
+
from = await finalState.getMinId(selectorFlags);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
inline.log(
|
|
104
|
+
`[MODE INDEXER] mode=${mode}, from=${from}, to=${
|
|
105
|
+
to > 0 ? to : "undefined"
|
|
106
|
+
}, env=${getEnvironment()}, ${toSelectorString(selectorFlags, ", ")}`
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (mode === "reset") {
|
|
110
|
+
await runReset(selectorFlags, from);
|
|
111
|
+
} else if (mode === "rebuild") {
|
|
112
|
+
await runReset(selectorFlags);
|
|
113
|
+
await runRebuild(selectorFlags, from, to > 0 ? to : await finalState.getMaxId(selectorFlags), verbose);
|
|
114
|
+
} else if (mode === "resume-rebuild") {
|
|
115
|
+
const previousRebuildEnds = await getIndexerLatestId(name, selectorFlags);
|
|
116
|
+
|
|
117
|
+
await runRebuild(
|
|
118
|
+
selectorFlags,
|
|
119
|
+
previousRebuildEnds ? previousRebuildEnds + 1 : from,
|
|
120
|
+
to > 0 ? to : await finalState.getMaxId(selectorFlags),
|
|
121
|
+
verbose
|
|
122
|
+
);
|
|
123
|
+
} else if (mode === "validate" || mode === "validation") {
|
|
124
|
+
const previousRebuildEnds = await getIndexerLatestId(name, selectorFlags);
|
|
125
|
+
|
|
126
|
+
const previousValidatedTo = await getIndexerValidatedId(name, selectorFlags);
|
|
127
|
+
|
|
128
|
+
const shouldSaveState = to === 0;
|
|
129
|
+
|
|
130
|
+
await runValidate(
|
|
131
|
+
selectorFlags,
|
|
132
|
+
from > 0 ? from : previousValidatedTo,
|
|
133
|
+
to > 0 ? to : previousRebuildEnds,
|
|
134
|
+
shouldSaveState,
|
|
135
|
+
verbose
|
|
136
|
+
);
|
|
137
|
+
} else if (mode === "one") {
|
|
138
|
+
if (to > 0) {
|
|
139
|
+
inline.log("[MODE INDEXER] one mode ignores --to option. you may want to use range mode instead");
|
|
140
|
+
}
|
|
141
|
+
await runRange(selectorFlags, from, from, verbose);
|
|
142
|
+
} else if (mode === "range") {
|
|
143
|
+
await runRange(selectorFlags, from, to, verbose);
|
|
144
|
+
} else {
|
|
145
|
+
await runDelta(selectorFlags, verbose);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function runRange(selectorFlags, from, to, verbose) {
|
|
150
|
+
const startTime = Date.now();
|
|
151
|
+
|
|
152
|
+
inline.log(
|
|
153
|
+
`[MODE INDEXER] building range, from=${from}, to=${to}, ${toSelectorString(
|
|
154
|
+
selectorFlags,
|
|
155
|
+
", "
|
|
156
|
+
)}, batchSize=${buildBatchSize}, concurrency=${buildConcurrency}`
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const failedIds = await execBuild(selectorFlags, from, to, verbose, false);
|
|
160
|
+
|
|
161
|
+
if (failedIds.length > 0) {
|
|
162
|
+
inline.log(`[MODE INDEXER] built with some failed ${finalState.type}`, failedIds);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
} else {
|
|
165
|
+
inline.log(`[MODE INDEXER] built successfully in ${Date.now() - startTime}ms`);
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function runValidate(selectorFlags, from, to, shouldSaveState, verbose) {
|
|
171
|
+
if (!validate) {
|
|
172
|
+
inline.log(`[MODE INDEXER] the indexer doesn't support validate mode, validate function not implemented`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const startTime = Date.now();
|
|
177
|
+
|
|
178
|
+
inline.log(
|
|
179
|
+
`[MODE INDEXER] validating, from=${from}, to=${to}, ${toSelectorString(
|
|
180
|
+
selectorFlags,
|
|
181
|
+
", "
|
|
182
|
+
)}, batchSize=${validateBatchSize}, concurrency=${validateConcurrency}`
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const windows = range(from, to, validateBatchSize * validateConcurrency);
|
|
186
|
+
|
|
187
|
+
inline.log(
|
|
188
|
+
`[MODE INDEXER] from=${from}, to=${to}, batchSize=${validateBatchSize}, concurrency=${validateConcurrency}`
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
for (let [windowStart, windowEnd] of windows) {
|
|
192
|
+
inline.log(`[MODE INDEXER] validating window ${windowStart}~${windowEnd}, concurrency=${validateConcurrency}`);
|
|
193
|
+
|
|
194
|
+
const batches = range(windowStart, windowEnd, validateBatchSize);
|
|
195
|
+
|
|
196
|
+
// add a retry for errors
|
|
197
|
+
await Promise.all(
|
|
198
|
+
batches.map(async ([batchStart, batchEnd]) => {
|
|
199
|
+
const result = await exponentialRetry(
|
|
200
|
+
async () => {
|
|
201
|
+
try {
|
|
202
|
+
await validate({
|
|
203
|
+
...selectorFlags,
|
|
204
|
+
from: batchStart,
|
|
205
|
+
to: batchEnd,
|
|
206
|
+
verbose,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return true;
|
|
210
|
+
} catch (err) {
|
|
211
|
+
inline.error(`got error in validation`, err);
|
|
212
|
+
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
maxRetry,
|
|
218
|
+
test: (r) => r,
|
|
219
|
+
verbose,
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (!result) {
|
|
224
|
+
throw new Error(`Terminate validation due to critical errors, from=${batchStart}, to=${batchEnd}`);
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (shouldSaveState) {
|
|
230
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
231
|
+
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
232
|
+
value: to,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
if (verbose) {
|
|
236
|
+
inline.log(`[MODE INDEXER] updated processed ${finalState.type} to ${windowEnd}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
inline.log(
|
|
242
|
+
`[MODE INDEXER] validated ${to - from + 1} ${finalState.type} successfully in ${Date.now() - startTime}ms`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function execBuild(selectorFlags, from, to, verbose, shouldSaveState = false) {
|
|
247
|
+
let failedIds = [];
|
|
248
|
+
|
|
249
|
+
const windows = range(from, to, buildBatchSize * buildConcurrency);
|
|
250
|
+
|
|
251
|
+
for (let [windowStart, windowEnd] of windows) {
|
|
252
|
+
inline.log(`[MODE INDEXER] building window ${windowStart}~${windowEnd}, concurrency = ${buildConcurrency}`);
|
|
253
|
+
|
|
254
|
+
const batches = range(windowStart, windowEnd, buildBatchSize);
|
|
255
|
+
|
|
256
|
+
// add a retry for errors
|
|
257
|
+
const batchResults = await Promise.all(
|
|
258
|
+
batches.map(async ([batchStart, batchEnd]) => {
|
|
259
|
+
await exponentialRetry(
|
|
260
|
+
async () => {
|
|
261
|
+
try {
|
|
262
|
+
const ids = await build({
|
|
263
|
+
...selectorFlags,
|
|
264
|
+
from: batchStart,
|
|
265
|
+
to: batchEnd,
|
|
266
|
+
verbose,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
if (ids && ids.length > 0) {
|
|
270
|
+
return ids;
|
|
271
|
+
} else {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
} catch (err) {
|
|
275
|
+
inline.error(`[MODE INDEXER] got error in build`, err);
|
|
276
|
+
|
|
277
|
+
return fillRange(batchStart, batchEnd);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
maxRetry,
|
|
282
|
+
test: (r) => !r,
|
|
283
|
+
verbose,
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
if (shouldSaveState) {
|
|
290
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
291
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
292
|
+
value: windowEnd,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
if (verbose) {
|
|
296
|
+
inline.log(`[MODE INDEXER] updated processed ${finalState.type} to ${windowEnd}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
batchResults.forEach((ids) => {
|
|
301
|
+
if (ids) {
|
|
302
|
+
failedIds = failedIds.concat(ids);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
failedIds.sort();
|
|
308
|
+
|
|
309
|
+
return failedIds;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function runRebuild(selectorFlags, from, to, verbose) {
|
|
313
|
+
const startTime = Date.now();
|
|
314
|
+
|
|
315
|
+
inline.log(
|
|
316
|
+
`[MODE INDEXER] rebuilding, from=${from}, to=${to}, ${toSelectorString(
|
|
317
|
+
selectorFlags,
|
|
318
|
+
", "
|
|
319
|
+
)}, batchSize=${buildBatchSize}, concurrency=${buildConcurrency}`
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
// add a flag to stop delta from running
|
|
323
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
324
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
325
|
+
value: "running",
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const failedIds = await execBuild(selectorFlags, from, to, verbose, true);
|
|
329
|
+
|
|
330
|
+
// even if some transactions are failed we should continue to allow delta job running
|
|
331
|
+
// because rebuild is usally heavy
|
|
332
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
333
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
334
|
+
value: to,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
338
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
339
|
+
value: "succeed",
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
if (failedIds.length > 0) {
|
|
343
|
+
inline.log(
|
|
344
|
+
`[MODE INDEXER] built ${to - from + 1} ${finalState.type} with some failed ${finalState.type}`,
|
|
345
|
+
failedIds
|
|
346
|
+
);
|
|
347
|
+
process.exit(1);
|
|
348
|
+
} else {
|
|
349
|
+
inline.log(
|
|
350
|
+
`[MODE INDEXER] built ${to - from + 1} ${finalState.type} successfully in ${Date.now() - startTime}ms`
|
|
351
|
+
);
|
|
352
|
+
process.exit(0);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function runDelta(selectorFlags, verbose) {
|
|
357
|
+
const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
358
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// only build when rebuild succeed
|
|
362
|
+
if (stateItem && stateItem.value === "succeed") {
|
|
363
|
+
const from = (await getIndexerLatestId(name, selectorFlags)) + 1;
|
|
364
|
+
|
|
365
|
+
const startTime = Date.now();
|
|
366
|
+
const to = await state.getMaxId(selectorFlags);
|
|
367
|
+
|
|
368
|
+
if (to <= from) {
|
|
369
|
+
inline.log(
|
|
370
|
+
`[MODE INDEXER] skip delta because there're no items need to be processed, ${toSelectorString(
|
|
371
|
+
selectorFlags,
|
|
372
|
+
", "
|
|
373
|
+
)}`
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
inline.log(
|
|
380
|
+
`[MODE INDEXER] starting delta, from=${from}, to=${to}, ${toSelectorString(
|
|
381
|
+
selectorFlags,
|
|
382
|
+
", "
|
|
383
|
+
)}, batchSize=${buildBatchSize}, concurrency=${buildConcurrency}`
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
const failedIds = await execBuild(selectorFlags, from, to, verbose, true);
|
|
388
|
+
|
|
389
|
+
if (failedIds.length > 0) {
|
|
390
|
+
inline.log("[MODE INDEXER] built with some failed txs", failedIds);
|
|
391
|
+
|
|
392
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
393
|
+
name: `${name}DeltaState(${toSelectorString(selectorFlags)})`,
|
|
394
|
+
value: "failed",
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
398
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
399
|
+
value: Math.min(to, failedIds[0]),
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
process.exit(1);
|
|
403
|
+
} else {
|
|
404
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
405
|
+
name: `${name}DeltaState(${toSelectorString(selectorFlags)})`,
|
|
406
|
+
value: "succeed",
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
410
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
411
|
+
value: to,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
inline.log(`[MODE INDEXER] built successfully in ${Date.now() - startTime}ms`);
|
|
415
|
+
process.exit(0);
|
|
416
|
+
}
|
|
417
|
+
} catch (err) {
|
|
418
|
+
inline.error("[MODE INDEXER] delta build failed", from, to, err);
|
|
419
|
+
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
inline.log("[MODE INDEXER] skip because rebuild hasn't done yet");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async function runReset(selectorFlags) {
|
|
428
|
+
const startTime = Date.now();
|
|
429
|
+
|
|
430
|
+
inline.log(`[MODE INDEXER] starting reset, ${toSelectorString(selectorFlags, ", ")}`);
|
|
431
|
+
|
|
432
|
+
inline.log("[MODE INDEXER] reset state", STATE_TABLE_NAME);
|
|
433
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
434
|
+
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
435
|
+
value: 0,
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
439
|
+
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
440
|
+
value: 0,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
444
|
+
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
445
|
+
value: "init",
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
inline.log(`[MODE INDEXER] reset successfully in ${Date.now() - startTime}ms`);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function run() {
|
|
452
|
+
if (!binaryName) {
|
|
453
|
+
binaryName = getBinaryName();
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const cli = meow(
|
|
457
|
+
`
|
|
458
|
+
Usage
|
|
459
|
+
|
|
460
|
+
$ ${binaryName} <options>
|
|
461
|
+
|
|
462
|
+
Options
|
|
463
|
+
${getSelectorDesc(selector)}
|
|
464
|
+
--mode could be delta/rebuild/resume-rebuild/validate/one/range/reset
|
|
465
|
+
--from min ${finalState.type} to build
|
|
466
|
+
--to max ${finalState.type} to build
|
|
467
|
+
--status print status of indexer and exit
|
|
468
|
+
--verbose Output debug messages
|
|
469
|
+
`,
|
|
470
|
+
{
|
|
471
|
+
description: false,
|
|
472
|
+
version: false,
|
|
473
|
+
flags: {
|
|
474
|
+
...getSelectorFlags(selector),
|
|
475
|
+
mode: {
|
|
476
|
+
type: "string",
|
|
477
|
+
default: "delta",
|
|
478
|
+
},
|
|
479
|
+
from: {
|
|
480
|
+
alias: "since",
|
|
481
|
+
type: "number",
|
|
482
|
+
default: 0,
|
|
483
|
+
},
|
|
484
|
+
to: {
|
|
485
|
+
alias: "until",
|
|
486
|
+
type: "number",
|
|
487
|
+
default: 0,
|
|
488
|
+
},
|
|
489
|
+
status: {
|
|
490
|
+
type: "boolean",
|
|
491
|
+
default: false,
|
|
492
|
+
},
|
|
493
|
+
verbose: {
|
|
494
|
+
type: "boolean",
|
|
495
|
+
default: false,
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
runMode(cli.flags).catch((err) => {
|
|
502
|
+
inline.error(err);
|
|
503
|
+
process.exit(1);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return { run };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// for those indexers that does not rely on a curosr
|
|
511
|
+
// e.g. should always rebuild everything from scratch
|
|
512
|
+
// or that the state can be easily inferred from existing data
|
|
513
|
+
function createIndexerApp({ binaryName, name, selector = {}, build, maxRetry = 2 }) {
|
|
514
|
+
function run() {
|
|
515
|
+
if (!binaryName) {
|
|
516
|
+
binaryName = getBinaryName();
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const cli = meow(
|
|
520
|
+
`
|
|
521
|
+
Usage
|
|
522
|
+
$ ${binaryName} <options>
|
|
523
|
+
|
|
524
|
+
Options
|
|
525
|
+
${getSelectorDesc(selector)}
|
|
526
|
+
--verbose Output debug messages
|
|
527
|
+
`,
|
|
528
|
+
{
|
|
529
|
+
description: false,
|
|
530
|
+
version: false,
|
|
531
|
+
flags: {
|
|
532
|
+
...getSelectorFlags(selector),
|
|
533
|
+
verbose: {
|
|
534
|
+
type: "boolean",
|
|
535
|
+
default: false,
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
async function runBuild({ verbose, ...selectorFlags }) {
|
|
542
|
+
const startTime = Date.now();
|
|
543
|
+
|
|
544
|
+
if (Object.keys(selectorFlags).length > 0) {
|
|
545
|
+
inline.log(`[INDEXER] starting build, ${toSelectorString(selectorFlags, ", ")}`);
|
|
546
|
+
} else {
|
|
547
|
+
inline.log(`[INDEXER] starting build`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const result = await exponentialRetry(
|
|
551
|
+
async () => {
|
|
552
|
+
try {
|
|
553
|
+
await build({ verbose, ...selectorFlags });
|
|
554
|
+
|
|
555
|
+
return true;
|
|
556
|
+
} catch (err) {
|
|
557
|
+
inline.log(`[INDEXER] got error in build`, err);
|
|
558
|
+
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
maxRetry,
|
|
564
|
+
test: (r) => r,
|
|
565
|
+
verbose,
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
if (!result) {
|
|
570
|
+
throw new Error(`[INDEXER] Build failed due to critical errors`);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
await createRecord(STATE_TABLE_NAME, {
|
|
574
|
+
name: `${name}UpdatedAt(${toSelectorString(selectorFlags)})`,
|
|
575
|
+
value: new Date().toISOString(),
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
inline.log(`[INDEXER] build successfully in ${Date.now() - startTime}ms`);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
runBuild(cli.flags).catch((err) => {
|
|
582
|
+
inline.error(err);
|
|
583
|
+
process.exit(1);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return { run };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
module.exports = {
|
|
591
|
+
createModeIndexerApp,
|
|
592
|
+
createIndexerApp,
|
|
593
|
+
getIndexerState,
|
|
594
|
+
getIndexerLatestId,
|
|
595
|
+
getIndexerValidatedId,
|
|
596
|
+
};
|