envio 3.2.1 → 3.3.0-alpha.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/package.json +6 -7
- package/src/Batch.res +12 -15
- package/src/Batch.res.mjs +4 -5
- package/src/BatchProcessing.res +199 -0
- package/src/BatchProcessing.res.mjs +125 -0
- package/src/ChainFetching.res +375 -0
- package/src/ChainFetching.res.mjs +206 -0
- package/src/ChainMetadata.res +27 -0
- package/src/ChainMetadata.res.mjs +27 -0
- package/src/ChainState.res +618 -0
- package/src/ChainState.res.mjs +461 -0
- package/src/ChainState.resi +85 -0
- package/src/Config.res +13 -4
- package/src/Config.res.mjs +8 -3
- package/src/ContractRegisterContext.res +106 -0
- package/src/ContractRegisterContext.res.mjs +76 -0
- package/src/Core.res +3 -0
- package/src/CrossChainState.res +269 -0
- package/src/CrossChainState.res.mjs +197 -0
- package/src/CrossChainState.resi +47 -0
- package/src/Ecosystem.res +58 -0
- package/src/Ecosystem.res.mjs +43 -1
- package/src/Env.res +7 -2
- package/src/Env.res.mjs +5 -2
- package/src/EventConfigBuilder.res +2 -2
- package/src/EventProcessing.res +60 -46
- package/src/EventProcessing.res.mjs +33 -32
- package/src/EventUtils.res +0 -4
- package/src/EventUtils.res.mjs +0 -4
- package/src/ExitOnCaughtUp.res +10 -0
- package/src/ExitOnCaughtUp.res.mjs +22 -0
- package/src/FetchState.res +124 -62
- package/src/FetchState.res.mjs +159 -93
- package/src/InMemoryStore.res +36 -451
- package/src/InMemoryStore.res.mjs +20 -369
- package/src/IndexerLoop.res +44 -0
- package/src/IndexerLoop.res.mjs +46 -0
- package/src/IndexerState.res +544 -0
- package/src/IndexerState.res.mjs +547 -0
- package/src/IndexerState.resi +132 -0
- package/src/Internal.res +29 -8
- package/src/LoadLayer.res +20 -18
- package/src/LoadLayer.res.mjs +14 -12
- package/src/LoadLayer.resi +6 -3
- package/src/Logging.res +11 -44
- package/src/Logging.res.mjs +10 -42
- package/src/Main.res +54 -79
- package/src/Main.res.mjs +44 -56
- package/src/PgStorage.res +8 -71
- package/src/PgStorage.res.mjs +3 -47
- package/src/Prometheus.res +7 -8
- package/src/Prometheus.res.mjs +7 -4
- package/src/PruneStaleHistory.res +45 -0
- package/src/PruneStaleHistory.res.mjs +46 -0
- package/src/RawEvent.res +73 -0
- package/src/RawEvent.res.mjs +51 -0
- package/src/Rollback.res +204 -0
- package/src/Rollback.res.mjs +118 -0
- package/src/SimulateItems.res +12 -10
- package/src/SimulateItems.res.mjs +1 -1
- package/src/UserContext.res +26 -114
- package/src/UserContext.res.mjs +15 -78
- package/src/Writing.res +242 -0
- package/src/Writing.res.mjs +215 -0
- package/src/db/InternalTable.res +14 -27
- package/src/sources/Evm.res +40 -1
- package/src/sources/Evm.res.mjs +94 -84
- package/src/sources/Fuel.res +40 -1
- package/src/sources/Fuel.res.mjs +36 -26
- package/src/sources/HyperFuel.res +41 -120
- package/src/sources/HyperFuel.res.mjs +42 -80
- package/src/sources/HyperFuel.resi +1 -24
- package/src/sources/HyperFuelClient.res +16 -297
- package/src/sources/HyperFuelClient.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +33 -8
- package/src/sources/HyperFuelSource.res.mjs +56 -10
- package/src/sources/HyperSyncSource.res +5 -3
- package/src/sources/HyperSyncSource.res.mjs +1 -1
- package/src/sources/RpcSource.res +2 -2
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SourceManager.res +8 -18
- package/src/sources/SourceManager.res.mjs +8 -5
- package/src/sources/SourceManager.resi +4 -1
- package/src/sources/Svm.res +18 -1
- package/src/sources/Svm.res.mjs +30 -22
- package/src/sources/SvmHyperSyncSource.res +1 -1
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/tui/Tui.res +38 -36
- package/src/tui/Tui.res.mjs +51 -51
- package/src/ChainFetcher.res +0 -519
- package/src/ChainFetcher.res.mjs +0 -314
- package/src/ChainManager.res +0 -358
- package/src/ChainManager.res.mjs +0 -291
- package/src/Ctx.res +0 -6
- package/src/Ctx.res.mjs +0 -2
- package/src/GlobalState.res +0 -1056
- package/src/GlobalState.res.mjs +0 -1086
- package/src/GlobalStateManager.res +0 -57
- package/src/GlobalStateManager.res.mjs +0 -68
- package/src/GlobalStateManager.resi +0 -7
- package/src/Ports.res +0 -5
- package/src/Ports.res.mjs +0 -9
- package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
- package/src/sources/EnvioApiClient.res +0 -15
- package/src/sources/EnvioApiClient.res.mjs +0 -24
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Whole-indexer view over every chain's ChainState. `t` is opaque: other modules
|
|
2
|
+
// read it through the accessors and change it only through the transitions here.
|
|
3
|
+
|
|
4
|
+
type t
|
|
5
|
+
|
|
6
|
+
let calculateTargetBufferSize: unit => int
|
|
7
|
+
|
|
8
|
+
let make: (
|
|
9
|
+
~chainStates: dict<ChainState.t>,
|
|
10
|
+
~isInReorgThreshold: bool,
|
|
11
|
+
~isRealtime: bool,
|
|
12
|
+
~maxBackfillConcurrency: int=?,
|
|
13
|
+
~maxRealtimeConcurrency: int=?,
|
|
14
|
+
~targetBufferSize: int=?,
|
|
15
|
+
) => t
|
|
16
|
+
|
|
17
|
+
// Accessors.
|
|
18
|
+
let chainStates: t => dict<ChainState.t>
|
|
19
|
+
let isRealtime: t => bool
|
|
20
|
+
let isInReorgThreshold: t => bool
|
|
21
|
+
let maxConcurrency: t => int
|
|
22
|
+
let inFlight: t => int
|
|
23
|
+
|
|
24
|
+
// Derived (pure).
|
|
25
|
+
let nextItemIsNone: t => bool
|
|
26
|
+
let getSafeCheckpointId: t => option<Internal.checkpointId>
|
|
27
|
+
|
|
28
|
+
// Cross-chain transitions.
|
|
29
|
+
let createBatch: (
|
|
30
|
+
t,
|
|
31
|
+
~processedCheckpointId: Internal.checkpointId,
|
|
32
|
+
~batchSizeTarget: int,
|
|
33
|
+
~isRollback: bool,
|
|
34
|
+
) => Batch.t
|
|
35
|
+
let enterReorgThreshold: t => unit
|
|
36
|
+
let applyBatchProgress: (t, ~batch: Batch.t) => unit
|
|
37
|
+
|
|
38
|
+
// Fetch control.
|
|
39
|
+
let priorityOrder: t => array<ChainState.t>
|
|
40
|
+
let checkAndFetch: (
|
|
41
|
+
t,
|
|
42
|
+
~fetchChain: (
|
|
43
|
+
~chain: ChainMap.Chain.t,
|
|
44
|
+
~concurrencyLimit: int,
|
|
45
|
+
~bufferLimit: int,
|
|
46
|
+
) => promise<unit>,
|
|
47
|
+
) => promise<unit>
|
package/src/Ecosystem.res
CHANGED
|
@@ -29,8 +29,66 @@ type t = {
|
|
|
29
29
|
`LogSelection.res`. SVM does not support event handlers, so its
|
|
30
30
|
schema always surfaces `None`. */
|
|
31
31
|
onEventBlockFilterSchema: S.t<option<unknown>>,
|
|
32
|
+
/** Base logger injected at construction. Used to build per-item child
|
|
33
|
+
loggers (see `getItemLogger`). */
|
|
34
|
+
logger: Pino.t,
|
|
35
|
+
/** Materialise the user-facing event handed to handlers and contract
|
|
36
|
+
registration from an item's opaque payload. */
|
|
37
|
+
toEvent: Internal.eventItem => Internal.event,
|
|
38
|
+
/** Build the per-item child logger for an event item, with
|
|
39
|
+
ecosystem-specific log fields (EVM/Fuel: contract/event/address; SVM:
|
|
40
|
+
program/instruction/programId). Closes over the injected logger. */
|
|
41
|
+
toEventLogger: Internal.eventItem => Pino.t,
|
|
42
|
+
/** Build a raw event row for the `raw_events` table. Unsupported on SVM,
|
|
43
|
+
where the implementation throws. */
|
|
44
|
+
toRawEvent: Internal.eventItem => Internal.rawEvent,
|
|
32
45
|
}
|
|
33
46
|
|
|
47
|
+
// The materialised event and the child logger are both memoised on the item
|
|
48
|
+
// object (an item is processed across preload + execution passes, and logged
|
|
49
|
+
// from several places). Hidden keys mirror each other.
|
|
50
|
+
let getItemEvent = {
|
|
51
|
+
let cacheKey = "_event"
|
|
52
|
+
(item: Internal.item, ~ecosystem: t): Internal.event => {
|
|
53
|
+
let cache = item->(Utils.magic: Internal.item => dict<Internal.event>)
|
|
54
|
+
switch cache->Utils.Dict.dangerouslyGetNonOption(cacheKey) {
|
|
55
|
+
| Some(event) => event
|
|
56
|
+
| None =>
|
|
57
|
+
let event = ecosystem.toEvent(item->Internal.castUnsafeEventItem)
|
|
58
|
+
cache->Dict.set(cacheKey, event)
|
|
59
|
+
event
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let getItemLogger = {
|
|
65
|
+
let cacheKey = "_logger"
|
|
66
|
+
(item: Internal.item, ~ecosystem: t): Pino.t => {
|
|
67
|
+
let cache = item->(Utils.magic: Internal.item => dict<Pino.t>)
|
|
68
|
+
switch cache->Utils.Dict.dangerouslyGetNonOption(cacheKey) {
|
|
69
|
+
| Some(logger) => logger
|
|
70
|
+
| None =>
|
|
71
|
+
let logger = switch item {
|
|
72
|
+
| Internal.Event(_) => ecosystem.toEventLogger(item->Internal.castUnsafeEventItem)
|
|
73
|
+
| Block({blockNumber, onBlockConfig}) =>
|
|
74
|
+
Logging.createChildFrom(
|
|
75
|
+
~logger=ecosystem.logger,
|
|
76
|
+
~params={
|
|
77
|
+
"onBlock": onBlockConfig.name,
|
|
78
|
+
"chainId": onBlockConfig.chainId,
|
|
79
|
+
"block": blockNumber,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
cache->Dict.set(cacheKey, logger)
|
|
84
|
+
logger
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let getItemUserLogger = (item: Internal.item, ~ecosystem: t): Envio.logger =>
|
|
90
|
+
getItemLogger(item, ~ecosystem)->Logging.userLogger
|
|
91
|
+
|
|
34
92
|
let makeOnBlockArgs = (~blockNumber: int, ~ecosystem: t, ~context): Internal.onBlockArgs => {
|
|
35
93
|
switch ecosystem.name {
|
|
36
94
|
| Svm => {slot: blockNumber, context}
|
package/src/Ecosystem.res.mjs
CHANGED
|
@@ -1,7 +1,46 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Logging from "./Logging.res.mjs";
|
|
3
4
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
4
5
|
|
|
6
|
+
let cacheKey = "_event";
|
|
7
|
+
|
|
8
|
+
function getItemEvent(item, ecosystem) {
|
|
9
|
+
let event = item[cacheKey];
|
|
10
|
+
if (event !== undefined) {
|
|
11
|
+
return Primitive_option.valFromOption(event);
|
|
12
|
+
}
|
|
13
|
+
let event$1 = ecosystem.toEvent(item);
|
|
14
|
+
item[cacheKey] = event$1;
|
|
15
|
+
return event$1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let cacheKey$1 = "_logger";
|
|
19
|
+
|
|
20
|
+
function getItemLogger(item, ecosystem) {
|
|
21
|
+
let logger = item[cacheKey$1];
|
|
22
|
+
if (logger !== undefined) {
|
|
23
|
+
return logger;
|
|
24
|
+
}
|
|
25
|
+
let logger$1;
|
|
26
|
+
if (item.kind === 0) {
|
|
27
|
+
logger$1 = ecosystem.toEventLogger(item);
|
|
28
|
+
} else {
|
|
29
|
+
let onBlockConfig = item.onBlockConfig;
|
|
30
|
+
logger$1 = Logging.createChildFrom(ecosystem.logger, {
|
|
31
|
+
onBlock: onBlockConfig.name,
|
|
32
|
+
chainId: onBlockConfig.chainId,
|
|
33
|
+
block: item.blockNumber
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
item[cacheKey$1] = logger$1;
|
|
37
|
+
return logger$1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getItemUserLogger(item, ecosystem) {
|
|
41
|
+
return Logging.userLogger(getItemLogger(item, ecosystem));
|
|
42
|
+
}
|
|
43
|
+
|
|
5
44
|
function makeOnBlockArgs(blockNumber, ecosystem, context) {
|
|
6
45
|
let match = ecosystem.name;
|
|
7
46
|
switch (match) {
|
|
@@ -23,6 +62,9 @@ function makeOnBlockArgs(blockNumber, ecosystem, context) {
|
|
|
23
62
|
}
|
|
24
63
|
|
|
25
64
|
export {
|
|
65
|
+
getItemEvent,
|
|
66
|
+
getItemLogger,
|
|
67
|
+
getItemUserLogger,
|
|
26
68
|
makeOnBlockArgs,
|
|
27
69
|
}
|
|
28
|
-
/*
|
|
70
|
+
/* Logging Not a pure module */
|
package/src/Env.res
CHANGED
|
@@ -8,8 +8,13 @@ let updateSyncTimeOnRestart =
|
|
|
8
8
|
envSafe->EnvSafe.get("UPDATE_SYNC_TIME_ON_RESTART", S.bool, ~fallback=true)
|
|
9
9
|
let targetBufferSize = envSafe->EnvSafe.get("ENVIO_INDEXING_MAX_BUFFER_SIZE", S.option(S.int))
|
|
10
10
|
let maxAddrInPartition = envSafe->EnvSafe.get("MAX_PARTITION_SIZE", S.int, ~fallback=5_000)
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// Global caps on concurrent data-source queries across the whole indexer (all
|
|
12
|
+
// chains share the budget), not per chain. Realtime allows far more since head
|
|
13
|
+
// queries are small and many chains follow the head at once.
|
|
14
|
+
let maxBackfillConcurrency =
|
|
15
|
+
envSafe->EnvSafe.get("ENVIO_MAX_BACKFILL_CONCURRENCY", S.int, ~fallback=30)
|
|
16
|
+
let maxRealtimeConcurrency =
|
|
17
|
+
envSafe->EnvSafe.get("ENVIO_MAX_REALTIME_CONCURRENCY", S.int, ~fallback=200)
|
|
13
18
|
|
|
14
19
|
// Target number of in-memory objects (uncommitted entity/effect changes plus
|
|
15
20
|
// unwritten batch items) the store holds before processing waits for the write
|
package/src/Env.res.mjs
CHANGED
|
@@ -19,7 +19,9 @@ let targetBufferSize = EnvSafe.get(envSafe, "ENVIO_INDEXING_MAX_BUFFER_SIZE", S$
|
|
|
19
19
|
|
|
20
20
|
let maxAddrInPartition = EnvSafe.get(envSafe, "MAX_PARTITION_SIZE", S$RescriptSchema.int, undefined, 5000, undefined, undefined);
|
|
21
21
|
|
|
22
|
-
let
|
|
22
|
+
let maxBackfillConcurrency = EnvSafe.get(envSafe, "ENVIO_MAX_BACKFILL_CONCURRENCY", S$RescriptSchema.int, undefined, 30, undefined, undefined);
|
|
23
|
+
|
|
24
|
+
let maxRealtimeConcurrency = EnvSafe.get(envSafe, "ENVIO_MAX_REALTIME_CONCURRENCY", S$RescriptSchema.int, undefined, 200, undefined, undefined);
|
|
23
25
|
|
|
24
26
|
let inMemoryObjectsTarget = EnvSafe.get(envSafe, "ENVIO_IN_MEMORY_OBJECTS_TARGET", S$RescriptSchema.int, undefined, 100000, undefined, undefined);
|
|
25
27
|
|
|
@@ -222,7 +224,8 @@ export {
|
|
|
222
224
|
updateSyncTimeOnRestart,
|
|
223
225
|
targetBufferSize,
|
|
224
226
|
maxAddrInPartition,
|
|
225
|
-
|
|
227
|
+
maxBackfillConcurrency,
|
|
228
|
+
maxRealtimeConcurrency,
|
|
226
229
|
inMemoryObjectsTarget,
|
|
227
230
|
serverPort,
|
|
228
231
|
tuiEnvVar,
|
|
@@ -312,7 +312,7 @@ let resolveFieldSelection = (
|
|
|
312
312
|
// ============== Client-side address filter ==============
|
|
313
313
|
|
|
314
314
|
let compileAddressFilter: string => (
|
|
315
|
-
Internal.
|
|
315
|
+
Internal.eventPayload,
|
|
316
316
|
int,
|
|
317
317
|
dict<Internal.indexingContract>,
|
|
318
318
|
) => bool = %raw(`function (body) {
|
|
@@ -339,7 +339,7 @@ let buildAddressFilterBody = (groups: array<array<string>>): option<string> => {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
let buildAddressFilter = (groups: array<array<string>>): option<
|
|
342
|
-
(Internal.
|
|
342
|
+
(Internal.eventPayload, int, dict<Internal.indexingContract>) => bool,
|
|
343
343
|
> => buildAddressFilterBody(groups)->Option.map(compileAddressFilter)
|
|
344
344
|
|
|
345
345
|
// ============== Build complete EVM event config ==============
|
package/src/EventProcessing.res
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
let allChainsEventsProcessedToEndblock = (
|
|
2
|
-
|
|
3
|
-
->
|
|
4
|
-
->Array.every(
|
|
1
|
+
let allChainsEventsProcessedToEndblock = (chainStates: dict<ChainState.t>) => {
|
|
2
|
+
chainStates
|
|
3
|
+
->Dict.valuesToArray
|
|
4
|
+
->Array.every(cs => cs->ChainState.hasProcessedToEndblock)
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
let computeChainsState = (
|
|
7
|
+
let computeChainsState = (chainStates: dict<ChainState.t>): Internal.chains => {
|
|
8
8
|
let chains = Dict.make()
|
|
9
9
|
|
|
10
|
-
let
|
|
10
|
+
let values = chainStates->Dict.valuesToArray
|
|
11
|
+
let isRealtime = values->Array.every(cs => cs->ChainState.isReady)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
->Array.forEach(chain => {
|
|
15
|
-
let chainId = chain->ChainMap.Chain.toChainId
|
|
13
|
+
values->Array.forEach(cs => {
|
|
14
|
+
let chainId = (cs->ChainState.chainConfig).id
|
|
16
15
|
chains->Dict.set(
|
|
17
16
|
chainId->Int.toString,
|
|
18
17
|
{
|
|
@@ -31,7 +30,7 @@ let runEventHandlerOrThrow = async (
|
|
|
31
30
|
item: Internal.item,
|
|
32
31
|
~checkpointId,
|
|
33
32
|
~handler,
|
|
34
|
-
~
|
|
33
|
+
~indexerState,
|
|
35
34
|
~loadManager,
|
|
36
35
|
~persistence,
|
|
37
36
|
~chains: Internal.chains,
|
|
@@ -46,7 +45,7 @@ let runEventHandlerOrThrow = async (
|
|
|
46
45
|
let contextParams: UserContext.contextParams = {
|
|
47
46
|
item,
|
|
48
47
|
checkpointId,
|
|
49
|
-
|
|
48
|
+
indexerState,
|
|
50
49
|
loadManager,
|
|
51
50
|
persistence,
|
|
52
51
|
isPreload: false,
|
|
@@ -57,7 +56,7 @@ let runEventHandlerOrThrow = async (
|
|
|
57
56
|
await handler(
|
|
58
57
|
(
|
|
59
58
|
{
|
|
60
|
-
event:
|
|
59
|
+
event: item->Ecosystem.getItemEvent(~ecosystem=config.ecosystem),
|
|
61
60
|
context: UserContext.getHandlerContext(contextParams),
|
|
62
61
|
}: Internal.handlerArgs
|
|
63
62
|
),
|
|
@@ -84,9 +83,10 @@ let runEventHandlerOrThrow = async (
|
|
|
84
83
|
let runHandlerOrThrow = async (
|
|
85
84
|
item: Internal.item,
|
|
86
85
|
~checkpointId,
|
|
87
|
-
~
|
|
86
|
+
~indexerState,
|
|
88
87
|
~loadManager,
|
|
89
|
-
~
|
|
88
|
+
~persistence: Persistence.t,
|
|
89
|
+
~config: Config.t,
|
|
90
90
|
~chains: Internal.chains,
|
|
91
91
|
) => {
|
|
92
92
|
switch item {
|
|
@@ -94,19 +94,19 @@ let runHandlerOrThrow = async (
|
|
|
94
94
|
try {
|
|
95
95
|
let contextParams: UserContext.contextParams = {
|
|
96
96
|
item,
|
|
97
|
-
|
|
97
|
+
indexerState,
|
|
98
98
|
loadManager,
|
|
99
|
-
persistence
|
|
99
|
+
persistence,
|
|
100
100
|
checkpointId,
|
|
101
101
|
isPreload: false,
|
|
102
102
|
chains,
|
|
103
|
-
config
|
|
103
|
+
config,
|
|
104
104
|
isResolved: false,
|
|
105
105
|
}
|
|
106
106
|
await handler(
|
|
107
107
|
Ecosystem.makeOnBlockArgs(
|
|
108
108
|
~blockNumber,
|
|
109
|
-
~ecosystem=
|
|
109
|
+
~ecosystem=config.ecosystem,
|
|
110
110
|
~context=UserContext.getHandlerContext(contextParams),
|
|
111
111
|
),
|
|
112
112
|
)
|
|
@@ -121,16 +121,17 @@ let runHandlerOrThrow = async (
|
|
|
121
121
|
}),
|
|
122
122
|
)
|
|
123
123
|
}
|
|
124
|
-
| Event({eventConfig}) =>
|
|
124
|
+
| Event({eventConfig}) =>
|
|
125
|
+
switch eventConfig.handler {
|
|
125
126
|
| Some(handler) =>
|
|
126
127
|
await item->runEventHandlerOrThrow(
|
|
127
128
|
~handler,
|
|
128
129
|
~checkpointId,
|
|
129
|
-
~
|
|
130
|
+
~indexerState,
|
|
130
131
|
~loadManager,
|
|
131
|
-
~persistence
|
|
132
|
+
~persistence,
|
|
132
133
|
~chains,
|
|
133
|
-
~config
|
|
134
|
+
~config,
|
|
134
135
|
)
|
|
135
136
|
| None => ()
|
|
136
137
|
}
|
|
@@ -142,7 +143,7 @@ let preloadBatchOrThrow = async (
|
|
|
142
143
|
~loadManager,
|
|
143
144
|
~persistence,
|
|
144
145
|
~config: Config.t,
|
|
145
|
-
~
|
|
146
|
+
~indexerState,
|
|
146
147
|
~chains: Internal.chains,
|
|
147
148
|
) => {
|
|
148
149
|
// On the first run of loaders, we don't care about the result,
|
|
@@ -160,7 +161,7 @@ let preloadBatchOrThrow = async (
|
|
|
160
161
|
for idx in 0 to checkpointEventsProcessed - 1 {
|
|
161
162
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
162
163
|
switch item {
|
|
163
|
-
| Event({eventConfig: {handler, contractName, name: eventName}
|
|
164
|
+
| Event({eventConfig: {handler, contractName, name: eventName}}) =>
|
|
164
165
|
switch handler {
|
|
165
166
|
| None => ()
|
|
166
167
|
| Some(handler) =>
|
|
@@ -171,10 +172,10 @@ let preloadBatchOrThrow = async (
|
|
|
171
172
|
)
|
|
172
173
|
promises->Array.push(
|
|
173
174
|
handler({
|
|
174
|
-
event,
|
|
175
|
+
event: item->Ecosystem.getItemEvent(~ecosystem=config.ecosystem),
|
|
175
176
|
context: UserContext.getHandlerContext({
|
|
176
177
|
item,
|
|
177
|
-
|
|
178
|
+
indexerState,
|
|
178
179
|
loadManager,
|
|
179
180
|
persistence,
|
|
180
181
|
checkpointId,
|
|
@@ -208,7 +209,7 @@ let preloadBatchOrThrow = async (
|
|
|
208
209
|
~ecosystem=config.ecosystem,
|
|
209
210
|
~context=UserContext.getHandlerContext({
|
|
210
211
|
item,
|
|
211
|
-
|
|
212
|
+
indexerState,
|
|
212
213
|
loadManager,
|
|
213
214
|
persistence,
|
|
214
215
|
checkpointId,
|
|
@@ -234,9 +235,10 @@ let preloadBatchOrThrow = async (
|
|
|
234
235
|
|
|
235
236
|
let runBatchHandlersOrThrow = async (
|
|
236
237
|
batch: Batch.t,
|
|
237
|
-
~
|
|
238
|
+
~indexerState,
|
|
238
239
|
~loadManager,
|
|
239
|
-
~
|
|
240
|
+
~persistence,
|
|
241
|
+
~config,
|
|
240
242
|
~chains: Internal.chains,
|
|
241
243
|
) => {
|
|
242
244
|
let itemIdx = ref(0)
|
|
@@ -248,7 +250,15 @@ let runBatchHandlersOrThrow = async (
|
|
|
248
250
|
for idx in 0 to checkpointEventsProcessed - 1 {
|
|
249
251
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
250
252
|
|
|
251
|
-
await runHandlerOrThrow(
|
|
253
|
+
await runHandlerOrThrow(
|
|
254
|
+
item,
|
|
255
|
+
~checkpointId,
|
|
256
|
+
~indexerState,
|
|
257
|
+
~loadManager,
|
|
258
|
+
~persistence,
|
|
259
|
+
~config,
|
|
260
|
+
~chains,
|
|
261
|
+
)
|
|
252
262
|
}
|
|
253
263
|
itemIdx := itemIdx.contents + checkpointEventsProcessed
|
|
254
264
|
}
|
|
@@ -273,14 +283,15 @@ type logPartitionInfo = {
|
|
|
273
283
|
|
|
274
284
|
let processEventBatch = async (
|
|
275
285
|
~batch: Batch.t,
|
|
276
|
-
~
|
|
286
|
+
~indexerState: IndexerState.t,
|
|
277
287
|
~loadManager,
|
|
278
|
-
~
|
|
279
|
-
~
|
|
288
|
+
~persistence: Persistence.t,
|
|
289
|
+
~config: Config.t,
|
|
290
|
+
~chainStates: dict<ChainState.t>,
|
|
280
291
|
) => {
|
|
281
292
|
let totalBatchSize = batch.totalBatchSize
|
|
282
293
|
// Compute chains state for this batch
|
|
283
|
-
let chains: Internal.chains =
|
|
294
|
+
let chains: Internal.chains = chainStates->computeChainsState
|
|
284
295
|
|
|
285
296
|
let logger = Logging.getLogger()
|
|
286
297
|
logger->Logging.childTrace({
|
|
@@ -296,29 +307,29 @@ let processEventBatch = async (
|
|
|
296
307
|
|
|
297
308
|
try {
|
|
298
309
|
// Backpressure: keep processing within keepLatestChangesLimit of the cycle.
|
|
299
|
-
await
|
|
310
|
+
await indexerState->Writing.awaitCapacity
|
|
300
311
|
|
|
301
312
|
let timeRef = Hrtime.makeTimer()
|
|
302
313
|
|
|
303
314
|
if batch.items->Utils.Array.notEmpty {
|
|
304
|
-
await batch->preloadBatchOrThrow(
|
|
305
|
-
~loadManager,
|
|
306
|
-
~persistence=ctx.persistence,
|
|
307
|
-
~inMemoryStore,
|
|
308
|
-
~chains,
|
|
309
|
-
~config=ctx.config,
|
|
310
|
-
)
|
|
315
|
+
await batch->preloadBatchOrThrow(~loadManager, ~persistence, ~indexerState, ~chains, ~config)
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
let elapsedTimeAfterLoaders = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
314
319
|
|
|
315
320
|
if batch.items->Utils.Array.notEmpty {
|
|
316
|
-
await batch->runBatchHandlersOrThrow(
|
|
321
|
+
await batch->runBatchHandlersOrThrow(
|
|
322
|
+
~indexerState,
|
|
323
|
+
~loadManager,
|
|
324
|
+
~persistence,
|
|
325
|
+
~config,
|
|
326
|
+
~chains,
|
|
327
|
+
)
|
|
317
328
|
}
|
|
318
329
|
|
|
319
330
|
let elapsedTimeAfterProcessing = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
320
331
|
|
|
321
|
-
|
|
332
|
+
indexerState->Writing.commitBatch(~batch)
|
|
322
333
|
|
|
323
334
|
let loaderDuration = elapsedTimeAfterLoaders
|
|
324
335
|
let handlerDuration = elapsedTimeAfterProcessing -. loaderDuration
|
|
@@ -329,7 +340,10 @@ let processEventBatch = async (
|
|
|
329
340
|
reason->ErrorHandling.make(~msg=message, ~logger)->Error
|
|
330
341
|
| ProcessingError({message, exn, item}) =>
|
|
331
342
|
exn
|
|
332
|
-
->ErrorHandling.make(
|
|
343
|
+
->ErrorHandling.make(
|
|
344
|
+
~msg=message,
|
|
345
|
+
~logger=Ecosystem.getItemLogger(item, ~ecosystem=config.ecosystem),
|
|
346
|
+
)
|
|
333
347
|
->Error
|
|
334
348
|
| exn => exn->ErrorHandling.make(~msg="Failed processing batch", ~logger)->Error
|
|
335
349
|
}
|
|
@@ -3,26 +3,27 @@
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
4
|
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
5
|
import * as Logging from "./Logging.res.mjs";
|
|
6
|
-
import * as
|
|
6
|
+
import * as Writing from "./Writing.res.mjs";
|
|
7
7
|
import * as Ecosystem from "./Ecosystem.res.mjs";
|
|
8
|
+
import * as ChainState from "./ChainState.res.mjs";
|
|
8
9
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
9
10
|
import * as Persistence from "./Persistence.res.mjs";
|
|
10
11
|
import * as UserContext from "./UserContext.res.mjs";
|
|
11
|
-
import * as ChainFetcher from "./ChainFetcher.res.mjs";
|
|
12
12
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
13
|
-
import * as InMemoryStore from "./InMemoryStore.res.mjs";
|
|
14
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
15
14
|
|
|
16
|
-
function allChainsEventsProcessedToEndblock(
|
|
17
|
-
return
|
|
15
|
+
function allChainsEventsProcessedToEndblock(chainStates) {
|
|
16
|
+
return Object.values(chainStates).every(ChainState.hasProcessedToEndblock);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
function computeChainsState(
|
|
19
|
+
function computeChainsState(chainStates) {
|
|
21
20
|
let chains = {};
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
let values = Object.values(chainStates);
|
|
22
|
+
let isRealtime = values.every(ChainState.isReady);
|
|
23
|
+
values.forEach(cs => {
|
|
24
|
+
let chainId = ChainState.chainConfig(cs).id;
|
|
25
|
+
chains[chainId.toString()] = {
|
|
26
|
+
id: chainId,
|
|
26
27
|
isRealtime: isRealtime
|
|
27
28
|
};
|
|
28
29
|
});
|
|
@@ -31,13 +32,13 @@ function computeChainsState(chainFetchers) {
|
|
|
31
32
|
|
|
32
33
|
let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessing.ProcessingError");
|
|
33
34
|
|
|
34
|
-
async function runEventHandlerOrThrow(item, checkpointId, handler,
|
|
35
|
+
async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config) {
|
|
35
36
|
let timeBeforeHandler = Hrtime.makeTimer();
|
|
36
37
|
try {
|
|
37
38
|
let contextParams = {
|
|
38
39
|
item: item,
|
|
39
40
|
checkpointId: checkpointId,
|
|
40
|
-
|
|
41
|
+
indexerState: indexerState,
|
|
41
42
|
loadManager: loadManager,
|
|
42
43
|
persistence: persistence,
|
|
43
44
|
isPreload: false,
|
|
@@ -46,7 +47,7 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore
|
|
|
46
47
|
isResolved: false
|
|
47
48
|
};
|
|
48
49
|
await handler({
|
|
49
|
-
event: item.
|
|
50
|
+
event: Ecosystem.getItemEvent(item, config.ecosystem),
|
|
50
51
|
context: UserContext.getHandlerContext(contextParams)
|
|
51
52
|
});
|
|
52
53
|
contextParams.isResolved = true;
|
|
@@ -64,11 +65,11 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore
|
|
|
64
65
|
return Prometheus.ProcessingHandler.increment(item.eventConfig.contractName, item.eventConfig.name, handlerDuration);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
async function runHandlerOrThrow(item, checkpointId,
|
|
68
|
+
async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains) {
|
|
68
69
|
if (item.kind === 0) {
|
|
69
70
|
let handler = item.eventConfig.handler;
|
|
70
71
|
if (handler !== undefined) {
|
|
71
|
-
return await runEventHandlerOrThrow(item, checkpointId, handler,
|
|
72
|
+
return await runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config);
|
|
72
73
|
} else {
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
@@ -77,15 +78,15 @@ async function runHandlerOrThrow(item, checkpointId, inMemoryStore, loadManager,
|
|
|
77
78
|
let contextParams = {
|
|
78
79
|
item: item,
|
|
79
80
|
checkpointId: checkpointId,
|
|
80
|
-
|
|
81
|
+
indexerState: indexerState,
|
|
81
82
|
loadManager: loadManager,
|
|
82
|
-
persistence:
|
|
83
|
+
persistence: persistence,
|
|
83
84
|
isPreload: false,
|
|
84
85
|
chains: chains,
|
|
85
|
-
config:
|
|
86
|
+
config: config,
|
|
86
87
|
isResolved: false
|
|
87
88
|
};
|
|
88
|
-
await item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber,
|
|
89
|
+
await item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
|
|
89
90
|
contextParams.isResolved = true;
|
|
90
91
|
return;
|
|
91
92
|
} catch (raw_exn) {
|
|
@@ -100,7 +101,7 @@ async function runHandlerOrThrow(item, checkpointId, inMemoryStore, loadManager,
|
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
async function preloadBatchOrThrow(batch, loadManager, persistence, config,
|
|
104
|
+
async function preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains) {
|
|
104
105
|
let promises = [];
|
|
105
106
|
let itemIdx = 0;
|
|
106
107
|
for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) {
|
|
@@ -117,11 +118,11 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inMe
|
|
|
117
118
|
try {
|
|
118
119
|
let timerRef = Prometheus.PreloadHandler.startOperation(contractName, eventName);
|
|
119
120
|
promises.push(Utils.$$Promise.silentCatch(handler({
|
|
120
|
-
event: item.
|
|
121
|
+
event: Ecosystem.getItemEvent(item, config.ecosystem),
|
|
121
122
|
context: UserContext.getHandlerContext({
|
|
122
123
|
item: item,
|
|
123
124
|
checkpointId: checkpointId,
|
|
124
|
-
|
|
125
|
+
indexerState: indexerState,
|
|
125
126
|
loadManager: loadManager,
|
|
126
127
|
persistence: persistence,
|
|
127
128
|
isPreload: true,
|
|
@@ -139,7 +140,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inMe
|
|
|
139
140
|
promises.push(Utils.$$Promise.silentCatch(item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext({
|
|
140
141
|
item: item,
|
|
141
142
|
checkpointId: checkpointId,
|
|
142
|
-
|
|
143
|
+
indexerState: indexerState,
|
|
143
144
|
loadManager: loadManager,
|
|
144
145
|
persistence: persistence,
|
|
145
146
|
isPreload: true,
|
|
@@ -157,14 +158,14 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inMe
|
|
|
157
158
|
await Promise.all(promises);
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
async function runBatchHandlersOrThrow(batch,
|
|
161
|
+
async function runBatchHandlersOrThrow(batch, indexerState, loadManager, persistence, config, chains) {
|
|
161
162
|
let itemIdx = 0;
|
|
162
163
|
for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) {
|
|
163
164
|
let checkpointId = batch.checkpointIds[checkpointIdx];
|
|
164
165
|
let checkpointEventsProcessed = batch.checkpointEventsProcessed[checkpointIdx];
|
|
165
166
|
for (let idx = 0; idx < checkpointEventsProcessed; ++idx) {
|
|
166
167
|
let item = batch.items[itemIdx + idx | 0];
|
|
167
|
-
await runHandlerOrThrow(item, checkpointId,
|
|
168
|
+
await runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains);
|
|
168
169
|
}
|
|
169
170
|
itemIdx = itemIdx + checkpointEventsProcessed | 0;
|
|
170
171
|
}
|
|
@@ -179,9 +180,9 @@ function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration)
|
|
|
179
180
|
Prometheus.ProcessingBatch.registerMetrics(loadDuration, handlerDuration);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
async function processEventBatch(batch,
|
|
183
|
+
async function processEventBatch(batch, indexerState, loadManager, persistence, config, chainStates) {
|
|
183
184
|
let totalBatchSize = batch.totalBatchSize;
|
|
184
|
-
let chains = computeChainsState(
|
|
185
|
+
let chains = computeChainsState(chainStates);
|
|
185
186
|
let logger = Logging.getLogger();
|
|
186
187
|
Logging.childTrace(logger, {
|
|
187
188
|
msg: "Started processing batch",
|
|
@@ -192,17 +193,17 @@ async function processEventBatch(batch, inMemoryStore, loadManager, ctx, chainFe
|
|
|
192
193
|
}))
|
|
193
194
|
});
|
|
194
195
|
try {
|
|
195
|
-
await
|
|
196
|
+
await Writing.awaitCapacity(indexerState);
|
|
196
197
|
let timeRef = Hrtime.makeTimer();
|
|
197
198
|
if (Utils.$$Array.notEmpty(batch.items)) {
|
|
198
|
-
await preloadBatchOrThrow(batch, loadManager,
|
|
199
|
+
await preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains);
|
|
199
200
|
}
|
|
200
201
|
let elapsedTimeAfterLoaders = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
|
|
201
202
|
if (Utils.$$Array.notEmpty(batch.items)) {
|
|
202
|
-
await runBatchHandlersOrThrow(batch,
|
|
203
|
+
await runBatchHandlersOrThrow(batch, indexerState, loadManager, persistence, config, chains);
|
|
203
204
|
}
|
|
204
205
|
let elapsedTimeAfterProcessing = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
|
|
205
|
-
|
|
206
|
+
Writing.commitBatch(indexerState, batch);
|
|
206
207
|
let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders;
|
|
207
208
|
registerProcessEventBatchMetrics(logger, elapsedTimeAfterLoaders, handlerDuration);
|
|
208
209
|
return {
|
|
@@ -219,7 +220,7 @@ async function processEventBatch(batch, inMemoryStore, loadManager, ctx, chainFe
|
|
|
219
220
|
} else if (exn.RE_EXN_ID === ProcessingError) {
|
|
220
221
|
return {
|
|
221
222
|
TAG: "Error",
|
|
222
|
-
_0: ErrorHandling.make(exn.exn,
|
|
223
|
+
_0: ErrorHandling.make(exn.exn, Ecosystem.getItemLogger(exn.item, config.ecosystem), exn.message)
|
|
223
224
|
};
|
|
224
225
|
} else {
|
|
225
226
|
return {
|