envio 3.2.0 → 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 +35 -0
- package/src/EventConfigBuilder.res.mjs +21 -0
- 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 +162 -113
- package/src/FetchState.res.mjs +181 -119
- package/src/HandlerLoader.res +6 -1
- package/src/HandlerLoader.res.mjs +13 -36
- 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 +44 -7
- package/src/LoadLayer.res +20 -18
- package/src/LoadLayer.res.mjs +14 -12
- package/src/LoadLayer.resi +6 -3
- package/src/LogSelection.res +86 -17
- package/src/LogSelection.res.mjs +67 -14
- 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/TestIndexer.res +34 -27
- package/src/TestIndexer.res.mjs +4 -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 +7 -5
- package/src/sources/HyperSyncSource.res.mjs +3 -3
- 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,461 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Env from "./Env.res.mjs";
|
|
4
|
+
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
|
+
import * as Batch from "./Batch.res.mjs";
|
|
6
|
+
import * as Utils from "./Utils.res.mjs";
|
|
7
|
+
import * as Logging from "./Logging.res.mjs";
|
|
8
|
+
import * as ChainMap from "./ChainMap.res.mjs";
|
|
9
|
+
import * as EvmChain from "./sources/EvmChain.res.mjs";
|
|
10
|
+
import * as FetchState from "./FetchState.res.mjs";
|
|
11
|
+
import * as Prometheus from "./Prometheus.res.mjs";
|
|
12
|
+
import * as EventRouter from "./sources/EventRouter.res.mjs";
|
|
13
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
14
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
15
|
+
import * as SourceManager from "./sources/SourceManager.res.mjs";
|
|
16
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
17
|
+
import * as ReorgDetection from "./ReorgDetection.res.mjs";
|
|
18
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
19
|
+
import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
|
|
20
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
21
|
+
import * as SvmHyperSyncSource from "./sources/SvmHyperSyncSource.res.mjs";
|
|
22
|
+
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
23
|
+
|
|
24
|
+
function configAddresses(chainConfig) {
|
|
25
|
+
let addresses = [];
|
|
26
|
+
chainConfig.contracts.forEach(contract => {
|
|
27
|
+
contract.addresses.forEach(address => {
|
|
28
|
+
addresses.push({
|
|
29
|
+
address: address,
|
|
30
|
+
contractName: contract.name,
|
|
31
|
+
registrationBlock: -1
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return addresses;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function make(chainConfig, fetchState, sourceManager, reorgDetection, committedProgressBlockNumber, safeCheckpointTrackingOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, logger) {
|
|
39
|
+
let safeCheckpointTracking = safeCheckpointTrackingOpt !== undefined ? Primitive_option.valFromOption(safeCheckpointTrackingOpt) : undefined;
|
|
40
|
+
let numEventsProcessed = numEventsProcessedOpt !== undefined ? numEventsProcessedOpt : 0;
|
|
41
|
+
let timestampCaughtUpToHeadOrEndblock = timestampCaughtUpToHeadOrEndblockOpt !== undefined ? Primitive_option.valFromOption(timestampCaughtUpToHeadOrEndblockOpt) : undefined;
|
|
42
|
+
let isProgressAtHead = isProgressAtHeadOpt !== undefined ? isProgressAtHeadOpt : false;
|
|
43
|
+
return {
|
|
44
|
+
logger: logger,
|
|
45
|
+
fetchState: fetchState,
|
|
46
|
+
sourceManager: sourceManager,
|
|
47
|
+
chainConfig: chainConfig,
|
|
48
|
+
isProgressAtHead: isProgressAtHead,
|
|
49
|
+
timestampCaughtUpToHeadOrEndblock: timestampCaughtUpToHeadOrEndblock,
|
|
50
|
+
committedProgressBlockNumber: committedProgressBlockNumber,
|
|
51
|
+
numEventsProcessed: numEventsProcessed,
|
|
52
|
+
reorgDetection: reorgDetection,
|
|
53
|
+
safeCheckpointTracking: safeCheckpointTracking
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrations, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, reducedPollingInterval) {
|
|
58
|
+
let firstEventBlock = firstEventBlockOpt !== undefined ? Primitive_option.valFromOption(firstEventBlockOpt) : undefined;
|
|
59
|
+
let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
|
|
60
|
+
let eventRouter = EventRouter.empty();
|
|
61
|
+
let eventConfigs = [];
|
|
62
|
+
let notRegisteredEvents = [];
|
|
63
|
+
chainConfig.contracts.forEach(contract => {
|
|
64
|
+
let contractName = contract.name;
|
|
65
|
+
contract.events.forEach(eventConfig => {
|
|
66
|
+
let hasContractRegister = Stdlib_Option.isSome(eventConfig.contractRegister);
|
|
67
|
+
EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, eventConfig.isWildcard, eventConfig.name, ChainMap.Chain.makeUnsafe(chainConfig.id));
|
|
68
|
+
let shouldBeIncluded;
|
|
69
|
+
if (config.enableRawEvents) {
|
|
70
|
+
shouldBeIncluded = true;
|
|
71
|
+
} else {
|
|
72
|
+
let isRegistered = hasContractRegister || Stdlib_Option.isSome(eventConfig.handler);
|
|
73
|
+
if (!isRegistered) {
|
|
74
|
+
notRegisteredEvents.push(eventConfig);
|
|
75
|
+
}
|
|
76
|
+
shouldBeIncluded = isRegistered;
|
|
77
|
+
}
|
|
78
|
+
let shouldSkip;
|
|
79
|
+
try {
|
|
80
|
+
let getEventFiltersOrThrow = eventConfig.getEventFiltersOrThrow;
|
|
81
|
+
if (getEventFiltersOrThrow) {
|
|
82
|
+
let match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
|
|
83
|
+
shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
|
|
84
|
+
} else {
|
|
85
|
+
shouldSkip = false;
|
|
86
|
+
}
|
|
87
|
+
} catch (exn) {
|
|
88
|
+
shouldSkip = false;
|
|
89
|
+
}
|
|
90
|
+
if (shouldBeIncluded && !shouldSkip) {
|
|
91
|
+
eventConfigs.push(eventConfig);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
let startBlock = contract.startBlock;
|
|
96
|
+
if (startBlock !== undefined && startBlock < chainConfig.startBlock) {
|
|
97
|
+
return Stdlib_JsError.throwWithMessage(`The start block for contract "` + contractName + `" is less than the chain start block. This is not supported yet.`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (Utils.$$Array.notEmpty(notRegisteredEvents)) {
|
|
101
|
+
Logging.childInfo(logger, `The event` + (
|
|
102
|
+
notRegisteredEvents.length > 1 ? "s" : ""
|
|
103
|
+
) + ` ` + notRegisteredEvents.map(eventConfig => eventConfig.contractName + `.` + eventConfig.name).join(", ") + ` don't have an event handler and skipped for indexing.`);
|
|
104
|
+
}
|
|
105
|
+
let onBlockConfigs = registrations.onBlockByChainId[chainConfig.id.toString()];
|
|
106
|
+
if (onBlockConfigs !== undefined) {
|
|
107
|
+
onBlockConfigs.forEach(onBlockConfig => {
|
|
108
|
+
if (Stdlib_Option.getOr(onBlockConfig.startBlock, startBlock) < startBlock) {
|
|
109
|
+
Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + onBlockConfig.name + `" is less than the chain start block (` + startBlock.toString() + `). This is not supported yet.`);
|
|
110
|
+
}
|
|
111
|
+
if (endBlock !== undefined && Stdlib_Option.getOr(onBlockConfig.endBlock, endBlock) > endBlock) {
|
|
112
|
+
return Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + onBlockConfig.name + `" is greater than the chain end block (` + endBlock.toString() + `). This is not supported yet.`);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
let fetchState = FetchState.make(startBlock, endBlock, eventConfigs, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, onBlockConfigs, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock));
|
|
117
|
+
let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
|
|
118
|
+
if (reorgCheckpoint.chain_id === chainConfig.id) {
|
|
119
|
+
return reorgCheckpoint;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
|
|
123
|
+
let lowercaseAddresses = config.lowercaseAddresses;
|
|
124
|
+
let sources = chainConfig.sourceConfig;
|
|
125
|
+
let sources$1;
|
|
126
|
+
switch (sources.TAG) {
|
|
127
|
+
case "EvmSourceConfig" :
|
|
128
|
+
let evmContracts = chainConfig.contracts.map(contract => ({
|
|
129
|
+
name: contract.name,
|
|
130
|
+
abi: contract.abi,
|
|
131
|
+
events: contract.events
|
|
132
|
+
}));
|
|
133
|
+
let evmRpcs = sources.rpcs.map(rpc => {
|
|
134
|
+
let syncConfig = rpc.syncConfig;
|
|
135
|
+
let ws = rpc.ws;
|
|
136
|
+
return {
|
|
137
|
+
url: rpc.url,
|
|
138
|
+
sourceFor: rpc.sourceFor,
|
|
139
|
+
syncConfig: syncConfig,
|
|
140
|
+
ws: ws
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
sources$1 = EvmChain.makeSources(chain, evmContracts, sources.hypersync, evmRpcs, lowercaseAddresses);
|
|
144
|
+
break;
|
|
145
|
+
case "FuelSourceConfig" :
|
|
146
|
+
sources$1 = [HyperFuelSource.make({
|
|
147
|
+
chain: chain,
|
|
148
|
+
endpointUrl: sources.hypersync,
|
|
149
|
+
apiToken: Env.envioApiToken
|
|
150
|
+
})];
|
|
151
|
+
break;
|
|
152
|
+
case "SvmSourceConfig" :
|
|
153
|
+
let rpc = sources.rpc;
|
|
154
|
+
let hypersync = sources.hypersync;
|
|
155
|
+
if (hypersync !== undefined) {
|
|
156
|
+
let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
|
|
157
|
+
sources$1 = [SvmHyperSyncSource.make({
|
|
158
|
+
chain: chain,
|
|
159
|
+
endpointUrl: hypersync,
|
|
160
|
+
apiToken: Env.envioApiToken,
|
|
161
|
+
eventConfigs: svmEventConfigs,
|
|
162
|
+
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis
|
|
163
|
+
})];
|
|
164
|
+
} else {
|
|
165
|
+
sources$1 = rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`);
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case "CustomSources" :
|
|
169
|
+
sources$1 = sources._0;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
return make(chainConfig, fetchState, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, logger);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function makeFromConfig(chainConfig, config, registrations, knownHeight) {
|
|
176
|
+
let logger = Logging.createChild({
|
|
177
|
+
chainId: chainConfig.id
|
|
178
|
+
});
|
|
179
|
+
return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrations, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, reducedPollingInterval) {
|
|
183
|
+
let chainId = chainConfig.id;
|
|
184
|
+
let logger = Logging.createChild({
|
|
185
|
+
chainId: chainId
|
|
186
|
+
});
|
|
187
|
+
Prometheus.ProgressEventsCount.set(resumedChainState.numEventsProcessed, chainId);
|
|
188
|
+
let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
|
|
189
|
+
return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrations, logger, Env.updateSyncTimeOnRestart ? undefined : resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, reducedPollingInterval);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function logger(cs) {
|
|
193
|
+
return cs.logger;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function fetchState(cs) {
|
|
197
|
+
return cs.fetchState;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function sourceManager(cs) {
|
|
201
|
+
return cs.sourceManager;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function chainConfig(cs) {
|
|
205
|
+
return cs.chainConfig;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function reorgDetection(cs) {
|
|
209
|
+
return cs.reorgDetection;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function safeCheckpointTracking(cs) {
|
|
213
|
+
return cs.safeCheckpointTracking;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isProgressAtHead(cs) {
|
|
217
|
+
return cs.isProgressAtHead;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function committedProgressBlockNumber(cs) {
|
|
221
|
+
return cs.committedProgressBlockNumber;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function numEventsProcessed(cs) {
|
|
225
|
+
return cs.numEventsProcessed;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function timestampCaughtUpToHeadOrEndblock(cs) {
|
|
229
|
+
return cs.timestampCaughtUpToHeadOrEndblock;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function hasProcessedToEndblock(cs) {
|
|
233
|
+
let fetchState = cs.fetchState;
|
|
234
|
+
let committedProgressBlockNumber = cs.committedProgressBlockNumber;
|
|
235
|
+
let endBlock = fetchState.endBlock;
|
|
236
|
+
if (endBlock !== undefined) {
|
|
237
|
+
return committedProgressBlockNumber >= endBlock;
|
|
238
|
+
} else {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function getHighestBlockBelowThreshold(cs) {
|
|
244
|
+
let highestBlockBelowThreshold = cs.fetchState.knownHeight - cs.chainConfig.maxReorgDepth | 0;
|
|
245
|
+
if (highestBlockBelowThreshold < 0) {
|
|
246
|
+
return 0;
|
|
247
|
+
} else {
|
|
248
|
+
return highestBlockBelowThreshold;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function isActivelyIndexing(cs) {
|
|
253
|
+
return FetchState.isActivelyIndexing(cs.fetchState);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function isReady(cs) {
|
|
257
|
+
return cs.timestampCaughtUpToHeadOrEndblock !== undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function isFetchingAtHead(cs) {
|
|
261
|
+
return FetchState.isFetchingAtHead(cs.fetchState);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function handleQueryResult(cs, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight) {
|
|
265
|
+
let fs = newItemsWithDcs.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, newItemsWithDcs) : cs.fetchState;
|
|
266
|
+
cs.fetchState = FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, query, latestFetchedBlock, newItems), knownHeight);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function registerReorgGuard(cs, blockHashes, knownHeight) {
|
|
270
|
+
let match = ReorgDetection.registerReorgGuard(cs.reorgDetection, blockHashes, knownHeight);
|
|
271
|
+
cs.reorgDetection = match[0];
|
|
272
|
+
return match[1];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function prepareReorg(cs, eventsProcessedDiff) {
|
|
276
|
+
if (eventsProcessedDiff !== undefined) {
|
|
277
|
+
cs.numEventsProcessed = cs.numEventsProcessed + eventsProcessedDiff;
|
|
278
|
+
}
|
|
279
|
+
cs.fetchState = FetchState.resetPendingQueries(cs.fetchState);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function updateKnownHeight(cs, knownHeight) {
|
|
283
|
+
cs.fetchState = FetchState.updateKnownHeight(cs.fetchState, knownHeight);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function setEndBlockToFirstEvent(cs, blockNumber) {
|
|
287
|
+
let currentEndBlock = cs.fetchState.endBlock;
|
|
288
|
+
if (currentEndBlock !== undefined) {
|
|
289
|
+
if (blockNumber >= currentEndBlock) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
let init = cs.fetchState;
|
|
293
|
+
cs.fetchState = {
|
|
294
|
+
optimizedPartitions: init.optimizedPartitions,
|
|
295
|
+
startBlock: init.startBlock,
|
|
296
|
+
endBlock: blockNumber,
|
|
297
|
+
normalSelection: init.normalSelection,
|
|
298
|
+
indexingAddresses: init.indexingAddresses,
|
|
299
|
+
contractConfigs: init.contractConfigs,
|
|
300
|
+
chainId: init.chainId,
|
|
301
|
+
latestOnBlockBlockNumber: init.latestOnBlockBlockNumber,
|
|
302
|
+
blockLag: init.blockLag,
|
|
303
|
+
buffer: init.buffer,
|
|
304
|
+
maxOnBlockBufferSize: init.maxOnBlockBufferSize,
|
|
305
|
+
onBlockConfigs: init.onBlockConfigs,
|
|
306
|
+
knownHeight: init.knownHeight,
|
|
307
|
+
firstEventBlock: init.firstEventBlock
|
|
308
|
+
};
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
let init$1 = cs.fetchState;
|
|
312
|
+
cs.fetchState = {
|
|
313
|
+
optimizedPartitions: init$1.optimizedPartitions,
|
|
314
|
+
startBlock: init$1.startBlock,
|
|
315
|
+
endBlock: blockNumber,
|
|
316
|
+
normalSelection: init$1.normalSelection,
|
|
317
|
+
indexingAddresses: init$1.indexingAddresses,
|
|
318
|
+
contractConfigs: init$1.contractConfigs,
|
|
319
|
+
chainId: init$1.chainId,
|
|
320
|
+
latestOnBlockBlockNumber: init$1.latestOnBlockBlockNumber,
|
|
321
|
+
blockLag: init$1.blockLag,
|
|
322
|
+
buffer: init$1.buffer,
|
|
323
|
+
maxOnBlockBufferSize: init$1.maxOnBlockBufferSize,
|
|
324
|
+
onBlockConfigs: init$1.onBlockConfigs,
|
|
325
|
+
knownHeight: init$1.knownHeight,
|
|
326
|
+
firstEventBlock: init$1.firstEventBlock
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function enterReorgThreshold(cs) {
|
|
331
|
+
cs.fetchState = FetchState.updateInternal(cs.fetchState, undefined, undefined, undefined, cs.chainConfig.blockLag, undefined);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function advanceAfterBatch(cs, batch, enteringReorgThreshold) {
|
|
335
|
+
let chainAfterBatch = batch.progressedChainsById[cs.fetchState.chainId];
|
|
336
|
+
if (chainAfterBatch !== undefined) {
|
|
337
|
+
cs.fetchState = enteringReorgThreshold ? FetchState.updateInternal(chainAfterBatch.fetchState, undefined, undefined, undefined, cs.chainConfig.blockLag, undefined) : chainAfterBatch.fetchState;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function applyBatchProgress(cs, batch) {
|
|
343
|
+
let chainId = cs.chainConfig.id;
|
|
344
|
+
let chainAfterBatch = batch.progressedChainsById[chainId];
|
|
345
|
+
if (chainAfterBatch === undefined) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (cs.committedProgressBlockNumber !== chainAfterBatch.progressBlockNumber) {
|
|
349
|
+
Prometheus.ProgressBlockNumber.set(chainAfterBatch.progressBlockNumber, chainId);
|
|
350
|
+
}
|
|
351
|
+
if (cs.numEventsProcessed !== chainAfterBatch.totalEventsProcessed) {
|
|
352
|
+
Prometheus.ProgressEventsCount.set(chainAfterBatch.totalEventsProcessed, chainId);
|
|
353
|
+
}
|
|
354
|
+
let eventItem = Batch.findLastEventItem(batch, chainId);
|
|
355
|
+
if (eventItem !== undefined) {
|
|
356
|
+
let blockTimestampMs = eventItem.timestamp * 1000 | 0;
|
|
357
|
+
Prometheus.ProgressLatency.set((Date.now() | 0) - blockTimestampMs | 0, chainId);
|
|
358
|
+
}
|
|
359
|
+
let match = cs.fetchState.firstEventBlock;
|
|
360
|
+
if (match === undefined) {
|
|
361
|
+
let firstEventBlock = Batch.findFirstEventBlockNumber(batch, chainId);
|
|
362
|
+
if (firstEventBlock !== undefined) {
|
|
363
|
+
let init = cs.fetchState;
|
|
364
|
+
cs.fetchState = {
|
|
365
|
+
optimizedPartitions: init.optimizedPartitions,
|
|
366
|
+
startBlock: init.startBlock,
|
|
367
|
+
endBlock: init.endBlock,
|
|
368
|
+
normalSelection: init.normalSelection,
|
|
369
|
+
indexingAddresses: init.indexingAddresses,
|
|
370
|
+
contractConfigs: init.contractConfigs,
|
|
371
|
+
chainId: init.chainId,
|
|
372
|
+
latestOnBlockBlockNumber: init.latestOnBlockBlockNumber,
|
|
373
|
+
blockLag: init.blockLag,
|
|
374
|
+
buffer: init.buffer,
|
|
375
|
+
maxOnBlockBufferSize: init.maxOnBlockBufferSize,
|
|
376
|
+
onBlockConfigs: init.onBlockConfigs,
|
|
377
|
+
knownHeight: init.knownHeight,
|
|
378
|
+
firstEventBlock: firstEventBlock
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
cs.committedProgressBlockNumber = chainAfterBatch.progressBlockNumber;
|
|
383
|
+
cs.numEventsProcessed = chainAfterBatch.totalEventsProcessed;
|
|
384
|
+
cs.isProgressAtHead = cs.isProgressAtHead || chainAfterBatch.isProgressAtHeadWhenBatchCreated;
|
|
385
|
+
let safeCheckpointTracking = cs.safeCheckpointTracking;
|
|
386
|
+
if (safeCheckpointTracking !== undefined) {
|
|
387
|
+
cs.safeCheckpointTracking = SafeCheckpointTracking.updateOnNewBatch(safeCheckpointTracking, cs.fetchState.knownHeight, chainId, batch.checkpointIds, batch.checkpointBlockNumbers, batch.checkpointChainIds);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function markReady(cs) {
|
|
393
|
+
if (cs.timestampCaughtUpToHeadOrEndblock === undefined) {
|
|
394
|
+
cs.timestampCaughtUpToHeadOrEndblock = new Date();
|
|
395
|
+
return Prometheus.ProgressReady.set(cs.chainConfig.id);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTargetBlockNumber, isReorgChain) {
|
|
400
|
+
let chainId = cs.chainConfig.id;
|
|
401
|
+
if (newProgressBlockNumber === undefined) {
|
|
402
|
+
if (isReorgChain) {
|
|
403
|
+
cs.reorgDetection = ReorgDetection.rollbackToValidBlockNumber(cs.reorgDetection, rollbackTargetBlockNumber);
|
|
404
|
+
cs.fetchState = FetchState.rollback(cs.fetchState, rollbackTargetBlockNumber);
|
|
405
|
+
cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, rollbackTargetBlockNumber);
|
|
406
|
+
return;
|
|
407
|
+
} else {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
let newTotalEventsProcessed = cs.numEventsProcessed - Stdlib_Option.getOrThrow(eventsProcessedDiff, "Missing events-processed diff for rolled-back chain");
|
|
412
|
+
if (cs.committedProgressBlockNumber !== newProgressBlockNumber) {
|
|
413
|
+
Prometheus.ProgressBlockNumber.set(newProgressBlockNumber, chainId);
|
|
414
|
+
}
|
|
415
|
+
if (cs.numEventsProcessed !== newTotalEventsProcessed) {
|
|
416
|
+
Prometheus.ProgressEventsCount.set(newTotalEventsProcessed, chainId);
|
|
417
|
+
}
|
|
418
|
+
if (isReorgChain) {
|
|
419
|
+
cs.reorgDetection = ReorgDetection.rollbackToValidBlockNumber(cs.reorgDetection, rollbackTargetBlockNumber);
|
|
420
|
+
}
|
|
421
|
+
let safeCheckpointTracking = cs.safeCheckpointTracking;
|
|
422
|
+
if (safeCheckpointTracking !== undefined) {
|
|
423
|
+
cs.safeCheckpointTracking = SafeCheckpointTracking.rollback(safeCheckpointTracking, newProgressBlockNumber);
|
|
424
|
+
}
|
|
425
|
+
cs.fetchState = FetchState.rollback(cs.fetchState, newProgressBlockNumber);
|
|
426
|
+
cs.committedProgressBlockNumber = newProgressBlockNumber;
|
|
427
|
+
cs.numEventsProcessed = newTotalEventsProcessed;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export {
|
|
431
|
+
configAddresses,
|
|
432
|
+
make,
|
|
433
|
+
makeFromConfig,
|
|
434
|
+
makeFromDbState,
|
|
435
|
+
logger,
|
|
436
|
+
fetchState,
|
|
437
|
+
sourceManager,
|
|
438
|
+
chainConfig,
|
|
439
|
+
reorgDetection,
|
|
440
|
+
safeCheckpointTracking,
|
|
441
|
+
isProgressAtHead,
|
|
442
|
+
committedProgressBlockNumber,
|
|
443
|
+
numEventsProcessed,
|
|
444
|
+
timestampCaughtUpToHeadOrEndblock,
|
|
445
|
+
hasProcessedToEndblock,
|
|
446
|
+
getHighestBlockBelowThreshold,
|
|
447
|
+
isActivelyIndexing,
|
|
448
|
+
isReady,
|
|
449
|
+
isFetchingAtHead,
|
|
450
|
+
handleQueryResult,
|
|
451
|
+
registerReorgGuard,
|
|
452
|
+
prepareReorg,
|
|
453
|
+
updateKnownHeight,
|
|
454
|
+
setEndBlockToFirstEvent,
|
|
455
|
+
enterReorgThreshold,
|
|
456
|
+
advanceAfterBatch,
|
|
457
|
+
applyBatchProgress,
|
|
458
|
+
markReady,
|
|
459
|
+
rollback,
|
|
460
|
+
}
|
|
461
|
+
/* Env Not a pure module */
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Per-chain runtime state. `t` is opaque: other modules read it through the
|
|
2
|
+
// accessors and change it only through the mutators exposed here.
|
|
3
|
+
|
|
4
|
+
type t
|
|
5
|
+
|
|
6
|
+
let configAddresses: Config.chain => array<Internal.indexingAddress>
|
|
7
|
+
|
|
8
|
+
let make: (
|
|
9
|
+
~chainConfig: Config.chain,
|
|
10
|
+
~fetchState: FetchState.t,
|
|
11
|
+
~sourceManager: SourceManager.t,
|
|
12
|
+
~reorgDetection: ReorgDetection.t,
|
|
13
|
+
~committedProgressBlockNumber: int,
|
|
14
|
+
~safeCheckpointTracking: option<SafeCheckpointTracking.t>=?,
|
|
15
|
+
~numEventsProcessed: float=?,
|
|
16
|
+
~timestampCaughtUpToHeadOrEndblock: option<Date.t>=?,
|
|
17
|
+
~isProgressAtHead: bool=?,
|
|
18
|
+
~logger: Pino.t,
|
|
19
|
+
) => t
|
|
20
|
+
|
|
21
|
+
let makeFromConfig: (
|
|
22
|
+
Config.chain,
|
|
23
|
+
~config: Config.t,
|
|
24
|
+
~registrations: HandlerRegister.registrations,
|
|
25
|
+
~knownHeight: int,
|
|
26
|
+
) => t
|
|
27
|
+
|
|
28
|
+
let makeFromDbState: (
|
|
29
|
+
Config.chain,
|
|
30
|
+
~resumedChainState: Persistence.initialChainState,
|
|
31
|
+
~reorgCheckpoints: array<Internal.reorgCheckpoint>,
|
|
32
|
+
~isInReorgThreshold: bool,
|
|
33
|
+
~isRealtime: bool,
|
|
34
|
+
~config: Config.t,
|
|
35
|
+
~registrations: HandlerRegister.registrations,
|
|
36
|
+
~reducedPollingInterval: int=?,
|
|
37
|
+
) => t
|
|
38
|
+
|
|
39
|
+
// Accessors.
|
|
40
|
+
let logger: t => Pino.t
|
|
41
|
+
let fetchState: t => FetchState.t
|
|
42
|
+
let sourceManager: t => SourceManager.t
|
|
43
|
+
let chainConfig: t => Config.chain
|
|
44
|
+
let reorgDetection: t => ReorgDetection.t
|
|
45
|
+
let safeCheckpointTracking: t => option<SafeCheckpointTracking.t>
|
|
46
|
+
let isProgressAtHead: t => bool
|
|
47
|
+
let committedProgressBlockNumber: t => int
|
|
48
|
+
let numEventsProcessed: t => float
|
|
49
|
+
let timestampCaughtUpToHeadOrEndblock: t => option<Date.t>
|
|
50
|
+
|
|
51
|
+
// Derived (pure).
|
|
52
|
+
let hasProcessedToEndblock: t => bool
|
|
53
|
+
let getHighestBlockBelowThreshold: t => int
|
|
54
|
+
let isActivelyIndexing: t => bool
|
|
55
|
+
let isReady: t => bool
|
|
56
|
+
let isFetchingAtHead: t => bool
|
|
57
|
+
|
|
58
|
+
// State transitions. The chain state is mutated only through these.
|
|
59
|
+
let handleQueryResult: (
|
|
60
|
+
t,
|
|
61
|
+
~query: FetchState.query,
|
|
62
|
+
~newItems: array<Internal.item>,
|
|
63
|
+
~newItemsWithDcs: array<Internal.item>,
|
|
64
|
+
~latestFetchedBlock: FetchState.blockNumberAndTimestamp,
|
|
65
|
+
~knownHeight: int,
|
|
66
|
+
) => unit
|
|
67
|
+
let registerReorgGuard: (
|
|
68
|
+
t,
|
|
69
|
+
~blockHashes: array<ReorgDetection.blockData>,
|
|
70
|
+
~knownHeight: int,
|
|
71
|
+
) => ReorgDetection.reorgResult
|
|
72
|
+
let prepareReorg: (t, ~eventsProcessedDiff: option<float>) => unit
|
|
73
|
+
let updateKnownHeight: (t, ~knownHeight: int) => unit
|
|
74
|
+
let setEndBlockToFirstEvent: (t, ~blockNumber: int) => unit
|
|
75
|
+
let enterReorgThreshold: t => unit
|
|
76
|
+
let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
|
|
77
|
+
let applyBatchProgress: (t, ~batch: Batch.t) => unit
|
|
78
|
+
let markReady: t => unit
|
|
79
|
+
let rollback: (
|
|
80
|
+
t,
|
|
81
|
+
~newProgressBlockNumber: option<int>,
|
|
82
|
+
~eventsProcessedDiff: option<float>,
|
|
83
|
+
~rollbackTargetBlockNumber: int,
|
|
84
|
+
~isReorgChain: bool,
|
|
85
|
+
) => unit
|
package/src/Config.res
CHANGED
|
@@ -17,7 +17,7 @@ type contract = {
|
|
|
17
17
|
startBlock: option<int>,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// Sources are instantiated lazily in
|
|
20
|
+
// Sources are instantiated lazily in ChainState from this config.
|
|
21
21
|
type evmRpcConfig = {
|
|
22
22
|
url: string,
|
|
23
23
|
sourceFor: Source.sourceFor,
|
|
@@ -546,10 +546,19 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
546
546
|
)
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
let logger = Logging.getLogger()
|
|
549
550
|
let ecosystem = switch ecosystemName {
|
|
550
|
-
| Ecosystem.Evm => Evm.
|
|
551
|
-
| Ecosystem.Fuel => Fuel.
|
|
552
|
-
| Ecosystem.Svm => Svm.
|
|
551
|
+
| Ecosystem.Evm => Evm.make(~logger)
|
|
552
|
+
| Ecosystem.Fuel => Fuel.make(~logger)
|
|
553
|
+
| Ecosystem.Svm => Svm.make(~logger)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// SVM has no raw-events representation (`Svm.toRawEvent` throws), so reject
|
|
557
|
+
// it at config time instead of failing mid-indexing.
|
|
558
|
+
if ecosystemName === Ecosystem.Svm && publicConfig["rawEvents"]->Option.getOr(false) {
|
|
559
|
+
JsError.throwWithMessage(
|
|
560
|
+
"Invalid indexer config: rawEvents is not supported for the SVM ecosystem",
|
|
561
|
+
)
|
|
553
562
|
}
|
|
554
563
|
|
|
555
564
|
// Extract EVM-specific options with defaults
|
package/src/Config.res.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import * as Fuel from "./sources/Fuel.res.mjs";
|
|
|
8
8
|
import * as Table from "./db/Table.res.mjs";
|
|
9
9
|
import * as Utils from "./Utils.res.mjs";
|
|
10
10
|
import * as Address from "./Address.res.mjs";
|
|
11
|
+
import * as Logging from "./Logging.res.mjs";
|
|
11
12
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
12
13
|
import * as Internal from "./Internal.res.mjs";
|
|
13
14
|
import * as BigDecimal from "./bindings/BigDecimal.res.mjs";
|
|
@@ -424,18 +425,22 @@ function fromPublic(publicConfigJson) {
|
|
|
424
425
|
);
|
|
425
426
|
let ecosystemName = match$3[1];
|
|
426
427
|
let publicChainsConfig = match$3[0];
|
|
428
|
+
let logger = Logging.getLogger();
|
|
427
429
|
let ecosystem;
|
|
428
430
|
switch (ecosystemName) {
|
|
429
431
|
case "evm" :
|
|
430
|
-
ecosystem = Evm.
|
|
432
|
+
ecosystem = Evm.make(logger);
|
|
431
433
|
break;
|
|
432
434
|
case "fuel" :
|
|
433
|
-
ecosystem = Fuel.
|
|
435
|
+
ecosystem = Fuel.make(logger);
|
|
434
436
|
break;
|
|
435
437
|
case "svm" :
|
|
436
|
-
ecosystem = Svm.
|
|
438
|
+
ecosystem = Svm.make(logger);
|
|
437
439
|
break;
|
|
438
440
|
}
|
|
441
|
+
if (ecosystemName === "svm" && Stdlib_Option.getOr(publicConfig.rawEvents, false)) {
|
|
442
|
+
Stdlib_JsError.throwWithMessage("Invalid indexer config: rawEvents is not supported for the SVM ecosystem");
|
|
443
|
+
}
|
|
439
444
|
let evm = publicConfig.evm;
|
|
440
445
|
let lowercaseAddresses = evm !== undefined ? Stdlib_Option.getOr(Primitive_option.valFromOption(evm).addressFormat, "checksum") === "lowercase" : false;
|
|
441
446
|
let match$4 = publicConfig.evm;
|