envio 3.5.0-alpha.2 → 3.5.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/Batch.res +8 -8
- package/src/Batch.res.mjs +4 -3
- package/src/BatchProcessing.res +24 -0
- package/src/BatchProcessing.res.mjs +12 -0
- package/src/ChainFetching.res +20 -19
- package/src/ChainFetching.res.mjs +14 -14
- package/src/ChainId.res +58 -0
- package/src/ChainId.res.mjs +49 -0
- package/src/ChainId.resi +27 -0
- package/src/ChainMap.res +12 -26
- package/src/ChainMap.res.mjs +5 -41
- package/src/ChainMap.resi +5 -20
- package/src/ChainMetadata.res +1 -1
- package/src/ChainMetadata.res.mjs +3 -2
- package/src/ChainState.res +45 -24
- package/src/ChainState.res.mjs +40 -16
- package/src/ChainState.resi +3 -1
- package/src/Config.res +43 -26
- package/src/Config.res.mjs +19 -16
- package/src/ContractRegisterContext.res +1 -1
- package/src/ContractRegisterContext.res.mjs +1 -1
- package/src/Core.res +1 -0
- package/src/CrossChainState.res +90 -22
- package/src/CrossChainState.res.mjs +55 -16
- package/src/CrossChainState.resi +5 -1
- package/src/Env.res +0 -3
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +1 -1
- package/src/EventProcessing.res +4 -4
- package/src/EventProcessing.res.mjs +5 -5
- package/src/FetchState.res +489 -153
- package/src/FetchState.res.mjs +399 -129
- package/src/FinalizeBackfill.res +61 -0
- package/src/FinalizeBackfill.res.mjs +44 -0
- package/src/HandlerRegister.res +8 -8
- package/src/HandlerRegister.res.mjs +5 -4
- package/src/HandlerRegister.resi +1 -1
- package/src/InMemoryStore.res +4 -0
- package/src/InMemoryStore.res.mjs +1 -1
- package/src/InMemoryTable.res +15 -15
- package/src/InMemoryTable.res.mjs +14 -14
- package/src/IndexerLoop.res +9 -2
- package/src/IndexerLoop.res.mjs +8 -1
- package/src/IndexerState.res +52 -23
- package/src/IndexerState.res.mjs +52 -14
- package/src/IndexerState.resi +11 -6
- package/src/Internal.res +19 -17
- package/src/Internal.res.mjs +18 -9
- package/src/LoadLayer.res +10 -2
- package/src/LoadLayer.res.mjs +3 -1
- package/src/LogSelection.res +2 -2
- package/src/Main.res +7 -11
- package/src/Main.res.mjs +4 -6
- package/src/Metrics.res +6 -6
- package/src/Metrics.res.mjs +4 -3
- package/src/Persistence.res +23 -4
- package/src/PgStorage.res +447 -100
- package/src/PgStorage.res.mjs +285 -99
- package/src/RawEvent.res +1 -2
- package/src/RawEvent.res.mjs +1 -1
- package/src/Rollback.res +18 -20
- package/src/Rollback.res.mjs +9 -9
- package/src/RollbackCommit.res +2 -2
- package/src/RollbackCommit.res.mjs +3 -3
- package/src/SafeCheckpointTracking.res +2 -2
- package/src/SimulateDeadInputTracker.res +17 -21
- package/src/SimulateDeadInputTracker.res.mjs +9 -8
- package/src/SimulateItems.res +8 -10
- package/src/SimulateItems.res.mjs +9 -10
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +3 -2
- package/src/TestIndexer.res +14 -14
- package/src/TestIndexer.res.mjs +16 -10
- package/src/UserContext.res +2 -2
- package/src/UserContext.res.mjs +2 -1
- package/src/Utils.res +0 -4
- package/src/Utils.res.mjs +1 -6
- package/src/bindings/ClickHouse.res +20 -2
- package/src/bindings/ClickHouse.res.mjs +25 -14
- package/src/db/EntityFilter.res +0 -4
- package/src/db/EntityFilter.res.mjs +1 -8
- package/src/db/EntityHistory.res +1 -1
- package/src/db/IndexCatalog.res +248 -0
- package/src/db/IndexCatalog.res.mjs +222 -0
- package/src/db/IndexDefinition.res +131 -0
- package/src/db/IndexDefinition.res.mjs +138 -0
- package/src/db/IndexManager.res +145 -0
- package/src/db/IndexManager.res.mjs +130 -0
- package/src/db/InternalTable.res +54 -23
- package/src/db/InternalTable.res.mjs +38 -23
- package/src/db/Table.res +24 -14
- package/src/db/Table.res.mjs +21 -16
- package/src/sources/AddressSet.res +5 -4
- package/src/sources/AddressStore.res +25 -14
- package/src/sources/AddressStore.res.mjs +10 -12
- package/src/sources/Evm.res +2 -2
- package/src/sources/Evm.res.mjs +1 -1
- package/src/sources/EvmChain.res +3 -3
- package/src/sources/EvmChain.res.mjs +3 -3
- package/src/sources/EvmHyperSyncSource.res +7 -7
- package/src/sources/EvmHyperSyncSource.res.mjs +6 -6
- package/src/sources/Fuel.res +2 -2
- package/src/sources/Fuel.res.mjs +1 -1
- package/src/sources/FuelHyperSyncClient.res +3 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +1 -0
- package/src/sources/FuelHyperSyncSource.res +5 -7
- package/src/sources/FuelHyperSyncSource.res.mjs +5 -5
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +5 -0
- package/src/sources/HyperSyncClient.res.mjs +1 -0
- package/src/sources/RpcSource.res +13 -14
- package/src/sources/RpcSource.res.mjs +13 -12
- package/src/sources/SimulateSource.res +42 -15
- package/src/sources/SimulateSource.res.mjs +27 -9
- package/src/sources/Source.res +1 -5
- package/src/sources/SourceManager.res +12 -12
- package/src/sources/SourceManager.res.mjs +11 -10
- package/src/sources/SourceManager.resi +2 -2
- package/src/sources/Svm.res +4 -5
- package/src/sources/Svm.res.mjs +5 -4
- package/src/sources/SvmHyperSyncClient.res +3 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +1 -0
- package/src/sources/SvmHyperSyncSource.res +4 -4
- package/src/sources/SvmHyperSyncSource.res.mjs +3 -3
- package/src/tui/Tui.res +1 -1
- package/src/tui/Tui.res.mjs +2 -1
- package/src/tui/components/CustomHooks.res +5 -4
- package/src/tui/components/CustomHooks.res.mjs +4 -2
package/src/ChainMap.res.mjs
CHANGED
|
@@ -1,78 +1,42 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Belt_Id from "@rescript/runtime/lib/es6/Belt_Id.js";
|
|
4
|
+
import * as ChainId from "./ChainId.res.mjs";
|
|
4
5
|
import * as Belt_Map from "@rescript/runtime/lib/es6/Belt_Map.js";
|
|
5
|
-
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
6
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
6
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
7
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
9
8
|
|
|
10
|
-
function toString(chainId) {
|
|
11
|
-
return chainId.toString();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function makeUnsafe(chainId) {
|
|
15
|
-
return chainId;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let Chain = {
|
|
19
|
-
toString: toString,
|
|
20
|
-
makeUnsafe: makeUnsafe
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
function cmp(a, b) {
|
|
24
|
-
return Primitive_int.compare(a, b) | 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
9
|
let ChainIdCmp = Belt_Id.MakeComparable({
|
|
28
|
-
cmp:
|
|
10
|
+
cmp: ChainId.compare
|
|
29
11
|
});
|
|
30
12
|
|
|
31
13
|
function fromArrayUnsafe(arr) {
|
|
32
14
|
return Belt_Map.fromArray(arr, ChainIdCmp);
|
|
33
15
|
}
|
|
34
16
|
|
|
35
|
-
function get(self,
|
|
36
|
-
let v = Belt_Map.get(self,
|
|
17
|
+
function get(self, chainId) {
|
|
18
|
+
let v = Belt_Map.get(self, chainId);
|
|
37
19
|
if (v !== undefined) {
|
|
38
20
|
return Primitive_option.valFromOption(v);
|
|
39
21
|
} else {
|
|
40
|
-
return Stdlib_JsError.throwWithMessage("No chain with id " +
|
|
22
|
+
return Stdlib_JsError.throwWithMessage("No chain with id " + ChainId.toString(chainId) + " found in chain map");
|
|
41
23
|
}
|
|
42
24
|
}
|
|
43
25
|
|
|
44
|
-
let set = Belt_Map.set;
|
|
45
|
-
|
|
46
26
|
let values = Belt_Map.valuesToArray;
|
|
47
27
|
|
|
48
28
|
let keys = Belt_Map.keysToArray;
|
|
49
29
|
|
|
50
|
-
let entries = Belt_Map.toArray;
|
|
51
|
-
|
|
52
30
|
let has = Belt_Map.has;
|
|
53
31
|
|
|
54
|
-
let map = Belt_Map.map;
|
|
55
|
-
|
|
56
32
|
let mapWithKey = Belt_Map.mapWithKey;
|
|
57
33
|
|
|
58
|
-
let size = Belt_Map.size;
|
|
59
|
-
|
|
60
|
-
function update(map, chain, updateFn) {
|
|
61
|
-
return Belt_Map.update(map, chain, opt => Stdlib_Option.map(opt, updateFn));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
34
|
export {
|
|
65
|
-
Chain,
|
|
66
35
|
fromArrayUnsafe,
|
|
67
36
|
get,
|
|
68
|
-
set,
|
|
69
37
|
values,
|
|
70
38
|
keys,
|
|
71
|
-
entries,
|
|
72
39
|
has,
|
|
73
|
-
map,
|
|
74
40
|
mapWithKey,
|
|
75
|
-
size,
|
|
76
|
-
update,
|
|
77
41
|
}
|
|
78
42
|
/* ChainIdCmp Not a pure module */
|
package/src/ChainMap.resi
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
module Chain: {
|
|
2
|
-
type t
|
|
3
|
-
|
|
4
|
-
external toChainId: t => int = "%identity"
|
|
5
|
-
|
|
6
|
-
let toString: t => string
|
|
7
|
-
|
|
8
|
-
let makeUnsafe: (~chainId: int) => t
|
|
9
|
-
}
|
|
10
|
-
|
|
11
1
|
type t<'a>
|
|
12
|
-
let fromArrayUnsafe: array<(
|
|
13
|
-
let get: (t<'a>,
|
|
14
|
-
let set: (t<'a>, Chain.t, 'a) => t<'a>
|
|
2
|
+
let fromArrayUnsafe: array<(ChainId.t, 'a)> => t<'a>
|
|
3
|
+
let get: (t<'a>, ChainId.t) => 'a
|
|
15
4
|
let values: t<'a> => array<'a>
|
|
16
|
-
let keys: t<'a> => array<
|
|
17
|
-
let
|
|
18
|
-
let
|
|
19
|
-
let map: (t<'a>, 'a => 'b) => t<'b>
|
|
20
|
-
let mapWithKey: (t<'a>, (Chain.t, 'a) => 'b) => t<'b>
|
|
21
|
-
let size: t<'a> => int
|
|
22
|
-
let update: (t<'a>, Chain.t, 'a => 'a) => t<'a>
|
|
5
|
+
let keys: t<'a> => array<ChainId.t>
|
|
6
|
+
let has: (t<'a>, ChainId.t) => bool
|
|
7
|
+
let mapWithKey: (t<'a>, (ChainId.t, 'a) => 'b) => t<'b>
|
package/src/ChainMetadata.res
CHANGED
|
@@ -8,7 +8,7 @@ let stage = (state: IndexerState.t) => {
|
|
|
8
8
|
->Dict.valuesToArray
|
|
9
9
|
->Array.forEach(cs => {
|
|
10
10
|
chainsData->Dict.set(
|
|
11
|
-
(cs->ChainState.chainConfig).id->
|
|
11
|
+
(cs->ChainState.chainConfig).id->ChainId.toString,
|
|
12
12
|
cs->ChainState.toChainMetadata,
|
|
13
13
|
)
|
|
14
14
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as ChainId from "./ChainId.res.mjs";
|
|
3
4
|
import * as Writing from "./Writing.res.mjs";
|
|
4
5
|
import * as ChainState from "./ChainState.res.mjs";
|
|
5
6
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
@@ -7,7 +8,7 @@ import * as IndexerState from "./IndexerState.res.mjs";
|
|
|
7
8
|
function stage(state) {
|
|
8
9
|
let chainsData = {};
|
|
9
10
|
Object.values(IndexerState.chainStates(state)).forEach(cs => {
|
|
10
|
-
chainsData[ChainState.chainConfig(cs).id
|
|
11
|
+
chainsData[ChainId.toString(ChainState.chainConfig(cs).id)] = ChainState.toChainMetadata(cs);
|
|
11
12
|
});
|
|
12
13
|
Writing.setChainMeta(state, chainsData);
|
|
13
14
|
}
|
|
@@ -15,4 +16,4 @@ function stage(state) {
|
|
|
15
16
|
export {
|
|
16
17
|
stage,
|
|
17
18
|
}
|
|
18
|
-
/*
|
|
19
|
+
/* ChainId Not a pure module */
|
package/src/ChainState.res
CHANGED
|
@@ -69,13 +69,13 @@ let configAddresses = (chainConfig: Config.chain): array<Internal.indexingAddres
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
let validateOnEventRegistrations = (
|
|
72
|
-
~chainId:
|
|
72
|
+
~chainId: ChainId.t,
|
|
73
73
|
registrations: array<Internal.onEventRegistration>,
|
|
74
74
|
) =>
|
|
75
75
|
registrations->Array.forEachWithIndex((registration, expectedIndex) => {
|
|
76
76
|
if registration.index !== expectedIndex {
|
|
77
77
|
JsError.throwWithMessage(
|
|
78
|
-
`Invalid onEvent registration index for chain ${chainId->
|
|
78
|
+
`Invalid onEvent registration index for chain ${chainId->ChainId.toString}: ${registration.eventConfig.contractName}.${registration.eventConfig.name} has index ${registration.index->Int.toString}, but its ChainState position is ${expectedIndex->Int.toString}.`,
|
|
79
79
|
)
|
|
80
80
|
}
|
|
81
81
|
})
|
|
@@ -147,6 +147,7 @@ let makeInternal = (
|
|
|
147
147
|
~reorgCheckpoints: array<Internal.reorgCheckpoint>,
|
|
148
148
|
~maxReorgDepth,
|
|
149
149
|
~knownHeight=0,
|
|
150
|
+
~isResumed=false,
|
|
150
151
|
~reducedPollingInterval=?,
|
|
151
152
|
): t => {
|
|
152
153
|
// Handler binding + `where`-derived fetch state, and onBlock registrations,
|
|
@@ -154,7 +155,7 @@ let makeInternal = (
|
|
|
154
155
|
// chain - this just looks up this chain's slice.
|
|
155
156
|
let {onEventRegistrations, onBlockRegistrations} =
|
|
156
157
|
registrationsByChainId
|
|
157
|
-
->Utils.Dict.dangerouslyGetNonOption(chainConfig.id->
|
|
158
|
+
->Utils.Dict.dangerouslyGetNonOption(chainConfig.id->ChainId.toString)
|
|
158
159
|
->Option.getOr({onEventRegistrations: [], onBlockRegistrations: []})
|
|
159
160
|
|
|
160
161
|
chainConfig.contracts->Array.forEach(contract => {
|
|
@@ -203,6 +204,7 @@ let makeInternal = (
|
|
|
203
204
|
| Evm => Some(config.clientFilterAddressThreshold)
|
|
204
205
|
| Fuel | Svm => None
|
|
205
206
|
},
|
|
207
|
+
~isResumed,
|
|
206
208
|
)
|
|
207
209
|
|
|
208
210
|
let chainReorgCheckpoints = reorgCheckpoints->Array.filterMap(reorgCheckpoint => {
|
|
@@ -214,7 +216,7 @@ let makeInternal = (
|
|
|
214
216
|
})
|
|
215
217
|
|
|
216
218
|
// Create sources lazily here - this is where API token validation happens
|
|
217
|
-
let
|
|
219
|
+
let chainId = chainConfig.id
|
|
218
220
|
let sources = switch chainConfig.sourceConfig {
|
|
219
221
|
| Config.EvmSourceConfig({hypersync, rpcs}) =>
|
|
220
222
|
let evmRpcs: array<EvmChain.rpc> = rpcs->Array.map((rpc): EvmChain.rpc => {
|
|
@@ -230,7 +232,7 @@ let makeInternal = (
|
|
|
230
232
|
}
|
|
231
233
|
})
|
|
232
234
|
EvmChain.makeSources(
|
|
233
|
-
~
|
|
235
|
+
~chainId,
|
|
234
236
|
~onEventRegistrations=onEventRegistrations->(
|
|
235
237
|
Utils.magic: array<Internal.onEventRegistration> => array<Internal.evmOnEventRegistration>
|
|
236
238
|
),
|
|
@@ -241,7 +243,7 @@ let makeInternal = (
|
|
|
241
243
|
)
|
|
242
244
|
| Config.FuelSourceConfig({hypersync}) => [
|
|
243
245
|
FuelHyperSyncSource.make({
|
|
244
|
-
|
|
246
|
+
chainId,
|
|
245
247
|
endpointUrl: hypersync,
|
|
246
248
|
apiToken: Env.envioApiToken,
|
|
247
249
|
onEventRegistrations,
|
|
@@ -251,17 +253,15 @@ let makeInternal = (
|
|
|
251
253
|
| Config.SvmSourceConfig({hypersync, rpc}) =>
|
|
252
254
|
switch (hypersync, rpc) {
|
|
253
255
|
| (None, None) =>
|
|
254
|
-
JsError.throwWithMessage(
|
|
255
|
-
|
|
256
|
-
)
|
|
257
|
-
| (None, Some(rpc)) => [Svm.makeRPCSource(~chain, ~rpc)]
|
|
256
|
+
JsError.throwWithMessage(`Chain ${chainId->ChainId.toString} has no SVM data source`)
|
|
257
|
+
| (None, Some(rpc)) => [Svm.makeRPCSource(~chainId, ~rpc)]
|
|
258
258
|
| (Some(hypersyncUrl), _) =>
|
|
259
259
|
// HyperSync drives instruction sync. A configured RPC is ignored for now
|
|
260
260
|
// (RPC fallback isn't wired up yet).
|
|
261
261
|
let apiToken = Env.envioApiToken
|
|
262
262
|
[
|
|
263
263
|
SvmHyperSyncSource.make({
|
|
264
|
-
|
|
264
|
+
chainId,
|
|
265
265
|
endpointUrl: hypersyncUrl,
|
|
266
266
|
apiToken,
|
|
267
267
|
onEventRegistrations,
|
|
@@ -270,6 +270,9 @@ let makeInternal = (
|
|
|
270
270
|
}),
|
|
271
271
|
]
|
|
272
272
|
}
|
|
273
|
+
| Config.SimulateSourceConfig({items, endBlock}) => [
|
|
274
|
+
SimulateSource.make(~items, ~endBlock, ~chainId, ~addressStore),
|
|
275
|
+
]
|
|
273
276
|
// For tests: use ready-to-use sources directly
|
|
274
277
|
| Config.CustomSources(sources) => sources
|
|
275
278
|
}
|
|
@@ -375,14 +378,13 @@ let makeFromDbState = (
|
|
|
375
378
|
~maxReorgDepth=resumedChainState.maxReorgDepth,
|
|
376
379
|
~firstEventBlock=resumedChainState.firstEventBlockNumber,
|
|
377
380
|
~progressBlockNumber,
|
|
378
|
-
~timestampCaughtUpToHeadOrEndblock=
|
|
379
|
-
? None
|
|
380
|
-
: resumedChainState.timestampCaughtUpToHeadOrEndblock,
|
|
381
|
+
~timestampCaughtUpToHeadOrEndblock=resumedChainState.timestampCaughtUpToHeadOrEndblock,
|
|
381
382
|
~numEventsProcessed=resumedChainState.numEventsProcessed,
|
|
382
383
|
~logger,
|
|
383
384
|
~isInReorgThreshold,
|
|
384
385
|
~isRealtime,
|
|
385
386
|
~knownHeight=resumedChainState.sourceBlockNumber,
|
|
387
|
+
~isResumed=true,
|
|
386
388
|
~reducedPollingInterval?,
|
|
387
389
|
)
|
|
388
390
|
}
|
|
@@ -612,6 +614,24 @@ let hasProcessedToEndblock = (cs: t) => {
|
|
|
612
614
|
}
|
|
613
615
|
}
|
|
614
616
|
|
|
617
|
+
// Caught up as judged by persisted values alone: progress reached the endBlock,
|
|
618
|
+
// or the head the previous run had already observed (less the lag that holds the
|
|
619
|
+
// tip back). Unlike `isFetchingAtHead` this doesn't move when a fresh height
|
|
620
|
+
// lands, so a run resumed at the head still knows it was caught up even once the
|
|
621
|
+
// head has run away from it while the indexer was down.
|
|
622
|
+
let isDurablyCaughtUp = (cs: t) => {
|
|
623
|
+
let {committedProgressBlockNumber, fetchState} = cs
|
|
624
|
+
switch fetchState.endBlock {
|
|
625
|
+
| Some(endBlock) => committedProgressBlockNumber >= endBlock
|
|
626
|
+
| None =>
|
|
627
|
+
// The configured lag, not the fetch state's: pre-threshold that one also
|
|
628
|
+
// carries maxReorgDepth, which would read a chain a whole reorg depth behind
|
|
629
|
+
// the head as caught up.
|
|
630
|
+
fetchState.knownHeight > 0 &&
|
|
631
|
+
committedProgressBlockNumber >= fetchState.knownHeight - cs.chainConfig.blockLag
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
615
635
|
let getHighestBlockBelowThreshold = (cs: t): int => {
|
|
616
636
|
let highestBlockBelowThreshold = cs.fetchState.knownHeight - cs.chainConfig.maxReorgDepth
|
|
617
637
|
highestBlockBelowThreshold < 0 ? 0 : highestBlockBelowThreshold
|
|
@@ -908,7 +928,7 @@ let toChainMetadata = (cs: t): InternalTable.Chains.metaFields => {
|
|
|
908
928
|
}
|
|
909
929
|
|
|
910
930
|
let toMetrics = (cs: t): Metrics.chainMetrics => {
|
|
911
|
-
chainId: cs.chainConfig.id
|
|
931
|
+
chainId: cs.chainConfig.id,
|
|
912
932
|
poweredByHyperSync: (cs.sourceManager->SourceManager.getActiveSource).poweredByHyperSync,
|
|
913
933
|
firstEventBlockNumber: cs.fetchState.firstEventBlock,
|
|
914
934
|
latestProcessedBlock: cs.committedProgressBlockNumber === -1
|
|
@@ -958,7 +978,7 @@ let toChainBeforeBatch = (cs: t): Batch.chainBeforeBatch => {
|
|
|
958
978
|
// Whether the chain's post-batch fetch frontier is ready to cross into the reorg
|
|
959
979
|
// threshold, using the batch's progressed frontier when this chain advanced.
|
|
960
980
|
let isReadyToEnterReorgThresholdAfterBatch = (cs: t, ~batch: Batch.t) => {
|
|
961
|
-
let fetchState = switch batch.progressedChainsById->
|
|
981
|
+
let fetchState = switch batch.progressedChainsById->ChainId.Dict.dangerouslyGetNonOption(
|
|
962
982
|
cs.fetchState.chainId,
|
|
963
983
|
) {
|
|
964
984
|
| Some(chainAfterBatch) => chainAfterBatch.fetchState
|
|
@@ -970,9 +990,7 @@ let isReadyToEnterReorgThresholdAfterBatch = (cs: t, ~batch: Batch.t) => {
|
|
|
970
990
|
// Commit the post-batch fetch frontier for a chain that progressed in the batch,
|
|
971
991
|
// applying blockLag when this batch also crosses into the reorg threshold.
|
|
972
992
|
let advanceAfterBatch = (cs: t, ~batch: Batch.t, ~enteringReorgThreshold) =>
|
|
973
|
-
switch batch.progressedChainsById->
|
|
974
|
-
cs.fetchState.chainId,
|
|
975
|
-
) {
|
|
993
|
+
switch batch.progressedChainsById->ChainId.Dict.dangerouslyGetNonOption(cs.fetchState.chainId) {
|
|
976
994
|
| Some(chainAfterBatch) =>
|
|
977
995
|
cs.fetchState = enteringReorgThreshold
|
|
978
996
|
? chainAfterBatch.fetchState->FetchState.updateInternal(~blockLag=cs.chainConfig.blockLag)
|
|
@@ -992,7 +1010,7 @@ let advanceAfterBatch = (cs: t, ~batch: Batch.t, ~enteringReorgThreshold) =>
|
|
|
992
1010
|
let applyBatchProgress = (cs: t, ~batch: Batch.t, ~blockTimestampName: string) => {
|
|
993
1011
|
let chainId = cs.chainConfig.id
|
|
994
1012
|
|
|
995
|
-
switch batch.progressedChainsById->
|
|
1013
|
+
switch batch.progressedChainsById->ChainId.Dict.dangerouslyGetNonOption(chainId) {
|
|
996
1014
|
| Some(chainAfterBatch) => {
|
|
997
1015
|
// Calculate and set latency metrics. The payload block is materialised or
|
|
998
1016
|
// inline by processing time; its timestamp may still be absent (e.g. an
|
|
@@ -1082,11 +1100,14 @@ let applyBatchProgress = (cs: t, ~batch: Batch.t, ~blockTimestampName: string) =
|
|
|
1082
1100
|
}
|
|
1083
1101
|
|
|
1084
1102
|
// Mark the chain caught up to head/endblock. Called by CrossChainState only once
|
|
1085
|
-
// every chain in the indexer is caught up
|
|
1086
|
-
//
|
|
1087
|
-
|
|
1103
|
+
// every chain in the indexer is caught up and the deferred schema indexes are
|
|
1104
|
+
// committed, so no chain flips to ready while another is still backfilling or
|
|
1105
|
+
// while an index the schema promises is still missing. `readyAt` is the
|
|
1106
|
+
// timestamp already committed to `envio_chains.ready_at` in that same
|
|
1107
|
+
// transaction. Sticky: a chain stays ready once set.
|
|
1108
|
+
let markReady = (cs: t, ~readyAt) =>
|
|
1088
1109
|
if !(cs->isReady) {
|
|
1089
|
-
cs.timestampCaughtUpToHeadOrEndblock =
|
|
1110
|
+
cs.timestampCaughtUpToHeadOrEndblock = Some(readyAt)
|
|
1090
1111
|
}
|
|
1091
1112
|
|
|
1092
1113
|
// Roll a chain back to a reorg target. With a progress diff, restore fetch/
|
package/src/ChainState.res.mjs
CHANGED
|
@@ -4,8 +4,8 @@ import * as Env from "./Env.res.mjs";
|
|
|
4
4
|
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
5
|
import * as Batch from "./Batch.res.mjs";
|
|
6
6
|
import * as Utils from "./Utils.res.mjs";
|
|
7
|
+
import * as ChainId from "./ChainId.res.mjs";
|
|
7
8
|
import * as Logging from "./Logging.res.mjs";
|
|
8
|
-
import * as ChainMap from "./ChainMap.res.mjs";
|
|
9
9
|
import * as EvmChain from "./sources/EvmChain.res.mjs";
|
|
10
10
|
import * as FieldMask from "./sources/FieldMask.res.mjs";
|
|
11
11
|
import * as BlockStore from "./sources/BlockStore.res.mjs";
|
|
@@ -17,6 +17,7 @@ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
|
17
17
|
import * as SourceManager from "./sources/SourceManager.res.mjs";
|
|
18
18
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
19
19
|
import * as ReorgDetection from "./ReorgDetection.res.mjs";
|
|
20
|
+
import * as SimulateSource from "./sources/SimulateSource.res.mjs";
|
|
20
21
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
21
22
|
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
|
|
22
23
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
@@ -42,7 +43,7 @@ function configAddresses(chainConfig) {
|
|
|
42
43
|
function validateOnEventRegistrations(chainId, registrations) {
|
|
43
44
|
registrations.forEach((registration, expectedIndex) => {
|
|
44
45
|
if (registration.index !== expectedIndex) {
|
|
45
|
-
return Stdlib_JsError.throwWithMessage(`Invalid onEvent registration index for chain ` +
|
|
46
|
+
return Stdlib_JsError.throwWithMessage(`Invalid onEvent registration index for chain ` + ChainId.toString(chainId) + `: ` + registration.eventConfig.contractName + `.` + registration.eventConfig.name + ` has index ` + registration.index.toString() + `, but its ChainState position is ` + expectedIndex.toString() + `.`);
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
}
|
|
@@ -89,10 +90,11 @@ function make(chainConfig, fetchState, onEventRegistrationsOpt, addressStore, so
|
|
|
89
90
|
};
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrationsByChainId, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, reducedPollingInterval) {
|
|
93
|
+
function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrationsByChainId, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, isResumedOpt, reducedPollingInterval) {
|
|
93
94
|
let firstEventBlock = firstEventBlockOpt !== undefined ? Primitive_option.valFromOption(firstEventBlockOpt) : undefined;
|
|
94
95
|
let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
|
|
95
|
-
let
|
|
96
|
+
let isResumed = isResumedOpt !== undefined ? isResumedOpt : false;
|
|
97
|
+
let match = Stdlib_Option.getOr(registrationsByChainId[ChainId.toString(chainConfig.id)], {
|
|
96
98
|
onEventRegistrations: [],
|
|
97
99
|
onBlockRegistrations: []
|
|
98
100
|
});
|
|
@@ -116,13 +118,13 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
116
118
|
tmp = undefined;
|
|
117
119
|
break;
|
|
118
120
|
}
|
|
119
|
-
let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, match.onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock), Primitive_option.some(tmp));
|
|
121
|
+
let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, addressStore, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, match.onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock), Primitive_option.some(tmp), isResumed);
|
|
120
122
|
let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
|
|
121
123
|
if (reorgCheckpoint.chain_id === chainConfig.id) {
|
|
122
124
|
return reorgCheckpoint;
|
|
123
125
|
}
|
|
124
126
|
});
|
|
125
|
-
let
|
|
127
|
+
let chainId = chainConfig.id;
|
|
126
128
|
let sources = chainConfig.sourceConfig;
|
|
127
129
|
let sources$1;
|
|
128
130
|
switch (sources.TAG) {
|
|
@@ -139,11 +141,11 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
139
141
|
headers: headers
|
|
140
142
|
};
|
|
141
143
|
});
|
|
142
|
-
sources$1 = EvmChain.makeSources(
|
|
144
|
+
sources$1 = EvmChain.makeSources(chainId, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore);
|
|
143
145
|
break;
|
|
144
146
|
case "FuelSourceConfig" :
|
|
145
147
|
sources$1 = [FuelHyperSyncSource.make({
|
|
146
|
-
|
|
148
|
+
chainId: chainId,
|
|
147
149
|
endpointUrl: sources.hypersync,
|
|
148
150
|
apiToken: Env.envioApiToken,
|
|
149
151
|
onEventRegistrations: onEventRegistrations,
|
|
@@ -154,16 +156,19 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
|
|
|
154
156
|
let rpc = sources.rpc;
|
|
155
157
|
let hypersync = sources.hypersync;
|
|
156
158
|
sources$1 = hypersync !== undefined ? [SvmHyperSyncSource.make({
|
|
157
|
-
|
|
159
|
+
chainId: chainId,
|
|
158
160
|
endpointUrl: hypersync,
|
|
159
161
|
apiToken: Env.envioApiToken,
|
|
160
162
|
onEventRegistrations: onEventRegistrations,
|
|
161
163
|
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
|
|
162
164
|
addressStore: addressStore
|
|
163
165
|
})] : (
|
|
164
|
-
rpc !== undefined ? [Svm.makeRPCSource(
|
|
166
|
+
rpc !== undefined ? [Svm.makeRPCSource(chainId, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + ChainId.toString(chainId) + ` has no SVM data source`)
|
|
165
167
|
);
|
|
166
168
|
break;
|
|
169
|
+
case "SimulateSourceConfig" :
|
|
170
|
+
sources$1 = [SimulateSource.make(sources.items, sources.endBlock, chainId, addressStore)];
|
|
171
|
+
break;
|
|
167
172
|
case "CustomSources" :
|
|
168
173
|
sources$1 = sources._0;
|
|
169
174
|
break;
|
|
@@ -177,7 +182,7 @@ function makeFromConfig(chainConfig, config, registrationsByChainId, knownHeight
|
|
|
177
182
|
let logger = Logging.createChild({
|
|
178
183
|
chainId: chainConfig.id
|
|
179
184
|
});
|
|
180
|
-
return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrationsByChainId, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
|
|
185
|
+
return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrationsByChainId, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined, undefined);
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval) {
|
|
@@ -186,7 +191,7 @@ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInR
|
|
|
186
191
|
chainId: chainId
|
|
187
192
|
});
|
|
188
193
|
let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
|
|
189
|
-
return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrationsByChainId, logger,
|
|
194
|
+
return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrationsByChainId, logger, resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, true, reducedPollingInterval);
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
function logger(cs) {
|
|
@@ -283,6 +288,11 @@ function startFetchingQueries(cs, queries) {
|
|
|
283
288
|
cs.pendingBudget = cs.pendingBudget + Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.itemsEst);
|
|
284
289
|
}
|
|
285
290
|
|
|
291
|
+
function resetPendingQueries(cs) {
|
|
292
|
+
cs.fetchState = FetchState.resetPendingQueries(cs.fetchState);
|
|
293
|
+
cs.pendingBudget = 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
286
296
|
function isReady(cs) {
|
|
287
297
|
return cs.timestampCaughtUpToHeadOrEndblock !== undefined;
|
|
288
298
|
}
|
|
@@ -389,6 +399,19 @@ function hasProcessedToEndblock(cs) {
|
|
|
389
399
|
}
|
|
390
400
|
}
|
|
391
401
|
|
|
402
|
+
function isDurablyCaughtUp(cs) {
|
|
403
|
+
let fetchState = cs.fetchState;
|
|
404
|
+
let committedProgressBlockNumber = cs.committedProgressBlockNumber;
|
|
405
|
+
let endBlock = fetchState.endBlock;
|
|
406
|
+
if (endBlock !== undefined) {
|
|
407
|
+
return committedProgressBlockNumber >= endBlock;
|
|
408
|
+
} else if (fetchState.knownHeight > 0) {
|
|
409
|
+
return committedProgressBlockNumber >= (fetchState.knownHeight - cs.chainConfig.blockLag | 0);
|
|
410
|
+
} else {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
392
415
|
function getHighestBlockBelowThreshold(cs) {
|
|
393
416
|
let highestBlockBelowThreshold = cs.fetchState.knownHeight - cs.chainConfig.maxReorgDepth | 0;
|
|
394
417
|
if (highestBlockBelowThreshold < 0) {
|
|
@@ -564,8 +587,7 @@ function prepareReorg(cs, eventsProcessedDiff) {
|
|
|
564
587
|
if (eventsProcessedDiff !== undefined) {
|
|
565
588
|
cs.numEventsProcessed = cs.numEventsProcessed + eventsProcessedDiff;
|
|
566
589
|
}
|
|
567
|
-
|
|
568
|
-
cs.pendingBudget = 0;
|
|
590
|
+
resetPendingQueries(cs);
|
|
569
591
|
}
|
|
570
592
|
|
|
571
593
|
function updateKnownHeight(cs, knownHeight) {
|
|
@@ -757,9 +779,9 @@ function applyBatchProgress(cs, batch, blockTimestampName) {
|
|
|
757
779
|
}
|
|
758
780
|
}
|
|
759
781
|
|
|
760
|
-
function markReady(cs) {
|
|
782
|
+
function markReady(cs, readyAt) {
|
|
761
783
|
if (cs.timestampCaughtUpToHeadOrEndblock === undefined) {
|
|
762
|
-
cs.timestampCaughtUpToHeadOrEndblock =
|
|
784
|
+
cs.timestampCaughtUpToHeadOrEndblock = readyAt;
|
|
763
785
|
return;
|
|
764
786
|
}
|
|
765
787
|
}
|
|
@@ -831,6 +853,7 @@ export {
|
|
|
831
853
|
toChainBeforeBatch,
|
|
832
854
|
isReadyToEnterReorgThresholdAfterBatch,
|
|
833
855
|
hasProcessedToEndblock,
|
|
856
|
+
isDurablyCaughtUp,
|
|
834
857
|
getHighestBlockBelowThreshold,
|
|
835
858
|
isActivelyIndexing,
|
|
836
859
|
isReady,
|
|
@@ -841,6 +864,7 @@ export {
|
|
|
841
864
|
materializePageItems,
|
|
842
865
|
registerReorgGuard,
|
|
843
866
|
prepareReorg,
|
|
867
|
+
resetPendingQueries,
|
|
844
868
|
updateKnownHeight,
|
|
845
869
|
setEndBlockToFirstEvent,
|
|
846
870
|
enterReorgThreshold,
|
package/src/ChainState.resi
CHANGED
|
@@ -98,6 +98,7 @@ let isReadyToEnterReorgThresholdAfterBatch: (t, ~batch: Batch.t) => bool
|
|
|
98
98
|
|
|
99
99
|
// Derived (pure).
|
|
100
100
|
let hasProcessedToEndblock: t => bool
|
|
101
|
+
let isDurablyCaughtUp: t => bool
|
|
101
102
|
let getHighestBlockBelowThreshold: t => int
|
|
102
103
|
let isActivelyIndexing: t => bool
|
|
103
104
|
let isReady: t => bool
|
|
@@ -132,12 +133,13 @@ let registerReorgGuard: (
|
|
|
132
133
|
~knownHeight: int,
|
|
133
134
|
) => ReorgDetection.reorgResult
|
|
134
135
|
let prepareReorg: (t, ~eventsProcessedDiff: option<float>) => unit
|
|
136
|
+
let resetPendingQueries: t => unit
|
|
135
137
|
let updateKnownHeight: (t, ~knownHeight: int) => unit
|
|
136
138
|
let setEndBlockToFirstEvent: (t, ~blockNumber: int) => unit
|
|
137
139
|
let enterReorgThreshold: t => unit
|
|
138
140
|
let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
|
|
139
141
|
let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
|
|
140
|
-
let markReady: t => unit
|
|
142
|
+
let markReady: (t, ~readyAt: Date.t) => unit
|
|
141
143
|
let rollback: (
|
|
142
144
|
t,
|
|
143
145
|
~newProgressBlockNumber: option<int>,
|