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.
Files changed (184) hide show
  1. package/README.md +164 -30
  2. package/bin.mjs +49 -0
  3. package/evm.schema.json +79 -169
  4. package/fuel.schema.json +50 -21
  5. package/index.d.ts +578 -1
  6. package/index.js +4 -0
  7. package/package.json +47 -31
  8. package/rescript.json +4 -1
  9. package/src/Batch.res +11 -8
  10. package/src/Batch.res.mjs +11 -9
  11. package/src/ChainFetcher.res +531 -0
  12. package/src/ChainFetcher.res.mjs +339 -0
  13. package/src/ChainManager.res +190 -0
  14. package/src/ChainManager.res.mjs +166 -0
  15. package/src/Change.res +3 -3
  16. package/src/Config.gen.ts +19 -0
  17. package/src/Config.res +725 -25
  18. package/src/Config.res.mjs +692 -26
  19. package/src/{Indexer.res → Ctx.res} +1 -1
  20. package/src/Ecosystem.res +9 -124
  21. package/src/Ecosystem.res.mjs +19 -160
  22. package/src/Env.res +33 -73
  23. package/src/Env.res.mjs +29 -85
  24. package/src/Envio.gen.ts +3 -1
  25. package/src/Envio.res +77 -9
  26. package/src/Envio.res.mjs +39 -1
  27. package/src/EventConfigBuilder.res +408 -0
  28. package/src/EventConfigBuilder.res.mjs +376 -0
  29. package/src/EventProcessing.res +469 -0
  30. package/src/EventProcessing.res.mjs +337 -0
  31. package/src/EvmTypes.gen.ts +6 -0
  32. package/src/EvmTypes.res +1 -0
  33. package/src/FetchState.res +1256 -639
  34. package/src/FetchState.res.mjs +1135 -612
  35. package/src/GlobalState.res +1224 -0
  36. package/src/GlobalState.res.mjs +1291 -0
  37. package/src/GlobalStateManager.res +68 -0
  38. package/src/GlobalStateManager.res.mjs +75 -0
  39. package/src/GlobalStateManager.resi +7 -0
  40. package/src/HandlerLoader.res +89 -0
  41. package/src/HandlerLoader.res.mjs +79 -0
  42. package/src/HandlerRegister.res +357 -0
  43. package/src/HandlerRegister.res.mjs +299 -0
  44. package/src/HandlerRegister.resi +30 -0
  45. package/src/Hasura.res +111 -175
  46. package/src/Hasura.res.mjs +88 -150
  47. package/src/InMemoryStore.res +1 -1
  48. package/src/InMemoryStore.res.mjs +3 -3
  49. package/src/InMemoryTable.res +1 -1
  50. package/src/InMemoryTable.res.mjs +1 -1
  51. package/src/Internal.gen.ts +6 -0
  52. package/src/Internal.res +265 -12
  53. package/src/Internal.res.mjs +115 -1
  54. package/src/LoadLayer.res +444 -0
  55. package/src/LoadLayer.res.mjs +296 -0
  56. package/src/LoadLayer.resi +32 -0
  57. package/src/LogSelection.res +33 -27
  58. package/src/LogSelection.res.mjs +6 -0
  59. package/src/Logging.res +21 -7
  60. package/src/Logging.res.mjs +16 -8
  61. package/src/Main.res +390 -0
  62. package/src/Main.res.mjs +341 -0
  63. package/src/Persistence.res +7 -21
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PgStorage.gen.ts +10 -0
  66. package/src/PgStorage.res +116 -69
  67. package/src/PgStorage.res.d.mts +5 -0
  68. package/src/PgStorage.res.mjs +93 -50
  69. package/src/Prometheus.res +294 -224
  70. package/src/Prometheus.res.mjs +353 -340
  71. package/src/ReorgDetection.res +6 -10
  72. package/src/ReorgDetection.res.mjs +6 -6
  73. package/src/SafeCheckpointTracking.res +4 -4
  74. package/src/SafeCheckpointTracking.res.mjs +2 -2
  75. package/src/SimulateItems.res +353 -0
  76. package/src/SimulateItems.res.mjs +335 -0
  77. package/src/Sink.res +4 -2
  78. package/src/Sink.res.mjs +2 -1
  79. package/src/TableIndices.res +0 -1
  80. package/src/TestIndexer.res +913 -0
  81. package/src/TestIndexer.res.mjs +698 -0
  82. package/src/TestIndexerProxyStorage.res +205 -0
  83. package/src/TestIndexerProxyStorage.res.mjs +151 -0
  84. package/src/TopicFilter.res +1 -1
  85. package/src/Types.ts +1 -1
  86. package/src/UserContext.res +424 -0
  87. package/src/UserContext.res.mjs +279 -0
  88. package/src/Utils.res +97 -26
  89. package/src/Utils.res.mjs +91 -44
  90. package/src/bindings/BigInt.res +10 -0
  91. package/src/bindings/BigInt.res.mjs +15 -0
  92. package/src/bindings/ClickHouse.res +120 -23
  93. package/src/bindings/ClickHouse.res.mjs +118 -28
  94. package/src/bindings/DateFns.res +74 -0
  95. package/src/bindings/DateFns.res.mjs +22 -0
  96. package/src/bindings/EventSource.res +11 -2
  97. package/src/bindings/EventSource.res.mjs +8 -1
  98. package/src/bindings/Express.res +1 -0
  99. package/src/bindings/Hrtime.res +14 -1
  100. package/src/bindings/Hrtime.res.mjs +22 -2
  101. package/src/bindings/Hrtime.resi +4 -0
  102. package/src/bindings/Lodash.res +0 -1
  103. package/src/bindings/NodeJs.res +49 -3
  104. package/src/bindings/NodeJs.res.mjs +11 -3
  105. package/src/bindings/Pino.res +24 -10
  106. package/src/bindings/Pino.res.mjs +14 -8
  107. package/src/bindings/Postgres.gen.ts +8 -0
  108. package/src/bindings/Postgres.res +5 -1
  109. package/src/bindings/Postgres.res.d.mts +5 -0
  110. package/src/bindings/PromClient.res +0 -10
  111. package/src/bindings/PromClient.res.mjs +0 -3
  112. package/src/bindings/Vitest.res +144 -0
  113. package/src/bindings/Vitest.res.mjs +9 -0
  114. package/src/bindings/WebSocket.res +27 -0
  115. package/src/bindings/WebSocket.res.mjs +2 -0
  116. package/src/bindings/Yargs.res +8 -0
  117. package/src/bindings/Yargs.res.mjs +2 -0
  118. package/src/db/EntityHistory.res +7 -7
  119. package/src/db/EntityHistory.res.mjs +9 -9
  120. package/src/db/InternalTable.res +59 -111
  121. package/src/db/InternalTable.res.mjs +73 -104
  122. package/src/db/Table.res +27 -8
  123. package/src/db/Table.res.mjs +25 -14
  124. package/src/sources/Evm.res +84 -0
  125. package/src/sources/Evm.res.mjs +105 -0
  126. package/src/sources/EvmChain.res +94 -0
  127. package/src/sources/EvmChain.res.mjs +60 -0
  128. package/src/sources/Fuel.res +19 -34
  129. package/src/sources/Fuel.res.mjs +34 -16
  130. package/src/sources/FuelSDK.res +38 -0
  131. package/src/sources/FuelSDK.res.mjs +29 -0
  132. package/src/sources/HyperFuel.res +2 -2
  133. package/src/sources/HyperFuel.resi +1 -1
  134. package/src/sources/HyperFuelClient.res +2 -2
  135. package/src/sources/HyperFuelSource.res +35 -13
  136. package/src/sources/HyperFuelSource.res.mjs +26 -16
  137. package/src/sources/HyperSync.res +61 -60
  138. package/src/sources/HyperSync.res.mjs +53 -67
  139. package/src/sources/HyperSync.resi +6 -4
  140. package/src/sources/HyperSyncClient.res +29 -2
  141. package/src/sources/HyperSyncClient.res.mjs +9 -0
  142. package/src/sources/HyperSyncHeightStream.res +76 -118
  143. package/src/sources/HyperSyncHeightStream.res.mjs +68 -75
  144. package/src/sources/HyperSyncSource.res +122 -143
  145. package/src/sources/HyperSyncSource.res.mjs +106 -121
  146. package/src/sources/Rpc.res +86 -14
  147. package/src/sources/Rpc.res.mjs +101 -9
  148. package/src/sources/RpcSource.res +731 -364
  149. package/src/sources/RpcSource.res.mjs +845 -410
  150. package/src/sources/RpcWebSocketHeightStream.res +181 -0
  151. package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
  152. package/src/sources/SimulateSource.res +59 -0
  153. package/src/sources/SimulateSource.res.mjs +50 -0
  154. package/src/sources/Source.res +7 -5
  155. package/src/sources/SourceManager.res +358 -221
  156. package/src/sources/SourceManager.res.mjs +346 -171
  157. package/src/sources/SourceManager.resi +17 -6
  158. package/src/sources/Svm.res +81 -0
  159. package/src/sources/Svm.res.mjs +90 -0
  160. package/src/tui/Tui.res +247 -0
  161. package/src/tui/Tui.res.mjs +337 -0
  162. package/src/tui/bindings/Ink.res +371 -0
  163. package/src/tui/bindings/Ink.res.mjs +72 -0
  164. package/src/tui/bindings/Style.res +123 -0
  165. package/src/tui/bindings/Style.res.mjs +2 -0
  166. package/src/tui/components/BufferedProgressBar.res +40 -0
  167. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  168. package/src/tui/components/CustomHooks.res +122 -0
  169. package/src/tui/components/CustomHooks.res.mjs +179 -0
  170. package/src/tui/components/Messages.res +41 -0
  171. package/src/tui/components/Messages.res.mjs +75 -0
  172. package/src/tui/components/SyncETA.res +174 -0
  173. package/src/tui/components/SyncETA.res.mjs +263 -0
  174. package/src/tui/components/TuiData.res +47 -0
  175. package/src/tui/components/TuiData.res.mjs +34 -0
  176. package/svm.schema.json +112 -0
  177. package/bin.js +0 -48
  178. package/src/EventRegister.res +0 -241
  179. package/src/EventRegister.res.mjs +0 -240
  180. package/src/EventRegister.resi +0 -30
  181. package/src/bindings/Ethers.gen.ts +0 -14
  182. package/src/bindings/Ethers.res +0 -204
  183. package/src/bindings/Ethers.res.mjs +0 -130
  184. /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, newBlockFallbackStallTimeoutOpt, stalledPollingIntervalOpt, getHeightRetryIntervalOpt) {
28
- var newBlockFallbackStallTimeout = newBlockFallbackStallTimeoutOpt !== undefined ? newBlockFallbackStallTimeoutOpt : 20000;
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 === "Sync";
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
- sources: new Set(sources),
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
- newBlockFallbackStallTimeout: newBlockFallbackStallTimeout,
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.incrementMany(promCounter, sourceManager.activeSource.chain, Hrtime.intFromMillis(Hrtime.toMillis(Hrtime.timeSince(sourceManager.statusStart))));
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, currentBlockHeight, executeQuery, waitForNewBlock, onNewBlock, stateId) {
72
- var queries = FetchState.getNextQuery(fetchState, sourceManager.maxPartitionConcurrency - sourceManager.fetchingPartitionsCount | 0, currentBlockHeight, stateId);
73
- if (typeof queries !== "object") {
74
- switch (queries) {
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 currentBlockHeight$1 = await waitForNewBlock(currentBlockHeight);
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(currentBlockHeight$1);
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$1 = queries._0;
98
- FetchState.startFetchingQueries(fetchState, queries$1, stateId);
99
- sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries$1.length | 0;
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$1, (function (q) {
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
- async function getSourceNewHeight(sourceManager, source, currentBlockHeight, status, logger) {
119
- var newHeight = 0;
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 <= currentBlockHeight && status.contents !== "Done") {
122
- try {
123
- var endTimer = Prometheus.SourceGetHeightDuration.startTimer({
124
- source: source.name,
125
- chainId: source.chain
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 source.getHeightOrThrow();
128
- endTimer();
129
- newHeight = height;
130
- if (height <= currentBlockHeight) {
131
- retry = 0;
132
- var pollingInterval = status.contents === "Stalled" ? sourceManager.stalledPollingInterval : source.pollingInterval;
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
- catch (raw_exn){
138
- var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
139
- var retryInterval = sourceManager.getHeightRetryInterval(retry);
140
- Logging.childTrace(logger, {
141
- msg: "Height retrieval from " + source.name + " source failed. Retrying in " + String(retryInterval) + "ms.",
142
- source: source.name,
143
- err: Utils.prettifyExn(exn)
144
- });
145
- retry = retry + 1 | 0;
146
- await Utils.delay(retryInterval);
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
- Prometheus.SourceHeight.set(source.name, source.chain, newHeight);
150
- return newHeight;
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
- async function waitForNewBlock(sourceManager, currentBlockHeight) {
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
- currentBlockHeight: currentBlockHeight
365
+ knownHeight: knownHeight
157
366
  });
158
367
  Logging.childTrace(logger, "Initiating check for new blocks.");
159
- var isInitialHeightFetch = currentBlockHeight === 0;
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 match = await Promise.race(Belt_Array.concat(Belt_Array.map(syncSources, (async function (source) {
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, source, currentBlockHeight, status, logger)
375
+ sourceState.source,
376
+ await getSourceNewHeight(sourceManager, sourceState, knownHeight, stallTimeout, isLive, status, logger)
176
377
  ];
177
- })), [Utils.delay(sourceManager.newBlockFallbackStallTimeout).then(function () {
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(sourceManager.newBlockFallbackStallTimeout / 1000 | 0) + "s. Continuing polling with fallback RPC sources from the configuration.");
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(sourceManager.newBlockFallbackStallTimeout / 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");
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 (source) {
395
+ return Promise.race(Belt_Array.map(fallbackSources, (async function (sourceState) {
187
396
  return [
188
- source,
189
- await getSourceNewHeight(sourceManager, source, currentBlockHeight, status, logger)
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 getNextSyncSource(sourceManager, initialSource, currentSource, attemptFallbacksOpt) {
207
- var attemptFallbacks = attemptFallbacksOpt !== undefined ? attemptFallbacksOpt : false;
208
- var before = [];
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 source = sourceRef;
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, currentBlockHeight, query.partitionId, query.selection, retry, logger);
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$1 = error$1.retry;
478
+ var match = error$1.retry;
297
479
  var attemptedToBlock = error$1.attemptedToBlock;
298
480
  var exn = error$1.exn;
299
- switch (match$1.TAG) {
481
+ switch (match.TAG) {
300
482
  case "WithSuggestedToBlock" :
301
- var toBlock$1 = match$1.toBlock;
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$1.backoffMillis;
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$1.message,
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 = nextSource !== source;
502
+ var shouldSwitch = retry === 0 || retry === 1 ? false : retry % 2 === 0;
323
503
  if (shouldSwitch) {
324
- Logging.childInfo(logger, {
325
- msg: "Switching to another data-source",
326
- source: nextSource.name
327
- });
328
- sourceRef = nextSource;
329
- shouldUpdateActiveSource = true;
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 nextSource$1 = getNextSyncSource(sourceManager, initialSource, source, true);
337
- var hasAnotherSource = nextSource$1 !== initialSource;
338
- Logging.childWarn(logger, {
339
- msg: match$1.message + (
340
- hasAnotherSource ? " - Attempting to another source" : ""
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
- if (hasAnotherSource) {
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 nextSource$2 = getNextSyncSource(sourceManager, initialSource, source, undefined);
360
- var notAlreadyDeleted = sourceManager.sources.delete(source);
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
- if (nextSource$2 === source) {
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 ,