envio 3.1.2 → 3.2.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/evm.schema.json +83 -11
- package/fuel.schema.json +83 -11
- package/index.d.ts +184 -3
- package/package.json +6 -6
- package/src/Batch.res +2 -2
- package/src/ChainFetcher.res +27 -3
- package/src/ChainFetcher.res.mjs +17 -3
- package/src/ChainManager.res +163 -0
- package/src/ChainManager.res.mjs +136 -0
- package/src/Config.res +213 -30
- package/src/Config.res.mjs +102 -41
- package/src/Core.res +16 -10
- package/src/Ecosystem.res +0 -3
- package/src/Env.res +2 -2
- package/src/Env.res.mjs +2 -2
- package/src/Envio.res +101 -2
- package/src/Envio.res.mjs +2 -3
- package/src/EventConfigBuilder.res +52 -0
- package/src/EventConfigBuilder.res.mjs +32 -0
- package/src/EventUtils.res +2 -2
- package/src/FetchState.res +23 -14
- package/src/FetchState.res.mjs +21 -15
- package/src/GlobalState.res +219 -363
- package/src/GlobalState.res.mjs +314 -491
- package/src/GlobalStateManager.res +49 -59
- package/src/GlobalStateManager.res.mjs +5 -4
- package/src/GlobalStateManager.resi +1 -1
- package/src/HandlerLoader.res +12 -1
- package/src/HandlerLoader.res.mjs +6 -1
- package/src/HandlerRegister.res +9 -9
- package/src/HandlerRegister.res.mjs +9 -9
- package/src/Hasura.res +102 -32
- package/src/Hasura.res.mjs +88 -34
- package/src/InMemoryStore.res +10 -1
- package/src/InMemoryStore.res.mjs +4 -1
- package/src/InMemoryTable.res +83 -136
- package/src/InMemoryTable.res.mjs +57 -86
- package/src/Internal.res +54 -5
- package/src/Internal.res.mjs +2 -8
- package/src/LazyLoader.res +2 -2
- package/src/LazyLoader.res.mjs +3 -3
- package/src/LoadLayer.res +47 -60
- package/src/LoadLayer.res.mjs +28 -50
- package/src/LoadLayer.resi +2 -5
- package/src/LogSelection.res +4 -4
- package/src/LogSelection.res.mjs +5 -7
- package/src/Logging.res +1 -1
- package/src/Main.res +61 -2
- package/src/Main.res.mjs +37 -1
- package/src/Persistence.res +3 -16
- package/src/PgStorage.res +125 -114
- package/src/PgStorage.res.mjs +112 -95
- package/src/Ports.res +5 -0
- package/src/Ports.res.mjs +9 -0
- package/src/Prometheus.res +3 -3
- package/src/Prometheus.res.mjs +4 -4
- package/src/ReorgDetection.res +4 -4
- package/src/ReorgDetection.res.mjs +4 -5
- package/src/SafeCheckpointTracking.res +16 -16
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/SimulateItems.res +10 -14
- package/src/SimulateItems.res.mjs +5 -2
- package/src/Sink.res +1 -1
- package/src/Sink.res.mjs +1 -2
- package/src/SvmTypes.res +9 -0
- package/src/SvmTypes.res.mjs +14 -0
- package/src/TestIndexer.res +17 -57
- package/src/TestIndexer.res.mjs +14 -48
- package/src/TestIndexerProxyStorage.res +23 -23
- package/src/TestIndexerProxyStorage.res.mjs +12 -15
- package/src/Throttler.res +2 -2
- package/src/Time.res +2 -2
- package/src/Time.res.mjs +2 -2
- package/src/UserContext.res +19 -118
- package/src/UserContext.res.mjs +10 -66
- package/src/Utils.res +15 -15
- package/src/Utils.res.mjs +7 -8
- package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
- package/src/bindings/BigDecimal.res +1 -1
- package/src/bindings/BigDecimal.res.mjs +2 -2
- package/src/bindings/ClickHouse.res +8 -6
- package/src/bindings/ClickHouse.res.mjs +5 -5
- package/src/bindings/Hrtime.res +1 -1
- package/src/bindings/Pino.res +2 -2
- package/src/bindings/Pino.res.mjs +3 -4
- package/src/db/EntityFilter.res +410 -0
- package/src/db/EntityFilter.res.mjs +424 -0
- package/src/db/EntityHistory.res +1 -1
- package/src/db/EntityHistory.res.mjs +1 -1
- package/src/db/InternalTable.res +10 -10
- package/src/db/InternalTable.res.mjs +41 -45
- package/src/db/Schema.res +2 -2
- package/src/db/Schema.res.mjs +3 -3
- package/src/db/Table.res +106 -22
- package/src/db/Table.res.mjs +84 -35
- package/src/sources/EventRouter.res +67 -2
- package/src/sources/EventRouter.res.mjs +45 -3
- package/src/sources/Evm.res +0 -7
- package/src/sources/Evm.res.mjs +0 -15
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +1 -2
- package/src/sources/EvmRpcClient.res +42 -0
- package/src/sources/EvmRpcClient.res.mjs +64 -0
- package/src/sources/Fuel.res +0 -7
- package/src/sources/Fuel.res.mjs +0 -15
- package/src/sources/HyperFuelSource.res +5 -4
- package/src/sources/HyperFuelSource.res.mjs +2 -2
- package/src/sources/HyperSyncClient.res +9 -5
- package/src/sources/HyperSyncClient.res.mjs +2 -2
- package/src/sources/HyperSyncHeightStream.res +2 -2
- package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
- package/src/sources/HyperSyncSource.res +10 -9
- package/src/sources/HyperSyncSource.res.mjs +4 -4
- package/src/sources/Rpc.res +1 -5
- package/src/sources/Rpc.res.mjs +1 -9
- package/src/sources/RpcSource.res +57 -21
- package/src/sources/RpcSource.res.mjs +47 -20
- package/src/sources/RpcWebSocketHeightStream.res +1 -1
- package/src/sources/SourceManager.res +3 -2
- package/src/sources/SourceManager.res.mjs +1 -1
- package/src/sources/Svm.res +3 -10
- package/src/sources/Svm.res.mjs +4 -18
- package/src/sources/SvmHyperSyncClient.res +265 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
- package/src/sources/SvmHyperSyncSource.res +638 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
- package/src/tui/Tui.res +9 -2
- package/src/tui/Tui.res.mjs +18 -3
- package/src/tui/components/BufferedProgressBar.res +2 -2
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +523 -14
- package/src/TableIndices.res +0 -115
- package/src/TableIndices.res.mjs +0 -144
package/src/GlobalState.res
CHANGED
|
@@ -26,8 +26,6 @@ module WriteThrottlers = {
|
|
|
26
26
|
type t = {
|
|
27
27
|
ctx: Ctx.t,
|
|
28
28
|
chainManager: ChainManager.t,
|
|
29
|
-
processedBatches: int,
|
|
30
|
-
currentlyProcessingBatch: bool,
|
|
31
29
|
rollbackState: rollbackState,
|
|
32
30
|
indexerStartTime: Date.t,
|
|
33
31
|
writeThrottlers: WriteThrottlers.t,
|
|
@@ -51,8 +49,6 @@ let make = (
|
|
|
51
49
|
) => {
|
|
52
50
|
{
|
|
53
51
|
ctx,
|
|
54
|
-
currentlyProcessingBatch: false,
|
|
55
|
-
processedBatches: 0,
|
|
56
52
|
chainManager,
|
|
57
53
|
indexerStartTime: Date.make(),
|
|
58
54
|
rollbackState: NoRollback,
|
|
@@ -109,7 +105,6 @@ type action =
|
|
|
109
105
|
})
|
|
110
106
|
| FinishWaitingForNewBlock({chain: chain, knownHeight: int})
|
|
111
107
|
| EventBatchProcessed({batch: Batch.t})
|
|
112
|
-
| StartProcessingBatch
|
|
113
108
|
| StartFindingReorgDepth
|
|
114
109
|
| FindReorgDepth({chain: chain, rollbackTargetBlockNumber: int})
|
|
115
110
|
| EnterReorgThreshold
|
|
@@ -140,9 +135,9 @@ let updateChainMetadataTable = (cm: ChainManager.t, ~inMemoryStore: InMemoryStor
|
|
|
140
135
|
|
|
141
136
|
cm.chainFetchers
|
|
142
137
|
->ChainMap.values
|
|
143
|
-
->
|
|
138
|
+
->Array.forEach(cf => {
|
|
144
139
|
chainsData->Dict.set(
|
|
145
|
-
cf.chainConfig.id->
|
|
140
|
+
cf.chainConfig.id->Int.toString,
|
|
146
141
|
{
|
|
147
142
|
firstEventBlockNumber: cf.fetchState.firstEventBlock->Null.fromOption,
|
|
148
143
|
isHyperSync: (cf.sourceManager->SourceManager.getActiveSource).poweredByHyperSync,
|
|
@@ -156,169 +151,6 @@ let updateChainMetadataTable = (cm: ChainManager.t, ~inMemoryStore: InMemoryStor
|
|
|
156
151
|
inMemoryStore->InMemoryStore.setChainMeta(chainsData)
|
|
157
152
|
}
|
|
158
153
|
|
|
159
|
-
/**
|
|
160
|
-
Takes in a chain manager and sets all chains timestamp caught up to head
|
|
161
|
-
when valid state lines up and returns an updated chain manager
|
|
162
|
-
*/
|
|
163
|
-
let updateProgressedChains = (chainManager: ChainManager.t, ~batch: Batch.t, ~ctx: Ctx.t) => {
|
|
164
|
-
let nextQueueItemIsNone = chainManager->ChainManager.nextItemIsNone
|
|
165
|
-
|
|
166
|
-
let allChainsAtHead = chainManager->ChainManager.isProgressAtHead
|
|
167
|
-
//Update the timestampCaughtUpToHeadOrEndblock values
|
|
168
|
-
let allChainsReady = ref(true)
|
|
169
|
-
let chainFetchers = chainManager.chainFetchers->ChainMap.map(prev => {
|
|
170
|
-
let cf = prev
|
|
171
|
-
let chain = ChainMap.Chain.makeUnsafe(~chainId=cf.chainConfig.id)
|
|
172
|
-
|
|
173
|
-
let maybeChainAfterBatch =
|
|
174
|
-
batch.progressedChainsById->Utils.Dict.dangerouslyGetByIntNonOption(
|
|
175
|
-
chain->ChainMap.Chain.toChainId,
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
let cf = switch maybeChainAfterBatch {
|
|
179
|
-
| Some(chainAfterBatch) => {
|
|
180
|
-
if cf.committedProgressBlockNumber !== chainAfterBatch.progressBlockNumber {
|
|
181
|
-
Prometheus.ProgressBlockNumber.set(
|
|
182
|
-
~blockNumber=chainAfterBatch.progressBlockNumber,
|
|
183
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
184
|
-
)
|
|
185
|
-
}
|
|
186
|
-
if cf.numEventsProcessed !== chainAfterBatch.totalEventsProcessed {
|
|
187
|
-
Prometheus.ProgressEventsCount.set(
|
|
188
|
-
~processedCount=chainAfterBatch.totalEventsProcessed,
|
|
189
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Calculate and set latency metrics
|
|
194
|
-
switch batch->Batch.findLastEventItem(~chainId=chain->ChainMap.Chain.toChainId) {
|
|
195
|
-
| Some(eventItem) => {
|
|
196
|
-
let blockTimestamp = eventItem.event.block->ctx.config.ecosystem.getTimestamp
|
|
197
|
-
let currentTimeMs = Date.now()->Float.toInt
|
|
198
|
-
let blockTimestampMs = blockTimestamp * 1000
|
|
199
|
-
let latencyMs = currentTimeMs - blockTimestampMs
|
|
200
|
-
|
|
201
|
-
Prometheus.ProgressLatency.set(~latencyMs, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
202
|
-
}
|
|
203
|
-
| None => ()
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
{
|
|
207
|
-
...cf,
|
|
208
|
-
// Since we process per chain always in order,
|
|
209
|
-
// we need to calculate it once, by using the first item in a batch
|
|
210
|
-
fetchState: switch cf.fetchState.firstEventBlock {
|
|
211
|
-
| Some(_) => cf.fetchState
|
|
212
|
-
| None =>
|
|
213
|
-
switch batch->Batch.findFirstEventBlockNumber(
|
|
214
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
215
|
-
) {
|
|
216
|
-
| Some(_) as firstEventBlock => {...cf.fetchState, firstEventBlock}
|
|
217
|
-
| None => cf.fetchState
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
committedProgressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
221
|
-
numEventsProcessed: chainAfterBatch.totalEventsProcessed,
|
|
222
|
-
isProgressAtHead: cf.isProgressAtHead || chainAfterBatch.isProgressAtHeadWhenBatchCreated,
|
|
223
|
-
safeCheckpointTracking: switch cf.safeCheckpointTracking {
|
|
224
|
-
| Some(safeCheckpointTracking) =>
|
|
225
|
-
Some(
|
|
226
|
-
safeCheckpointTracking->SafeCheckpointTracking.updateOnNewBatch(
|
|
227
|
-
~sourceBlockNumber=cf.fetchState.knownHeight,
|
|
228
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
229
|
-
~batchCheckpointIds=batch.checkpointIds,
|
|
230
|
-
~batchCheckpointBlockNumbers=batch.checkpointBlockNumbers,
|
|
231
|
-
~batchCheckpointChainIds=batch.checkpointChainIds,
|
|
232
|
-
),
|
|
233
|
-
)
|
|
234
|
-
| None => None
|
|
235
|
-
},
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
| None => cf
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/* strategy for TUI synced status:
|
|
242
|
-
* Firstly -> only update synced status after batch is processed (not on batch creation). But also set when a batch tries to be created and there is no batch
|
|
243
|
-
*
|
|
244
|
-
* Secondly -> reset timestampCaughtUpToHead and isFetching at head when dynamic contracts get registered to a chain if they are not within 0.001 percent of the current block height
|
|
245
|
-
*
|
|
246
|
-
* New conditions for valid synced:
|
|
247
|
-
*
|
|
248
|
-
* CASE 1 (chains are being synchronised at the head)
|
|
249
|
-
*
|
|
250
|
-
* All chain fetchers are fetching at the head AND
|
|
251
|
-
* No events that can be processed on the queue (even if events still exist on the individual queues)
|
|
252
|
-
* CASE 2 (chain finishes earlier than any other chain)
|
|
253
|
-
*
|
|
254
|
-
* CASE 3 endblock has been reached and latest processed block is greater than or equal to endblock (both fields must be Some)
|
|
255
|
-
*
|
|
256
|
-
* The given chain fetcher is fetching at the head or latest processed block >= endblock
|
|
257
|
-
* The given chain has processed all events on the queue
|
|
258
|
-
* see https://github.com/Float-Capital/indexer/pull/1388 */
|
|
259
|
-
let cf = if cf->ChainFetcher.hasProcessedToEndblock {
|
|
260
|
-
// in the case this is already set, don't reset and instead propagate the existing value
|
|
261
|
-
let timestampCaughtUpToHeadOrEndblock =
|
|
262
|
-
cf->ChainFetcher.isReady ? cf.timestampCaughtUpToHeadOrEndblock : Date.make()->Some
|
|
263
|
-
{
|
|
264
|
-
...cf,
|
|
265
|
-
timestampCaughtUpToHeadOrEndblock,
|
|
266
|
-
}
|
|
267
|
-
} else if !(cf->ChainFetcher.isReady) && cf.isProgressAtHead {
|
|
268
|
-
//Only calculate and set timestampCaughtUpToHeadOrEndblock if chain fetcher is at the head and
|
|
269
|
-
//its not already set
|
|
270
|
-
//CASE1
|
|
271
|
-
//All chains are caught up to head chainManager queue returns None
|
|
272
|
-
//Meaning we are busy synchronizing chains at the head
|
|
273
|
-
if nextQueueItemIsNone && allChainsAtHead {
|
|
274
|
-
{
|
|
275
|
-
...cf,
|
|
276
|
-
timestampCaughtUpToHeadOrEndblock: Date.make()->Some,
|
|
277
|
-
}
|
|
278
|
-
} else {
|
|
279
|
-
//CASE2 -> Only calculate if case1 fails
|
|
280
|
-
//All events have been processed on the chain fetchers queue
|
|
281
|
-
//Other chains may be busy syncing
|
|
282
|
-
let hasNoMoreEventsToProcess = cf->ChainFetcher.hasNoMoreEventsToProcess
|
|
283
|
-
|
|
284
|
-
if hasNoMoreEventsToProcess {
|
|
285
|
-
{
|
|
286
|
-
...cf,
|
|
287
|
-
timestampCaughtUpToHeadOrEndblock: Date.make()->Some,
|
|
288
|
-
}
|
|
289
|
-
} else {
|
|
290
|
-
//Default to just returning cf
|
|
291
|
-
cf
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
} else {
|
|
295
|
-
//Default to just returning cf
|
|
296
|
-
cf
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Set envio_progress_ready per-chain when it first becomes ready
|
|
300
|
-
if cf->ChainFetcher.isReady {
|
|
301
|
-
if !(prev->ChainFetcher.isReady) {
|
|
302
|
-
Prometheus.ProgressReady.set(~chainId=chain->ChainMap.Chain.toChainId)
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
allChainsReady := false
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
cf
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
if allChainsReady.contents {
|
|
312
|
-
Prometheus.ProgressReady.setAllReady()
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
{
|
|
316
|
-
...chainManager,
|
|
317
|
-
chainFetchers,
|
|
318
|
-
isRealtime: chainManager.isRealtime || allChainsReady.contents,
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
154
|
let validatePartitionQueryResponse = (
|
|
323
155
|
state,
|
|
324
156
|
{chain, response} as partitionQueryResponse: partitionQueryResponse,
|
|
@@ -347,7 +179,7 @@ let validatePartitionQueryResponse = (
|
|
|
347
179
|
Prometheus.FetchingBlockRange.increment(
|
|
348
180
|
~chainId=chain->ChainMap.Chain.toChainId,
|
|
349
181
|
~totalTimeElapsed=stats.totalTimeElapsed,
|
|
350
|
-
~parsingTimeElapsed=stats.parsingTimeElapsed->
|
|
182
|
+
~parsingTimeElapsed=stats.parsingTimeElapsed->Option.getOr(0.),
|
|
351
183
|
~numEvents=parsedQueueItems->Array.length,
|
|
352
184
|
~blockRangeSize=latestFetchedBlockNumber - fromBlockQueried + 1,
|
|
353
185
|
)
|
|
@@ -587,209 +419,212 @@ let onEnterReorgThreshold = (~state: t) => {
|
|
|
587
419
|
}
|
|
588
420
|
}
|
|
589
421
|
|
|
590
|
-
let
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
{
|
|
600
|
-
|
|
601
|
-
|
|
422
|
+
let injectedActionReducer = (~markBatchProcessed: Ports.MarkBatchProcessed.t) =>
|
|
423
|
+
(state: t, action: action) => {
|
|
424
|
+
switch action {
|
|
425
|
+
| FinishWaitingForNewBlock({chain, knownHeight}) => {
|
|
426
|
+
let updatedChainFetchers = state.chainManager.chainFetchers->ChainMap.update(
|
|
427
|
+
chain,
|
|
428
|
+
chainFetcher => {
|
|
429
|
+
let updatedFetchState =
|
|
430
|
+
chainFetcher.fetchState->FetchState.updateKnownHeight(~knownHeight)
|
|
431
|
+
if updatedFetchState !== chainFetcher.fetchState {
|
|
432
|
+
{
|
|
433
|
+
...chainFetcher,
|
|
434
|
+
fetchState: updatedFetchState,
|
|
435
|
+
}
|
|
436
|
+
} else {
|
|
437
|
+
chainFetcher
|
|
602
438
|
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
439
|
+
},
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
let isBelowReorgThreshold =
|
|
443
|
+
!state.chainManager.isInReorgThreshold && state.ctx.config.shouldRollbackOnReorg
|
|
444
|
+
let shouldEnterReorgThreshold =
|
|
445
|
+
isBelowReorgThreshold &&
|
|
446
|
+
updatedChainFetchers
|
|
447
|
+
->ChainMap.values
|
|
448
|
+
->Array.every(chainFetcher => {
|
|
449
|
+
chainFetcher.fetchState->FetchState.isReadyToEnterReorgThreshold
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
let state = {
|
|
453
|
+
...state,
|
|
454
|
+
chainManager: {
|
|
455
|
+
...state.chainManager,
|
|
456
|
+
chainFetchers: updatedChainFetchers,
|
|
457
|
+
},
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Attempt ProcessEventBatch in case if we have block handlers to run
|
|
461
|
+
if shouldEnterReorgThreshold {
|
|
462
|
+
(onEnterReorgThreshold(~state), [NextQuery(CheckAllChains), ProcessEventBatch])
|
|
463
|
+
} else {
|
|
464
|
+
(state, [NextQuery(Chain(chain)), ProcessEventBatch])
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
| ValidatePartitionQueryResponse(partitionQueryResponse) =>
|
|
468
|
+
state->validatePartitionQueryResponse(partitionQueryResponse)
|
|
469
|
+
| SubmitPartitionQueryResponse({
|
|
470
|
+
newItems,
|
|
471
|
+
newItemsWithDcs,
|
|
472
|
+
knownHeight,
|
|
473
|
+
latestFetchedBlock,
|
|
474
|
+
query,
|
|
475
|
+
chain,
|
|
476
|
+
}) =>
|
|
477
|
+
state->submitPartitionQueryResponse(
|
|
478
|
+
~newItems,
|
|
479
|
+
~newItemsWithDcs,
|
|
480
|
+
~knownHeight,
|
|
481
|
+
~latestFetchedBlock,
|
|
482
|
+
~query,
|
|
483
|
+
~chain,
|
|
607
484
|
)
|
|
485
|
+
| EventBatchProcessed({batch}) =>
|
|
486
|
+
let maybePruneEntityHistory =
|
|
487
|
+
state.ctx.config->Config.shouldPruneHistory(
|
|
488
|
+
~isInReorgThreshold=state.chainManager.isInReorgThreshold,
|
|
489
|
+
)
|
|
490
|
+
? [PruneStaleEntityHistory]
|
|
491
|
+
: []
|
|
608
492
|
|
|
609
|
-
|
|
610
|
-
!state.chainManager.isInReorgThreshold && state.ctx.config.shouldRollbackOnReorg
|
|
611
|
-
let shouldEnterReorgThreshold =
|
|
612
|
-
isBelowReorgThreshold &&
|
|
613
|
-
updatedChainFetchers
|
|
614
|
-
->ChainMap.values
|
|
615
|
-
->Array.every(chainFetcher => {
|
|
616
|
-
chainFetcher.fetchState->FetchState.isReadyToEnterReorgThreshold
|
|
617
|
-
})
|
|
493
|
+
markBatchProcessed()
|
|
618
494
|
|
|
619
495
|
let state = {
|
|
620
496
|
...state,
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
497
|
+
// Can safely reset rollback state, since overwrite is not possible.
|
|
498
|
+
// If rollback is pending, the EventBatchProcessed will be handled by the invalid action reducer instead.
|
|
499
|
+
rollbackState: NoRollback,
|
|
500
|
+
chainManager: state.chainManager->ChainManager.updateProgressedChains(~batch),
|
|
625
501
|
}
|
|
626
502
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
(onEnterReorgThreshold(~state), [NextQuery(CheckAllChains), ProcessEventBatch])
|
|
630
|
-
} else {
|
|
631
|
-
(state, [NextQuery(Chain(chain)), ProcessEventBatch])
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
| ValidatePartitionQueryResponse(partitionQueryResponse) =>
|
|
635
|
-
state->validatePartitionQueryResponse(partitionQueryResponse)
|
|
636
|
-
| SubmitPartitionQueryResponse({
|
|
637
|
-
newItems,
|
|
638
|
-
newItemsWithDcs,
|
|
639
|
-
knownHeight,
|
|
640
|
-
latestFetchedBlock,
|
|
641
|
-
query,
|
|
642
|
-
chain,
|
|
643
|
-
}) =>
|
|
644
|
-
state->submitPartitionQueryResponse(
|
|
645
|
-
~newItems,
|
|
646
|
-
~newItemsWithDcs,
|
|
647
|
-
~knownHeight,
|
|
648
|
-
~latestFetchedBlock,
|
|
649
|
-
~query,
|
|
650
|
-
~chain,
|
|
651
|
-
)
|
|
652
|
-
| EventBatchProcessed({batch}) =>
|
|
653
|
-
let maybePruneEntityHistory =
|
|
654
|
-
state.ctx.config->Config.shouldPruneHistory(
|
|
655
|
-
~isInReorgThreshold=state.chainManager.isInReorgThreshold,
|
|
503
|
+
let shouldExit = EventProcessing.allChainsEventsProcessedToEndblock(
|
|
504
|
+
state.chainManager.chainFetchers,
|
|
656
505
|
)
|
|
657
|
-
?
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
let state = {
|
|
661
|
-
...state,
|
|
662
|
-
// Can safely reset rollback state, since overwrite is not possible.
|
|
663
|
-
// If rollback is pending, the EventBatchProcessed will be handled by the invalid action reducer instead.
|
|
664
|
-
rollbackState: NoRollback,
|
|
665
|
-
chainManager: state.chainManager->updateProgressedChains(~batch, ~ctx=state.ctx),
|
|
666
|
-
currentlyProcessingBatch: false,
|
|
667
|
-
processedBatches: state.processedBatches + 1,
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
let shouldExit = EventProcessing.allChainsEventsProcessedToEndblock(
|
|
671
|
-
state.chainManager.chainFetchers,
|
|
672
|
-
)
|
|
673
|
-
? {
|
|
674
|
-
Logging.info("All chains are caught up to end blocks.")
|
|
506
|
+
? {
|
|
507
|
+
Logging.info("All chains are caught up to end blocks.")
|
|
675
508
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
509
|
+
// Keep the indexer process running when in development mode (for Dev Console)
|
|
510
|
+
// or when TUI is enabled (for display)
|
|
511
|
+
if state.keepProcessAlive {
|
|
512
|
+
NoExit
|
|
513
|
+
} else {
|
|
514
|
+
ExitWithSuccess
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
: if (
|
|
518
|
+
// In auto-exit mode, error if all chains reached head with no events found
|
|
519
|
+
state.exitAfterFirstEventBlock &&
|
|
520
|
+
state.chainManager.chainFetchers
|
|
521
|
+
->ChainMap.values
|
|
522
|
+
->Array.every(cf => cf.isProgressAtHead && cf.fetchState.endBlock->Option.isNone)
|
|
523
|
+
) {
|
|
524
|
+
ExitWithError(
|
|
525
|
+
"No events found between startBlock and chain head. Cannot auto-detect endBlock.",
|
|
526
|
+
)
|
|
680
527
|
} else {
|
|
681
|
-
|
|
528
|
+
NoExit
|
|
682
529
|
}
|
|
683
|
-
}
|
|
684
|
-
: if (
|
|
685
|
-
// In auto-exit mode, error if all chains reached head with no events found
|
|
686
|
-
state.exitAfterFirstEventBlock &&
|
|
687
|
-
state.chainManager.chainFetchers
|
|
688
|
-
->ChainMap.values
|
|
689
|
-
->Array.every(cf => cf.isProgressAtHead && cf.fetchState.endBlock->Belt.Option.isNone)
|
|
690
|
-
) {
|
|
691
|
-
ExitWithError(
|
|
692
|
-
"No events found between startBlock and chain head. Cannot auto-detect endBlock.",
|
|
693
|
-
)
|
|
694
|
-
} else {
|
|
695
|
-
NoExit
|
|
696
|
-
}
|
|
697
530
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
531
|
+
// On exit, stop dispatching ProcessEventBatch: the flush is async and would
|
|
532
|
+
// otherwise keep processing further batches while it runs.
|
|
533
|
+
let tasks = switch shouldExit {
|
|
534
|
+
| ExitWithSuccess
|
|
535
|
+
| ExitWithError(_) => [UpdateChainMetaDataAndCheckForExit(shouldExit)]
|
|
536
|
+
| NoExit =>
|
|
537
|
+
[UpdateChainMetaDataAndCheckForExit(shouldExit), ProcessEventBatch]->Array.concat(
|
|
538
|
+
maybePruneEntityHistory,
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
(state, tasks)
|
|
542
|
+
|
|
543
|
+
| StartFindingReorgDepth => ({...state, rollbackState: FindingReorgDepth}, [])
|
|
544
|
+
| FindReorgDepth({chain, rollbackTargetBlockNumber}) => (
|
|
545
|
+
{
|
|
546
|
+
...state,
|
|
547
|
+
rollbackState: FoundReorgDepth({
|
|
548
|
+
chain,
|
|
549
|
+
rollbackTargetBlockNumber,
|
|
550
|
+
}),
|
|
551
|
+
},
|
|
552
|
+
[Rollback],
|
|
706
553
|
)
|
|
707
|
-
|
|
708
|
-
(
|
|
554
|
+
| EnterReorgThreshold => (onEnterReorgThreshold(~state), [NextQuery(CheckAllChains)])
|
|
555
|
+
| UpdateQueues({progressedChainsById, shouldEnterReorgThreshold}) =>
|
|
556
|
+
let chainFetchers = state.chainManager.chainFetchers->ChainMap.mapWithKey((chain, cf) => {
|
|
557
|
+
let fs = switch progressedChainsById->Utils.Dict.dangerouslyGetByIntNonOption(
|
|
558
|
+
chain->ChainMap.Chain.toChainId,
|
|
559
|
+
) {
|
|
560
|
+
| Some(chainAfterBatch) => chainAfterBatch.fetchState
|
|
561
|
+
| None => cf.fetchState
|
|
562
|
+
}
|
|
563
|
+
{
|
|
564
|
+
...cf,
|
|
565
|
+
fetchState: shouldEnterReorgThreshold
|
|
566
|
+
? fs->FetchState.updateInternal(~blockLag=cf.chainConfig.blockLag)
|
|
567
|
+
: fs,
|
|
568
|
+
}
|
|
569
|
+
})
|
|
709
570
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
{
|
|
714
|
-
...state,
|
|
715
|
-
rollbackState: FoundReorgDepth({
|
|
716
|
-
chain,
|
|
717
|
-
rollbackTargetBlockNumber,
|
|
718
|
-
}),
|
|
719
|
-
},
|
|
720
|
-
[Rollback],
|
|
721
|
-
)
|
|
722
|
-
| EnterReorgThreshold => (onEnterReorgThreshold(~state), [NextQuery(CheckAllChains)])
|
|
723
|
-
| UpdateQueues({progressedChainsById, shouldEnterReorgThreshold}) =>
|
|
724
|
-
let chainFetchers = state.chainManager.chainFetchers->ChainMap.mapWithKey((chain, cf) => {
|
|
725
|
-
let fs = switch progressedChainsById->Utils.Dict.dangerouslyGetByIntNonOption(
|
|
726
|
-
chain->ChainMap.Chain.toChainId,
|
|
727
|
-
) {
|
|
728
|
-
| Some(chainAfterBatch) => chainAfterBatch.fetchState
|
|
729
|
-
| None => cf.fetchState
|
|
730
|
-
}
|
|
731
|
-
{
|
|
732
|
-
...cf,
|
|
733
|
-
fetchState: shouldEnterReorgThreshold
|
|
734
|
-
? fs->FetchState.updateInternal(~blockLag=cf.chainConfig.blockLag)
|
|
735
|
-
: fs,
|
|
571
|
+
let chainManager = {
|
|
572
|
+
...state.chainManager,
|
|
573
|
+
chainFetchers,
|
|
736
574
|
}
|
|
737
|
-
})
|
|
738
|
-
|
|
739
|
-
let chainManager = {
|
|
740
|
-
...state.chainManager,
|
|
741
|
-
chainFetchers,
|
|
742
|
-
}
|
|
743
575
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
576
|
+
(
|
|
577
|
+
{
|
|
578
|
+
...state,
|
|
579
|
+
chainManager,
|
|
580
|
+
},
|
|
581
|
+
[NextQuery(CheckAllChains)],
|
|
582
|
+
)
|
|
583
|
+
| SetRollbackState({rollbackedChainManager, eventsProcessedDiffByChain}) => (
|
|
584
|
+
{
|
|
585
|
+
...state,
|
|
586
|
+
rollbackState: RollbackReady({
|
|
587
|
+
eventsProcessedDiffByChain: eventsProcessedDiffByChain,
|
|
588
|
+
}),
|
|
589
|
+
chainManager: rollbackedChainManager,
|
|
590
|
+
},
|
|
591
|
+
[NextQuery(CheckAllChains), ProcessEventBatch],
|
|
592
|
+
)
|
|
593
|
+
| SuccessExit => {
|
|
594
|
+
Logging.info("Exiting with success")
|
|
595
|
+
NodeJs.process->NodeJs.exitWithCode(Success)
|
|
596
|
+
(state, [])
|
|
597
|
+
}
|
|
598
|
+
| ErrorExit(errHandler) =>
|
|
599
|
+
state.onError(errHandler)
|
|
764
600
|
(state, [])
|
|
765
601
|
}
|
|
766
|
-
| ErrorExit(errHandler) =>
|
|
767
|
-
state.onError(errHandler)
|
|
768
|
-
(state, [])
|
|
769
602
|
}
|
|
770
|
-
}
|
|
771
603
|
|
|
772
|
-
let
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
604
|
+
let injectedInvalidatedActionReducer = (
|
|
605
|
+
~markBatchProcessed: Ports.MarkBatchProcessed.t,
|
|
606
|
+
~actionReducer: (t, action) => (t, array<task>),
|
|
607
|
+
) =>
|
|
608
|
+
(state: t, action: action) =>
|
|
609
|
+
switch action {
|
|
610
|
+
| EventBatchProcessed({batch}) if state->isPreparingRollback =>
|
|
611
|
+
Logging.info("Finished processing batch before rollback, actioning rollback")
|
|
612
|
+
markBatchProcessed()
|
|
613
|
+
(
|
|
614
|
+
{
|
|
615
|
+
...state,
|
|
616
|
+
chainManager: state.chainManager->ChainManager.updateProgressedChains(~batch),
|
|
617
|
+
},
|
|
618
|
+
[Rollback],
|
|
619
|
+
)
|
|
620
|
+
| ErrorExit(_) => actionReducer(state, action)
|
|
621
|
+
| _ =>
|
|
622
|
+
Logging.trace({
|
|
623
|
+
"msg": "Invalidated action discarded",
|
|
624
|
+
"action": action->S.convertOrThrow(Utils.Schema.variantTag),
|
|
625
|
+
})
|
|
626
|
+
(state, [])
|
|
627
|
+
}
|
|
793
628
|
|
|
794
629
|
let checkAndFetchForChain = (
|
|
795
630
|
//Used for dependency injection for tests
|
|
@@ -919,7 +754,7 @@ let injectedTaskReducer = (
|
|
|
919
754
|
->Promise.all
|
|
920
755
|
}
|
|
921
756
|
| ProcessEventBatch =>
|
|
922
|
-
if !state.
|
|
757
|
+
if !state.ctx.inMemoryStore.isProcessing && !isPreparingRollback(state) {
|
|
923
758
|
let isRollbackBatch = switch state.rollbackState {
|
|
924
759
|
| RollbackReady(_) => true
|
|
925
760
|
| _ => false
|
|
@@ -966,10 +801,10 @@ let injectedTaskReducer = (
|
|
|
966
801
|
}
|
|
967
802
|
}
|
|
968
803
|
} else {
|
|
969
|
-
|
|
804
|
+
let inMemoryStore = state.ctx.inMemoryStore
|
|
805
|
+
inMemoryStore.isProcessing = true
|
|
970
806
|
dispatchAction(UpdateQueues({progressedChainsById, shouldEnterReorgThreshold}))
|
|
971
807
|
|
|
972
|
-
let inMemoryStore = state.ctx.inMemoryStore
|
|
973
808
|
inMemoryStore->InMemoryStore.setBatchDcs(~batch)
|
|
974
809
|
|
|
975
810
|
switch await EventProcessing.processEventBatch(
|
|
@@ -1019,7 +854,7 @@ let injectedTaskReducer = (
|
|
|
1019
854
|
// while we are still finding the reorg depth
|
|
1020
855
|
// Do nothing here, just wait for reorg depth to be found
|
|
1021
856
|
| {rollbackState: FindingReorgDepth} => ()
|
|
1022
|
-
| {rollbackState: FoundReorgDepth(_)
|
|
857
|
+
| {rollbackState: FoundReorgDepth(_)} if state.ctx.inMemoryStore.isProcessing =>
|
|
1023
858
|
Logging.info("Waiting for batch to finish processing before executing rollback")
|
|
1024
859
|
| {rollbackState: FoundReorgDepth({chain: reorgChain, rollbackTargetBlockNumber})} =>
|
|
1025
860
|
let startTime = Hrtime.makeTimer()
|
|
@@ -1042,6 +877,13 @@ let injectedTaskReducer = (
|
|
|
1042
877
|
|
|
1043
878
|
let reorgChainId = reorgChain->ChainMap.Chain.toChainId
|
|
1044
879
|
|
|
880
|
+
// Finish pending batch writes first: the target checkpoint, the progress
|
|
881
|
+
// diff and the rollback diff below must all be computed from the same db
|
|
882
|
+
// state. Otherwise an in-flight batch lands after the progress reads and
|
|
883
|
+
// its entity changes get reverted without the chain progress being
|
|
884
|
+
// rolled back, so the events are never reprocessed.
|
|
885
|
+
await state.ctx.inMemoryStore->InMemoryStore.flush
|
|
886
|
+
|
|
1045
887
|
let rollbackTargetCheckpointId = {
|
|
1046
888
|
switch await state.ctx.persistence.storage.getRollbackTargetCheckpoint(
|
|
1047
889
|
~reorgChainId,
|
|
@@ -1144,6 +986,10 @@ let injectedTaskReducer = (
|
|
|
1144
986
|
fetchState: cf.fetchState->FetchState.rollback(
|
|
1145
987
|
~targetBlockNumber=rollbackTargetBlockNumber,
|
|
1146
988
|
),
|
|
989
|
+
committedProgressBlockNumber: Pervasives.min(
|
|
990
|
+
cf.committedProgressBlockNumber,
|
|
991
|
+
rollbackTargetBlockNumber,
|
|
992
|
+
),
|
|
1147
993
|
}
|
|
1148
994
|
} else {
|
|
1149
995
|
cf
|
|
@@ -1151,10 +997,6 @@ let injectedTaskReducer = (
|
|
|
1151
997
|
}
|
|
1152
998
|
})
|
|
1153
999
|
|
|
1154
|
-
// Finish pending writes so committedCheckpointId reflects the db before
|
|
1155
|
-
// computing the rollback diff against it.
|
|
1156
|
-
await state.ctx.inMemoryStore->InMemoryStore.flush
|
|
1157
|
-
|
|
1158
1000
|
let diff = await state.ctx.inMemoryStore->InMemoryStore.prepareRollbackDiff(
|
|
1159
1001
|
~persistence=state.ctx.persistence,
|
|
1160
1002
|
~rollbackTargetCheckpointId,
|
|
@@ -1192,9 +1034,23 @@ let injectedTaskReducer = (
|
|
|
1192
1034
|
}
|
|
1193
1035
|
}
|
|
1194
1036
|
|
|
1195
|
-
|
|
1037
|
+
type reducers = {
|
|
1038
|
+
actionReducer: (t, action) => (t, array<task>),
|
|
1039
|
+
invalidatedActionReducer: (t, action) => (t, array<task>),
|
|
1040
|
+
taskReducer: (t, task, ~dispatchAction: action => unit) => promise<unit>,
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
let makeReducers = (
|
|
1196
1044
|
~waitForNewBlock=SourceManager.waitForNewBlock,
|
|
1197
1045
|
~executeQuery=SourceManager.executeQuery,
|
|
1198
1046
|
~getLastKnownValidBlock=(chainFetcher, ~reorgBlockNumber, ~isRealtime) =>
|
|
1199
1047
|
chainFetcher->ChainFetcher.getLastKnownValidBlock(~reorgBlockNumber, ~isRealtime),
|
|
1200
|
-
|
|
1048
|
+
~markBatchProcessed: Ports.MarkBatchProcessed.t,
|
|
1049
|
+
) => {
|
|
1050
|
+
let actionReducer = injectedActionReducer(~markBatchProcessed)
|
|
1051
|
+
{
|
|
1052
|
+
actionReducer,
|
|
1053
|
+
invalidatedActionReducer: injectedInvalidatedActionReducer(~markBatchProcessed, ~actionReducer),
|
|
1054
|
+
taskReducer: injectedTaskReducer(~waitForNewBlock, ~executeQuery, ~getLastKnownValidBlock),
|
|
1055
|
+
}
|
|
1056
|
+
}
|