envio 3.0.0-alpha.2 → 3.0.0-alpha.21
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/README.md +164 -30
- package/bin.mjs +49 -0
- package/evm.schema.json +79 -169
- package/fuel.schema.json +50 -21
- package/index.d.ts +578 -1
- package/index.js +4 -0
- package/package.json +47 -31
- package/rescript.json +4 -1
- package/src/Batch.res +11 -8
- package/src/Batch.res.mjs +11 -9
- package/src/ChainFetcher.res +531 -0
- package/src/ChainFetcher.res.mjs +339 -0
- package/src/ChainManager.res +190 -0
- package/src/ChainManager.res.mjs +166 -0
- package/src/Change.res +3 -3
- package/src/Config.gen.ts +19 -0
- package/src/Config.res +725 -25
- package/src/Config.res.mjs +692 -26
- package/src/{Indexer.res → Ctx.res} +1 -1
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +33 -73
- package/src/Env.res.mjs +29 -85
- package/src/Envio.gen.ts +3 -1
- package/src/Envio.res +77 -9
- package/src/Envio.res.mjs +39 -1
- package/src/EventConfigBuilder.res +408 -0
- package/src/EventConfigBuilder.res.mjs +376 -0
- package/src/EventProcessing.res +469 -0
- package/src/EventProcessing.res.mjs +337 -0
- package/src/EvmTypes.gen.ts +6 -0
- package/src/EvmTypes.res +1 -0
- package/src/FetchState.res +1256 -639
- package/src/FetchState.res.mjs +1135 -612
- package/src/GlobalState.res +1224 -0
- package/src/GlobalState.res.mjs +1291 -0
- package/src/GlobalStateManager.res +68 -0
- package/src/GlobalStateManager.res.mjs +75 -0
- package/src/GlobalStateManager.resi +7 -0
- package/src/HandlerLoader.res +89 -0
- package/src/HandlerLoader.res.mjs +79 -0
- package/src/HandlerRegister.res +357 -0
- package/src/HandlerRegister.res.mjs +299 -0
- package/src/HandlerRegister.resi +30 -0
- package/src/Hasura.res +111 -175
- package/src/Hasura.res.mjs +88 -150
- package/src/InMemoryStore.res +1 -1
- package/src/InMemoryStore.res.mjs +3 -3
- package/src/InMemoryTable.res +1 -1
- package/src/InMemoryTable.res.mjs +1 -1
- package/src/Internal.gen.ts +6 -0
- package/src/Internal.res +265 -12
- package/src/Internal.res.mjs +115 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/LogSelection.res +33 -27
- package/src/LogSelection.res.mjs +6 -0
- package/src/Logging.res +21 -7
- package/src/Logging.res.mjs +16 -8
- package/src/Main.res +390 -0
- package/src/Main.res.mjs +341 -0
- package/src/Persistence.res +7 -21
- package/src/Persistence.res.mjs +3 -3
- package/src/PgStorage.gen.ts +10 -0
- package/src/PgStorage.res +116 -69
- package/src/PgStorage.res.d.mts +5 -0
- package/src/PgStorage.res.mjs +93 -50
- package/src/Prometheus.res +294 -224
- package/src/Prometheus.res.mjs +353 -340
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/SimulateItems.res +353 -0
- package/src/SimulateItems.res.mjs +335 -0
- package/src/Sink.res +4 -2
- package/src/Sink.res.mjs +2 -1
- package/src/TableIndices.res +0 -1
- package/src/TestIndexer.res +913 -0
- package/src/TestIndexer.res.mjs +698 -0
- package/src/TestIndexerProxyStorage.res +205 -0
- package/src/TestIndexerProxyStorage.res.mjs +151 -0
- package/src/TopicFilter.res +1 -1
- package/src/Types.ts +1 -1
- package/src/UserContext.res +424 -0
- package/src/UserContext.res.mjs +279 -0
- package/src/Utils.res +97 -26
- package/src/Utils.res.mjs +91 -44
- package/src/bindings/BigInt.res +10 -0
- package/src/bindings/BigInt.res.mjs +15 -0
- package/src/bindings/ClickHouse.res +120 -23
- package/src/bindings/ClickHouse.res.mjs +118 -28
- package/src/bindings/DateFns.res +74 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/bindings/EventSource.res +11 -2
- package/src/bindings/EventSource.res.mjs +8 -1
- package/src/bindings/Express.res +1 -0
- package/src/bindings/Hrtime.res +14 -1
- package/src/bindings/Hrtime.res.mjs +22 -2
- package/src/bindings/Hrtime.resi +4 -0
- package/src/bindings/Lodash.res +0 -1
- package/src/bindings/NodeJs.res +49 -3
- package/src/bindings/NodeJs.res.mjs +11 -3
- package/src/bindings/Pino.res +24 -10
- package/src/bindings/Pino.res.mjs +14 -8
- package/src/bindings/Postgres.gen.ts +8 -0
- package/src/bindings/Postgres.res +5 -1
- package/src/bindings/Postgres.res.d.mts +5 -0
- package/src/bindings/PromClient.res +0 -10
- package/src/bindings/PromClient.res.mjs +0 -3
- package/src/bindings/Vitest.res +144 -0
- package/src/bindings/Vitest.res.mjs +9 -0
- package/src/bindings/WebSocket.res +27 -0
- package/src/bindings/WebSocket.res.mjs +2 -0
- package/src/bindings/Yargs.res +8 -0
- package/src/bindings/Yargs.res.mjs +2 -0
- package/src/db/EntityHistory.res +7 -7
- package/src/db/EntityHistory.res.mjs +9 -9
- package/src/db/InternalTable.res +59 -111
- package/src/db/InternalTable.res.mjs +73 -104
- package/src/db/Table.res +27 -8
- package/src/db/Table.res.mjs +25 -14
- package/src/sources/Evm.res +84 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +94 -0
- package/src/sources/EvmChain.res.mjs +60 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +38 -0
- package/src/sources/FuelSDK.res.mjs +29 -0
- package/src/sources/HyperFuel.res +2 -2
- package/src/sources/HyperFuel.resi +1 -1
- package/src/sources/HyperFuelClient.res +2 -2
- package/src/sources/HyperFuelSource.res +35 -13
- package/src/sources/HyperFuelSource.res.mjs +26 -16
- package/src/sources/HyperSync.res +61 -60
- package/src/sources/HyperSync.res.mjs +53 -67
- package/src/sources/HyperSync.resi +6 -4
- package/src/sources/HyperSyncClient.res +29 -2
- package/src/sources/HyperSyncClient.res.mjs +9 -0
- package/src/sources/HyperSyncHeightStream.res +76 -118
- package/src/sources/HyperSyncHeightStream.res.mjs +68 -75
- package/src/sources/HyperSyncSource.res +122 -143
- package/src/sources/HyperSyncSource.res.mjs +106 -121
- package/src/sources/Rpc.res +86 -14
- package/src/sources/Rpc.res.mjs +101 -9
- package/src/sources/RpcSource.res +731 -364
- package/src/sources/RpcSource.res.mjs +845 -410
- package/src/sources/RpcWebSocketHeightStream.res +181 -0
- package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
- package/src/sources/SimulateSource.res +59 -0
- package/src/sources/SimulateSource.res.mjs +50 -0
- package/src/sources/Source.res +7 -5
- package/src/sources/SourceManager.res +358 -221
- package/src/sources/SourceManager.res.mjs +346 -171
- package/src/sources/SourceManager.resi +17 -6
- package/src/sources/Svm.res +81 -0
- package/src/sources/Svm.res.mjs +90 -0
- package/src/tui/Tui.res +247 -0
- package/src/tui/Tui.res.mjs +337 -0
- package/src/tui/bindings/Ink.res +371 -0
- package/src/tui/bindings/Ink.res.mjs +72 -0
- package/src/tui/bindings/Style.res +123 -0
- package/src/tui/bindings/Style.res.mjs +2 -0
- package/src/tui/components/BufferedProgressBar.res +40 -0
- package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
- package/src/tui/components/CustomHooks.res +122 -0
- package/src/tui/components/CustomHooks.res.mjs +179 -0
- package/src/tui/components/Messages.res +41 -0
- package/src/tui/components/Messages.res.mjs +75 -0
- package/src/tui/components/SyncETA.res +174 -0
- package/src/tui/components/SyncETA.res.mjs +263 -0
- package/src/tui/components/TuiData.res +47 -0
- package/src/tui/components/TuiData.res.mjs +34 -0
- package/svm.schema.json +112 -0
- package/bin.js +0 -48
- package/src/EventRegister.res +0 -241
- package/src/EventRegister.res.mjs +0 -240
- package/src/EventRegister.resi +0 -30
- package/src/bindings/Ethers.gen.ts +0 -14
- package/src/bindings/Ethers.res +0 -204
- package/src/bindings/Ethers.res.mjs +0 -130
- /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
|
@@ -10,6 +10,7 @@ import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
|
|
|
10
10
|
import * as FetchState from "../FetchState.res.mjs";
|
|
11
11
|
import * as Prometheus from "../Prometheus.res.mjs";
|
|
12
12
|
import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
|
|
13
|
+
import * as Caml_option from "rescript/lib/es6/caml_option.js";
|
|
13
14
|
import * as ErrorHandling from "../ErrorHandling.res.mjs";
|
|
14
15
|
import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";
|
|
15
16
|
|
|
@@ -17,6 +18,34 @@ function getActiveSource(sourceManager) {
|
|
|
17
18
|
return sourceManager.activeSource;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
function getSourceRole(sourceFor, isLive, hasLive) {
|
|
22
|
+
if (isLive) {
|
|
23
|
+
switch (sourceFor) {
|
|
24
|
+
case "Sync" :
|
|
25
|
+
if (hasLive) {
|
|
26
|
+
return "Secondary";
|
|
27
|
+
} else {
|
|
28
|
+
return "Primary";
|
|
29
|
+
}
|
|
30
|
+
case "Fallback" :
|
|
31
|
+
return "Secondary";
|
|
32
|
+
case "Live" :
|
|
33
|
+
return "Primary";
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
switch (sourceFor) {
|
|
38
|
+
case "Sync" :
|
|
39
|
+
return "Primary";
|
|
40
|
+
case "Fallback" :
|
|
41
|
+
return "Secondary";
|
|
42
|
+
case "Live" :
|
|
43
|
+
return ;
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
20
49
|
function makeGetHeightRetryInterval(initialRetryInterval, backoffMultiplicative, maxRetryInterval) {
|
|
21
50
|
return function (retry) {
|
|
22
51
|
var backoff = retry === 0 ? 1 : Math.imul(retry, backoffMultiplicative);
|
|
@@ -24,27 +53,44 @@ function makeGetHeightRetryInterval(initialRetryInterval, backoffMultiplicative,
|
|
|
24
53
|
};
|
|
25
54
|
}
|
|
26
55
|
|
|
27
|
-
function make(sources, maxPartitionConcurrency,
|
|
28
|
-
var
|
|
56
|
+
function make(sources, maxPartitionConcurrency, isLive, newBlockStallTimeoutOpt, newBlockStallTimeoutLiveOpt, stalledPollingIntervalOpt, recoveryTimeoutOpt, getHeightRetryIntervalOpt) {
|
|
57
|
+
var newBlockStallTimeout = newBlockStallTimeoutOpt !== undefined ? newBlockStallTimeoutOpt : 60000;
|
|
58
|
+
var newBlockStallTimeoutLive = newBlockStallTimeoutLiveOpt !== undefined ? newBlockStallTimeoutLiveOpt : 20000;
|
|
29
59
|
var stalledPollingInterval = stalledPollingIntervalOpt !== undefined ? stalledPollingIntervalOpt : 5000;
|
|
60
|
+
var recoveryTimeout = recoveryTimeoutOpt !== undefined ? recoveryTimeoutOpt : 60000.0;
|
|
30
61
|
var getHeightRetryInterval = getHeightRetryIntervalOpt !== undefined ? getHeightRetryIntervalOpt : makeGetHeightRetryInterval(1000, 2, 60000);
|
|
62
|
+
var hasLive = sources.some(function (s) {
|
|
63
|
+
return s.sourceFor === "Live";
|
|
64
|
+
});
|
|
31
65
|
var source = sources.find(function (source) {
|
|
32
|
-
return source.sourceFor === "
|
|
66
|
+
return getSourceRole(source.sourceFor, isLive, hasLive) === "Primary";
|
|
33
67
|
});
|
|
34
68
|
var initialActiveSource = source !== undefined ? source : Js_exn.raiseError("Invalid configuration, no data-source for historical sync provided");
|
|
35
69
|
Prometheus.IndexingMaxConcurrency.set(maxPartitionConcurrency, initialActiveSource.chain);
|
|
36
70
|
Prometheus.IndexingConcurrency.set(0, initialActiveSource.chain);
|
|
37
71
|
return {
|
|
38
|
-
|
|
72
|
+
sourcesState: Belt_Array.map(sources, (function (source) {
|
|
73
|
+
return {
|
|
74
|
+
source: source,
|
|
75
|
+
knownHeight: 0,
|
|
76
|
+
unsubscribe: undefined,
|
|
77
|
+
pendingHeightResolvers: [],
|
|
78
|
+
disabled: false,
|
|
79
|
+
lastFailedAt: undefined
|
|
80
|
+
};
|
|
81
|
+
})),
|
|
39
82
|
statusStart: Hrtime.makeTimer(),
|
|
40
83
|
status: "Idle",
|
|
41
84
|
maxPartitionConcurrency: maxPartitionConcurrency,
|
|
42
|
-
|
|
85
|
+
newBlockStallTimeout: newBlockStallTimeout,
|
|
86
|
+
newBlockStallTimeoutLive: newBlockStallTimeoutLive,
|
|
43
87
|
stalledPollingInterval: stalledPollingInterval,
|
|
44
88
|
getHeightRetryInterval: getHeightRetryInterval,
|
|
45
89
|
activeSource: initialActiveSource,
|
|
46
90
|
waitingForNewBlockStateId: undefined,
|
|
47
|
-
fetchingPartitionsCount: 0
|
|
91
|
+
fetchingPartitionsCount: 0,
|
|
92
|
+
recoveryTimeout: recoveryTimeout,
|
|
93
|
+
hasLive: hasLive
|
|
48
94
|
};
|
|
49
95
|
}
|
|
50
96
|
|
|
@@ -63,15 +109,15 @@ function trackNewStatus(sourceManager, newStatus) {
|
|
|
63
109
|
break;
|
|
64
110
|
|
|
65
111
|
}
|
|
66
|
-
Prometheus.SafeCounter.
|
|
112
|
+
Prometheus.SafeCounter.handleFloat(promCounter, sourceManager.activeSource.chain, Hrtime.toSecondsFloat(Hrtime.timeSince(sourceManager.statusStart)));
|
|
67
113
|
sourceManager.statusStart = Hrtime.makeTimer();
|
|
68
114
|
sourceManager.status = newStatus;
|
|
69
115
|
}
|
|
70
116
|
|
|
71
|
-
async function fetchNext(sourceManager, fetchState,
|
|
72
|
-
var
|
|
73
|
-
if (typeof
|
|
74
|
-
switch (
|
|
117
|
+
async function fetchNext(sourceManager, fetchState, executeQuery, waitForNewBlock, onNewBlock, stateId) {
|
|
118
|
+
var nextQuery = FetchState.getNextQuery(fetchState, sourceManager.maxPartitionConcurrency - sourceManager.fetchingPartitionsCount | 0);
|
|
119
|
+
if (typeof nextQuery !== "object") {
|
|
120
|
+
switch (nextQuery) {
|
|
75
121
|
case "WaitingForNewBlock" :
|
|
76
122
|
var waitingStateId = sourceManager.waitingForNewBlockStateId;
|
|
77
123
|
if (waitingStateId !== undefined && waitingStateId >= stateId) {
|
|
@@ -79,12 +125,12 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
79
125
|
}
|
|
80
126
|
trackNewStatus(sourceManager, "WaitingForNewBlock");
|
|
81
127
|
sourceManager.waitingForNewBlockStateId = stateId;
|
|
82
|
-
var
|
|
128
|
+
var knownHeight = await waitForNewBlock(fetchState.knownHeight);
|
|
83
129
|
var waitingStateId$1 = sourceManager.waitingForNewBlockStateId;
|
|
84
130
|
if (waitingStateId$1 !== undefined && waitingStateId$1 === stateId) {
|
|
85
131
|
trackNewStatus(sourceManager, "Idle");
|
|
86
132
|
sourceManager.waitingForNewBlockStateId = undefined;
|
|
87
|
-
return onNewBlock(
|
|
133
|
+
return onNewBlock(knownHeight);
|
|
88
134
|
} else {
|
|
89
135
|
return ;
|
|
90
136
|
}
|
|
@@ -94,12 +140,12 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
94
140
|
|
|
95
141
|
}
|
|
96
142
|
} else {
|
|
97
|
-
var queries
|
|
98
|
-
FetchState.startFetchingQueries(fetchState, queries
|
|
99
|
-
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries
|
|
143
|
+
var queries = nextQuery._0;
|
|
144
|
+
FetchState.startFetchingQueries(fetchState, queries);
|
|
145
|
+
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries.length | 0;
|
|
100
146
|
Prometheus.IndexingConcurrency.set(sourceManager.fetchingPartitionsCount, sourceManager.activeSource.chain);
|
|
101
147
|
trackNewStatus(sourceManager, "Querieng");
|
|
102
|
-
await Promise.all(Belt_Array.map(queries
|
|
148
|
+
await Promise.all(Belt_Array.map(queries, (function (q) {
|
|
103
149
|
var promise = executeQuery(q);
|
|
104
150
|
promise.then(function (param) {
|
|
105
151
|
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount - 1 | 0;
|
|
@@ -115,78 +161,241 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
115
161
|
}
|
|
116
162
|
}
|
|
117
163
|
|
|
118
|
-
|
|
119
|
-
|
|
164
|
+
function disableSource(sourceManager, sourceState) {
|
|
165
|
+
if (sourceState.disabled) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
sourceState.disabled = true;
|
|
169
|
+
var unsubscribe = sourceState.unsubscribe;
|
|
170
|
+
if (unsubscribe !== undefined) {
|
|
171
|
+
unsubscribe();
|
|
172
|
+
}
|
|
173
|
+
if (sourceState.source.sourceFor === "Live") {
|
|
174
|
+
var hasOtherLive = sourceManager.sourcesState.some(function (s) {
|
|
175
|
+
if (s !== sourceState && !s.disabled) {
|
|
176
|
+
return s.source.sourceFor === "Live";
|
|
177
|
+
} else {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
sourceManager.hasLive = hasOtherLive;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function getSourceNewHeight(sourceManager, sourceState, knownHeight, stallTimeout, isLive, status, logger) {
|
|
187
|
+
var source = sourceState.source;
|
|
188
|
+
var initialHeight = sourceState.knownHeight;
|
|
189
|
+
var newHeight = {
|
|
190
|
+
contents: initialHeight
|
|
191
|
+
};
|
|
120
192
|
var retry = 0;
|
|
121
|
-
while(newHeight <=
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
193
|
+
while(newHeight.contents <= knownHeight && status.contents !== "Done") {
|
|
194
|
+
var match = sourceState.unsubscribe;
|
|
195
|
+
if (match !== undefined) {
|
|
196
|
+
var subscriptionPromise = new Promise((function (resolve, _reject) {
|
|
197
|
+
sourceState.pendingHeightResolvers.push(resolve);
|
|
198
|
+
}));
|
|
199
|
+
var pollingFallback = Utils.delay(stallTimeout / 2 | 0).then(async function () {
|
|
200
|
+
Logging.childTrace(logger, {
|
|
201
|
+
msg: "onHeight subscription stale, switching to polling fallback",
|
|
202
|
+
source: source.name,
|
|
203
|
+
chainId: source.chain
|
|
204
|
+
});
|
|
205
|
+
var h = initialHeight;
|
|
206
|
+
while(h <= knownHeight && newHeight.contents <= initialHeight) {
|
|
207
|
+
try {
|
|
208
|
+
h = await source.getHeightOrThrow();
|
|
209
|
+
}
|
|
210
|
+
catch (exn){
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
if (h <= knownHeight && newHeight.contents <= initialHeight) {
|
|
214
|
+
await Utils.delay(source.pollingInterval);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
};
|
|
218
|
+
return h;
|
|
126
219
|
});
|
|
127
|
-
var height = await
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
await Utils.delay(pollingInterval);
|
|
220
|
+
var height = await Promise.race([
|
|
221
|
+
subscriptionPromise,
|
|
222
|
+
pollingFallback
|
|
223
|
+
]);
|
|
224
|
+
if (height > initialHeight) {
|
|
225
|
+
newHeight.contents = height;
|
|
134
226
|
}
|
|
135
227
|
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
228
|
+
} else {
|
|
229
|
+
try {
|
|
230
|
+
var height$1 = await source.getHeightOrThrow();
|
|
231
|
+
newHeight.contents = height$1;
|
|
232
|
+
if (height$1 <= knownHeight) {
|
|
233
|
+
retry = 0;
|
|
234
|
+
var createSubscription = source.createHeightSubscription;
|
|
235
|
+
var exit = 0;
|
|
236
|
+
if (createSubscription !== undefined && isLive) {
|
|
237
|
+
var unsubscribe = createSubscription(function (newHeight) {
|
|
238
|
+
sourceState.knownHeight = newHeight;
|
|
239
|
+
var resolvers = sourceState.pendingHeightResolvers;
|
|
240
|
+
sourceState.pendingHeightResolvers = [];
|
|
241
|
+
Belt_Array.forEach(resolvers, (function (resolve) {
|
|
242
|
+
resolve(newHeight);
|
|
243
|
+
}));
|
|
244
|
+
});
|
|
245
|
+
sourceState.unsubscribe = unsubscribe;
|
|
246
|
+
} else {
|
|
247
|
+
exit = 1;
|
|
248
|
+
}
|
|
249
|
+
if (exit === 1) {
|
|
250
|
+
var pollingInterval = status.contents === "Stalled" ? sourceManager.stalledPollingInterval : source.pollingInterval;
|
|
251
|
+
await Utils.delay(pollingInterval);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
}
|
|
257
|
+
catch (raw_exn){
|
|
258
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
259
|
+
var retryInterval = sourceManager.getHeightRetryInterval(retry);
|
|
260
|
+
Logging.childTrace(logger, {
|
|
261
|
+
msg: "Height retrieval from " + source.name + " source failed. Retrying in " + String(retryInterval) + "ms.",
|
|
262
|
+
source: source.name,
|
|
263
|
+
err: Utils.prettifyExn(exn)
|
|
264
|
+
});
|
|
265
|
+
retry = retry + 1 | 0;
|
|
266
|
+
await Utils.delay(retryInterval);
|
|
267
|
+
}
|
|
147
268
|
}
|
|
148
269
|
};
|
|
149
|
-
|
|
150
|
-
|
|
270
|
+
if (newHeight.contents > initialHeight) {
|
|
271
|
+
Prometheus.SourceHeight.set(source.name, source.chain, newHeight.contents);
|
|
272
|
+
}
|
|
273
|
+
return newHeight.contents;
|
|
151
274
|
}
|
|
152
275
|
|
|
153
|
-
|
|
276
|
+
function compareByOldestFailure(a, b) {
|
|
277
|
+
var match = a.lastFailedAt;
|
|
278
|
+
var match$1 = b.lastFailedAt;
|
|
279
|
+
if (match !== undefined) {
|
|
280
|
+
if (match$1 !== undefined) {
|
|
281
|
+
if (match < match$1) {
|
|
282
|
+
return -1;
|
|
283
|
+
} else if (match > match$1) {
|
|
284
|
+
return 1;
|
|
285
|
+
} else {
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
return 1;
|
|
290
|
+
}
|
|
291
|
+
} else if (match$1 !== undefined) {
|
|
292
|
+
return -1;
|
|
293
|
+
} else {
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function getNextSources(sourceManager, isLive, excludedSources) {
|
|
299
|
+
var now = Date.now();
|
|
300
|
+
var workingPrimarySources = [];
|
|
301
|
+
var allPrimarySources = [];
|
|
302
|
+
var workingSecondarySources = [];
|
|
303
|
+
for(var i = 0 ,i_finish = sourceManager.sourcesState.length; i < i_finish; ++i){
|
|
304
|
+
var sourceState = sourceManager.sourcesState[i];
|
|
305
|
+
if (!sourceState.disabled) {
|
|
306
|
+
var isExcluded = excludedSources !== undefined ? Caml_option.valFromOption(excludedSources).has(sourceState) : false;
|
|
307
|
+
if (!isExcluded) {
|
|
308
|
+
var failedAt = sourceState.lastFailedAt;
|
|
309
|
+
var isWorking = failedAt !== undefined ? now - failedAt >= sourceManager.recoveryTimeout : true;
|
|
310
|
+
var match = getSourceRole(sourceState.source.sourceFor, isLive, sourceManager.hasLive);
|
|
311
|
+
if (match !== undefined) {
|
|
312
|
+
if (match === "Primary") {
|
|
313
|
+
allPrimarySources.push(sourceState);
|
|
314
|
+
if (isWorking) {
|
|
315
|
+
workingPrimarySources.push(sourceState);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
} else if (isWorking) {
|
|
319
|
+
workingSecondarySources.push(sourceState);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
}
|
|
329
|
+
if (workingPrimarySources.length !== 0) {
|
|
330
|
+
return workingPrimarySources;
|
|
331
|
+
} else if (workingSecondarySources.length !== 0) {
|
|
332
|
+
return workingSecondarySources;
|
|
333
|
+
} else {
|
|
334
|
+
return allPrimarySources.sort(compareByOldestFailure);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function getNextSource(sourceManager, isLive, excludedSources) {
|
|
339
|
+
var sources = getNextSources(sourceManager, isLive, excludedSources);
|
|
340
|
+
var first = Belt_Array.get(sources, 0);
|
|
341
|
+
if (first === undefined) {
|
|
342
|
+
return ;
|
|
343
|
+
}
|
|
344
|
+
if (first.source === sourceManager.activeSource) {
|
|
345
|
+
return first;
|
|
346
|
+
}
|
|
347
|
+
var result = sources.find(function (s) {
|
|
348
|
+
return s.source === sourceManager.activeSource;
|
|
349
|
+
});
|
|
350
|
+
if (result !== undefined) {
|
|
351
|
+
if (result === undefined) {
|
|
352
|
+
return ;
|
|
353
|
+
} else {
|
|
354
|
+
return Caml_option.some(result);
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
return Belt_Array.get(sources, 0);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async function waitForNewBlock(sourceManager, knownHeight, isLive) {
|
|
362
|
+
var sourcesState = sourceManager.sourcesState;
|
|
154
363
|
var logger = Logging.createChild({
|
|
155
364
|
chainId: sourceManager.activeSource.chain,
|
|
156
|
-
|
|
365
|
+
knownHeight: knownHeight
|
|
157
366
|
});
|
|
158
367
|
Logging.childTrace(logger, "Initiating check for new blocks.");
|
|
159
|
-
var
|
|
160
|
-
var syncSources = [];
|
|
161
|
-
var fallbackSources = [];
|
|
162
|
-
sourceManager.sources.forEach(function (source) {
|
|
163
|
-
if (source.sourceFor === "Sync" || source.sourceFor === "Live" && !isInitialHeightFetch || source === sourceManager.activeSource) {
|
|
164
|
-
syncSources.push(source);
|
|
165
|
-
} else {
|
|
166
|
-
fallbackSources.push(source);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
368
|
+
var mainSources = getNextSources(sourceManager, isLive, undefined);
|
|
169
369
|
var status = {
|
|
170
370
|
contents: "Active"
|
|
171
371
|
};
|
|
172
|
-
var
|
|
372
|
+
var stallTimeout = isLive ? sourceManager.newBlockStallTimeoutLive : sourceManager.newBlockStallTimeout;
|
|
373
|
+
var match = await Promise.race(Belt_Array.concat(Belt_Array.map(mainSources, (async function (sourceState) {
|
|
173
374
|
return [
|
|
174
|
-
source,
|
|
175
|
-
await getSourceNewHeight(sourceManager,
|
|
375
|
+
sourceState.source,
|
|
376
|
+
await getSourceNewHeight(sourceManager, sourceState, knownHeight, stallTimeout, isLive, status, logger)
|
|
176
377
|
];
|
|
177
|
-
})), [Utils.delay(
|
|
378
|
+
})), [Utils.delay(stallTimeout).then(function () {
|
|
379
|
+
var fallbackSources = [];
|
|
380
|
+
Belt_Array.forEach(sourcesState, (function (sourceState) {
|
|
381
|
+
if (!mainSources.includes(sourceState) && Belt_Option.isSome(getSourceRole(sourceState.source.sourceFor, isLive, sourceManager.hasLive))) {
|
|
382
|
+
fallbackSources.push(sourceState);
|
|
383
|
+
return ;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
}));
|
|
178
387
|
if (status.contents !== "Done") {
|
|
179
388
|
status.contents = "Stalled";
|
|
180
389
|
if (fallbackSources.length !== 0) {
|
|
181
|
-
Logging.childWarn(logger, "No new blocks detected within " + String(
|
|
390
|
+
Logging.childWarn(logger, "No new blocks detected within " + String(stallTimeout / 1000 | 0) + "s. Continuing polling with secondary RPC sources from the configuration.");
|
|
182
391
|
} else {
|
|
183
|
-
Logging.childWarn(logger, "No new blocks detected within " + String(
|
|
392
|
+
Logging.childWarn(logger, "No new blocks detected within " + String(stallTimeout / 1000 | 0) + "s. Polling will continue at a reduced rate. For better reliability, refer to our RPC fallback guide: https://docs.envio.dev/docs/HyperIndex/rpc-sync");
|
|
184
393
|
}
|
|
185
394
|
}
|
|
186
|
-
return Promise.race(Belt_Array.map(fallbackSources, (async function (
|
|
395
|
+
return Promise.race(Belt_Array.map(fallbackSources, (async function (sourceState) {
|
|
187
396
|
return [
|
|
188
|
-
source,
|
|
189
|
-
await getSourceNewHeight(sourceManager,
|
|
397
|
+
sourceState.source,
|
|
398
|
+
await getSourceNewHeight(sourceManager, sourceState, knownHeight, stallTimeout, isLive, status, logger)
|
|
190
399
|
];
|
|
191
400
|
})));
|
|
192
401
|
})]));
|
|
@@ -203,66 +412,38 @@ async function waitForNewBlock(sourceManager, currentBlockHeight) {
|
|
|
203
412
|
return newBlockHeight;
|
|
204
413
|
}
|
|
205
414
|
|
|
206
|
-
function
|
|
207
|
-
var
|
|
208
|
-
var
|
|
209
|
-
var after = [];
|
|
210
|
-
var hasActive = {
|
|
211
|
-
contents: false
|
|
212
|
-
};
|
|
213
|
-
sourceManager.sources.forEach(function (source) {
|
|
214
|
-
if (source === currentSource) {
|
|
215
|
-
hasActive.contents = true;
|
|
216
|
-
return ;
|
|
217
|
-
}
|
|
218
|
-
var match = source.sourceFor;
|
|
219
|
-
var tmp;
|
|
220
|
-
switch (match) {
|
|
221
|
-
case "Sync" :
|
|
222
|
-
tmp = true;
|
|
223
|
-
break;
|
|
224
|
-
case "Fallback" :
|
|
225
|
-
case "Live" :
|
|
226
|
-
tmp = attemptFallbacks || source === initialSource;
|
|
227
|
-
break;
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
if (tmp) {
|
|
231
|
-
(
|
|
232
|
-
hasActive.contents ? after : before
|
|
233
|
-
).push(source);
|
|
234
|
-
return ;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
});
|
|
238
|
-
var s = Belt_Array.get(after, 0);
|
|
239
|
-
if (s !== undefined) {
|
|
240
|
-
return s;
|
|
241
|
-
}
|
|
242
|
-
var s$1 = Belt_Array.get(before, 0);
|
|
243
|
-
if (s$1 !== undefined) {
|
|
244
|
-
return s$1;
|
|
245
|
-
} else {
|
|
246
|
-
return currentSource;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
251
|
-
var match = query.target;
|
|
252
|
-
var toBlockRef;
|
|
253
|
-
toBlockRef = typeof match !== "object" ? undefined : (
|
|
254
|
-
match.TAG === "EndBlock" ? match.toBlock : match.toBlock
|
|
255
|
-
);
|
|
415
|
+
async function executeQuery(sourceManager, query, knownHeight, isLive) {
|
|
416
|
+
var excludedSourcesRef;
|
|
417
|
+
var toBlockRef = query.toBlock;
|
|
256
418
|
var responseRef;
|
|
257
419
|
var retryRef = 0;
|
|
258
|
-
var initialSource = sourceManager.activeSource;
|
|
259
|
-
var sourceRef = initialSource;
|
|
260
|
-
var shouldUpdateActiveSource = false;
|
|
261
420
|
while(Belt_Option.isNone(responseRef)) {
|
|
262
|
-
var
|
|
421
|
+
var s = getNextSource(sourceManager, isLive, excludedSourcesRef);
|
|
422
|
+
var sourceState;
|
|
423
|
+
if (s !== undefined) {
|
|
424
|
+
if (s.source !== sourceManager.activeSource) {
|
|
425
|
+
var logger = Logging.createChild({
|
|
426
|
+
chainId: sourceManager.activeSource.chain
|
|
427
|
+
});
|
|
428
|
+
Logging.childInfo(logger, {
|
|
429
|
+
msg: "Switching data-source",
|
|
430
|
+
source: s.source.name,
|
|
431
|
+
previousSource: sourceManager.activeSource.name,
|
|
432
|
+
fromBlock: query.fromBlock
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
sourceState = s;
|
|
436
|
+
} else {
|
|
437
|
+
var logger$1 = Logging.createChild({
|
|
438
|
+
chainId: sourceManager.activeSource.chain
|
|
439
|
+
});
|
|
440
|
+
sourceState = ErrorHandling.mkLogAndRaise(logger$1, "The indexer doesn't have data-sources which can continue fetching. Please, check the error logs or reach out to the Envio team.", null);
|
|
441
|
+
}
|
|
442
|
+
sourceManager.activeSource = sourceState.source;
|
|
443
|
+
var source = sourceState.source;
|
|
263
444
|
var toBlock = toBlockRef;
|
|
264
445
|
var retry = retryRef;
|
|
265
|
-
var logger = Logging.createChild({
|
|
446
|
+
var logger$2 = Logging.createChild({
|
|
266
447
|
chainId: source.chain,
|
|
267
448
|
logType: "Block Range Query",
|
|
268
449
|
partitionId: query.partitionId,
|
|
@@ -273,13 +454,14 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
273
454
|
retry: retry
|
|
274
455
|
});
|
|
275
456
|
try {
|
|
276
|
-
var response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addressesByContractName, query.indexingContracts,
|
|
277
|
-
Logging.childTrace(logger, {
|
|
457
|
+
var response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addressesByContractName, query.indexingContracts, knownHeight, query.partitionId, query.selection, retry, logger$2);
|
|
458
|
+
Logging.childTrace(logger$2, {
|
|
278
459
|
msg: "Fetched block range from server",
|
|
279
460
|
toBlock: response.latestFetchedBlockNumber,
|
|
280
461
|
numEvents: response.parsedQueueItems.length,
|
|
281
462
|
stats: response.stats
|
|
282
463
|
});
|
|
464
|
+
sourceState.lastFailedAt = undefined;
|
|
283
465
|
responseRef = response;
|
|
284
466
|
}
|
|
285
467
|
catch (raw_error){
|
|
@@ -293,13 +475,13 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
293
475
|
exit = 1;
|
|
294
476
|
break;
|
|
295
477
|
case "FailedGettingItems" :
|
|
296
|
-
var match
|
|
478
|
+
var match = error$1.retry;
|
|
297
479
|
var attemptedToBlock = error$1.attemptedToBlock;
|
|
298
480
|
var exn = error$1.exn;
|
|
299
|
-
switch (match
|
|
481
|
+
switch (match.TAG) {
|
|
300
482
|
case "WithSuggestedToBlock" :
|
|
301
|
-
var toBlock$1 = match
|
|
302
|
-
Logging.childTrace(logger, {
|
|
483
|
+
var toBlock$1 = match.toBlock;
|
|
484
|
+
Logging.childTrace(logger$2, {
|
|
303
485
|
msg: "Failed getting data for the block range. Immediately retrying with the suggested block range from response.",
|
|
304
486
|
toBlock: attemptedToBlock,
|
|
305
487
|
suggestedToBlock: toBlock$1
|
|
@@ -308,47 +490,53 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
308
490
|
retryRef = 0;
|
|
309
491
|
break;
|
|
310
492
|
case "WithBackoff" :
|
|
311
|
-
var backoffMillis = match
|
|
312
|
-
var attemptFallbacks = retry >= 10;
|
|
313
|
-
var nextSource = !(retry === 0 || retry === 1) && retry % 2 === 0 ? getNextSyncSource(sourceManager, initialSource, source, attemptFallbacks) : source;
|
|
493
|
+
var backoffMillis = match.backoffMillis;
|
|
314
494
|
var log = retry >= 4 ? Logging.childWarn : Logging.childTrace;
|
|
315
|
-
log(logger, {
|
|
316
|
-
msg: match
|
|
495
|
+
log(logger$2, {
|
|
496
|
+
msg: match.message,
|
|
317
497
|
toBlock: attemptedToBlock,
|
|
318
498
|
backOffMilliseconds: backoffMillis,
|
|
319
499
|
retry: retry,
|
|
320
500
|
err: Utils.prettifyExn(exn)
|
|
321
501
|
});
|
|
322
|
-
var shouldSwitch =
|
|
502
|
+
var shouldSwitch = retry === 0 || retry === 1 ? false : retry % 2 === 0;
|
|
323
503
|
if (shouldSwitch) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
504
|
+
var now = Date.now();
|
|
505
|
+
sourceState.lastFailedAt = now;
|
|
506
|
+
var nextSource = getNextSource(sourceManager, isLive, excludedSourcesRef);
|
|
507
|
+
var hasWorkingAlternative;
|
|
508
|
+
if (nextSource !== undefined) {
|
|
509
|
+
var failedAt = nextSource.lastFailedAt;
|
|
510
|
+
hasWorkingAlternative = failedAt !== undefined ? now - failedAt >= sourceManager.recoveryTimeout : true;
|
|
511
|
+
} else {
|
|
512
|
+
hasWorkingAlternative = false;
|
|
513
|
+
}
|
|
514
|
+
if (!hasWorkingAlternative) {
|
|
515
|
+
await Utils.delay(backoffMillis < 60000 ? backoffMillis : 60000);
|
|
516
|
+
}
|
|
517
|
+
|
|
330
518
|
} else {
|
|
331
519
|
await Utils.delay(backoffMillis < 60000 ? backoffMillis : 60000);
|
|
332
520
|
}
|
|
333
521
|
retryRef = retryRef + 1 | 0;
|
|
334
522
|
break;
|
|
335
523
|
case "ImpossibleForTheQuery" :
|
|
336
|
-
var
|
|
337
|
-
var
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
524
|
+
var s$1 = excludedSourcesRef;
|
|
525
|
+
var excludedSources;
|
|
526
|
+
if (s$1 !== undefined) {
|
|
527
|
+
excludedSources = Caml_option.valFromOption(s$1);
|
|
528
|
+
} else {
|
|
529
|
+
var s$2 = new Set();
|
|
530
|
+
excludedSourcesRef = Caml_option.some(s$2);
|
|
531
|
+
excludedSources = s$2;
|
|
532
|
+
}
|
|
533
|
+
excludedSources.add(sourceState);
|
|
534
|
+
Logging.childWarn(logger$2, {
|
|
535
|
+
msg: match.message + " - Attempting another source",
|
|
342
536
|
toBlock: attemptedToBlock,
|
|
343
537
|
err: Utils.prettifyExn(exn)
|
|
344
538
|
});
|
|
345
|
-
|
|
346
|
-
sourceRef = nextSource$1;
|
|
347
|
-
shouldUpdateActiveSource = false;
|
|
348
|
-
retryRef = 0;
|
|
349
|
-
} else {
|
|
350
|
-
ErrorHandling.mkLogAndRaise(logger, "The indexer doesn't have data-sources which can continue fetching. Please, check the error logs or reach out to the Envio team.", null);
|
|
351
|
-
}
|
|
539
|
+
retryRef = 0;
|
|
352
540
|
break;
|
|
353
541
|
|
|
354
542
|
}
|
|
@@ -356,15 +544,14 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
356
544
|
|
|
357
545
|
}
|
|
358
546
|
if (exit === 1) {
|
|
359
|
-
var
|
|
360
|
-
|
|
361
|
-
if (notAlreadyDeleted) {
|
|
547
|
+
var notAlreadyDisabled = disableSource(sourceManager, sourceState);
|
|
548
|
+
if (notAlreadyDisabled) {
|
|
362
549
|
switch (error$1.TAG) {
|
|
363
550
|
case "UnsupportedSelection" :
|
|
364
|
-
Logging.childError(logger, error$1.message);
|
|
551
|
+
Logging.childError(logger$2, error$1.message);
|
|
365
552
|
break;
|
|
366
553
|
case "FailedGettingFieldSelection" :
|
|
367
|
-
Logging.childError(logger, {
|
|
554
|
+
Logging.childError(logger$2, {
|
|
368
555
|
msg: error$1.message,
|
|
369
556
|
err: Utils.prettifyExn(error$1.exn),
|
|
370
557
|
blockNumber: error$1.blockNumber,
|
|
@@ -376,31 +563,19 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
376
563
|
|
|
377
564
|
}
|
|
378
565
|
}
|
|
379
|
-
|
|
380
|
-
ErrorHandling.mkLogAndRaise(logger, "The indexer doesn't have data-sources which can continue fetching. Please, check the error logs or reach out to the Envio team.", null);
|
|
381
|
-
} else {
|
|
382
|
-
Logging.childInfo(logger, {
|
|
383
|
-
msg: "Switching to another data-source",
|
|
384
|
-
source: nextSource$2.name
|
|
385
|
-
});
|
|
386
|
-
sourceRef = nextSource$2;
|
|
387
|
-
shouldUpdateActiveSource = true;
|
|
388
|
-
retryRef = 0;
|
|
389
|
-
}
|
|
566
|
+
retryRef = 0;
|
|
390
567
|
}
|
|
391
568
|
|
|
392
569
|
} else {
|
|
393
|
-
ErrorHandling.mkLogAndRaise(logger, "Failed to fetch block Range", error);
|
|
570
|
+
ErrorHandling.mkLogAndRaise(logger$2, "Failed to fetch block Range", error);
|
|
394
571
|
}
|
|
395
572
|
}
|
|
396
573
|
};
|
|
397
|
-
if (shouldUpdateActiveSource) {
|
|
398
|
-
sourceManager.activeSource = sourceRef;
|
|
399
|
-
}
|
|
400
574
|
return responseRef;
|
|
401
575
|
}
|
|
402
576
|
|
|
403
577
|
export {
|
|
578
|
+
getSourceRole ,
|
|
404
579
|
make ,
|
|
405
580
|
getActiveSource ,
|
|
406
581
|
fetchNext ,
|