envio 3.1.0-rc.1 → 3.1.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/index.d.ts +12 -0
- package/package.json +6 -6
- package/src/Batch.res +7 -1
- package/src/Batch.res.mjs +2 -1
- package/src/ChainManager.res +3 -2
- package/src/ChainManager.res.mjs +3 -3
- package/src/Env.res +6 -0
- package/src/Env.res.mjs +3 -0
- package/src/EventProcessing.res +24 -122
- package/src/EventProcessing.res.mjs +24 -88
- package/src/GlobalState.res +31 -52
- package/src/GlobalState.res.mjs +54 -33
- package/src/GlobalStateManager.res +1 -3
- package/src/InMemoryStore.res +408 -110
- package/src/InMemoryStore.res.mjs +335 -84
- package/src/InMemoryTable.res +49 -30
- package/src/InMemoryTable.res.mjs +31 -39
- package/src/Internal.res +3 -0
- package/src/LoadLayer.res +9 -7
- package/src/LoadLayer.res.mjs +4 -10
- package/src/Main.res +31 -2
- package/src/Main.res.mjs +19 -5
- package/src/Persistence.res +6 -1
- package/src/PgStorage.res +171 -68
- package/src/PgStorage.res.mjs +125 -39
- package/src/RollbackCommit.res +32 -0
- package/src/RollbackCommit.res.mjs +35 -0
- package/src/TestIndexerProxyStorage.res +1 -1
- package/src/TestIndexerProxyStorage.res.mjs +1 -1
- package/src/Throttler.res +22 -15
- package/src/Throttler.res.mjs +19 -14
- package/src/UserContext.res +1 -0
- package/src/UserContext.res.mjs +3 -1
- package/src/bindings/NodeJs.res +1 -0
package/index.d.ts
CHANGED
|
@@ -1201,6 +1201,18 @@ export type IndexerFromConfig<Config extends IndexerConfigTypes = GlobalConfig>
|
|
|
1201
1201
|
readonly name: string;
|
|
1202
1202
|
/** The indexer description from config.yaml. */
|
|
1203
1203
|
readonly description: string | undefined;
|
|
1204
|
+
/**
|
|
1205
|
+
* Internal, unstable API that will be removed without notice. Registers a
|
|
1206
|
+
* callback fired once per chain affected by a reorg rollback, after the
|
|
1207
|
+
* rollback is durably written to the database. A throwing callback crashes
|
|
1208
|
+
* the indexer through the same path as a failed write.
|
|
1209
|
+
*/
|
|
1210
|
+
readonly "~internalAndWillBeRemovedSoon_onRollbackCommit": (
|
|
1211
|
+
callback: (args: {
|
|
1212
|
+
readonly chainId: number;
|
|
1213
|
+
readonly rollbackToBlock: number;
|
|
1214
|
+
}) => Promise<void>,
|
|
1215
|
+
) => void;
|
|
1204
1216
|
} & SingleEcosystemChains<Config>
|
|
1205
1217
|
>;
|
|
1206
1218
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "3.1.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.mjs",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"tsx": "4.21.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
|
-
"envio-linux-x64": "3.1.0
|
|
74
|
-
"envio-linux-x64-musl": "3.1.0
|
|
75
|
-
"envio-linux-arm64": "3.1.0
|
|
76
|
-
"envio-darwin-x64": "3.1.0
|
|
77
|
-
"envio-darwin-arm64": "3.1.0
|
|
73
|
+
"envio-linux-x64": "3.1.0",
|
|
74
|
+
"envio-linux-x64-musl": "3.1.0",
|
|
75
|
+
"envio-linux-arm64": "3.1.0",
|
|
76
|
+
"envio-darwin-x64": "3.1.0",
|
|
77
|
+
"envio-darwin-arm64": "3.1.0"
|
|
78
78
|
}
|
|
79
79
|
}
|
package/src/Batch.res
CHANGED
|
@@ -23,6 +23,9 @@ type t = {
|
|
|
23
23
|
totalBatchSize: int,
|
|
24
24
|
items: array<Internal.item>,
|
|
25
25
|
progressedChainsById: dict<chainAfterBatch>,
|
|
26
|
+
// Processed inside the reorg threshold. Drives whether history is saved, so
|
|
27
|
+
// writes never merge across a change in this value.
|
|
28
|
+
isInReorgThreshold: bool,
|
|
26
29
|
// Unnest-like checkpoint fields:
|
|
27
30
|
checkpointIds: array<bigint>,
|
|
28
31
|
checkpointChainIds: array<int>,
|
|
@@ -165,6 +168,7 @@ let prepareBatch = (
|
|
|
165
168
|
~checkpointIdBeforeBatch,
|
|
166
169
|
~chainsBeforeBatch: ChainMap.t<chainBeforeBatch>,
|
|
167
170
|
~batchSizeTarget,
|
|
171
|
+
~isInReorgThreshold,
|
|
168
172
|
) => {
|
|
169
173
|
let preparedFetchStates =
|
|
170
174
|
chainsBeforeBatch
|
|
@@ -286,6 +290,7 @@ let prepareBatch = (
|
|
|
286
290
|
~batchSizePerChain=mutBatchSizePerChain,
|
|
287
291
|
~progressBlockNumberPerChain=mutProgressBlockNumberPerChain,
|
|
288
292
|
),
|
|
293
|
+
isInReorgThreshold,
|
|
289
294
|
checkpointIds,
|
|
290
295
|
checkpointChainIds,
|
|
291
296
|
checkpointBlockNumbers,
|
|
@@ -298,8 +303,9 @@ let make = (
|
|
|
298
303
|
~checkpointIdBeforeBatch,
|
|
299
304
|
~chainsBeforeBatch: ChainMap.t<chainBeforeBatch>,
|
|
300
305
|
~batchSizeTarget,
|
|
306
|
+
~isInReorgThreshold,
|
|
301
307
|
) => {
|
|
302
|
-
prepareBatch(~checkpointIdBeforeBatch, ~chainsBeforeBatch, ~batchSizeTarget)
|
|
308
|
+
prepareBatch(~checkpointIdBeforeBatch, ~chainsBeforeBatch, ~batchSizeTarget, ~isInReorgThreshold)
|
|
303
309
|
}
|
|
304
310
|
|
|
305
311
|
let findFirstEventBlockNumber = (batch: t, ~chainId) => {
|
package/src/Batch.res.mjs
CHANGED
|
@@ -70,7 +70,7 @@ function addReorgCheckpoints(prevCheckpointId, reorgDetection, fromBlockExclusiv
|
|
|
70
70
|
return prevCheckpointId$1;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
function prepareBatch(checkpointIdBeforeBatch, chainsBeforeBatch, batchSizeTarget) {
|
|
73
|
+
function prepareBatch(checkpointIdBeforeBatch, chainsBeforeBatch, batchSizeTarget, isInReorgThreshold) {
|
|
74
74
|
let preparedFetchStates = FetchState.sortForUnorderedBatch(ChainMap.values(chainsBeforeBatch).map(chainBeforeBatch => chainBeforeBatch.fetchState), batchSizeTarget);
|
|
75
75
|
let chainIdx = 0;
|
|
76
76
|
let preparedNumber = preparedFetchStates.length;
|
|
@@ -168,6 +168,7 @@ function prepareBatch(checkpointIdBeforeBatch, chainsBeforeBatch, batchSizeTarge
|
|
|
168
168
|
totalBatchSize: totalBatchSize,
|
|
169
169
|
items: items,
|
|
170
170
|
progressedChainsById: getProgressedChainsById(chainsBeforeBatch, mutBatchSizePerChain, mutProgressBlockNumberPerChain),
|
|
171
|
+
isInReorgThreshold: isInReorgThreshold,
|
|
171
172
|
checkpointIds: checkpointIds,
|
|
172
173
|
checkpointChainIds: checkpointChainIds,
|
|
173
174
|
checkpointBlockNumbers: checkpointBlockNumbers,
|
package/src/ChainManager.res
CHANGED
|
@@ -135,12 +135,13 @@ let nextItemIsNone = (chainManager: t): bool => {
|
|
|
135
135
|
|
|
136
136
|
let createBatch = (
|
|
137
137
|
chainManager: t,
|
|
138
|
-
~
|
|
138
|
+
~processedCheckpointId,
|
|
139
139
|
~batchSizeTarget: int,
|
|
140
140
|
~isRollback: bool,
|
|
141
141
|
): Batch.t => {
|
|
142
142
|
Batch.make(
|
|
143
|
-
~
|
|
143
|
+
~isInReorgThreshold=chainManager.isInReorgThreshold,
|
|
144
|
+
~checkpointIdBeforeBatch=processedCheckpointId->BigInt.add(
|
|
144
145
|
// Since for rollback we have a diff checkpoint id.
|
|
145
146
|
// This is needed to currectly overwrite old state
|
|
146
147
|
// in an append-only ClickHouse insert.
|
package/src/ChainManager.res.mjs
CHANGED
|
@@ -99,8 +99,8 @@ function nextItemIsNone(chainManager) {
|
|
|
99
99
|
return !Batch.hasReadyItem(ChainMap.map(chainManager.chainFetchers, cf => cf.fetchState));
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function createBatch(chainManager,
|
|
103
|
-
return Batch.make(
|
|
102
|
+
function createBatch(chainManager, processedCheckpointId, batchSizeTarget, isRollback) {
|
|
103
|
+
return Batch.make(processedCheckpointId + (
|
|
104
104
|
isRollback ? 1n : 0n
|
|
105
105
|
), ChainMap.map(chainManager.chainFetchers, cf => ({
|
|
106
106
|
fetchState: cf.fetchState,
|
|
@@ -109,7 +109,7 @@ function createBatch(chainManager, committedCheckpointId, batchSizeTarget, isRol
|
|
|
109
109
|
sourceBlockNumber: cf.fetchState.knownHeight,
|
|
110
110
|
totalEventsProcessed: cf.numEventsProcessed,
|
|
111
111
|
chainConfig: cf.chainConfig
|
|
112
|
-
})), batchSizeTarget);
|
|
112
|
+
})), batchSizeTarget, chainManager.isInReorgThreshold);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function isProgressAtHead(chainManager) {
|
package/src/Env.res
CHANGED
|
@@ -11,6 +11,12 @@ let maxAddrInPartition = envSafe->EnvSafe.get("MAX_PARTITION_SIZE", S.int, ~fall
|
|
|
11
11
|
let maxPartitionConcurrency =
|
|
12
12
|
envSafe->EnvSafe.get("ENVIO_MAX_PARTITION_CONCURRENCY", S.int, ~fallback=10)
|
|
13
13
|
|
|
14
|
+
// Target number of in-memory objects (uncommitted entity/effect changes plus
|
|
15
|
+
// unwritten batch items) the store holds before processing waits for the write
|
|
16
|
+
// cycle to catch up.
|
|
17
|
+
let inMemoryObjectsTarget =
|
|
18
|
+
envSafe->EnvSafe.get("ENVIO_IN_MEMORY_OBJECTS_TARGET", S.int, ~fallback=100_000)->Belt.Int.toFloat
|
|
19
|
+
|
|
14
20
|
// FIXME: This broke HS grafana dashboard. Should investigate it later. Maybe we should use :: as a default value?
|
|
15
21
|
// We want to be able to set it to 0.0.0.0
|
|
16
22
|
// to allow to passthrough the port from a Docker container
|
package/src/Env.res.mjs
CHANGED
|
@@ -21,6 +21,8 @@ let maxAddrInPartition = EnvSafe.get(envSafe, "MAX_PARTITION_SIZE", S$RescriptSc
|
|
|
21
21
|
|
|
22
22
|
let maxPartitionConcurrency = EnvSafe.get(envSafe, "ENVIO_MAX_PARTITION_CONCURRENCY", S$RescriptSchema.int, undefined, 10, undefined, undefined);
|
|
23
23
|
|
|
24
|
+
let inMemoryObjectsTarget = EnvSafe.get(envSafe, "ENVIO_IN_MEMORY_OBJECTS_TARGET", S$RescriptSchema.int, undefined, 100000, undefined, undefined);
|
|
25
|
+
|
|
24
26
|
let serverPort = EnvSafe.get(envSafe, "ENVIO_INDEXER_PORT", S$RescriptSchema.port(S$RescriptSchema.int, undefined), undefined, EnvSafe.get(envSafe, "METRICS_PORT", S$RescriptSchema.port(S$RescriptSchema.int, undefined), undefined, 9898, undefined, undefined), undefined, undefined);
|
|
25
27
|
|
|
26
28
|
let tuiEnvVar = EnvSafe.get(envSafe, "ENVIO_TUI", S$RescriptSchema.option(S$RescriptSchema.bool), undefined, undefined, undefined, undefined);
|
|
@@ -221,6 +223,7 @@ export {
|
|
|
221
223
|
targetBufferSize,
|
|
222
224
|
maxAddrInPartition,
|
|
223
225
|
maxPartitionConcurrency,
|
|
226
|
+
inMemoryObjectsTarget,
|
|
224
227
|
serverPort,
|
|
225
228
|
tuiEnvVar,
|
|
226
229
|
logLevelSchema,
|
package/src/EventProcessing.res
CHANGED
|
@@ -25,77 +25,6 @@ let computeChainsState = (chainFetchers: ChainMap.t<ChainFetcher.t>): Internal.c
|
|
|
25
25
|
chains
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
let convertFieldsToJson = (fields: option<dict<unknown>>) => {
|
|
29
|
-
switch fields {
|
|
30
|
-
| None => %raw(`{}`)
|
|
31
|
-
| Some(fields) =>
|
|
32
|
-
// Convert bigint fields to string. There are no fields with nested
|
|
33
|
-
// bigints, so iterating only the top level is safe.
|
|
34
|
-
fields
|
|
35
|
-
->Utils.Dict.mapValues(value =>
|
|
36
|
-
typeof(value) === #bigint
|
|
37
|
-
? value
|
|
38
|
-
->(Utils.magic: unknown => bigint)
|
|
39
|
-
->BigInt.toString
|
|
40
|
-
->(Utils.magic: string => unknown)
|
|
41
|
-
: value
|
|
42
|
-
)
|
|
43
|
-
->(Utils.magic: dict<unknown> => JSON.t)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let addItemToRawEvents = (
|
|
48
|
-
eventItem: Internal.eventItem,
|
|
49
|
-
~inMemoryStore: InMemoryStore.t,
|
|
50
|
-
~config: Config.t,
|
|
51
|
-
) => {
|
|
52
|
-
let {event, eventConfig, chain, blockNumber, timestamp: blockTimestamp} = eventItem
|
|
53
|
-
let {block, transaction, params, logIndex, srcAddress} = event
|
|
54
|
-
let chainId = chain->ChainMap.Chain.toChainId
|
|
55
|
-
let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
|
|
56
|
-
let blockFields =
|
|
57
|
-
block
|
|
58
|
-
->(Utils.magic: Internal.eventBlock => option<dict<unknown>>)
|
|
59
|
-
->convertFieldsToJson
|
|
60
|
-
let transactionFields =
|
|
61
|
-
transaction
|
|
62
|
-
->(Utils.magic: Internal.eventTransaction => option<dict<unknown>>)
|
|
63
|
-
->convertFieldsToJson
|
|
64
|
-
|
|
65
|
-
blockFields->config.ecosystem.cleanUpRawEventFieldsInPlace
|
|
66
|
-
|
|
67
|
-
// Serialize to unknown, because serializing to Js.Json.t fails for Bytes Fuel type, since it has unknown schema
|
|
68
|
-
let params =
|
|
69
|
-
params
|
|
70
|
-
->S.reverseConvertOrThrow(eventConfig.paramsRawEventSchema)
|
|
71
|
-
->(Utils.magic: unknown => JSON.t)
|
|
72
|
-
let params = if params === %raw(`null`) {
|
|
73
|
-
// Should probably make the params field nullable
|
|
74
|
-
// But this is currently needed to make events
|
|
75
|
-
// with empty params work
|
|
76
|
-
%raw(`"null"`)
|
|
77
|
-
} else {
|
|
78
|
-
params
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
let rawEvent: InternalTable.RawEvents.t = {
|
|
82
|
-
chainId,
|
|
83
|
-
eventId,
|
|
84
|
-
eventName: eventConfig.name,
|
|
85
|
-
contractName: eventConfig.contractName,
|
|
86
|
-
blockNumber,
|
|
87
|
-
logIndex,
|
|
88
|
-
srcAddress,
|
|
89
|
-
blockHash: block->config.ecosystem.getId,
|
|
90
|
-
blockTimestamp,
|
|
91
|
-
blockFields,
|
|
92
|
-
transactionFields,
|
|
93
|
-
params,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
inMemoryStore.rawEvents->Array.push(rawEvent)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
28
|
exception ProcessingError({message: string, exn: exn, item: Internal.item})
|
|
100
29
|
|
|
101
30
|
let runEventHandlerOrThrow = async (
|
|
@@ -192,26 +121,18 @@ let runHandlerOrThrow = async (
|
|
|
192
121
|
}),
|
|
193
122
|
)
|
|
194
123
|
}
|
|
195
|
-
| Event({eventConfig}) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
| None => ()
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if ctx.config.enableRawEvents {
|
|
211
|
-
item
|
|
212
|
-
->Internal.castUnsafeEventItem
|
|
213
|
-
->addItemToRawEvents(~inMemoryStore, ~config=ctx.config)
|
|
214
|
-
}
|
|
124
|
+
| Event({eventConfig}) => switch eventConfig.handler {
|
|
125
|
+
| Some(handler) =>
|
|
126
|
+
await item->runEventHandlerOrThrow(
|
|
127
|
+
~handler,
|
|
128
|
+
~checkpointId,
|
|
129
|
+
~inMemoryStore,
|
|
130
|
+
~loadManager,
|
|
131
|
+
~persistence=ctx.persistence,
|
|
132
|
+
~chains,
|
|
133
|
+
~config=ctx.config,
|
|
134
|
+
)
|
|
135
|
+
| None => ()
|
|
215
136
|
}
|
|
216
137
|
}
|
|
217
138
|
}
|
|
@@ -333,17 +254,11 @@ let runBatchHandlersOrThrow = async (
|
|
|
333
254
|
}
|
|
334
255
|
}
|
|
335
256
|
|
|
336
|
-
let registerProcessEventBatchMetrics = (
|
|
337
|
-
~logger,
|
|
338
|
-
~loadDuration,
|
|
339
|
-
~handlerDuration,
|
|
340
|
-
~dbWriteDuration,
|
|
341
|
-
) => {
|
|
257
|
+
let registerProcessEventBatchMetrics = (~logger, ~loadDuration, ~handlerDuration) => {
|
|
342
258
|
logger->Logging.childTrace({
|
|
343
259
|
"msg": "Finished processing batch",
|
|
344
260
|
"loader_time_elapsed": loadDuration,
|
|
345
261
|
"handlers_time_elapsed": handlerDuration,
|
|
346
|
-
"write_time_elapsed": dbWriteDuration,
|
|
347
262
|
})
|
|
348
263
|
|
|
349
264
|
Prometheus.ProcessingBatch.registerMetrics(~loadDuration, ~handlerDuration)
|
|
@@ -359,7 +274,6 @@ type logPartitionInfo = {
|
|
|
359
274
|
let processEventBatch = async (
|
|
360
275
|
~batch: Batch.t,
|
|
361
276
|
~inMemoryStore: InMemoryStore.t,
|
|
362
|
-
~isInReorgThreshold,
|
|
363
277
|
~loadManager,
|
|
364
278
|
~ctx: Ctx.t,
|
|
365
279
|
~chainFetchers: ChainMap.t<ChainFetcher.t>,
|
|
@@ -381,6 +295,9 @@ let processEventBatch = async (
|
|
|
381
295
|
})
|
|
382
296
|
|
|
383
297
|
try {
|
|
298
|
+
// Backpressure: keep processing within keepLatestChangesLimit of the cycle.
|
|
299
|
+
await inMemoryStore->InMemoryStore.awaitCapacity
|
|
300
|
+
|
|
384
301
|
let timeRef = Hrtime.makeTimer()
|
|
385
302
|
|
|
386
303
|
if batch.items->Utils.Array.notEmpty {
|
|
@@ -401,34 +318,19 @@ let processEventBatch = async (
|
|
|
401
318
|
|
|
402
319
|
let elapsedTimeAfterProcessing = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
403
320
|
|
|
404
|
-
|
|
405
|
-
await inMemoryStore->InMemoryStore.writeBatch(
|
|
406
|
-
~persistence=ctx.persistence,
|
|
407
|
-
~batch,
|
|
408
|
-
~config=ctx.config,
|
|
409
|
-
~isInReorgThreshold,
|
|
410
|
-
)
|
|
321
|
+
inMemoryStore->InMemoryStore.commitBatch(~batch)
|
|
411
322
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
registerProcessEventBatchMetrics(
|
|
417
|
-
~logger,
|
|
418
|
-
~loadDuration=loaderDuration,
|
|
419
|
-
~handlerDuration,
|
|
420
|
-
~dbWriteDuration,
|
|
421
|
-
)
|
|
422
|
-
Ok()
|
|
423
|
-
} catch {
|
|
424
|
-
| Persistence.StorageError({message, reason}) =>
|
|
425
|
-
reason->ErrorHandling.make(~msg=message, ~logger)->Error
|
|
426
|
-
| exn => exn->ErrorHandling.make(~msg="Failed writing batch to database", ~logger)->Error
|
|
427
|
-
}
|
|
323
|
+
let loaderDuration = elapsedTimeAfterLoaders
|
|
324
|
+
let handlerDuration = elapsedTimeAfterProcessing -. loaderDuration
|
|
325
|
+
registerProcessEventBatchMetrics(~logger, ~loadDuration=loaderDuration, ~handlerDuration)
|
|
326
|
+
Ok()
|
|
428
327
|
} catch {
|
|
328
|
+
| Persistence.StorageError({message, reason}) =>
|
|
329
|
+
reason->ErrorHandling.make(~msg=message, ~logger)->Error
|
|
429
330
|
| ProcessingError({message, exn, item}) =>
|
|
430
331
|
exn
|
|
431
332
|
->ErrorHandling.make(~msg=message, ~logger=item->Logging.getItemLogger)
|
|
432
333
|
->Error
|
|
334
|
+
| exn => exn->ErrorHandling.make(~msg="Failed processing batch", ~logger)->Error
|
|
433
335
|
}
|
|
434
336
|
}
|
|
@@ -5,14 +5,12 @@ import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
|
5
5
|
import * as Logging from "./Logging.res.mjs";
|
|
6
6
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
7
7
|
import * as Ecosystem from "./Ecosystem.res.mjs";
|
|
8
|
-
import * as EventUtils from "./EventUtils.res.mjs";
|
|
9
8
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
10
9
|
import * as Persistence from "./Persistence.res.mjs";
|
|
11
10
|
import * as UserContext from "./UserContext.res.mjs";
|
|
12
11
|
import * as ChainFetcher from "./ChainFetcher.res.mjs";
|
|
13
12
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
14
13
|
import * as InMemoryStore from "./InMemoryStore.res.mjs";
|
|
15
|
-
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
16
14
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
17
15
|
|
|
18
16
|
function allChainsEventsProcessedToEndblock(chainFetchers) {
|
|
@@ -31,55 +29,6 @@ function computeChainsState(chainFetchers) {
|
|
|
31
29
|
return chains;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
function convertFieldsToJson(fields) {
|
|
35
|
-
if (fields !== undefined) {
|
|
36
|
-
return Utils.Dict.mapValues(fields, value => {
|
|
37
|
-
if (typeof value === "bigint") {
|
|
38
|
-
return value.toString();
|
|
39
|
-
} else {
|
|
40
|
-
return value;
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
} else {
|
|
44
|
-
return {};
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function addItemToRawEvents(eventItem, inMemoryStore, config) {
|
|
49
|
-
let event = eventItem.event;
|
|
50
|
-
let block = event.block;
|
|
51
|
-
let logIndex = event.logIndex;
|
|
52
|
-
let blockNumber = eventItem.blockNumber;
|
|
53
|
-
let eventConfig = eventItem.eventConfig;
|
|
54
|
-
let eventId = EventUtils.packEventIndex(blockNumber, logIndex);
|
|
55
|
-
let blockFields = convertFieldsToJson(block);
|
|
56
|
-
let transactionFields = convertFieldsToJson(event.transaction);
|
|
57
|
-
config.ecosystem.cleanUpRawEventFieldsInPlace(blockFields);
|
|
58
|
-
let params = S$RescriptSchema.reverseConvertOrThrow(event.params, eventConfig.paramsRawEventSchema);
|
|
59
|
-
let params$1 = params === null ? "null" : params;
|
|
60
|
-
let rawEvent_chain_id = eventItem.chain;
|
|
61
|
-
let rawEvent_event_name = eventConfig.name;
|
|
62
|
-
let rawEvent_contract_name = eventConfig.contractName;
|
|
63
|
-
let rawEvent_src_address = event.srcAddress;
|
|
64
|
-
let rawEvent_block_hash = config.ecosystem.getId(block);
|
|
65
|
-
let rawEvent_block_timestamp = eventItem.timestamp;
|
|
66
|
-
let rawEvent = {
|
|
67
|
-
chain_id: rawEvent_chain_id,
|
|
68
|
-
event_id: eventId,
|
|
69
|
-
event_name: rawEvent_event_name,
|
|
70
|
-
contract_name: rawEvent_contract_name,
|
|
71
|
-
block_number: blockNumber,
|
|
72
|
-
log_index: logIndex,
|
|
73
|
-
src_address: rawEvent_src_address,
|
|
74
|
-
block_hash: rawEvent_block_hash,
|
|
75
|
-
block_timestamp: rawEvent_block_timestamp,
|
|
76
|
-
block_fields: blockFields,
|
|
77
|
-
transaction_fields: transactionFields,
|
|
78
|
-
params: params$1
|
|
79
|
-
};
|
|
80
|
-
inMemoryStore.rawEvents.push(rawEvent);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
32
|
let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessing.ProcessingError");
|
|
84
33
|
|
|
85
34
|
async function runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore, loadManager, persistence, chains, config) {
|
|
@@ -119,10 +68,7 @@ async function runHandlerOrThrow(item, checkpointId, inMemoryStore, loadManager,
|
|
|
119
68
|
if (item.kind === 0) {
|
|
120
69
|
let handler = item.eventConfig.handler;
|
|
121
70
|
if (handler !== undefined) {
|
|
122
|
-
await runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore, loadManager, ctx.persistence, chains, ctx.config);
|
|
123
|
-
}
|
|
124
|
-
if (ctx.config.enableRawEvents) {
|
|
125
|
-
return addItemToRawEvents(item, inMemoryStore, ctx.config);
|
|
71
|
+
return await runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore, loadManager, ctx.persistence, chains, ctx.config);
|
|
126
72
|
} else {
|
|
127
73
|
return;
|
|
128
74
|
}
|
|
@@ -224,17 +170,16 @@ async function runBatchHandlersOrThrow(batch, inMemoryStore, loadManager, ctx, c
|
|
|
224
170
|
}
|
|
225
171
|
}
|
|
226
172
|
|
|
227
|
-
function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration
|
|
173
|
+
function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration) {
|
|
228
174
|
Logging.childTrace(logger, {
|
|
229
175
|
msg: "Finished processing batch",
|
|
230
176
|
loader_time_elapsed: loadDuration,
|
|
231
|
-
handlers_time_elapsed: handlerDuration
|
|
232
|
-
write_time_elapsed: dbWriteDuration
|
|
177
|
+
handlers_time_elapsed: handlerDuration
|
|
233
178
|
});
|
|
234
179
|
Prometheus.ProcessingBatch.registerMetrics(loadDuration, handlerDuration);
|
|
235
180
|
}
|
|
236
181
|
|
|
237
|
-
async function processEventBatch(batch, inMemoryStore,
|
|
182
|
+
async function processEventBatch(batch, inMemoryStore, loadManager, ctx, chainFetchers) {
|
|
238
183
|
let totalBatchSize = batch.totalBatchSize;
|
|
239
184
|
let chains = computeChainsState(chainFetchers);
|
|
240
185
|
let logger = Logging.getLogger();
|
|
@@ -247,6 +192,7 @@ async function processEventBatch(batch, inMemoryStore, isInReorgThreshold, loadM
|
|
|
247
192
|
}))
|
|
248
193
|
});
|
|
249
194
|
try {
|
|
195
|
+
await InMemoryStore.awaitCapacity(inMemoryStore);
|
|
250
196
|
let timeRef = Hrtime.makeTimer();
|
|
251
197
|
if (Utils.$$Array.notEmpty(batch.items)) {
|
|
252
198
|
await preloadBatchOrThrow(batch, loadManager, ctx.persistence, ctx.config, inMemoryStore, chains);
|
|
@@ -256,47 +202,37 @@ async function processEventBatch(batch, inMemoryStore, isInReorgThreshold, loadM
|
|
|
256
202
|
await runBatchHandlersOrThrow(batch, inMemoryStore, loadManager, ctx, chains);
|
|
257
203
|
}
|
|
258
204
|
let elapsedTimeAfterProcessing = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
205
|
+
InMemoryStore.commitBatch(inMemoryStore, batch);
|
|
206
|
+
let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders;
|
|
207
|
+
registerProcessEventBatchMetrics(logger, elapsedTimeAfterLoaders, handlerDuration);
|
|
208
|
+
return {
|
|
209
|
+
TAG: "Ok",
|
|
210
|
+
_0: undefined
|
|
211
|
+
};
|
|
212
|
+
} catch (raw_exn) {
|
|
213
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
214
|
+
if (exn.RE_EXN_ID === Persistence.StorageError) {
|
|
265
215
|
return {
|
|
266
|
-
TAG: "
|
|
267
|
-
_0:
|
|
216
|
+
TAG: "Error",
|
|
217
|
+
_0: ErrorHandling.make(exn.reason, logger, exn.message)
|
|
268
218
|
};
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
};
|
|
276
|
-
} else {
|
|
277
|
-
return {
|
|
278
|
-
TAG: "Error",
|
|
279
|
-
_0: ErrorHandling.make(exn, logger, "Failed writing batch to database")
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
} catch (raw_exn$1) {
|
|
284
|
-
let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
|
|
285
|
-
if (exn$1.RE_EXN_ID === ProcessingError) {
|
|
219
|
+
} else if (exn.RE_EXN_ID === ProcessingError) {
|
|
220
|
+
return {
|
|
221
|
+
TAG: "Error",
|
|
222
|
+
_0: ErrorHandling.make(exn.exn, Logging.getItemLogger(exn.item), exn.message)
|
|
223
|
+
};
|
|
224
|
+
} else {
|
|
286
225
|
return {
|
|
287
226
|
TAG: "Error",
|
|
288
|
-
_0: ErrorHandling.make(exn
|
|
227
|
+
_0: ErrorHandling.make(exn, logger, "Failed processing batch")
|
|
289
228
|
};
|
|
290
229
|
}
|
|
291
|
-
throw exn$1;
|
|
292
230
|
}
|
|
293
231
|
}
|
|
294
232
|
|
|
295
233
|
export {
|
|
296
234
|
allChainsEventsProcessedToEndblock,
|
|
297
235
|
computeChainsState,
|
|
298
|
-
convertFieldsToJson,
|
|
299
|
-
addItemToRawEvents,
|
|
300
236
|
ProcessingError,
|
|
301
237
|
runEventHandlerOrThrow,
|
|
302
238
|
runHandlerOrThrow,
|