envio 3.0.0-alpha.2 → 3.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/evm.schema.json +44 -33
- package/fuel.schema.json +32 -21
- package/index.d.ts +1 -0
- package/package.json +7 -6
- package/src/Batch.res.mjs +1 -1
- package/src/Benchmark.res +394 -0
- package/src/Benchmark.res.mjs +398 -0
- package/src/ChainFetcher.res +459 -0
- package/src/ChainFetcher.res.mjs +281 -0
- package/src/ChainManager.res +179 -0
- package/src/ChainManager.res.mjs +139 -0
- package/src/Config.res +15 -1
- package/src/Config.res.mjs +27 -4
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +0 -1
- package/src/Env.res.mjs +0 -3
- package/src/Envio.gen.ts +9 -1
- package/src/Envio.res +12 -9
- package/src/EventProcessing.res +476 -0
- package/src/EventProcessing.res.mjs +341 -0
- package/src/FetchState.res +54 -29
- package/src/FetchState.res.mjs +62 -35
- package/src/GlobalState.res +1169 -0
- package/src/GlobalState.res.mjs +1196 -0
- package/src/Internal.res +2 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/Prometheus.res +8 -8
- package/src/Prometheus.res.mjs +10 -10
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/UserContext.res +356 -0
- package/src/UserContext.res.mjs +238 -0
- package/src/bindings/DateFns.res +71 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/sources/Evm.res +87 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +95 -0
- package/src/sources/EvmChain.res.mjs +61 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +37 -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 +8 -8
- package/src/sources/HyperFuelSource.res.mjs +5 -5
- package/src/sources/HyperSyncSource.res +5 -5
- package/src/sources/HyperSyncSource.res.mjs +5 -5
- package/src/sources/RpcSource.res +4 -4
- package/src/sources/RpcSource.res.mjs +3 -3
- package/src/sources/Solana.res +59 -0
- package/src/sources/Solana.res.mjs +79 -0
- package/src/sources/Source.res +2 -2
- package/src/sources/SourceManager.res +24 -32
- package/src/sources/SourceManager.res.mjs +20 -20
- package/src/sources/SourceManager.resi +4 -5
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Utils from "./Utils.res.mjs";
|
|
4
|
+
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
|
+
import * as Logging from "./Logging.res.mjs";
|
|
6
|
+
import * as Internal from "./Internal.res.mjs";
|
|
7
|
+
import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
|
|
8
|
+
import * as Prometheus from "./Prometheus.res.mjs";
|
|
9
|
+
import * as Caml_option from "rescript/lib/es6/caml_option.js";
|
|
10
|
+
import * as LoadManager from "./LoadManager.res.mjs";
|
|
11
|
+
import * as Persistence from "./Persistence.res.mjs";
|
|
12
|
+
import * as TableIndices from "./TableIndices.res.mjs";
|
|
13
|
+
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
14
|
+
import * as InMemoryStore from "./InMemoryStore.res.mjs";
|
|
15
|
+
import * as InMemoryTable from "./InMemoryTable.res.mjs";
|
|
16
|
+
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
17
|
+
import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";
|
|
18
|
+
|
|
19
|
+
function loadById(loadManager, persistence, entityConfig, inMemoryStore, shouldGroup, item, entityId) {
|
|
20
|
+
var key = entityConfig.name + ".get";
|
|
21
|
+
var inMemTable = InMemoryStore.getInMemTable(inMemoryStore, entityConfig);
|
|
22
|
+
var load = async function (idsToLoad, param) {
|
|
23
|
+
var timerRef = Prometheus.StorageLoad.startOperation(key);
|
|
24
|
+
var dbEntities;
|
|
25
|
+
try {
|
|
26
|
+
dbEntities = await Persistence.getInitializedStorageOrThrow(persistence).loadByIdsOrThrow(idsToLoad, entityConfig.table, entityConfig.rowsSchema);
|
|
27
|
+
}
|
|
28
|
+
catch (raw_exn){
|
|
29
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
30
|
+
if (exn.RE_EXN_ID === Persistence.StorageError) {
|
|
31
|
+
dbEntities = ErrorHandling.mkLogAndRaise(Logging.getItemLogger(item), exn.message, exn.reason);
|
|
32
|
+
} else {
|
|
33
|
+
throw exn;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
var entitiesMap = {};
|
|
37
|
+
for(var idx = 0 ,idx_finish = dbEntities.length; idx < idx_finish; ++idx){
|
|
38
|
+
var entity = dbEntities[idx];
|
|
39
|
+
entitiesMap[entity.id] = entity;
|
|
40
|
+
}
|
|
41
|
+
idsToLoad.forEach(function (entityId) {
|
|
42
|
+
InMemoryTable.Entity.initValue(inMemTable, entityId, entitiesMap[entityId], false);
|
|
43
|
+
});
|
|
44
|
+
return Prometheus.StorageLoad.endOperation(timerRef, key, idsToLoad.length, dbEntities.length);
|
|
45
|
+
};
|
|
46
|
+
return LoadManager.call(loadManager, entityId, key, load, LoadManager.noopHasher, shouldGroup, (function (hash) {
|
|
47
|
+
return InMemoryTable.hasByHash(inMemTable.table, hash);
|
|
48
|
+
}), InMemoryTable.Entity.getUnsafe(inMemTable));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function callEffect(effect, arg, inMemTable, timerRef, onError) {
|
|
52
|
+
var effectName = effect.name;
|
|
53
|
+
var hadActiveCalls = effect.activeCallsCount > 0;
|
|
54
|
+
effect.activeCallsCount = effect.activeCallsCount + 1 | 0;
|
|
55
|
+
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, effectName, effect.activeCallsCount);
|
|
56
|
+
if (hadActiveCalls) {
|
|
57
|
+
var elapsed = Hrtime.millisBetween(effect.prevCallStartTimerRef, timerRef);
|
|
58
|
+
if (elapsed > 0) {
|
|
59
|
+
Prometheus.SafeCounter.incrementMany(Prometheus.EffectCalls.timeCounter, effectName, Hrtime.millisBetween(effect.prevCallStartTimerRef, timerRef));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
effect.prevCallStartTimerRef = timerRef;
|
|
64
|
+
return effect.handler(arg).then(function (output) {
|
|
65
|
+
inMemTable.dict[arg.cacheKey] = output;
|
|
66
|
+
if (arg.context.cache) {
|
|
67
|
+
inMemTable.idsToStore.push(arg.cacheKey);
|
|
68
|
+
return ;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}).catch(function (exn) {
|
|
72
|
+
onError(arg.cacheKey, exn);
|
|
73
|
+
}).finally(function () {
|
|
74
|
+
effect.activeCallsCount = effect.activeCallsCount - 1 | 0;
|
|
75
|
+
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, effectName, effect.activeCallsCount);
|
|
76
|
+
var newTimer = Hrtime.makeTimer();
|
|
77
|
+
Prometheus.SafeCounter.incrementMany(Prometheus.EffectCalls.timeCounter, effectName, Hrtime.millisBetween(effect.prevCallStartTimerRef, newTimer));
|
|
78
|
+
effect.prevCallStartTimerRef = newTimer;
|
|
79
|
+
Prometheus.SafeCounter.increment(Prometheus.EffectCalls.totalCallsCount, effectName);
|
|
80
|
+
Prometheus.SafeCounter.incrementMany(Prometheus.EffectCalls.sumTimeCounter, effectName, Hrtime.intFromMillis(Hrtime.toMillis(Hrtime.timeSince(timerRef))));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQueue) {
|
|
85
|
+
var effectName = effect.name;
|
|
86
|
+
var timerRef = Hrtime.makeTimer();
|
|
87
|
+
var promises = [];
|
|
88
|
+
var state = effect.rateLimit;
|
|
89
|
+
if (state !== undefined) {
|
|
90
|
+
var now = Date.now();
|
|
91
|
+
if (now >= state.windowStartTime + state.durationMs) {
|
|
92
|
+
state.availableCalls = state.callsPerDuration;
|
|
93
|
+
state.windowStartTime = now;
|
|
94
|
+
state.nextWindowPromise = undefined;
|
|
95
|
+
}
|
|
96
|
+
var immediateCount = Math.min(state.availableCalls, effectArgs.length);
|
|
97
|
+
var immediateArgs = Belt_Array.slice(effectArgs, 0, immediateCount);
|
|
98
|
+
var queuedArgs = Belt_Array.sliceToEnd(effectArgs, immediateCount);
|
|
99
|
+
state.availableCalls = state.availableCalls - immediateCount | 0;
|
|
100
|
+
for(var idx = 0 ,idx_finish = immediateArgs.length; idx < idx_finish; ++idx){
|
|
101
|
+
promises.push(callEffect(effect, immediateArgs[idx], inMemTable, timerRef, onError));
|
|
102
|
+
}
|
|
103
|
+
if (immediateCount > 0 && isFromQueue) {
|
|
104
|
+
state.queueCount = state.queueCount - immediateCount | 0;
|
|
105
|
+
Prometheus.EffectQueueCount.set(state.queueCount, effectName);
|
|
106
|
+
}
|
|
107
|
+
if (Utils.$$Array.notEmpty(queuedArgs)) {
|
|
108
|
+
if (!isFromQueue) {
|
|
109
|
+
state.queueCount = state.queueCount + queuedArgs.length | 0;
|
|
110
|
+
Prometheus.EffectQueueCount.set(state.queueCount, effectName);
|
|
111
|
+
}
|
|
112
|
+
var millisUntilReset = {
|
|
113
|
+
contents: 0
|
|
114
|
+
};
|
|
115
|
+
var p = state.nextWindowPromise;
|
|
116
|
+
var nextWindowPromise;
|
|
117
|
+
if (p !== undefined) {
|
|
118
|
+
nextWindowPromise = Caml_option.valFromOption(p);
|
|
119
|
+
} else {
|
|
120
|
+
millisUntilReset.contents = state.windowStartTime + state.durationMs - now | 0;
|
|
121
|
+
var p$1 = Utils.delay(millisUntilReset.contents);
|
|
122
|
+
state.nextWindowPromise = Caml_option.some(p$1);
|
|
123
|
+
nextWindowPromise = p$1;
|
|
124
|
+
}
|
|
125
|
+
promises.push(nextWindowPromise.then(function () {
|
|
126
|
+
if (millisUntilReset.contents > 0) {
|
|
127
|
+
Prometheus.SafeCounter.incrementMany(Prometheus.EffectQueueCount.timeCounter, effectName, millisUntilReset.contents);
|
|
128
|
+
}
|
|
129
|
+
return executeWithRateLimit(effect, queuedArgs, inMemTable, onError, true);
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
} else {
|
|
134
|
+
for(var idx$1 = 0 ,idx_finish$1 = effectArgs.length; idx$1 < idx_finish$1; ++idx$1){
|
|
135
|
+
promises.push(callEffect(effect, effectArgs[idx$1], inMemTable, timerRef, onError));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return Promise.all(promises);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function loadEffect(loadManager, persistence, effect, effectArgs, inMemoryStore, shouldGroup, item) {
|
|
142
|
+
var effectName = effect.name;
|
|
143
|
+
var key = effectName + ".effect";
|
|
144
|
+
var inMemTable = InMemoryStore.getEffectInMemTable(inMemoryStore, effect);
|
|
145
|
+
var load = async function (args, onError) {
|
|
146
|
+
var idsToLoad = args.map(function (arg) {
|
|
147
|
+
return arg.cacheKey;
|
|
148
|
+
});
|
|
149
|
+
var idsFromCache = new Set();
|
|
150
|
+
var match = persistence.storageStatus;
|
|
151
|
+
var tmp;
|
|
152
|
+
tmp = typeof match !== "object" || match.TAG === "Initializing" ? false : Utils.Dict.has(match._0.cache, effectName);
|
|
153
|
+
if (tmp) {
|
|
154
|
+
var timerRef = Prometheus.StorageLoad.startOperation(key);
|
|
155
|
+
var match$1 = effect.storageMeta;
|
|
156
|
+
var outputSchema = match$1.outputSchema;
|
|
157
|
+
var dbEntities;
|
|
158
|
+
try {
|
|
159
|
+
dbEntities = await Persistence.getInitializedStorageOrThrow(persistence).loadByIdsOrThrow(idsToLoad, match$1.table, Internal.effectCacheItemRowsSchema);
|
|
160
|
+
}
|
|
161
|
+
catch (raw_exn){
|
|
162
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
163
|
+
Logging.childWarn(Logging.getItemLogger(item), {
|
|
164
|
+
msg: "Failed to load cache effect cache. The indexer will continue working, but the effect will not be able to use the cache.",
|
|
165
|
+
err: Utils.prettifyExn(exn),
|
|
166
|
+
effect: effectName
|
|
167
|
+
});
|
|
168
|
+
dbEntities = [];
|
|
169
|
+
}
|
|
170
|
+
dbEntities.forEach(function (dbEntity) {
|
|
171
|
+
try {
|
|
172
|
+
var output = S$RescriptSchema.parseOrThrow(dbEntity.output, outputSchema);
|
|
173
|
+
idsFromCache.add(dbEntity.id);
|
|
174
|
+
inMemTable.dict[dbEntity.id] = output;
|
|
175
|
+
return ;
|
|
176
|
+
}
|
|
177
|
+
catch (raw_error){
|
|
178
|
+
var error = Caml_js_exceptions.internalToOCamlException(raw_error);
|
|
179
|
+
if (error.RE_EXN_ID === S$RescriptSchema.Raised) {
|
|
180
|
+
inMemTable.invalidationsCount = inMemTable.invalidationsCount + 1 | 0;
|
|
181
|
+
Prometheus.EffectCacheInvalidationsCount.increment(effectName);
|
|
182
|
+
return Logging.childTrace(Logging.getItemLogger(item), {
|
|
183
|
+
msg: "Invalidated effect cache",
|
|
184
|
+
input: dbEntity.id,
|
|
185
|
+
effect: effectName,
|
|
186
|
+
err: S$RescriptSchema.$$Error.message(error._1)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
Prometheus.StorageLoad.endOperation(timerRef, key, idsToLoad.length, dbEntities.length);
|
|
193
|
+
}
|
|
194
|
+
var remainingCallsCount = idsToLoad.length - idsFromCache.size | 0;
|
|
195
|
+
if (remainingCallsCount <= 0) {
|
|
196
|
+
return ;
|
|
197
|
+
}
|
|
198
|
+
var argsToCall = [];
|
|
199
|
+
for(var idx = 0 ,idx_finish = args.length; idx < idx_finish; ++idx){
|
|
200
|
+
var arg = args[idx];
|
|
201
|
+
if (!idsFromCache.has(arg.cacheKey)) {
|
|
202
|
+
argsToCall.push(arg);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
if (Utils.$$Array.notEmpty(argsToCall)) {
|
|
207
|
+
return await executeWithRateLimit(effect, argsToCall, inMemTable, onError, false);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
};
|
|
211
|
+
return LoadManager.call(loadManager, effectArgs, key, load, (function (args) {
|
|
212
|
+
return args.cacheKey;
|
|
213
|
+
}), shouldGroup, (function (hash) {
|
|
214
|
+
return Utils.Dict.has(inMemTable.dict, hash);
|
|
215
|
+
}), (function (hash) {
|
|
216
|
+
return inMemTable.dict[hash];
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function loadByField(loadManager, persistence, operator, entityConfig, inMemoryStore, fieldName, fieldValueSchema, shouldGroup, item, fieldValue) {
|
|
221
|
+
var operatorCallName;
|
|
222
|
+
switch (operator) {
|
|
223
|
+
case "Eq" :
|
|
224
|
+
operatorCallName = "eq";
|
|
225
|
+
break;
|
|
226
|
+
case "Gt" :
|
|
227
|
+
operatorCallName = "gt";
|
|
228
|
+
break;
|
|
229
|
+
case "Lt" :
|
|
230
|
+
operatorCallName = "lt";
|
|
231
|
+
break;
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
var key = entityConfig.name + ".getWhere." + fieldName + "." + operatorCallName;
|
|
235
|
+
var inMemTable = InMemoryStore.getInMemTable(inMemoryStore, entityConfig);
|
|
236
|
+
var load = async function (fieldValues, param) {
|
|
237
|
+
var timerRef = Prometheus.StorageLoad.startOperation(key);
|
|
238
|
+
var size = {
|
|
239
|
+
contents: 0
|
|
240
|
+
};
|
|
241
|
+
var indiciesToLoad = fieldValues.map(function (fieldValue) {
|
|
242
|
+
return {
|
|
243
|
+
fieldName: fieldName,
|
|
244
|
+
fieldValue: fieldValue,
|
|
245
|
+
operator: operator
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
await Promise.all(indiciesToLoad.map(async function (index) {
|
|
249
|
+
InMemoryTable.Entity.addEmptyIndex(inMemTable, index);
|
|
250
|
+
try {
|
|
251
|
+
var tmp;
|
|
252
|
+
switch (index.operator) {
|
|
253
|
+
case "Eq" :
|
|
254
|
+
tmp = "=";
|
|
255
|
+
break;
|
|
256
|
+
case "Gt" :
|
|
257
|
+
tmp = ">";
|
|
258
|
+
break;
|
|
259
|
+
case "Lt" :
|
|
260
|
+
tmp = "<";
|
|
261
|
+
break;
|
|
262
|
+
|
|
263
|
+
}
|
|
264
|
+
var entities = await Persistence.getInitializedStorageOrThrow(persistence).loadByFieldOrThrow(TableIndices.Index.getFieldName(index), fieldValueSchema, index.fieldValue, tmp, entityConfig.table, entityConfig.rowsSchema);
|
|
265
|
+
Belt_Array.forEach(entities, (function (entity) {
|
|
266
|
+
InMemoryTable.Entity.initValue(inMemTable, entity.id, entity, false);
|
|
267
|
+
}));
|
|
268
|
+
size.contents = size.contents + entities.length | 0;
|
|
269
|
+
return ;
|
|
270
|
+
}
|
|
271
|
+
catch (raw_exn){
|
|
272
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
273
|
+
if (exn.RE_EXN_ID === Persistence.StorageError) {
|
|
274
|
+
return ErrorHandling.mkLogAndRaise(Logging.createChildFrom(Logging.getItemLogger(item), {
|
|
275
|
+
operator: operatorCallName,
|
|
276
|
+
tableName: entityConfig.table.tableName,
|
|
277
|
+
fieldName: fieldName,
|
|
278
|
+
fieldValue: fieldValue
|
|
279
|
+
}), exn.message, exn.reason);
|
|
280
|
+
}
|
|
281
|
+
throw exn;
|
|
282
|
+
}
|
|
283
|
+
}));
|
|
284
|
+
return Prometheus.StorageLoad.endOperation(timerRef, key, fieldValues.length, size.contents);
|
|
285
|
+
};
|
|
286
|
+
return LoadManager.call(loadManager, fieldValue, key, load, (function (fieldValue) {
|
|
287
|
+
return TableIndices.FieldValue.toString(fieldValue);
|
|
288
|
+
}), shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable, fieldName, operator), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable, fieldName, operator));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export {
|
|
292
|
+
loadById ,
|
|
293
|
+
loadByField ,
|
|
294
|
+
loadEffect ,
|
|
295
|
+
}
|
|
296
|
+
/* Utils Not a pure module */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
let loadById: (
|
|
2
|
+
~loadManager: LoadManager.t,
|
|
3
|
+
~persistence: Persistence.t,
|
|
4
|
+
~entityConfig: Internal.entityConfig,
|
|
5
|
+
~inMemoryStore: InMemoryStore.t,
|
|
6
|
+
~shouldGroup: bool,
|
|
7
|
+
~item: Internal.item,
|
|
8
|
+
~entityId: string,
|
|
9
|
+
) => promise<option<Internal.entity>>
|
|
10
|
+
|
|
11
|
+
let loadByField: (
|
|
12
|
+
~loadManager: LoadManager.t,
|
|
13
|
+
~persistence: Persistence.t,
|
|
14
|
+
~operator: TableIndices.Operator.t,
|
|
15
|
+
~entityConfig: Internal.entityConfig,
|
|
16
|
+
~inMemoryStore: InMemoryStore.t,
|
|
17
|
+
~fieldName: string,
|
|
18
|
+
~fieldValueSchema: RescriptSchema.S.t<'fieldValue>,
|
|
19
|
+
~shouldGroup: bool,
|
|
20
|
+
~item: Internal.item,
|
|
21
|
+
~fieldValue: 'fieldValue,
|
|
22
|
+
) => promise<array<Internal.entity>>
|
|
23
|
+
|
|
24
|
+
let loadEffect: (
|
|
25
|
+
~loadManager: LoadManager.t,
|
|
26
|
+
~persistence: Persistence.t,
|
|
27
|
+
~effect: Internal.effect,
|
|
28
|
+
~effectArgs: Internal.effectArgs,
|
|
29
|
+
~inMemoryStore: InMemoryStore.t,
|
|
30
|
+
~shouldGroup: bool,
|
|
31
|
+
~item: Internal.item,
|
|
32
|
+
) => promise<Internal.effectOutput>
|
package/src/Prometheus.res
CHANGED
|
@@ -34,12 +34,6 @@ let allChainsSyncedToHead = PromClient.Gauge.makeGauge({
|
|
|
34
34
|
"labelNames": [],
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
let sourceChainHeight = PromClient.Gauge.makeGauge({
|
|
38
|
-
"name": "chain_block_height",
|
|
39
|
-
"help": "Chain Height of Source Chain",
|
|
40
|
-
"labelNames": ["chainId"],
|
|
41
|
-
})
|
|
42
|
-
|
|
43
37
|
module Labels = {
|
|
44
38
|
let rec schemaIsString = (schema: S.t<'a>) =>
|
|
45
39
|
switch schema->S.classify {
|
|
@@ -233,8 +227,14 @@ let incrementStorageWriteCounter = () => {
|
|
|
233
227
|
storageWriteCounter->PromClient.Counter.inc
|
|
234
228
|
}
|
|
235
229
|
|
|
236
|
-
let
|
|
237
|
-
|
|
230
|
+
let knownHeightGauge = PromClient.Gauge.makeGauge({
|
|
231
|
+
"name": "envio_indexing_known_height",
|
|
232
|
+
"help": "The latest known block number reported by the active indexing source. This value may lag behind the actual chain height, as it is updated only when needed.",
|
|
233
|
+
"labelNames": ["chainId"],
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
let setKnownHeight = (~blockNumber, ~chainId) => {
|
|
237
|
+
knownHeightGauge
|
|
238
238
|
->PromClient.Gauge.labels({"chainId": chainId})
|
|
239
239
|
->PromClient.Gauge.set(blockNumber)
|
|
240
240
|
}
|
package/src/Prometheus.res.mjs
CHANGED
|
@@ -44,12 +44,6 @@ var allChainsSyncedToHead = new PromClient.Gauge({
|
|
|
44
44
|
labelNames: []
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
var sourceChainHeight = new PromClient.Gauge({
|
|
48
|
-
name: "chain_block_height",
|
|
49
|
-
help: "Chain Height of Source Chain",
|
|
50
|
-
labelNames: ["chainId"]
|
|
51
|
-
});
|
|
52
|
-
|
|
53
47
|
function schemaIsString(_schema) {
|
|
54
48
|
while(true) {
|
|
55
49
|
var schema = _schema;
|
|
@@ -333,8 +327,14 @@ function incrementStorageWriteCounter() {
|
|
|
333
327
|
storageWriteCounter.inc();
|
|
334
328
|
}
|
|
335
329
|
|
|
336
|
-
|
|
337
|
-
|
|
330
|
+
var knownHeightGauge = new PromClient.Gauge({
|
|
331
|
+
name: "envio_indexing_known_height",
|
|
332
|
+
help: "The latest known block number reported by the active indexing source. This value may lag behind the actual chain height, as it is updated only when needed.",
|
|
333
|
+
labelNames: ["chainId"]
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
function setKnownHeight(blockNumber, chainId) {
|
|
337
|
+
knownHeightGauge.labels({
|
|
338
338
|
chainId: chainId
|
|
339
339
|
}).set(blockNumber);
|
|
340
340
|
}
|
|
@@ -854,7 +854,6 @@ export {
|
|
|
854
854
|
storageWriteTimeCounter ,
|
|
855
855
|
storageWriteCounter ,
|
|
856
856
|
allChainsSyncedToHead ,
|
|
857
|
-
sourceChainHeight ,
|
|
858
857
|
Labels ,
|
|
859
858
|
metricNames ,
|
|
860
859
|
MakeSafePromMetric ,
|
|
@@ -867,7 +866,8 @@ export {
|
|
|
867
866
|
incrementExecuteBatchDurationCounter ,
|
|
868
867
|
incrementStorageWriteTimeCounter ,
|
|
869
868
|
incrementStorageWriteCounter ,
|
|
870
|
-
|
|
869
|
+
knownHeightGauge ,
|
|
870
|
+
setKnownHeight ,
|
|
871
871
|
setAllChainsSyncedToHead ,
|
|
872
872
|
BenchmarkCounters ,
|
|
873
873
|
chainIdLabelsSchema ,
|
package/src/ReorgDetection.res
CHANGED
|
@@ -77,13 +77,10 @@ let make = (
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
let getDataByBlockNumberCopyInThreshold = (
|
|
81
|
-
{dataByBlockNumber, maxReorgDepth}: t,
|
|
82
|
-
~currentBlockHeight,
|
|
83
|
-
) => {
|
|
80
|
+
let getDataByBlockNumberCopyInThreshold = ({dataByBlockNumber, maxReorgDepth}: t, ~knownHeight) => {
|
|
84
81
|
// Js engine automatically orders numeric object keys
|
|
85
82
|
let ascBlockNumberKeys = dataByBlockNumber->Js.Dict.keys
|
|
86
|
-
let thresholdBlockNumber =
|
|
83
|
+
let thresholdBlockNumber = knownHeight - maxReorgDepth
|
|
87
84
|
|
|
88
85
|
let copy = Js.Dict.empty()
|
|
89
86
|
|
|
@@ -105,10 +102,9 @@ let getDataByBlockNumberCopyInThreshold = (
|
|
|
105
102
|
let registerReorgGuard = (
|
|
106
103
|
{maxReorgDepth, shouldRollbackOnReorg} as self: t,
|
|
107
104
|
~reorgGuard: reorgGuard,
|
|
108
|
-
~
|
|
105
|
+
~knownHeight,
|
|
109
106
|
) => {
|
|
110
|
-
let dataByBlockNumberCopyInThreshold =
|
|
111
|
-
self->getDataByBlockNumberCopyInThreshold(~currentBlockHeight)
|
|
107
|
+
let dataByBlockNumberCopyInThreshold = self->getDataByBlockNumberCopyInThreshold(~knownHeight)
|
|
112
108
|
|
|
113
109
|
let {rangeLastBlock, prevRangeLastBlock} = reorgGuard
|
|
114
110
|
|
|
@@ -248,12 +244,12 @@ let rollbackToValidBlockNumber = (
|
|
|
248
244
|
}
|
|
249
245
|
}
|
|
250
246
|
|
|
251
|
-
let getThresholdBlockNumbersBelowBlock = (self: t, ~blockNumber: int, ~
|
|
247
|
+
let getThresholdBlockNumbersBelowBlock = (self: t, ~blockNumber: int, ~knownHeight) => {
|
|
252
248
|
let arr = []
|
|
253
249
|
|
|
254
250
|
// Js engine automatically orders numeric object keys
|
|
255
251
|
let ascBlockNumberKeys = self.dataByBlockNumber->Js.Dict.keys
|
|
256
|
-
let thresholdBlockNumber =
|
|
252
|
+
let thresholdBlockNumber = knownHeight - self.maxReorgDepth
|
|
257
253
|
|
|
258
254
|
for idx in 0 to ascBlockNumberKeys->Array.length - 1 {
|
|
259
255
|
let blockNumberKey = ascBlockNumberKeys->Js.Array2.unsafe_get(idx)
|
|
@@ -30,10 +30,10 @@ function make(chainReorgCheckpoints, maxReorgDepth, shouldRollbackOnReorg) {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function getDataByBlockNumberCopyInThreshold(param,
|
|
33
|
+
function getDataByBlockNumberCopyInThreshold(param, knownHeight) {
|
|
34
34
|
var dataByBlockNumber = param.dataByBlockNumber;
|
|
35
35
|
var ascBlockNumberKeys = Object.keys(dataByBlockNumber);
|
|
36
|
-
var thresholdBlockNumber =
|
|
36
|
+
var thresholdBlockNumber = knownHeight - param.maxReorgDepth | 0;
|
|
37
37
|
var copy = {};
|
|
38
38
|
for(var idx = 0 ,idx_finish = ascBlockNumberKeys.length; idx < idx_finish; ++idx){
|
|
39
39
|
var blockNumberKey = ascBlockNumberKeys[idx];
|
|
@@ -47,10 +47,10 @@ function getDataByBlockNumberCopyInThreshold(param, currentBlockHeight) {
|
|
|
47
47
|
return copy;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function registerReorgGuard(self, reorgGuard,
|
|
50
|
+
function registerReorgGuard(self, reorgGuard, knownHeight) {
|
|
51
51
|
var maxReorgDepth = self.maxReorgDepth;
|
|
52
52
|
var shouldRollbackOnReorg = self.shouldRollbackOnReorg;
|
|
53
|
-
var dataByBlockNumberCopyInThreshold = getDataByBlockNumberCopyInThreshold(self,
|
|
53
|
+
var dataByBlockNumberCopyInThreshold = getDataByBlockNumberCopyInThreshold(self, knownHeight);
|
|
54
54
|
var prevRangeLastBlock = reorgGuard.prevRangeLastBlock;
|
|
55
55
|
var rangeLastBlock = reorgGuard.rangeLastBlock;
|
|
56
56
|
var scannedBlock = dataByBlockNumberCopyInThreshold[String(rangeLastBlock.blockNumber)];
|
|
@@ -159,10 +159,10 @@ function rollbackToValidBlockNumber(param, blockNumber) {
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
function getThresholdBlockNumbersBelowBlock(self, blockNumber,
|
|
162
|
+
function getThresholdBlockNumbersBelowBlock(self, blockNumber, knownHeight) {
|
|
163
163
|
var arr = [];
|
|
164
164
|
var ascBlockNumberKeys = Object.keys(self.dataByBlockNumber);
|
|
165
|
-
var thresholdBlockNumber =
|
|
165
|
+
var thresholdBlockNumber = knownHeight - self.maxReorgDepth | 0;
|
|
166
166
|
for(var idx = 0 ,idx_finish = ascBlockNumberKeys.length; idx < idx_finish; ++idx){
|
|
167
167
|
var blockNumberKey = ascBlockNumberKeys[idx];
|
|
168
168
|
var scannedBlock = self.dataByBlockNumber[blockNumberKey];
|