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
package/src/ChainFetcher.res
DELETED
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
//A filter should return true if the event should be kept and isValid should return
|
|
2
|
-
//false when the filter should be removed/cleaned up
|
|
3
|
-
type processingFilter = {
|
|
4
|
-
filter: Internal.item => bool,
|
|
5
|
-
isValid: (~fetchState: FetchState.t) => bool,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
type t = {
|
|
9
|
-
logger: Pino.t,
|
|
10
|
-
fetchState: FetchState.t,
|
|
11
|
-
sourceManager: SourceManager.t,
|
|
12
|
-
chainConfig: Config.chain,
|
|
13
|
-
isProgressAtHead: bool,
|
|
14
|
-
timestampCaughtUpToHeadOrEndblock: option<Date.t>,
|
|
15
|
-
committedProgressBlockNumber: int,
|
|
16
|
-
numEventsProcessed: float,
|
|
17
|
-
reorgDetection: ReorgDetection.t,
|
|
18
|
-
safeCheckpointTracking: option<SafeCheckpointTracking.t>,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
//CONSTRUCTION
|
|
22
|
-
let configAddresses = (chainConfig: Config.chain): array<Internal.indexingAddress> => {
|
|
23
|
-
let addresses = []
|
|
24
|
-
chainConfig.contracts->Array.forEach(contract => {
|
|
25
|
-
contract.addresses->Array.forEach(address => {
|
|
26
|
-
addresses->Array.push({
|
|
27
|
-
Internal.address,
|
|
28
|
-
contractName: contract.name,
|
|
29
|
-
registrationBlock: -1,
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
addresses
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let make = (
|
|
37
|
-
~chainConfig: Config.chain,
|
|
38
|
-
~indexingAddresses: array<Internal.indexingAddress>,
|
|
39
|
-
~startBlock,
|
|
40
|
-
~endBlock,
|
|
41
|
-
~firstEventBlock=None,
|
|
42
|
-
~progressBlockNumber,
|
|
43
|
-
~config: Config.t,
|
|
44
|
-
~registrations: HandlerRegister.registrations,
|
|
45
|
-
~targetBufferSize,
|
|
46
|
-
~logger,
|
|
47
|
-
~timestampCaughtUpToHeadOrEndblock,
|
|
48
|
-
~numEventsProcessed,
|
|
49
|
-
~isInReorgThreshold,
|
|
50
|
-
~isRealtime,
|
|
51
|
-
~reorgCheckpoints: array<Internal.reorgCheckpoint>,
|
|
52
|
-
~maxReorgDepth,
|
|
53
|
-
~knownHeight=0,
|
|
54
|
-
~reducedPollingInterval=?,
|
|
55
|
-
): t => {
|
|
56
|
-
// We don't need the router itself, but only validation logic,
|
|
57
|
-
// since now event router is created for selection of events
|
|
58
|
-
// and validation doesn't work correctly in routers.
|
|
59
|
-
// Ideally to split it into two different parts.
|
|
60
|
-
let eventRouter = EventRouter.empty()
|
|
61
|
-
|
|
62
|
-
// Aggregate events we want to fetch
|
|
63
|
-
let eventConfigs: array<Internal.eventConfig> = []
|
|
64
|
-
|
|
65
|
-
let notRegisteredEvents = []
|
|
66
|
-
|
|
67
|
-
chainConfig.contracts->Array.forEach(contract => {
|
|
68
|
-
let contractName = contract.name
|
|
69
|
-
|
|
70
|
-
contract.events->Array.forEach(eventConfig => {
|
|
71
|
-
let {isWildcard} = eventConfig
|
|
72
|
-
let hasContractRegister = eventConfig.contractRegister->Option.isSome
|
|
73
|
-
|
|
74
|
-
// Should validate the events
|
|
75
|
-
eventRouter->EventRouter.addOrThrow(
|
|
76
|
-
eventConfig.id,
|
|
77
|
-
(),
|
|
78
|
-
~contractName,
|
|
79
|
-
~chain=ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id),
|
|
80
|
-
~eventName=eventConfig.name,
|
|
81
|
-
~isWildcard,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
// Filter out non-preRegistration events on preRegistration phase
|
|
85
|
-
// so we don't care about it in fetch state and workers anymore
|
|
86
|
-
let shouldBeIncluded = if config.enableRawEvents {
|
|
87
|
-
true
|
|
88
|
-
} else {
|
|
89
|
-
let isRegistered = hasContractRegister || eventConfig.handler->Option.isSome
|
|
90
|
-
if !isRegistered {
|
|
91
|
-
notRegisteredEvents->Array.push(eventConfig)
|
|
92
|
-
}
|
|
93
|
-
isRegistered
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Check if event has Static([]) filters (from a dynamic where
|
|
97
|
-
// callback returning `false` / SkipAll for this chain).
|
|
98
|
-
// If so, skip it entirely - it should never be fetched
|
|
99
|
-
let shouldSkip = try {
|
|
100
|
-
let getEventFiltersOrThrow = (
|
|
101
|
-
eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
|
|
102
|
-
).getEventFiltersOrThrow
|
|
103
|
-
|
|
104
|
-
// Check for non-evm chains
|
|
105
|
-
if (
|
|
106
|
-
getEventFiltersOrThrow->(Utils.magic: (ChainMap.Chain.t => Internal.eventFilters) => bool)
|
|
107
|
-
) {
|
|
108
|
-
switch getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)) {
|
|
109
|
-
| Static([]) => true
|
|
110
|
-
| _ => false
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
false
|
|
114
|
-
}
|
|
115
|
-
} catch {
|
|
116
|
-
// Can throw when filter is invalid
|
|
117
|
-
// Don't skip an event in this case. Let it throw in a better place - source code
|
|
118
|
-
| _ => false
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if shouldBeIncluded && !shouldSkip {
|
|
122
|
-
eventConfigs->Array.push(eventConfig)
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
switch contract.startBlock {
|
|
127
|
-
| Some(startBlock) if startBlock < chainConfig.startBlock =>
|
|
128
|
-
JsError.throwWithMessage(
|
|
129
|
-
`The start block for contract "${contractName}" is less than the chain start block. This is not supported yet.`,
|
|
130
|
-
)
|
|
131
|
-
| _ => ()
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
if notRegisteredEvents->Utils.Array.notEmpty {
|
|
136
|
-
logger->Logging.childInfo(
|
|
137
|
-
`The event${if notRegisteredEvents->Array.length > 1 {
|
|
138
|
-
"s"
|
|
139
|
-
} else {
|
|
140
|
-
""
|
|
141
|
-
}} ${notRegisteredEvents
|
|
142
|
-
->Array.map(eventConfig => `${eventConfig.contractName}.${eventConfig.name}`)
|
|
143
|
-
->Array.joinUnsafe(", ")} don't have an event handler and skipped for indexing.`,
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
let onBlockConfigs =
|
|
148
|
-
registrations.onBlockByChainId->Utils.Dict.dangerouslyGetNonOption(chainConfig.id->Int.toString)
|
|
149
|
-
switch onBlockConfigs {
|
|
150
|
-
| Some(onBlockConfigs) =>
|
|
151
|
-
// TODO: Move it to the HandlerRegister module
|
|
152
|
-
// so the error is thrown with better stack trace
|
|
153
|
-
onBlockConfigs->Array.forEach(onBlockConfig => {
|
|
154
|
-
if onBlockConfig.startBlock->Option.getOr(startBlock) < startBlock {
|
|
155
|
-
JsError.throwWithMessage(
|
|
156
|
-
`The start block for onBlock handler "${onBlockConfig.name}" is less than the chain start block (${startBlock->Int.toString}). This is not supported yet.`,
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
switch endBlock {
|
|
160
|
-
| Some(chainEndBlock) =>
|
|
161
|
-
if onBlockConfig.endBlock->Option.getOr(chainEndBlock) > chainEndBlock {
|
|
162
|
-
JsError.throwWithMessage(
|
|
163
|
-
`The end block for onBlock handler "${onBlockConfig.name}" is greater than the chain end block (${chainEndBlock->Int.toString}). This is not supported yet.`,
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
| None => ()
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
| None => ()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
let fetchState = FetchState.make(
|
|
173
|
-
~maxAddrInPartition=config.maxAddrInPartition,
|
|
174
|
-
~addresses=indexingAddresses,
|
|
175
|
-
~progressBlockNumber,
|
|
176
|
-
~startBlock,
|
|
177
|
-
~endBlock,
|
|
178
|
-
~eventConfigs,
|
|
179
|
-
~targetBufferSize,
|
|
180
|
-
~knownHeight,
|
|
181
|
-
~chainId=chainConfig.id,
|
|
182
|
-
// FIXME: Shouldn't set with full history
|
|
183
|
-
~blockLag=Pervasives.max(
|
|
184
|
-
!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth,
|
|
185
|
-
chainConfig.blockLag,
|
|
186
|
-
),
|
|
187
|
-
~onBlockConfigs?,
|
|
188
|
-
~firstEventBlock,
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
let chainReorgCheckpoints = reorgCheckpoints->Array.filterMap(reorgCheckpoint => {
|
|
192
|
-
if reorgCheckpoint.chainId === chainConfig.id {
|
|
193
|
-
Some(reorgCheckpoint)
|
|
194
|
-
} else {
|
|
195
|
-
None
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
// Create sources lazily here - this is where API token validation happens
|
|
200
|
-
let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
|
|
201
|
-
let lowercaseAddresses = config.lowercaseAddresses
|
|
202
|
-
let sources = switch chainConfig.sourceConfig {
|
|
203
|
-
| Config.EvmSourceConfig({hypersync, rpcs}) =>
|
|
204
|
-
// Build Internal.evmContractConfig from contracts for EvmChain.makeSources
|
|
205
|
-
let evmContracts: array<Internal.evmContractConfig> = chainConfig.contracts->Array.map((
|
|
206
|
-
contract
|
|
207
|
-
): Internal.evmContractConfig => {
|
|
208
|
-
name: contract.name,
|
|
209
|
-
abi: contract.abi,
|
|
210
|
-
events: contract.events->(
|
|
211
|
-
Utils.magic: array<Internal.eventConfig> => array<Internal.evmEventConfig>
|
|
212
|
-
),
|
|
213
|
-
})
|
|
214
|
-
let evmRpcs: array<EvmChain.rpc> = rpcs->Array.map((rpc): EvmChain.rpc => {
|
|
215
|
-
let syncConfig = rpc.syncConfig
|
|
216
|
-
let ws = rpc.ws
|
|
217
|
-
{
|
|
218
|
-
url: rpc.url,
|
|
219
|
-
sourceFor: rpc.sourceFor,
|
|
220
|
-
?syncConfig,
|
|
221
|
-
?ws,
|
|
222
|
-
}
|
|
223
|
-
})
|
|
224
|
-
EvmChain.makeSources(
|
|
225
|
-
~chain,
|
|
226
|
-
~contracts=evmContracts,
|
|
227
|
-
~hyperSync=hypersync,
|
|
228
|
-
~rpcs=evmRpcs,
|
|
229
|
-
~lowercaseAddresses,
|
|
230
|
-
)
|
|
231
|
-
| Config.FuelSourceConfig({hypersync}) => [HyperFuelSource.make({chain, endpointUrl: hypersync})]
|
|
232
|
-
| Config.SvmSourceConfig({hypersync, rpc}) =>
|
|
233
|
-
switch (hypersync, rpc) {
|
|
234
|
-
| (None, None) =>
|
|
235
|
-
JsError.throwWithMessage(
|
|
236
|
-
`Chain ${chain->ChainMap.Chain.toChainId->Int.toString} has no SVM data source`,
|
|
237
|
-
)
|
|
238
|
-
| (None, Some(rpc)) => [Svm.makeRPCSource(~chain, ~rpc)]
|
|
239
|
-
| (Some(hypersyncUrl), _) =>
|
|
240
|
-
// HyperSync drives instruction sync. A configured RPC is ignored for now
|
|
241
|
-
// (RPC fallback isn't wired up yet).
|
|
242
|
-
let svmEventConfigs =
|
|
243
|
-
chainConfig.contracts
|
|
244
|
-
->Array.flatMap(contract => contract.events)
|
|
245
|
-
->(Utils.magic: array<Internal.eventConfig> => array<Internal.svmInstructionEventConfig>)
|
|
246
|
-
let apiToken = Env.envioApiToken
|
|
247
|
-
[
|
|
248
|
-
SvmHyperSyncSource.make({
|
|
249
|
-
chain,
|
|
250
|
-
endpointUrl: hypersyncUrl,
|
|
251
|
-
apiToken,
|
|
252
|
-
eventConfigs: svmEventConfigs,
|
|
253
|
-
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
|
|
254
|
-
}),
|
|
255
|
-
]
|
|
256
|
-
}
|
|
257
|
-
// For tests: use ready-to-use sources directly
|
|
258
|
-
| Config.CustomSources(sources) => sources
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
{
|
|
262
|
-
logger,
|
|
263
|
-
chainConfig,
|
|
264
|
-
sourceManager: SourceManager.make(
|
|
265
|
-
~sources,
|
|
266
|
-
~maxPartitionConcurrency=Env.maxPartitionConcurrency,
|
|
267
|
-
~isRealtime,
|
|
268
|
-
~reducedPollingInterval?,
|
|
269
|
-
),
|
|
270
|
-
reorgDetection: ReorgDetection.make(
|
|
271
|
-
~chainReorgCheckpoints,
|
|
272
|
-
~maxReorgDepth,
|
|
273
|
-
~shouldRollbackOnReorg=config.shouldRollbackOnReorg,
|
|
274
|
-
),
|
|
275
|
-
safeCheckpointTracking: SafeCheckpointTracking.make(
|
|
276
|
-
~maxReorgDepth,
|
|
277
|
-
~shouldRollbackOnReorg=config.shouldRollbackOnReorg,
|
|
278
|
-
~chainReorgCheckpoints,
|
|
279
|
-
),
|
|
280
|
-
isProgressAtHead: false,
|
|
281
|
-
fetchState,
|
|
282
|
-
committedProgressBlockNumber: progressBlockNumber,
|
|
283
|
-
timestampCaughtUpToHeadOrEndblock,
|
|
284
|
-
numEventsProcessed,
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
let makeFromConfig = (
|
|
289
|
-
chainConfig: Config.chain,
|
|
290
|
-
~config,
|
|
291
|
-
~registrations,
|
|
292
|
-
~targetBufferSize,
|
|
293
|
-
~knownHeight,
|
|
294
|
-
) => {
|
|
295
|
-
let logger = Logging.createChild(~params={"chainId": chainConfig.id})
|
|
296
|
-
|
|
297
|
-
make(
|
|
298
|
-
~chainConfig,
|
|
299
|
-
~config,
|
|
300
|
-
~registrations,
|
|
301
|
-
~startBlock=chainConfig.startBlock,
|
|
302
|
-
~endBlock=chainConfig.endBlock,
|
|
303
|
-
~reorgCheckpoints=[],
|
|
304
|
-
~maxReorgDepth=chainConfig.maxReorgDepth,
|
|
305
|
-
~progressBlockNumber=-1,
|
|
306
|
-
~timestampCaughtUpToHeadOrEndblock=None,
|
|
307
|
-
~numEventsProcessed=0.,
|
|
308
|
-
~targetBufferSize,
|
|
309
|
-
~logger,
|
|
310
|
-
~indexingAddresses=configAddresses(chainConfig),
|
|
311
|
-
~isInReorgThreshold=false,
|
|
312
|
-
~isRealtime=false,
|
|
313
|
-
~knownHeight,
|
|
314
|
-
)
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* This function allows a chain fetcher to be created from metadata, in particular this is useful for restarting an indexer and making sure it fetches blocks from the same place.
|
|
319
|
-
*/
|
|
320
|
-
let makeFromDbState = (
|
|
321
|
-
chainConfig: Config.chain,
|
|
322
|
-
~resumedChainState: Persistence.initialChainState,
|
|
323
|
-
~reorgCheckpoints,
|
|
324
|
-
~isInReorgThreshold,
|
|
325
|
-
~isRealtime,
|
|
326
|
-
~config,
|
|
327
|
-
~registrations,
|
|
328
|
-
~targetBufferSize,
|
|
329
|
-
~reducedPollingInterval=?,
|
|
330
|
-
) => {
|
|
331
|
-
let chainId = chainConfig.id
|
|
332
|
-
let logger = Logging.createChild(~params={"chainId": chainId})
|
|
333
|
-
|
|
334
|
-
Prometheus.ProgressEventsCount.set(~processedCount=resumedChainState.numEventsProcessed, ~chainId)
|
|
335
|
-
|
|
336
|
-
let progressBlockNumber =
|
|
337
|
-
// Can be -1 when not set
|
|
338
|
-
resumedChainState.progressBlockNumber >= 0
|
|
339
|
-
? resumedChainState.progressBlockNumber
|
|
340
|
-
: resumedChainState.startBlock - 1
|
|
341
|
-
|
|
342
|
-
make(
|
|
343
|
-
~indexingAddresses=resumedChainState.indexingAddresses,
|
|
344
|
-
~chainConfig,
|
|
345
|
-
~startBlock=resumedChainState.startBlock,
|
|
346
|
-
~endBlock=resumedChainState.endBlock,
|
|
347
|
-
~config,
|
|
348
|
-
~registrations,
|
|
349
|
-
~reorgCheckpoints,
|
|
350
|
-
~maxReorgDepth=resumedChainState.maxReorgDepth,
|
|
351
|
-
~firstEventBlock=resumedChainState.firstEventBlockNumber,
|
|
352
|
-
~progressBlockNumber,
|
|
353
|
-
~timestampCaughtUpToHeadOrEndblock=Env.updateSyncTimeOnRestart
|
|
354
|
-
? None
|
|
355
|
-
: resumedChainState.timestampCaughtUpToHeadOrEndblock,
|
|
356
|
-
~numEventsProcessed=resumedChainState.numEventsProcessed,
|
|
357
|
-
~logger,
|
|
358
|
-
~targetBufferSize,
|
|
359
|
-
~isInReorgThreshold,
|
|
360
|
-
~isRealtime,
|
|
361
|
-
~knownHeight=resumedChainState.sourceBlockNumber,
|
|
362
|
-
~reducedPollingInterval?,
|
|
363
|
-
)
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
let runContractRegistersOrThrow = async (
|
|
367
|
-
~itemsWithContractRegister: array<Internal.item>,
|
|
368
|
-
~config: Config.t,
|
|
369
|
-
) => {
|
|
370
|
-
let itemsWithDcs = []
|
|
371
|
-
|
|
372
|
-
let onRegister = (~item: Internal.item, ~contractAddress, ~contractName) => {
|
|
373
|
-
let eventItem = item->Internal.castUnsafeEventItem
|
|
374
|
-
let {blockNumber} = eventItem
|
|
375
|
-
|
|
376
|
-
let dc: Internal.indexingAddress = {
|
|
377
|
-
address: contractAddress,
|
|
378
|
-
contractName,
|
|
379
|
-
registrationBlock: blockNumber,
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
switch item->Internal.getItemDcs {
|
|
383
|
-
| None => {
|
|
384
|
-
item->Internal.setItemDcs([dc])
|
|
385
|
-
itemsWithDcs->Array.push(item)
|
|
386
|
-
}
|
|
387
|
-
| Some(dcs) => dcs->Array.push(dc)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
let promises = []
|
|
392
|
-
for idx in 0 to itemsWithContractRegister->Array.length - 1 {
|
|
393
|
-
let item = itemsWithContractRegister->Array.getUnsafe(idx)
|
|
394
|
-
let eventItem = item->Internal.castUnsafeEventItem
|
|
395
|
-
let contractRegister = switch eventItem {
|
|
396
|
-
| {eventConfig: {contractRegister: Some(contractRegister)}} => contractRegister
|
|
397
|
-
| {eventConfig: {contractRegister: None, name: eventName}} =>
|
|
398
|
-
// Unexpected case, since we should pass only events with contract register to this function
|
|
399
|
-
JsError.throwWithMessage("Contract register is not set for event " ++ eventName)
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
let errorMessage = "Event contractRegister failed, please fix the error to keep the indexer running smoothly"
|
|
403
|
-
|
|
404
|
-
// Catch sync and async errors
|
|
405
|
-
try {
|
|
406
|
-
let params: UserContext.contractRegisterParams = {
|
|
407
|
-
item,
|
|
408
|
-
onRegister,
|
|
409
|
-
config,
|
|
410
|
-
isResolved: false,
|
|
411
|
-
}
|
|
412
|
-
let result = contractRegister(UserContext.getContractRegisterArgs(params))
|
|
413
|
-
|
|
414
|
-
// Even though `contractRegister` always returns a promise,
|
|
415
|
-
// in the ReScript type, but it might return a non-promise value for TS API.
|
|
416
|
-
if result->Utils.Promise.isCatchable {
|
|
417
|
-
promises->Array.push(
|
|
418
|
-
result
|
|
419
|
-
->Promise.thenResolve(r => {
|
|
420
|
-
params.isResolved = true
|
|
421
|
-
r
|
|
422
|
-
})
|
|
423
|
-
->Promise.catch(exn => {
|
|
424
|
-
params.isResolved = true
|
|
425
|
-
exn->ErrorHandling.mkLogAndRaise(~msg=errorMessage, ~logger=item->Logging.getItemLogger)
|
|
426
|
-
}),
|
|
427
|
-
)
|
|
428
|
-
} else {
|
|
429
|
-
params.isResolved = true
|
|
430
|
-
}
|
|
431
|
-
} catch {
|
|
432
|
-
| exn =>
|
|
433
|
-
exn->ErrorHandling.mkLogAndRaise(~msg=errorMessage, ~logger=item->Logging.getItemLogger)
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
if promises->Utils.Array.notEmpty {
|
|
438
|
-
let _ = await Promise.all(promises)
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
itemsWithDcs
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
let handleQueryResult = (
|
|
445
|
-
chainFetcher: t,
|
|
446
|
-
~query: FetchState.query,
|
|
447
|
-
~newItems,
|
|
448
|
-
~newItemsWithDcs,
|
|
449
|
-
~latestFetchedBlock,
|
|
450
|
-
~knownHeight,
|
|
451
|
-
) => {
|
|
452
|
-
let fs = switch newItemsWithDcs {
|
|
453
|
-
| [] => chainFetcher.fetchState
|
|
454
|
-
| _ => chainFetcher.fetchState->FetchState.registerDynamicContracts(newItemsWithDcs)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
{
|
|
458
|
-
...chainFetcher,
|
|
459
|
-
fetchState: fs
|
|
460
|
-
->FetchState.handleQueryResult(~query, ~latestFetchedBlock, ~newItems)
|
|
461
|
-
->FetchState.updateKnownHeight(~knownHeight),
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
Gets the latest item on the front of the queue and returns updated fetcher
|
|
467
|
-
*/
|
|
468
|
-
let hasProcessedToEndblock = (self: t) => {
|
|
469
|
-
let {committedProgressBlockNumber, fetchState} = self
|
|
470
|
-
switch fetchState.endBlock {
|
|
471
|
-
| Some(endBlock) => committedProgressBlockNumber >= endBlock
|
|
472
|
-
| None => false
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
let hasNoMoreEventsToProcess = (self: t) => {
|
|
477
|
-
self.fetchState->FetchState.bufferSize === 0
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
let getHighestBlockBelowThreshold = (cf: t): int => {
|
|
481
|
-
let highestBlockBelowThreshold = cf.fetchState.knownHeight - cf.chainConfig.maxReorgDepth
|
|
482
|
-
highestBlockBelowThreshold < 0 ? 0 : highestBlockBelowThreshold
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
Finds the last known valid block number below the reorg block
|
|
487
|
-
If not found, returns the highest block below threshold
|
|
488
|
-
*/
|
|
489
|
-
let getLastKnownValidBlock = async (chainFetcher: t, ~reorgBlockNumber: int, ~isRealtime: bool) => {
|
|
490
|
-
// Don't include the reorg block itself — different source instances
|
|
491
|
-
// may have mismatching hashes at the head, so we always rollback
|
|
492
|
-
// the block where we detected the reorg.
|
|
493
|
-
let scannedBlockNumbers =
|
|
494
|
-
chainFetcher.reorgDetection->ReorgDetection.getThresholdBlockNumbersBelowBlock(
|
|
495
|
-
~blockNumber=reorgBlockNumber,
|
|
496
|
-
~knownHeight=chainFetcher.fetchState.knownHeight,
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
switch scannedBlockNumbers {
|
|
500
|
-
| [] => chainFetcher->getHighestBlockBelowThreshold
|
|
501
|
-
| _ => {
|
|
502
|
-
let blockNumbersAndHashes = await chainFetcher.sourceManager->SourceManager.getBlockHashes(
|
|
503
|
-
~blockNumbers=scannedBlockNumbers,
|
|
504
|
-
~isRealtime,
|
|
505
|
-
)
|
|
506
|
-
|
|
507
|
-
switch chainFetcher.reorgDetection->ReorgDetection.getLatestValidScannedBlock(
|
|
508
|
-
~blockNumbersAndHashes,
|
|
509
|
-
) {
|
|
510
|
-
| Some(blockNumber) => blockNumber
|
|
511
|
-
| None => chainFetcher->getHighestBlockBelowThreshold
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
let isActivelyIndexing = (chainFetcher: t) => chainFetcher.fetchState->FetchState.isActivelyIndexing
|
|
518
|
-
|
|
519
|
-
let isReady = (chainFetcher: t) => chainFetcher.timestampCaughtUpToHeadOrEndblock !== None
|